Coverage Report

Created: 2025-06-13 06:29

/src/gdal/ogr/ogrsf_frmts/generic/ogrlayerarrow.cpp
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 *
3
 * Project:  OpenGIS Simple Features Reference Implementation
4
 * Purpose:  Parts of OGRLayer dealing with Arrow C interface
5
 * Author:   Even Rouault, <even dot rouault at spatialys.com>
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2022-2023, Even Rouault <even dot rouault at spatialys.com>
9
 *
10
 * SPDX-License-Identifier: MIT
11
 ****************************************************************************/
12
13
#include "ogrsf_frmts.h"
14
#include "ogr_api.h"
15
#include "ogr_recordbatch.h"
16
#include "ograrrowarrayhelper.h"
17
#include "ogrlayerarrow.h"
18
#include "ogr_p.h"
19
#include "ogr_swq.h"
20
#include "ogr_wkb.h"
21
#include "ogr_p.h"
22
#include "ogrlayer_private.h"
23
24
#include "cpl_float.h"
25
#include "cpl_json.h"
26
#include "cpl_time.h"
27
28
#include <algorithm>
29
#include <cassert>
30
#include <cinttypes>
31
#include <limits>
32
#include <utility>
33
#include <set>
34
35
constexpr const char *MD_GDAL_OGR_TYPE = "GDAL:OGR:type";
36
constexpr const char *MD_GDAL_OGR_ALTERNATIVE_NAME =
37
    "GDAL:OGR:alternative_name";
38
constexpr const char *MD_GDAL_OGR_COMMENT = "GDAL:OGR:comment";
39
constexpr const char *MD_GDAL_OGR_DEFAULT = "GDAL:OGR:default";
40
constexpr const char *MD_GDAL_OGR_SUBTYPE = "GDAL:OGR:subtype";
41
constexpr const char *MD_GDAL_OGR_WIDTH = "GDAL:OGR:width";
42
constexpr const char *MD_GDAL_OGR_UNIQUE = "GDAL:OGR:unique";
43
constexpr const char *MD_GDAL_OGR_DOMAIN_NAME = "GDAL:OGR:domain_name";
44
45
constexpr char ARROW_LETTER_BOOLEAN = 'b';
46
constexpr char ARROW_LETTER_INT8 = 'c';
47
constexpr char ARROW_LETTER_UINT8 = 'C';
48
constexpr char ARROW_LETTER_INT16 = 's';
49
constexpr char ARROW_LETTER_UINT16 = 'S';
50
constexpr char ARROW_LETTER_INT32 = 'i';
51
constexpr char ARROW_LETTER_UINT32 = 'I';
52
constexpr char ARROW_LETTER_INT64 = 'l';
53
constexpr char ARROW_LETTER_UINT64 = 'L';
54
constexpr char ARROW_LETTER_FLOAT16 = 'e';
55
constexpr char ARROW_LETTER_FLOAT32 = 'f';
56
constexpr char ARROW_LETTER_FLOAT64 = 'g';
57
constexpr char ARROW_LETTER_STRING = 'u';
58
constexpr char ARROW_LETTER_LARGE_STRING = 'U';
59
constexpr char ARROW_LETTER_BINARY = 'z';
60
constexpr char ARROW_LETTER_LARGE_BINARY = 'Z';
61
constexpr char ARROW_LETTER_DECIMAL = 'd';
62
constexpr char ARROW_2ND_LETTER_LIST = 'l';
63
constexpr char ARROW_2ND_LETTER_LARGE_LIST = 'L';
64
65
static inline bool IsStructure(const char *format)
66
0
{
67
0
    return format[0] == '+' && format[1] == 's' && format[2] == 0;
68
0
}
69
70
static inline bool IsMap(const char *format)
71
0
{
72
0
    return format[0] == '+' && format[1] == 'm' && format[2] == 0;
73
0
}
74
75
static inline bool IsFixedWidthBinary(const char *format)
76
0
{
77
0
    return format[0] == 'w' && format[1] == ':';
78
0
}
79
80
static inline int GetFixedWithBinary(const char *format)
81
0
{
82
0
    return atoi(format + strlen("w:"));
83
0
}
84
85
static inline bool IsList(const char *format)
86
0
{
87
0
    return format[0] == '+' && format[1] == ARROW_2ND_LETTER_LIST &&
88
0
           format[2] == 0;
89
0
}
90
91
static inline bool IsLargeList(const char *format)
92
0
{
93
0
    return format[0] == '+' && format[1] == ARROW_2ND_LETTER_LARGE_LIST &&
94
0
           format[2] == 0;
95
0
}
96
97
static inline bool IsFixedSizeList(const char *format)
98
0
{
99
0
    return format[0] == '+' && format[1] == 'w' && format[2] == ':';
100
0
}
101
102
static inline int GetFixedSizeList(const char *format)
103
0
{
104
0
    return atoi(format + strlen("+w:"));
105
0
}
106
107
static inline bool IsDecimal(const char *format)
108
0
{
109
0
    return format[0] == ARROW_LETTER_DECIMAL && format[1] == ':';
110
0
}
111
112
static inline bool IsBoolean(const char *format)
113
0
{
114
0
    return format[0] == ARROW_LETTER_BOOLEAN && format[1] == 0;
115
0
}
116
117
static inline bool IsInt8(const char *format)
118
0
{
119
0
    return format[0] == ARROW_LETTER_INT8 && format[1] == 0;
120
0
}
121
122
static inline bool IsUInt8(const char *format)
123
0
{
124
0
    return format[0] == ARROW_LETTER_UINT8 && format[1] == 0;
125
0
}
126
127
static inline bool IsInt16(const char *format)
128
0
{
129
0
    return format[0] == ARROW_LETTER_INT16 && format[1] == 0;
130
0
}
131
132
static inline bool IsUInt16(const char *format)
133
0
{
134
0
    return format[0] == ARROW_LETTER_UINT16 && format[1] == 0;
135
0
}
136
137
static inline bool IsInt32(const char *format)
138
0
{
139
0
    return format[0] == ARROW_LETTER_INT32 && format[1] == 0;
140
0
}
141
142
static inline bool IsUInt32(const char *format)
143
0
{
144
0
    return format[0] == ARROW_LETTER_UINT32 && format[1] == 0;
145
0
}
146
147
static inline bool IsInt64(const char *format)
148
0
{
149
0
    return format[0] == ARROW_LETTER_INT64 && format[1] == 0;
150
0
}
151
152
static inline bool IsUInt64(const char *format)
153
0
{
154
0
    return format[0] == ARROW_LETTER_UINT64 && format[1] == 0;
155
0
}
156
157
static inline bool IsFloat16(const char *format)
158
0
{
159
0
    return format[0] == ARROW_LETTER_FLOAT16 && format[1] == 0;
160
0
}
161
162
static inline bool IsFloat32(const char *format)
163
0
{
164
0
    return format[0] == ARROW_LETTER_FLOAT32 && format[1] == 0;
165
0
}
166
167
static inline bool IsFloat64(const char *format)
168
0
{
169
0
    return format[0] == ARROW_LETTER_FLOAT64 && format[1] == 0;
170
0
}
171
172
static inline bool IsString(const char *format)
173
0
{
174
0
    return format[0] == ARROW_LETTER_STRING && format[1] == 0;
175
0
}
176
177
static inline bool IsLargeString(const char *format)
178
0
{
179
0
    return format[0] == ARROW_LETTER_LARGE_STRING && format[1] == 0;
180
0
}
181
182
static inline bool IsBinary(const char *format)
183
0
{
184
0
    return format[0] == ARROW_LETTER_BINARY && format[1] == 0;
185
0
}
186
187
static inline bool IsLargeBinary(const char *format)
188
0
{
189
0
    return format[0] == ARROW_LETTER_LARGE_BINARY && format[1] == 0;
190
0
}
191
192
static inline bool IsTimestampInternal(const char *format, char chType)
193
0
{
194
0
    return format[0] == 't' && format[1] == 's' && format[2] == chType &&
195
0
           format[3] == ':';
196
0
}
197
198
static inline bool IsTimestampSeconds(const char *format)
199
0
{
200
0
    return IsTimestampInternal(format, 's');
201
0
}
202
203
static inline bool IsTimestampMilliseconds(const char *format)
204
0
{
205
0
    return IsTimestampInternal(format, 'm');
206
0
}
207
208
static inline bool IsTimestampMicroseconds(const char *format)
209
0
{
210
0
    return IsTimestampInternal(format, 'u');
211
0
}
212
213
static inline bool IsTimestampNanoseconds(const char *format)
214
0
{
215
0
    return IsTimestampInternal(format, 'n');
216
0
}
217
218
static inline bool IsTimestamp(const char *format)
219
0
{
220
0
    return IsTimestampSeconds(format) || IsTimestampMilliseconds(format) ||
221
0
           IsTimestampMicroseconds(format) || IsTimestampNanoseconds(format);
222
0
}
223
224
static inline const char *GetTimestampTimezone(const char *format)
225
0
{
226
0
    return IsTimestamp(format) ? format + strlen("tm?:") : "";
227
0
}
228
229
/************************************************************************/
230
/*                            TestBit()                                 */
231
/************************************************************************/
232
233
inline bool TestBit(const uint8_t *pabyData, size_t nIdx)
234
0
{
235
0
    return (pabyData[nIdx / 8] & (1 << (nIdx % 8))) != 0;
236
0
}
237
238
/************************************************************************/
239
/*                            SetBit()                                  */
240
/************************************************************************/
241
242
inline void SetBit(uint8_t *pabyData, size_t nIdx)
243
0
{
244
0
    pabyData[nIdx / 8] |= (1 << (nIdx % 8));
245
0
}
246
247
/************************************************************************/
248
/*                           UnsetBit()                                 */
249
/************************************************************************/
250
251
inline void UnsetBit(uint8_t *pabyData, size_t nIdx)
252
0
{
253
0
    pabyData[nIdx / 8] &= uint8_t(~(1 << (nIdx % 8)));
254
0
}
255
256
/************************************************************************/
257
/*                          DefaultReleaseSchema()                      */
258
/************************************************************************/
259
260
static void OGRLayerReleaseSchema(struct ArrowSchema *schema,
261
                                  bool bFullFreeFormat)
262
0
{
263
0
    CPLAssert(schema->release != nullptr);
264
0
    if (bFullFreeFormat || STARTS_WITH(schema->format, "w:") ||
265
0
        STARTS_WITH(schema->format, "tsm:"))
266
0
    {
267
0
        CPLFree(const_cast<char *>(schema->format));
268
0
    }
269
0
    CPLFree(const_cast<char *>(schema->name));
270
0
    CPLFree(const_cast<char *>(schema->metadata));
271
0
    if (schema->children)
272
0
    {
273
0
        for (int i = 0; i < static_cast<int>(schema->n_children); ++i)
274
0
        {
275
0
            if (schema->children[i] && schema->children[i]->release)
276
0
            {
277
0
                schema->children[i]->release(schema->children[i]);
278
0
                CPLFree(schema->children[i]);
279
0
            }
280
0
        }
281
0
        CPLFree(schema->children);
282
0
    }
283
0
    if (schema->dictionary)
284
0
    {
285
0
        if (schema->dictionary->release)
286
0
        {
287
0
            schema->dictionary->release(schema->dictionary);
288
0
            CPLFree(schema->dictionary);
289
0
        }
290
0
    }
291
0
    schema->release = nullptr;
292
0
}
293
294
static void OGRLayerPartialReleaseSchema(struct ArrowSchema *schema)
295
0
{
296
0
    OGRLayerReleaseSchema(schema, /* bFullFreeFormat = */ false);
297
0
}
298
299
static void OGRLayerFullReleaseSchema(struct ArrowSchema *schema)
300
0
{
301
0
    OGRLayerReleaseSchema(schema, /* bFullFreeFormat = */ true);
302
0
}
303
304
/** Release a ArrowSchema.
305
 *
306
 * To be used by driver implementations that have a custom GetArrowStream()
307
 * implementation.
308
 *
309
 * @param schema Schema to release.
310
 * @since GDAL 3.6
311
 */
312
313
void OGRLayer::ReleaseSchema(struct ArrowSchema *schema)
314
0
{
315
0
    OGRLayerPartialReleaseSchema(schema);
316
0
}
317
318
/************************************************************************/
319
/*                        AddDictToSchema()                             */
320
/************************************************************************/
321
322
static void AddDictToSchema(struct ArrowSchema *psChild,
323
                            const OGRCodedFieldDomain *poCodedDomain)
324
0
{
325
0
    const OGRCodedValue *psIter = poCodedDomain->GetEnumeration();
326
0
    int nLastCode = -1;
327
0
    int nCountNull = 0;
328
0
    uint32_t nCountChars = 0;
329
0
    for (; psIter->pszCode; ++psIter)
330
0
    {
331
0
        if (CPLGetValueType(psIter->pszCode) != CPL_VALUE_INTEGER)
332
0
        {
333
0
            return;
334
0
        }
335
0
        int nCode = atoi(psIter->pszCode);
336
0
        if (nCode <= nLastCode || nCode - nLastCode > 100)
337
0
        {
338
0
            return;
339
0
        }
340
0
        for (int i = nLastCode + 1; i < nCode; ++i)
341
0
        {
342
0
            nCountNull++;
343
0
        }
344
0
        if (psIter->pszValue != nullptr)
345
0
        {
346
0
            const size_t nLen = strlen(psIter->pszValue);
347
0
            if (nLen > std::numeric_limits<uint32_t>::max() - nCountChars)
348
0
                return;
349
0
            nCountChars += static_cast<uint32_t>(nLen);
350
0
        }
351
0
        else
352
0
            nCountNull++;
353
0
        nLastCode = nCode;
354
0
    }
355
356
0
    auto psChildDict = static_cast<struct ArrowSchema *>(
357
0
        CPLCalloc(1, sizeof(struct ArrowSchema)));
358
0
    psChild->dictionary = psChildDict;
359
0
    psChildDict->release = OGRLayerPartialReleaseSchema;
360
0
    psChildDict->name = CPLStrdup(poCodedDomain->GetName().c_str());
361
0
    psChildDict->format = "u";
362
0
    if (nCountNull)
363
0
        psChildDict->flags = ARROW_FLAG_NULLABLE;
364
0
}
365
366
/************************************************************************/
367
/*                     DefaultGetArrowSchema()                          */
368
/************************************************************************/
369
370
/** Default implementation of the ArrowArrayStream::get_schema() callback.
371
 *
372
 * To be used by driver implementations that have a custom GetArrowStream()
373
 * implementation.
374
 *
375
 * @since GDAL 3.6
376
 */
377
int OGRLayer::GetArrowSchema(struct ArrowArrayStream *,
378
                             struct ArrowSchema *out_schema)
379
0
{
380
0
    const bool bIncludeFID = CPLTestBool(
381
0
        m_aosArrowArrayStreamOptions.FetchNameValueDef("INCLUDE_FID", "YES"));
382
0
    const bool bDateTimeAsString = m_aosArrowArrayStreamOptions.FetchBool(
383
0
        GAS_OPT_DATETIME_AS_STRING, false);
384
0
    memset(out_schema, 0, sizeof(*out_schema));
385
0
    out_schema->format = "+s";
386
0
    out_schema->name = CPLStrdup("");
387
0
    out_schema->metadata = nullptr;
388
0
    auto poLayerDefn = GetLayerDefn();
389
0
    const int nFieldCount = poLayerDefn->GetFieldCount();
390
0
    const int nGeomFieldCount = poLayerDefn->GetGeomFieldCount();
391
0
    const int nChildren = 1 + nFieldCount + nGeomFieldCount;
392
393
0
    out_schema->children = static_cast<struct ArrowSchema **>(
394
0
        CPLCalloc(nChildren, sizeof(struct ArrowSchema *)));
395
0
    int iSchemaChild = 0;
396
0
    if (bIncludeFID)
397
0
    {
398
0
        out_schema->children[iSchemaChild] = static_cast<struct ArrowSchema *>(
399
0
            CPLCalloc(1, sizeof(struct ArrowSchema)));
400
0
        auto psChild = out_schema->children[iSchemaChild];
401
0
        ++iSchemaChild;
402
0
        psChild->release = OGRLayer::ReleaseSchema;
403
0
        const char *pszFIDName = GetFIDColumn();
404
0
        psChild->name =
405
0
            CPLStrdup((pszFIDName && pszFIDName[0]) ? pszFIDName
406
0
                                                    : DEFAULT_ARROW_FID_NAME);
407
0
        psChild->format = "l";
408
0
    }
409
0
    for (int i = 0; i < nFieldCount; ++i)
410
0
    {
411
0
        const auto poFieldDefn = poLayerDefn->GetFieldDefn(i);
412
0
        if (poFieldDefn->IsIgnored())
413
0
        {
414
0
            continue;
415
0
        }
416
417
0
        out_schema->children[iSchemaChild] = static_cast<struct ArrowSchema *>(
418
0
            CPLCalloc(1, sizeof(struct ArrowSchema)));
419
0
        auto psChild = out_schema->children[iSchemaChild];
420
0
        ++iSchemaChild;
421
0
        psChild->release = OGRLayer::ReleaseSchema;
422
0
        psChild->name = CPLStrdup(poFieldDefn->GetNameRef());
423
0
        if (poFieldDefn->IsNullable())
424
0
            psChild->flags = ARROW_FLAG_NULLABLE;
425
0
        const auto eType = poFieldDefn->GetType();
426
0
        const auto eSubType = poFieldDefn->GetSubType();
427
0
        const char *item_format = nullptr;
428
0
        switch (eType)
429
0
        {
430
0
            case OFTInteger:
431
0
            {
432
0
                if (eSubType == OFSTBoolean)
433
0
                    psChild->format = "b";
434
0
                else if (eSubType == OFSTInt16)
435
0
                    psChild->format = "s";
436
0
                else
437
0
                    psChild->format = "i";
438
439
0
                const auto &osDomainName = poFieldDefn->GetDomainName();
440
0
                if (!osDomainName.empty())
441
0
                {
442
0
                    auto poDS = GetDataset();
443
0
                    if (poDS)
444
0
                    {
445
0
                        const auto poFieldDomain =
446
0
                            poDS->GetFieldDomain(osDomainName);
447
0
                        if (poFieldDomain &&
448
0
                            poFieldDomain->GetDomainType() == OFDT_CODED)
449
0
                        {
450
0
                            const OGRCodedFieldDomain *poCodedDomain =
451
0
                                static_cast<const OGRCodedFieldDomain *>(
452
0
                                    poFieldDomain);
453
0
                            AddDictToSchema(psChild, poCodedDomain);
454
0
                        }
455
0
                    }
456
0
                }
457
458
0
                break;
459
0
            }
460
461
0
            case OFTInteger64:
462
0
                psChild->format = "l";
463
0
                break;
464
465
0
            case OFTReal:
466
0
            {
467
0
                if (eSubType == OFSTFloat32)
468
0
                    psChild->format = "f";
469
0
                else
470
0
                    psChild->format = "g";
471
0
                break;
472
0
            }
473
474
0
            case OFTString:
475
0
            case OFTWideString:
476
0
                psChild->format = "u";
477
0
                break;
478
479
0
            case OFTBinary:
480
0
            {
481
0
                if (poFieldDefn->GetWidth() > 0)
482
0
                    psChild->format =
483
0
                        CPLStrdup(CPLSPrintf("w:%d", poFieldDefn->GetWidth()));
484
0
                else
485
0
                    psChild->format = "z";
486
0
                break;
487
0
            }
488
489
0
            case OFTIntegerList:
490
0
            {
491
0
                if (eSubType == OFSTBoolean)
492
0
                    item_format = "b";
493
0
                else if (eSubType == OFSTInt16)
494
0
                    item_format = "s";
495
0
                else
496
0
                    item_format = "i";
497
0
                break;
498
0
            }
499
500
0
            case OFTInteger64List:
501
0
                item_format = "l";
502
0
                break;
503
504
0
            case OFTRealList:
505
0
            {
506
0
                if (eSubType == OFSTFloat32)
507
0
                    item_format = "f";
508
0
                else
509
0
                    item_format = "g";
510
0
                break;
511
0
            }
512
513
0
            case OFTStringList:
514
0
            case OFTWideStringList:
515
0
                item_format = "u";
516
0
                break;
517
518
0
            case OFTDate:
519
0
                psChild->format = "tdD";
520
0
                break;
521
522
0
            case OFTTime:
523
0
                psChild->format = "ttm";
524
0
                break;
525
526
0
            case OFTDateTime:
527
0
            {
528
0
                const char *pszPrefix = "tsm:";
529
0
                const char *pszTZOverride =
530
0
                    m_aosArrowArrayStreamOptions.FetchNameValue("TIMEZONE");
531
0
                if (bDateTimeAsString)
532
0
                {
533
0
                    psChild->format = "u";
534
0
                }
535
0
                else if (pszTZOverride && EQUAL(pszTZOverride, "unknown"))
536
0
                {
537
0
                    psChild->format = CPLStrdup(pszPrefix);
538
0
                }
539
0
                else if (pszTZOverride)
540
0
                {
541
0
                    psChild->format = CPLStrdup(
542
0
                        (std::string(pszPrefix) + pszTZOverride).c_str());
543
0
                }
544
0
                else
545
0
                {
546
0
                    const int nTZFlag = poFieldDefn->GetTZFlag();
547
0
                    if (nTZFlag == OGR_TZFLAG_MIXED_TZ ||
548
0
                        nTZFlag == OGR_TZFLAG_UTC)
549
0
                    {
550
0
                        psChild->format =
551
0
                            CPLStrdup(CPLSPrintf("%sUTC", pszPrefix));
552
0
                    }
553
0
                    else if (nTZFlag == OGR_TZFLAG_UNKNOWN ||
554
0
                             nTZFlag == OGR_TZFLAG_LOCALTIME)
555
0
                    {
556
0
                        psChild->format = CPLStrdup(pszPrefix);
557
0
                    }
558
0
                    else
559
0
                    {
560
0
                        psChild->format = CPLStrdup(
561
0
                            (pszPrefix + OGRTZFlagToTimezone(nTZFlag, "UTC"))
562
0
                                .c_str());
563
0
                    }
564
0
                }
565
0
                break;
566
0
            }
567
0
        }
568
569
0
        if (item_format)
570
0
        {
571
0
            psChild->format = "+l";
572
0
            psChild->n_children = 1;
573
0
            psChild->children = static_cast<struct ArrowSchema **>(
574
0
                CPLCalloc(1, sizeof(struct ArrowSchema *)));
575
0
            psChild->children[0] = static_cast<struct ArrowSchema *>(
576
0
                CPLCalloc(1, sizeof(struct ArrowSchema)));
577
0
            psChild->children[0]->release = OGRLayer::ReleaseSchema;
578
0
            psChild->children[0]->name = CPLStrdup("item");
579
0
            psChild->children[0]->format = item_format;
580
0
        }
581
582
0
        std::vector<std::pair<std::string, std::string>> oMetadata;
583
584
0
        if (eType == OFTDateTime && bDateTimeAsString)
585
0
        {
586
0
            oMetadata.emplace_back(
587
0
                std::pair(MD_GDAL_OGR_TYPE, OGR_GetFieldTypeName(eType)));
588
0
        }
589
590
0
        const char *pszAlternativeName = poFieldDefn->GetAlternativeNameRef();
591
0
        if (pszAlternativeName && pszAlternativeName[0])
592
0
            oMetadata.emplace_back(
593
0
                std::pair(MD_GDAL_OGR_ALTERNATIVE_NAME, pszAlternativeName));
594
595
0
        const char *pszDefault = poFieldDefn->GetDefault();
596
0
        if (pszDefault && pszDefault[0])
597
0
            oMetadata.emplace_back(std::pair(MD_GDAL_OGR_DEFAULT, pszDefault));
598
599
0
        const std::string &osComment = poFieldDefn->GetComment();
600
0
        if (!osComment.empty())
601
0
            oMetadata.emplace_back(std::pair(MD_GDAL_OGR_COMMENT, osComment));
602
603
0
        if (eType == OFTString && eSubType == OFSTJSON)
604
0
        {
605
0
            oMetadata.emplace_back(
606
0
                std::pair(ARROW_EXTENSION_NAME_KEY, EXTENSION_NAME_ARROW_JSON));
607
0
        }
608
0
        else if (eSubType != OFSTNone && eSubType != OFSTBoolean &&
609
0
                 eSubType != OFSTFloat32)
610
0
        {
611
0
            oMetadata.emplace_back(std::pair(
612
0
                MD_GDAL_OGR_SUBTYPE, OGR_GetFieldSubTypeName(eSubType)));
613
0
        }
614
0
        if (eType == OFTString && poFieldDefn->GetWidth() > 0)
615
0
        {
616
0
            oMetadata.emplace_back(std::pair(
617
0
                MD_GDAL_OGR_WIDTH, CPLSPrintf("%d", poFieldDefn->GetWidth())));
618
0
        }
619
0
        if (poFieldDefn->IsUnique())
620
0
        {
621
0
            oMetadata.emplace_back(std::pair(MD_GDAL_OGR_UNIQUE, "true"));
622
0
        }
623
0
        if (!poFieldDefn->GetDomainName().empty())
624
0
        {
625
0
            oMetadata.emplace_back(std::pair(MD_GDAL_OGR_DOMAIN_NAME,
626
0
                                             poFieldDefn->GetDomainName()));
627
0
        }
628
629
0
        if (!oMetadata.empty())
630
0
        {
631
0
            uint64_t nLen64 = sizeof(int32_t);
632
0
            for (const auto &oPair : oMetadata)
633
0
            {
634
0
                nLen64 += sizeof(int32_t);
635
0
                nLen64 += oPair.first.size();
636
0
                nLen64 += sizeof(int32_t);
637
0
                nLen64 += oPair.second.size();
638
0
            }
639
0
            if (nLen64 <
640
0
                static_cast<uint64_t>(std::numeric_limits<int32_t>::max()))
641
0
            {
642
0
                const size_t nLen = static_cast<size_t>(nLen64);
643
0
                char *pszMetadata = static_cast<char *>(CPLMalloc(nLen));
644
0
                psChild->metadata = pszMetadata;
645
0
                size_t offsetMD = 0;
646
0
                int32_t nSize = static_cast<int>(oMetadata.size());
647
0
                memcpy(pszMetadata + offsetMD, &nSize, sizeof(nSize));
648
0
                offsetMD += sizeof(int32_t);
649
0
                for (const auto &oPair : oMetadata)
650
0
                {
651
0
                    nSize = static_cast<int32_t>(oPair.first.size());
652
0
                    memcpy(pszMetadata + offsetMD, &nSize, sizeof(nSize));
653
0
                    offsetMD += sizeof(int32_t);
654
0
                    memcpy(pszMetadata + offsetMD, oPair.first.data(),
655
0
                           oPair.first.size());
656
0
                    offsetMD += oPair.first.size();
657
658
0
                    nSize = static_cast<int32_t>(oPair.second.size());
659
0
                    memcpy(pszMetadata + offsetMD, &nSize, sizeof(nSize));
660
0
                    offsetMD += sizeof(int32_t);
661
0
                    memcpy(pszMetadata + offsetMD, oPair.second.data(),
662
0
                           oPair.second.size());
663
0
                    offsetMD += oPair.second.size();
664
0
                }
665
666
0
                CPLAssert(offsetMD == nLen);
667
0
                CPL_IGNORE_RET_VAL(offsetMD);
668
0
            }
669
0
            else
670
0
            {
671
                // Extremely unlikely !
672
0
                CPLError(CE_Warning, CPLE_AppDefined,
673
0
                         "Cannot write ArrowSchema::metadata due to "
674
0
                         "too large content");
675
0
            }
676
0
        }
677
0
    }
678
679
0
    const char *const pszGeometryMetadataEncoding =
680
0
        m_aosArrowArrayStreamOptions.FetchNameValue(
681
0
            "GEOMETRY_METADATA_ENCODING");
682
0
    const char *pszExtensionName = EXTENSION_NAME_OGC_WKB;
683
0
    if (pszGeometryMetadataEncoding)
684
0
    {
685
0
        if (EQUAL(pszGeometryMetadataEncoding, "OGC"))
686
0
            pszExtensionName = EXTENSION_NAME_OGC_WKB;
687
0
        else if (EQUAL(pszGeometryMetadataEncoding, "GEOARROW"))
688
0
            pszExtensionName = EXTENSION_NAME_GEOARROW_WKB;
689
0
        else
690
0
            CPLError(CE_Warning, CPLE_NotSupported,
691
0
                     "Unsupported GEOMETRY_METADATA_ENCODING value: %s",
692
0
                     pszGeometryMetadataEncoding);
693
0
    }
694
0
    for (int i = 0; i < nGeomFieldCount; ++i)
695
0
    {
696
0
        const auto poFieldDefn = poLayerDefn->GetGeomFieldDefn(i);
697
0
        if (poFieldDefn->IsIgnored())
698
0
        {
699
0
            continue;
700
0
        }
701
702
0
        out_schema->children[iSchemaChild] = CreateSchemaForWKBGeometryColumn(
703
0
            poFieldDefn, "z", pszExtensionName);
704
705
0
        ++iSchemaChild;
706
0
    }
707
708
0
    out_schema->n_children = iSchemaChild;
709
0
    out_schema->release = OGRLayer::ReleaseSchema;
710
0
    return 0;
711
0
}
712
713
/************************************************************************/
714
/*                  CreateSchemaForWKBGeometryColumn()                  */
715
/************************************************************************/
716
717
/** Return a ArrowSchema* corresponding to the WKB encoding of a geometry
718
 * column.
719
 */
720
721
/* static */
722
struct ArrowSchema *
723
OGRLayer::CreateSchemaForWKBGeometryColumn(const OGRGeomFieldDefn *poFieldDefn,
724
                                           const char *pszArrowFormat,
725
                                           const char *pszExtensionName)
726
0
{
727
0
    CPLAssert(strcmp(pszArrowFormat, "z") == 0 ||
728
0
              strcmp(pszArrowFormat, "Z") == 0);
729
0
    if (!EQUAL(pszExtensionName, EXTENSION_NAME_OGC_WKB) &&
730
0
        !EQUAL(pszExtensionName, EXTENSION_NAME_GEOARROW_WKB))
731
0
    {
732
0
        CPLError(CE_Failure, CPLE_NotSupported,
733
0
                 "Unsupported extension name '%s'. Defaulting to '%s'",
734
0
                 pszExtensionName, EXTENSION_NAME_OGC_WKB);
735
0
        pszExtensionName = EXTENSION_NAME_OGC_WKB;
736
0
    }
737
0
    auto psSchema = static_cast<struct ArrowSchema *>(
738
0
        CPLCalloc(1, sizeof(struct ArrowSchema)));
739
0
    psSchema->release = OGRLayer::ReleaseSchema;
740
0
    const char *pszGeomFieldName = poFieldDefn->GetNameRef();
741
0
    if (pszGeomFieldName[0] == '\0')
742
0
        pszGeomFieldName = DEFAULT_ARROW_GEOMETRY_NAME;
743
0
    psSchema->name = CPLStrdup(pszGeomFieldName);
744
0
    if (poFieldDefn->IsNullable())
745
0
        psSchema->flags = ARROW_FLAG_NULLABLE;
746
0
    psSchema->format = strcmp(pszArrowFormat, "z") == 0 ? "z" : "Z";
747
0
    std::string osExtensionMetadata;
748
0
    if (EQUAL(pszExtensionName, EXTENSION_NAME_GEOARROW_WKB))
749
0
    {
750
0
        const auto poSRS = poFieldDefn->GetSpatialRef();
751
0
        if (poSRS)
752
0
        {
753
0
            char *pszPROJJSON = nullptr;
754
0
            poSRS->exportToPROJJSON(&pszPROJJSON, nullptr);
755
0
            if (pszPROJJSON)
756
0
            {
757
0
                osExtensionMetadata = "{\"crs\":";
758
0
                osExtensionMetadata += pszPROJJSON;
759
0
                osExtensionMetadata += '}';
760
0
                CPLFree(pszPROJJSON);
761
0
            }
762
0
            else
763
0
            {
764
0
                CPLError(CE_Warning, CPLE_AppDefined,
765
0
                         "Cannot export CRS of geometry field %s to PROJJSON",
766
0
                         poFieldDefn->GetNameRef());
767
0
            }
768
0
        }
769
0
    }
770
0
    size_t nLen = sizeof(int32_t) + sizeof(int32_t) +
771
0
                  strlen(ARROW_EXTENSION_NAME_KEY) + sizeof(int32_t) +
772
0
                  strlen(pszExtensionName);
773
0
    if (!osExtensionMetadata.empty())
774
0
    {
775
0
        nLen += sizeof(int32_t) + strlen(ARROW_EXTENSION_METADATA_KEY) +
776
0
                sizeof(int32_t) + osExtensionMetadata.size();
777
0
    }
778
0
    char *pszMetadata = static_cast<char *>(CPLMalloc(nLen));
779
0
    psSchema->metadata = pszMetadata;
780
0
    size_t offsetMD = 0;
781
0
    *reinterpret_cast<int32_t *>(pszMetadata + offsetMD) =
782
0
        osExtensionMetadata.empty() ? 1 : 2;
783
0
    offsetMD += sizeof(int32_t);
784
0
    *reinterpret_cast<int32_t *>(pszMetadata + offsetMD) =
785
0
        static_cast<int32_t>(strlen(ARROW_EXTENSION_NAME_KEY));
786
0
    offsetMD += sizeof(int32_t);
787
0
    memcpy(pszMetadata + offsetMD, ARROW_EXTENSION_NAME_KEY,
788
0
           strlen(ARROW_EXTENSION_NAME_KEY));
789
0
    offsetMD += static_cast<int>(strlen(ARROW_EXTENSION_NAME_KEY));
790
0
    *reinterpret_cast<int32_t *>(pszMetadata + offsetMD) =
791
0
        static_cast<int32_t>(strlen(pszExtensionName));
792
0
    offsetMD += sizeof(int32_t);
793
0
    memcpy(pszMetadata + offsetMD, pszExtensionName, strlen(pszExtensionName));
794
0
    offsetMD += strlen(pszExtensionName);
795
0
    if (!osExtensionMetadata.empty())
796
0
    {
797
0
        *reinterpret_cast<int32_t *>(pszMetadata + offsetMD) =
798
0
            static_cast<int32_t>(strlen(ARROW_EXTENSION_METADATA_KEY));
799
0
        offsetMD += sizeof(int32_t);
800
0
        memcpy(pszMetadata + offsetMD, ARROW_EXTENSION_METADATA_KEY,
801
0
               strlen(ARROW_EXTENSION_METADATA_KEY));
802
0
        offsetMD += static_cast<int>(strlen(ARROW_EXTENSION_METADATA_KEY));
803
0
        *reinterpret_cast<int32_t *>(pszMetadata + offsetMD) =
804
0
            static_cast<int32_t>(osExtensionMetadata.size());
805
0
        offsetMD += sizeof(int32_t);
806
0
        memcpy(pszMetadata + offsetMD, osExtensionMetadata.c_str(),
807
0
               osExtensionMetadata.size());
808
0
        offsetMD += osExtensionMetadata.size();
809
0
    }
810
0
    CPLAssert(offsetMD == nLen);
811
0
    CPL_IGNORE_RET_VAL(offsetMD);
812
0
    return psSchema;
813
0
}
814
815
/************************************************************************/
816
/*                         StaticGetArrowSchema()                       */
817
/************************************************************************/
818
819
/** Default implementation of the ArrowArrayStream::get_schema() callback.
820
 *
821
 * To be used by driver implementations that have a custom GetArrowStream()
822
 * implementation.
823
 *
824
 * @since GDAL 3.6
825
 */
826
int OGRLayer::StaticGetArrowSchema(struct ArrowArrayStream *stream,
827
                                   struct ArrowSchema *out_schema)
828
0
{
829
0
    auto poLayer = static_cast<ArrowArrayStreamPrivateDataSharedDataWrapper *>(
830
0
                       stream->private_data)
831
0
                       ->poShared->m_poLayer;
832
0
    if (poLayer == nullptr)
833
0
    {
834
0
        CPLError(CE_Failure, CPLE_NotSupported,
835
0
                 "Calling get_schema() on a freed OGRLayer is not supported");
836
0
        return EINVAL;
837
0
    }
838
0
    return poLayer->GetArrowSchema(stream, out_schema);
839
0
}
840
841
/************************************************************************/
842
/*                         DefaultReleaseArray()                        */
843
/************************************************************************/
844
845
static void OGRLayerDefaultReleaseArray(struct ArrowArray *array)
846
0
{
847
0
    if (array->buffers)
848
0
    {
849
0
        for (int i = 0; i < static_cast<int>(array->n_buffers); ++i)
850
0
            VSIFreeAligned(const_cast<void *>(array->buffers[i]));
851
0
        CPLFree(array->buffers);
852
0
    }
853
0
    if (array->children)
854
0
    {
855
0
        for (int i = 0; i < static_cast<int>(array->n_children); ++i)
856
0
        {
857
0
            if (array->children[i] && array->children[i]->release)
858
0
            {
859
0
                array->children[i]->release(array->children[i]);
860
0
                CPLFree(array->children[i]);
861
0
            }
862
0
        }
863
0
        CPLFree(array->children);
864
0
    }
865
0
    if (array->dictionary)
866
0
    {
867
0
        if (array->dictionary->release)
868
0
        {
869
0
            array->dictionary->release(array->dictionary);
870
0
            CPLFree(array->dictionary);
871
0
        }
872
0
    }
873
0
    array->release = nullptr;
874
0
}
875
876
/** Release a ArrowArray.
877
 *
878
 * To be used by driver implementations that have a custom GetArrowStream()
879
 * implementation.
880
 *
881
 * @param array Arrow array to release.
882
 * @since GDAL 3.6
883
 */
884
void OGRLayer::ReleaseArray(struct ArrowArray *array)
885
0
{
886
0
    OGRLayerDefaultReleaseArray(array);
887
0
}
888
889
/************************************************************************/
890
/*                          IsValidField()                              */
891
/************************************************************************/
892
893
static inline bool IsValidField(const OGRField *psRawField)
894
0
{
895
0
    return (!(psRawField->Set.nMarker1 == OGRUnsetMarker &&
896
0
              psRawField->Set.nMarker2 == OGRUnsetMarker &&
897
0
              psRawField->Set.nMarker3 == OGRUnsetMarker) &&
898
0
            !(psRawField->Set.nMarker1 == OGRNullMarker &&
899
0
              psRawField->Set.nMarker2 == OGRNullMarker &&
900
0
              psRawField->Set.nMarker3 == OGRNullMarker));
901
0
}
902
903
/************************************************************************/
904
/*                    AllocValidityBitmap()                             */
905
/************************************************************************/
906
907
static uint8_t *AllocValidityBitmap(size_t nSize)
908
0
{
909
0
    auto pabyValidity = static_cast<uint8_t *>(
910
0
        VSI_MALLOC_ALIGNED_AUTO_VERBOSE((1 + nSize + 7) / 8));
911
0
    if (pabyValidity)
912
0
    {
913
        // All valid initially
914
0
        memset(pabyValidity, 0xFF, (nSize + 7) / 8);
915
0
    }
916
0
    return pabyValidity;
917
0
}
918
919
/************************************************************************/
920
/*                           FillArray()                                */
921
/************************************************************************/
922
923
template <class T, typename TMember>
924
static bool FillArray(struct ArrowArray *psChild,
925
                      std::deque<std::unique_ptr<OGRFeature>> &apoFeatures,
926
                      const size_t nFeatureCountLimit, const bool bIsNullable,
927
                      TMember member, const int i)
928
0
{
929
0
    psChild->n_buffers = 2;
930
0
    psChild->buffers = static_cast<const void **>(CPLCalloc(2, sizeof(void *)));
931
0
    uint8_t *pabyValidity = nullptr;
932
0
    T *panValues = static_cast<T *>(
933
0
        VSI_MALLOC_ALIGNED_AUTO_VERBOSE(sizeof(T) * (1 + nFeatureCountLimit)));
934
0
    if (panValues == nullptr)
935
0
        return false;
936
0
    psChild->buffers[1] = panValues;
937
0
    for (size_t iFeat = 0; iFeat < nFeatureCountLimit; ++iFeat)
938
0
    {
939
0
        auto &poFeature = apoFeatures[iFeat];
940
0
        const auto psRawField = poFeature->GetRawFieldRef(i);
941
0
        if (IsValidField(psRawField))
942
0
        {
943
0
            panValues[iFeat] = static_cast<T>((*psRawField).*member);
944
0
        }
945
0
        else if (bIsNullable)
946
0
        {
947
0
            panValues[iFeat] = 0;
948
0
            ++psChild->null_count;
949
0
            if (pabyValidity == nullptr)
950
0
            {
951
0
                pabyValidity = AllocValidityBitmap(nFeatureCountLimit);
952
0
                psChild->buffers[0] = pabyValidity;
953
0
                if (pabyValidity == nullptr)
954
0
                    return false;
955
0
            }
956
0
            UnsetBit(pabyValidity, iFeat);
957
0
        }
958
0
        else
959
0
        {
960
0
            panValues[iFeat] = 0;
961
0
        }
962
0
    }
963
0
    return true;
964
0
}
Unexecuted instantiation: ogrlayerarrow.cpp:bool FillArray<short, int OGRField::*>(ArrowArray*, std::__1::deque<std::__1::unique_ptr<OGRFeature, std::__1::default_delete<OGRFeature> >, std::__1::allocator<std::__1::unique_ptr<OGRFeature, std::__1::default_delete<OGRFeature> > > >&, unsigned long, bool, int OGRField::*, int)
Unexecuted instantiation: ogrlayerarrow.cpp:bool FillArray<int, int OGRField::*>(ArrowArray*, std::__1::deque<std::__1::unique_ptr<OGRFeature, std::__1::default_delete<OGRFeature> >, std::__1::allocator<std::__1::unique_ptr<OGRFeature, std::__1::default_delete<OGRFeature> > > >&, unsigned long, bool, int OGRField::*, int)
Unexecuted instantiation: ogrlayerarrow.cpp:bool FillArray<long, long long OGRField::*>(ArrowArray*, std::__1::deque<std::__1::unique_ptr<OGRFeature, std::__1::default_delete<OGRFeature> >, std::__1::allocator<std::__1::unique_ptr<OGRFeature, std::__1::default_delete<OGRFeature> > > >&, unsigned long, bool, long long OGRField::*, int)
Unexecuted instantiation: ogrlayerarrow.cpp:bool FillArray<float, double OGRField::*>(ArrowArray*, std::__1::deque<std::__1::unique_ptr<OGRFeature, std::__1::default_delete<OGRFeature> >, std::__1::allocator<std::__1::unique_ptr<OGRFeature, std::__1::default_delete<OGRFeature> > > >&, unsigned long, bool, double OGRField::*, int)
Unexecuted instantiation: ogrlayerarrow.cpp:bool FillArray<double, double OGRField::*>(ArrowArray*, std::__1::deque<std::__1::unique_ptr<OGRFeature, std::__1::default_delete<OGRFeature> >, std::__1::allocator<std::__1::unique_ptr<OGRFeature, std::__1::default_delete<OGRFeature> > > >&, unsigned long, bool, double OGRField::*, int)
965
966
/************************************************************************/
967
/*                         FillBoolArray()                              */
968
/************************************************************************/
969
970
template <typename TMember>
971
static bool FillBoolArray(struct ArrowArray *psChild,
972
                          std::deque<std::unique_ptr<OGRFeature>> &apoFeatures,
973
                          const size_t nFeatureCountLimit,
974
                          const bool bIsNullable, TMember member, const int i)
975
0
{
976
0
    psChild->n_buffers = 2;
977
0
    psChild->buffers = static_cast<const void **>(CPLCalloc(2, sizeof(void *)));
978
0
    uint8_t *pabyValidity = nullptr;
979
0
    uint8_t *panValues = static_cast<uint8_t *>(
980
0
        VSI_MALLOC_ALIGNED_AUTO_VERBOSE((nFeatureCountLimit + 7 + 1) / 8));
981
0
    if (panValues == nullptr)
982
0
        return false;
983
0
    memset(panValues, 0, (nFeatureCountLimit + 7) / 8);
984
0
    psChild->buffers[1] = panValues;
985
0
    for (size_t iFeat = 0; iFeat < nFeatureCountLimit; ++iFeat)
986
0
    {
987
0
        auto &poFeature = apoFeatures[iFeat];
988
0
        const auto psRawField = poFeature->GetRawFieldRef(i);
989
0
        if (IsValidField(psRawField))
990
0
        {
991
0
            if ((*psRawField).*member)
992
0
                SetBit(panValues, iFeat);
993
0
        }
994
0
        else if (bIsNullable)
995
0
        {
996
0
            ++psChild->null_count;
997
0
            if (pabyValidity == nullptr)
998
0
            {
999
0
                pabyValidity = AllocValidityBitmap(nFeatureCountLimit);
1000
0
                psChild->buffers[0] = pabyValidity;
1001
0
                if (pabyValidity == nullptr)
1002
0
                    return false;
1003
0
            }
1004
0
            UnsetBit(pabyValidity, iFeat);
1005
0
        }
1006
0
    }
1007
0
    return true;
1008
0
}
1009
1010
/************************************************************************/
1011
/*                        FillListArray()                               */
1012
/************************************************************************/
1013
1014
struct GetFromIntegerList
1015
{
1016
    static inline int getCount(const OGRField *psRawField)
1017
0
    {
1018
0
        return psRawField->IntegerList.nCount;
1019
0
    }
1020
1021
    static inline const int *getValues(const OGRField *psRawField)
1022
0
    {
1023
0
        return psRawField->IntegerList.paList;
1024
0
    }
1025
};
1026
1027
struct GetFromInteger64List
1028
{
1029
    static inline int getCount(const OGRField *psRawField)
1030
0
    {
1031
0
        return psRawField->Integer64List.nCount;
1032
0
    }
1033
1034
    static inline const GIntBig *getValues(const OGRField *psRawField)
1035
0
    {
1036
0
        return psRawField->Integer64List.paList;
1037
0
    }
1038
};
1039
1040
struct GetFromRealList
1041
{
1042
    static inline int getCount(const OGRField *psRawField)
1043
0
    {
1044
0
        return psRawField->RealList.nCount;
1045
0
    }
1046
1047
    static inline const double *getValues(const OGRField *psRawField)
1048
0
    {
1049
0
        return psRawField->RealList.paList;
1050
0
    }
1051
};
1052
1053
template <class OffsetType, class T, class GetFromList>
1054
static size_t
1055
FillListArray(struct ArrowArray *psChild,
1056
              std::deque<std::unique_ptr<OGRFeature>> &apoFeatures,
1057
              const size_t nFeatureCountLimit, const bool bIsNullable,
1058
              const int i, const size_t nMemLimit)
1059
0
{
1060
0
    psChild->n_buffers = 2;
1061
0
    psChild->buffers = static_cast<const void **>(CPLCalloc(2, sizeof(void *)));
1062
0
    uint8_t *pabyValidity = nullptr;
1063
0
    OffsetType *panOffsets =
1064
0
        static_cast<OffsetType *>(VSI_MALLOC_ALIGNED_AUTO_VERBOSE(
1065
0
            sizeof(OffsetType) * (1 + nFeatureCountLimit)));
1066
0
    if (panOffsets == nullptr)
1067
0
        return 0;
1068
0
    psChild->buffers[1] = panOffsets;
1069
1070
0
    OffsetType nOffset = 0;
1071
0
    size_t nFeatCount = 0;
1072
0
    for (size_t iFeat = 0; iFeat < nFeatureCountLimit; ++iFeat, ++nFeatCount)
1073
0
    {
1074
0
        panOffsets[iFeat] = nOffset;
1075
0
        auto &poFeature = apoFeatures[iFeat];
1076
0
        const auto psRawField = poFeature->GetRawFieldRef(i);
1077
0
        if (IsValidField(psRawField))
1078
0
        {
1079
0
            const unsigned nCount = GetFromList::getCount(psRawField);
1080
0
            if (nCount > static_cast<size_t>(nMemLimit - nOffset))
1081
0
            {
1082
0
                if (nFeatCount == 0)
1083
0
                    return 0;
1084
0
                break;
1085
0
            }
1086
0
            nOffset += static_cast<OffsetType>(nCount);
1087
0
        }
1088
0
        else if (bIsNullable)
1089
0
        {
1090
0
            ++psChild->null_count;
1091
0
            if (pabyValidity == nullptr)
1092
0
            {
1093
0
                pabyValidity = AllocValidityBitmap(nFeatureCountLimit);
1094
0
                psChild->buffers[0] = pabyValidity;
1095
0
                if (pabyValidity == nullptr)
1096
0
                    return 0;
1097
0
            }
1098
0
            UnsetBit(pabyValidity, iFeat);
1099
0
        }
1100
0
    }
1101
0
    panOffsets[nFeatCount] = nOffset;
1102
1103
0
    psChild->n_children = 1;
1104
0
    psChild->children = static_cast<struct ArrowArray **>(
1105
0
        CPLCalloc(1, sizeof(struct ArrowArray *)));
1106
0
    psChild->children[0] = static_cast<struct ArrowArray *>(
1107
0
        CPLCalloc(1, sizeof(struct ArrowArray)));
1108
0
    auto psValueChild = psChild->children[0];
1109
1110
0
    psValueChild->release = OGRLayerDefaultReleaseArray;
1111
0
    psValueChild->n_buffers = 2;
1112
0
    psValueChild->buffers =
1113
0
        static_cast<const void **>(CPLCalloc(2, sizeof(void *)));
1114
0
    psValueChild->length = nOffset;
1115
0
    T *panValues = static_cast<T *>(
1116
0
        VSI_MALLOC_ALIGNED_AUTO_VERBOSE(sizeof(T) * (nOffset + 1)));
1117
0
    if (panValues == nullptr)
1118
0
        return 0;
1119
0
    psValueChild->buffers[1] = panValues;
1120
1121
0
    nOffset = 0;
1122
0
    for (size_t iFeat = 0; iFeat < nFeatCount; ++iFeat)
1123
0
    {
1124
0
        auto &poFeature = apoFeatures[iFeat];
1125
0
        const auto psRawField = poFeature->GetRawFieldRef(i);
1126
0
        if (IsValidField(psRawField))
1127
0
        {
1128
0
            const int nCount = GetFromList::getCount(psRawField);
1129
0
            const auto paList = GetFromList::getValues(psRawField);
1130
0
            if (sizeof(*paList) == sizeof(T))
1131
0
                memcpy(panValues + nOffset, paList, nCount * sizeof(T));
1132
0
            else
1133
0
            {
1134
0
                for (int j = 0; j < nCount; ++j)
1135
0
                {
1136
0
                    panValues[nOffset + j] = static_cast<T>(paList[j]);
1137
0
                }
1138
0
            }
1139
0
            nOffset += static_cast<OffsetType>(nCount);
1140
0
        }
1141
0
    }
1142
1143
0
    return nFeatCount;
1144
0
}
Unexecuted instantiation: ogrlayerarrow.cpp:unsigned long FillListArray<int, short, GetFromIntegerList>(ArrowArray*, std::__1::deque<std::__1::unique_ptr<OGRFeature, std::__1::default_delete<OGRFeature> >, std::__1::allocator<std::__1::unique_ptr<OGRFeature, std::__1::default_delete<OGRFeature> > > >&, unsigned long, bool, int, unsigned long)
Unexecuted instantiation: ogrlayerarrow.cpp:unsigned long FillListArray<int, int, GetFromIntegerList>(ArrowArray*, std::__1::deque<std::__1::unique_ptr<OGRFeature, std::__1::default_delete<OGRFeature> >, std::__1::allocator<std::__1::unique_ptr<OGRFeature, std::__1::default_delete<OGRFeature> > > >&, unsigned long, bool, int, unsigned long)
Unexecuted instantiation: ogrlayerarrow.cpp:unsigned long FillListArray<int, long, GetFromInteger64List>(ArrowArray*, std::__1::deque<std::__1::unique_ptr<OGRFeature, std::__1::default_delete<OGRFeature> >, std::__1::allocator<std::__1::unique_ptr<OGRFeature, std::__1::default_delete<OGRFeature> > > >&, unsigned long, bool, int, unsigned long)
Unexecuted instantiation: ogrlayerarrow.cpp:unsigned long FillListArray<int, float, GetFromRealList>(ArrowArray*, std::__1::deque<std::__1::unique_ptr<OGRFeature, std::__1::default_delete<OGRFeature> >, std::__1::allocator<std::__1::unique_ptr<OGRFeature, std::__1::default_delete<OGRFeature> > > >&, unsigned long, bool, int, unsigned long)
Unexecuted instantiation: ogrlayerarrow.cpp:unsigned long FillListArray<int, double, GetFromRealList>(ArrowArray*, std::__1::deque<std::__1::unique_ptr<OGRFeature, std::__1::default_delete<OGRFeature> >, std::__1::allocator<std::__1::unique_ptr<OGRFeature, std::__1::default_delete<OGRFeature> > > >&, unsigned long, bool, int, unsigned long)
1145
1146
template <class OffsetType, class GetFromList>
1147
static size_t
1148
FillListArrayBool(struct ArrowArray *psChild,
1149
                  std::deque<std::unique_ptr<OGRFeature>> &apoFeatures,
1150
                  const size_t nFeatureCountLimit, const bool bIsNullable,
1151
                  const int i, const size_t nMemLimit)
1152
0
{
1153
0
    psChild->n_buffers = 2;
1154
0
    psChild->buffers = static_cast<const void **>(CPLCalloc(2, sizeof(void *)));
1155
0
    uint8_t *pabyValidity = nullptr;
1156
0
    OffsetType *panOffsets =
1157
0
        static_cast<OffsetType *>(VSI_MALLOC_ALIGNED_AUTO_VERBOSE(
1158
0
            sizeof(OffsetType) * (1 + nFeatureCountLimit)));
1159
0
    if (panOffsets == nullptr)
1160
0
        return 0;
1161
0
    psChild->buffers[1] = panOffsets;
1162
1163
0
    OffsetType nOffset = 0;
1164
0
    size_t nFeatCount = 0;
1165
0
    for (size_t iFeat = 0; iFeat < nFeatureCountLimit; ++iFeat, ++nFeatCount)
1166
0
    {
1167
0
        panOffsets[iFeat] = nOffset;
1168
0
        auto &poFeature = apoFeatures[iFeat];
1169
0
        const auto psRawField = poFeature->GetRawFieldRef(i);
1170
0
        if (IsValidField(psRawField))
1171
0
        {
1172
0
            const unsigned nCount = GetFromList::getCount(psRawField);
1173
0
            if (nCount > static_cast<size_t>(nMemLimit - nOffset))
1174
0
            {
1175
0
                if (nFeatCount == 0)
1176
0
                    return 0;
1177
0
                break;
1178
0
            }
1179
0
            nOffset += static_cast<OffsetType>(nCount);
1180
0
        }
1181
0
        else if (bIsNullable)
1182
0
        {
1183
0
            ++psChild->null_count;
1184
0
            if (pabyValidity == nullptr)
1185
0
            {
1186
0
                pabyValidity = AllocValidityBitmap(nFeatureCountLimit);
1187
0
                psChild->buffers[0] = pabyValidity;
1188
0
                if (pabyValidity == nullptr)
1189
0
                    return 0;
1190
0
            }
1191
0
            UnsetBit(pabyValidity, iFeat);
1192
0
        }
1193
0
    }
1194
0
    panOffsets[nFeatCount] = nOffset;
1195
1196
0
    psChild->n_children = 1;
1197
0
    psChild->children = static_cast<struct ArrowArray **>(
1198
0
        CPLCalloc(1, sizeof(struct ArrowArray *)));
1199
0
    psChild->children[0] = static_cast<struct ArrowArray *>(
1200
0
        CPLCalloc(1, sizeof(struct ArrowArray)));
1201
0
    auto psValueChild = psChild->children[0];
1202
1203
0
    psValueChild->release = OGRLayerDefaultReleaseArray;
1204
0
    psValueChild->n_buffers = 2;
1205
0
    psValueChild->buffers =
1206
0
        static_cast<const void **>(CPLCalloc(2, sizeof(void *)));
1207
0
    psValueChild->length = nOffset;
1208
0
    uint8_t *panValues = static_cast<uint8_t *>(
1209
0
        VSI_MALLOC_ALIGNED_AUTO_VERBOSE((nOffset + 7 + 1) / 8));
1210
0
    if (panValues == nullptr)
1211
0
        return 0;
1212
0
    memset(panValues, 0, (nOffset + 7) / 8);
1213
0
    psValueChild->buffers[1] = panValues;
1214
1215
0
    nOffset = 0;
1216
0
    for (size_t iFeat = 0; iFeat < nFeatureCountLimit; ++iFeat)
1217
0
    {
1218
0
        auto &poFeature = apoFeatures[iFeat];
1219
0
        const auto psRawField = poFeature->GetRawFieldRef(i);
1220
0
        if (IsValidField(psRawField))
1221
0
        {
1222
0
            const int nCount = GetFromList::getCount(psRawField);
1223
0
            const auto paList = GetFromList::getValues(psRawField);
1224
1225
0
            for (int j = 0; j < nCount; ++j)
1226
0
            {
1227
0
                if (paList[j])
1228
0
                    SetBit(panValues, nOffset + j);
1229
0
            }
1230
0
            nOffset += static_cast<OffsetType>(nCount);
1231
0
        }
1232
0
    }
1233
1234
0
    return nFeatCount;
1235
0
}
1236
1237
/************************************************************************/
1238
/*                        FillStringArray()                             */
1239
/************************************************************************/
1240
1241
template <class T>
1242
static size_t
1243
FillStringArray(struct ArrowArray *psChild,
1244
                std::deque<std::unique_ptr<OGRFeature>> &apoFeatures,
1245
                const size_t nFeatureCountLimit, const bool bIsNullable,
1246
                const int i, const size_t nMemLimit)
1247
0
{
1248
0
    psChild->n_buffers = 3;
1249
0
    psChild->buffers = static_cast<const void **>(CPLCalloc(3, sizeof(void *)));
1250
0
    uint8_t *pabyValidity = nullptr;
1251
0
    T *panOffsets = static_cast<T *>(
1252
0
        VSI_MALLOC_ALIGNED_AUTO_VERBOSE(sizeof(T) * (1 + nFeatureCountLimit)));
1253
0
    if (panOffsets == nullptr)
1254
0
        return 0;
1255
0
    psChild->buffers[1] = panOffsets;
1256
1257
0
    size_t nOffset = 0;
1258
0
    size_t nFeatCount = 0;
1259
0
    for (size_t iFeat = 0; iFeat < nFeatureCountLimit; ++iFeat, ++nFeatCount)
1260
0
    {
1261
0
        panOffsets[iFeat] = static_cast<T>(nOffset);
1262
0
        const auto psRawField = apoFeatures[iFeat]->GetRawFieldRef(i);
1263
0
        if (IsValidField(psRawField))
1264
0
        {
1265
0
            const size_t nLen = strlen(psRawField->String);
1266
0
            if (nLen > nMemLimit - nOffset)
1267
0
            {
1268
0
                if (nFeatCount == 0)
1269
0
                    return 0;
1270
0
                break;
1271
0
            }
1272
0
            nOffset += static_cast<T>(nLen);
1273
0
        }
1274
0
        else if (bIsNullable)
1275
0
        {
1276
0
            ++psChild->null_count;
1277
0
            if (pabyValidity == nullptr)
1278
0
            {
1279
0
                pabyValidity = AllocValidityBitmap(nFeatureCountLimit);
1280
0
                psChild->buffers[0] = pabyValidity;
1281
0
                if (pabyValidity == nullptr)
1282
0
                    return 0;
1283
0
            }
1284
0
            UnsetBit(pabyValidity, iFeat);
1285
0
        }
1286
0
    }
1287
0
    panOffsets[nFeatCount] = static_cast<T>(nOffset);
1288
1289
0
    char *pachValues =
1290
0
        static_cast<char *>(VSI_MALLOC_ALIGNED_AUTO_VERBOSE(nOffset + 1));
1291
0
    if (pachValues == nullptr)
1292
0
        return 0;
1293
0
    psChild->buffers[2] = pachValues;
1294
1295
0
    nOffset = 0;
1296
0
    for (size_t iFeat = 0; iFeat < nFeatCount; ++iFeat)
1297
0
    {
1298
0
        const size_t nLen =
1299
0
            static_cast<size_t>(panOffsets[iFeat + 1] - panOffsets[iFeat]);
1300
0
        if (nLen)
1301
0
        {
1302
0
            const auto psRawField = apoFeatures[iFeat]->GetRawFieldRef(i);
1303
0
            memcpy(pachValues + nOffset, psRawField->String, nLen);
1304
0
            nOffset += nLen;
1305
0
        }
1306
0
    }
1307
1308
0
    return nFeatCount;
1309
0
}
1310
1311
/************************************************************************/
1312
/*                        FillStringListArray()                         */
1313
/************************************************************************/
1314
1315
template <class OffsetType>
1316
static size_t
1317
FillStringListArray(struct ArrowArray *psChild,
1318
                    std::deque<std::unique_ptr<OGRFeature>> &apoFeatures,
1319
                    const size_t nFeatureCountLimit, const bool bIsNullable,
1320
                    const int i, const size_t nMemLimit)
1321
0
{
1322
0
    psChild->n_buffers = 2;
1323
0
    psChild->buffers = static_cast<const void **>(CPLCalloc(2, sizeof(void *)));
1324
0
    uint8_t *pabyValidity = nullptr;
1325
0
    OffsetType *panOffsets =
1326
0
        static_cast<OffsetType *>(VSI_MALLOC_ALIGNED_AUTO_VERBOSE(
1327
0
            sizeof(OffsetType) * (1 + nFeatureCountLimit)));
1328
0
    if (panOffsets == nullptr)
1329
0
        return false;
1330
0
    psChild->buffers[1] = panOffsets;
1331
1332
0
    OffsetType nStrings = 0;
1333
0
    OffsetType nCountChars = 0;
1334
0
    size_t nFeatCount = 0;
1335
0
    for (size_t iFeat = 0; iFeat < nFeatureCountLimit; ++iFeat, ++nFeatCount)
1336
0
    {
1337
0
        panOffsets[iFeat] = nStrings;
1338
0
        auto &poFeature = apoFeatures[iFeat];
1339
0
        const auto psRawField = poFeature->GetRawFieldRef(i);
1340
0
        if (IsValidField(psRawField))
1341
0
        {
1342
0
            const int nCount = psRawField->StringList.nCount;
1343
0
            if (static_cast<size_t>(nCount) >
1344
0
                static_cast<size_t>(nMemLimit - nStrings))
1345
0
            {
1346
0
                if (nFeatCount == 0)
1347
0
                    return 0;
1348
0
                goto after_loop;
1349
0
            }
1350
0
            for (int j = 0; j < nCount; ++j)
1351
0
            {
1352
0
                const size_t nLen = strlen(psRawField->StringList.paList[j]);
1353
0
                if (nLen > static_cast<size_t>(nMemLimit - nCountChars))
1354
0
                {
1355
0
                    if (nFeatCount == 0)
1356
0
                        return 0;
1357
0
                    goto after_loop;
1358
0
                }
1359
0
                nCountChars += static_cast<OffsetType>(nLen);
1360
0
            }
1361
0
            nStrings += static_cast<OffsetType>(nCount);
1362
0
        }
1363
0
        else if (bIsNullable)
1364
0
        {
1365
0
            ++psChild->null_count;
1366
0
            if (pabyValidity == nullptr)
1367
0
            {
1368
0
                pabyValidity = AllocValidityBitmap(nFeatureCountLimit);
1369
0
                psChild->buffers[0] = pabyValidity;
1370
0
                if (pabyValidity == nullptr)
1371
0
                    return 0;
1372
0
            }
1373
0
            UnsetBit(pabyValidity, iFeat);
1374
0
        }
1375
0
    }
1376
0
after_loop:
1377
0
    panOffsets[nFeatCount] = nStrings;
1378
1379
0
    psChild->n_children = 1;
1380
0
    psChild->children = static_cast<struct ArrowArray **>(
1381
0
        CPLCalloc(1, sizeof(struct ArrowArray *)));
1382
0
    psChild->children[0] = static_cast<struct ArrowArray *>(
1383
0
        CPLCalloc(1, sizeof(struct ArrowArray)));
1384
0
    auto psValueChild = psChild->children[0];
1385
1386
0
    psValueChild->release = OGRLayerDefaultReleaseArray;
1387
0
    psValueChild->length = nStrings;
1388
0
    psValueChild->n_buffers = 3;
1389
0
    psValueChild->buffers =
1390
0
        static_cast<const void **>(CPLCalloc(3, sizeof(void *)));
1391
1392
0
    OffsetType *panChildOffsets = static_cast<OffsetType *>(
1393
0
        VSI_MALLOC_ALIGNED_AUTO_VERBOSE(sizeof(OffsetType) * (1 + nStrings)));
1394
0
    if (panChildOffsets == nullptr)
1395
0
        return 0;
1396
0
    psValueChild->buffers[1] = panChildOffsets;
1397
1398
0
    char *pachValues =
1399
0
        static_cast<char *>(VSI_MALLOC_ALIGNED_AUTO_VERBOSE(nCountChars + 1));
1400
0
    if (pachValues == nullptr)
1401
0
        return 0;
1402
0
    psValueChild->buffers[2] = pachValues;
1403
1404
0
    nStrings = 0;
1405
0
    nCountChars = 0;
1406
0
    for (size_t iFeat = 0; iFeat < nFeatCount; ++iFeat)
1407
0
    {
1408
0
        auto &poFeature = apoFeatures[iFeat];
1409
0
        const auto psRawField = poFeature->GetRawFieldRef(i);
1410
0
        if (IsValidField(psRawField))
1411
0
        {
1412
0
            const int nCount = psRawField->StringList.nCount;
1413
0
            for (int j = 0; j < nCount; ++j)
1414
0
            {
1415
0
                panChildOffsets[nStrings] = nCountChars;
1416
0
                ++nStrings;
1417
0
                const size_t nLen = strlen(psRawField->StringList.paList[j]);
1418
0
                memcpy(pachValues + nCountChars,
1419
0
                       psRawField->StringList.paList[j], nLen);
1420
0
                nCountChars += static_cast<OffsetType>(nLen);
1421
0
            }
1422
0
        }
1423
0
    }
1424
0
    panChildOffsets[nStrings] = nCountChars;
1425
1426
0
    return nFeatCount;
1427
0
}
1428
1429
/************************************************************************/
1430
/*                        FillBinaryArray()                             */
1431
/************************************************************************/
1432
1433
template <class T>
1434
static size_t
1435
FillBinaryArray(struct ArrowArray *psChild,
1436
                std::deque<std::unique_ptr<OGRFeature>> &apoFeatures,
1437
                const size_t nFeatureCountLimit, const bool bIsNullable,
1438
                const int i, const size_t nMemLimit)
1439
0
{
1440
0
    psChild->n_buffers = 3;
1441
0
    psChild->buffers = static_cast<const void **>(CPLCalloc(3, sizeof(void *)));
1442
0
    uint8_t *pabyValidity = nullptr;
1443
0
    T *panOffsets = static_cast<T *>(
1444
0
        VSI_MALLOC_ALIGNED_AUTO_VERBOSE(sizeof(T) * (1 + nFeatureCountLimit)));
1445
0
    if (panOffsets == nullptr)
1446
0
        return 0;
1447
0
    psChild->buffers[1] = panOffsets;
1448
1449
0
    T nOffset = 0;
1450
0
    size_t nFeatCount = 0;
1451
0
    for (size_t iFeat = 0; iFeat < nFeatureCountLimit; ++iFeat, ++nFeatCount)
1452
0
    {
1453
0
        panOffsets[iFeat] = nOffset;
1454
0
        const auto psRawField = apoFeatures[iFeat]->GetRawFieldRef(i);
1455
0
        if (IsValidField(psRawField))
1456
0
        {
1457
0
            const size_t nLen = psRawField->Binary.nCount;
1458
0
            if (nLen > static_cast<size_t>(nMemLimit - nOffset))
1459
0
            {
1460
0
                if (iFeat == 0)
1461
0
                    return 0;
1462
0
                break;
1463
0
            }
1464
0
            nOffset += static_cast<T>(nLen);
1465
0
        }
1466
0
        else if (bIsNullable)
1467
0
        {
1468
0
            ++psChild->null_count;
1469
0
            if (pabyValidity == nullptr)
1470
0
            {
1471
0
                pabyValidity = AllocValidityBitmap(nFeatureCountLimit);
1472
0
                psChild->buffers[0] = pabyValidity;
1473
0
                if (pabyValidity == nullptr)
1474
0
                    return 0;
1475
0
            }
1476
0
            UnsetBit(pabyValidity, iFeat);
1477
0
        }
1478
0
    }
1479
0
    panOffsets[nFeatCount] = nOffset;
1480
1481
0
    GByte *pabyValues =
1482
0
        static_cast<GByte *>(VSI_MALLOC_ALIGNED_AUTO_VERBOSE(nOffset + 1));
1483
0
    if (pabyValues == nullptr)
1484
0
        return 0;
1485
0
    psChild->buffers[2] = pabyValues;
1486
1487
0
    nOffset = 0;
1488
0
    for (size_t iFeat = 0; iFeat < nFeatCount; ++iFeat)
1489
0
    {
1490
0
        const size_t nLen =
1491
0
            static_cast<size_t>(panOffsets[iFeat + 1] - panOffsets[iFeat]);
1492
0
        if (nLen)
1493
0
        {
1494
0
            const auto psRawField = apoFeatures[iFeat]->GetRawFieldRef(i);
1495
0
            memcpy(pabyValues + nOffset, psRawField->Binary.paData, nLen);
1496
0
            nOffset += static_cast<T>(nLen);
1497
0
        }
1498
0
    }
1499
1500
0
    return nFeatCount;
1501
0
}
1502
1503
/************************************************************************/
1504
/*                     FillFixedWidthBinaryArray()                      */
1505
/************************************************************************/
1506
1507
static bool
1508
FillFixedWidthBinaryArray(struct ArrowArray *psChild,
1509
                          std::deque<std::unique_ptr<OGRFeature>> &apoFeatures,
1510
                          const size_t nFeatureCountLimit,
1511
                          const bool bIsNullable, const int nWidth, const int i)
1512
0
{
1513
0
    psChild->n_buffers = 2;
1514
0
    psChild->buffers = static_cast<const void **>(CPLCalloc(3, sizeof(void *)));
1515
0
    uint8_t *pabyValidity = nullptr;
1516
1517
0
    assert(nFeatureCountLimit + 1 <=
1518
0
           std::numeric_limits<size_t>::max() / nWidth);
1519
0
    GByte *pabyValues = static_cast<GByte *>(
1520
0
        VSI_MALLOC_ALIGNED_AUTO_VERBOSE((nFeatureCountLimit + 1) * nWidth));
1521
0
    if (pabyValues == nullptr)
1522
0
        return false;
1523
0
    psChild->buffers[1] = pabyValues;
1524
1525
0
    for (size_t iFeat = 0; iFeat < nFeatureCountLimit; ++iFeat)
1526
0
    {
1527
0
        const auto psRawField = apoFeatures[iFeat]->GetRawFieldRef(i);
1528
0
        if (IsValidField(psRawField))
1529
0
        {
1530
0
            const auto nLen = psRawField->Binary.nCount;
1531
0
            if (nLen < nWidth)
1532
0
            {
1533
0
                memcpy(pabyValues + iFeat * nWidth, psRawField->Binary.paData,
1534
0
                       nLen);
1535
0
                memset(pabyValues + iFeat * nWidth + nLen, 0, nWidth - nLen);
1536
0
            }
1537
0
            else
1538
0
            {
1539
0
                memcpy(pabyValues + iFeat * nWidth, psRawField->Binary.paData,
1540
0
                       nWidth);
1541
0
            }
1542
0
        }
1543
0
        else
1544
0
        {
1545
0
            memset(pabyValues + iFeat * nWidth, 0, nWidth);
1546
0
            if (bIsNullable)
1547
0
            {
1548
0
                ++psChild->null_count;
1549
0
                if (pabyValidity == nullptr)
1550
0
                {
1551
0
                    pabyValidity = AllocValidityBitmap(nFeatureCountLimit);
1552
0
                    psChild->buffers[0] = pabyValidity;
1553
0
                    if (pabyValidity == nullptr)
1554
0
                        return false;
1555
0
                }
1556
0
                UnsetBit(pabyValidity, iFeat);
1557
0
            }
1558
0
        }
1559
0
    }
1560
1561
0
    return true;
1562
0
}
1563
1564
/************************************************************************/
1565
/*                      FillWKBGeometryArray()                          */
1566
/************************************************************************/
1567
1568
template <class T>
1569
static size_t
1570
FillWKBGeometryArray(struct ArrowArray *psChild,
1571
                     std::deque<std::unique_ptr<OGRFeature>> &apoFeatures,
1572
                     const size_t nFeatureCountLimit,
1573
                     const OGRGeomFieldDefn *poFieldDefn, const int i,
1574
                     const size_t nMemLimit)
1575
0
{
1576
0
    const bool bIsNullable = CPL_TO_BOOL(poFieldDefn->IsNullable());
1577
0
    psChild->n_buffers = 3;
1578
0
    psChild->buffers = static_cast<const void **>(CPLCalloc(3, sizeof(void *)));
1579
0
    uint8_t *pabyValidity = nullptr;
1580
0
    T *panOffsets = static_cast<T *>(
1581
0
        VSI_MALLOC_ALIGNED_AUTO_VERBOSE(sizeof(T) * (1 + nFeatureCountLimit)));
1582
0
    if (panOffsets == nullptr)
1583
0
        return 0;
1584
0
    psChild->buffers[1] = panOffsets;
1585
0
    const auto eGeomType = poFieldDefn->GetType();
1586
0
    auto poEmptyGeom =
1587
0
        std::unique_ptr<OGRGeometry>(OGRGeometryFactory::createGeometry(
1588
0
            (eGeomType == wkbNone || wkbFlatten(eGeomType) == wkbUnknown)
1589
0
                ? wkbGeometryCollection
1590
0
                : eGeomType));
1591
1592
0
    size_t nOffset = 0;
1593
0
    size_t nFeatCount = 0;
1594
0
    for (size_t iFeat = 0; iFeat < nFeatureCountLimit; ++iFeat, ++nFeatCount)
1595
0
    {
1596
0
        panOffsets[iFeat] = static_cast<T>(nOffset);
1597
0
        const auto poGeom = apoFeatures[iFeat]->GetGeomFieldRef(i);
1598
0
        if (poGeom != nullptr)
1599
0
        {
1600
0
            const size_t nLen = poGeom->WkbSize();
1601
0
            if (nLen > nMemLimit - nOffset)
1602
0
            {
1603
0
                if (nFeatCount == 0)
1604
0
                    return 0;
1605
0
                break;
1606
0
            }
1607
0
            nOffset += static_cast<T>(nLen);
1608
0
        }
1609
0
        else if (bIsNullable)
1610
0
        {
1611
0
            ++psChild->null_count;
1612
0
            if (pabyValidity == nullptr)
1613
0
            {
1614
0
                pabyValidity = AllocValidityBitmap(nFeatureCountLimit);
1615
0
                psChild->buffers[0] = pabyValidity;
1616
0
                if (pabyValidity == nullptr)
1617
0
                    return 0;
1618
0
            }
1619
0
            UnsetBit(pabyValidity, iFeat);
1620
0
        }
1621
0
        else if (poEmptyGeom)
1622
0
        {
1623
0
            const size_t nLen = poEmptyGeom->WkbSize();
1624
0
            if (nLen > nMemLimit - nOffset)
1625
0
            {
1626
0
                if (nFeatCount == 0)
1627
0
                    return 0;
1628
0
                break;
1629
0
            }
1630
0
            nOffset += static_cast<T>(nLen);
1631
0
        }
1632
0
    }
1633
0
    panOffsets[nFeatCount] = static_cast<T>(nOffset);
1634
1635
0
    GByte *pabyValues =
1636
0
        static_cast<GByte *>(VSI_MALLOC_ALIGNED_AUTO_VERBOSE(nOffset + 1));
1637
0
    if (pabyValues == nullptr)
1638
0
        return 0;
1639
0
    psChild->buffers[2] = pabyValues;
1640
1641
0
    nOffset = 0;
1642
0
    for (size_t iFeat = 0; iFeat < nFeatCount; ++iFeat)
1643
0
    {
1644
0
        const size_t nLen =
1645
0
            static_cast<size_t>(panOffsets[iFeat + 1] - panOffsets[iFeat]);
1646
0
        if (nLen)
1647
0
        {
1648
0
            const auto poGeom = apoFeatures[iFeat]->GetGeomFieldRef(i);
1649
0
            poGeom->exportToWkb(wkbNDR, pabyValues + nOffset, wkbVariantIso);
1650
0
            nOffset += nLen;
1651
0
        }
1652
0
        else if (!bIsNullable && poEmptyGeom)
1653
0
        {
1654
0
            poEmptyGeom->exportToWkb(wkbNDR, pabyValues + nOffset,
1655
0
                                     wkbVariantIso);
1656
0
            nOffset += nLen;
1657
0
        }
1658
0
    }
1659
1660
0
    return nFeatCount;
1661
0
}
1662
1663
/************************************************************************/
1664
/*                        FillDateArray()                               */
1665
/************************************************************************/
1666
1667
static bool FillDateArray(struct ArrowArray *psChild,
1668
                          std::deque<std::unique_ptr<OGRFeature>> &apoFeatures,
1669
                          const size_t nFeatureCountLimit,
1670
                          const bool bIsNullable, const int i)
1671
0
{
1672
0
    psChild->n_buffers = 2;
1673
0
    psChild->buffers = static_cast<const void **>(CPLCalloc(2, sizeof(void *)));
1674
0
    uint8_t *pabyValidity = nullptr;
1675
0
    int32_t *panValues = static_cast<int32_t *>(VSI_MALLOC_ALIGNED_AUTO_VERBOSE(
1676
0
        sizeof(int32_t) * (nFeatureCountLimit + 1)));
1677
0
    if (panValues == nullptr)
1678
0
        return false;
1679
0
    psChild->buffers[1] = panValues;
1680
0
    for (size_t iFeat = 0; iFeat < nFeatureCountLimit; ++iFeat)
1681
0
    {
1682
0
        auto &poFeature = apoFeatures[iFeat];
1683
0
        const auto psRawField = poFeature->GetRawFieldRef(i);
1684
0
        if (IsValidField(psRawField))
1685
0
        {
1686
0
            struct tm brokenDown;
1687
0
            memset(&brokenDown, 0, sizeof(brokenDown));
1688
0
            brokenDown.tm_year = psRawField->Date.Year - 1900;
1689
0
            brokenDown.tm_mon = psRawField->Date.Month - 1;
1690
0
            brokenDown.tm_mday = psRawField->Date.Day;
1691
0
            panValues[iFeat] =
1692
0
                static_cast<int>(CPLYMDHMSToUnixTime(&brokenDown) / 86400);
1693
0
        }
1694
0
        else if (bIsNullable)
1695
0
        {
1696
0
            panValues[iFeat] = 0;
1697
0
            ++psChild->null_count;
1698
0
            if (pabyValidity == nullptr)
1699
0
            {
1700
0
                pabyValidity = AllocValidityBitmap(nFeatureCountLimit);
1701
0
                psChild->buffers[0] = pabyValidity;
1702
0
                if (pabyValidity == nullptr)
1703
0
                    return false;
1704
0
            }
1705
0
            UnsetBit(pabyValidity, iFeat);
1706
0
        }
1707
0
        else
1708
0
        {
1709
0
            panValues[iFeat] = 0;
1710
0
        }
1711
0
    }
1712
0
    return true;
1713
0
}
1714
1715
/************************************************************************/
1716
/*                        FillTimeArray()                               */
1717
/************************************************************************/
1718
1719
static bool FillTimeArray(struct ArrowArray *psChild,
1720
                          std::deque<std::unique_ptr<OGRFeature>> &apoFeatures,
1721
                          const size_t nFeatureCountLimit,
1722
                          const bool bIsNullable, const int i)
1723
0
{
1724
0
    psChild->n_buffers = 2;
1725
0
    psChild->buffers = static_cast<const void **>(CPLCalloc(2, sizeof(void *)));
1726
0
    uint8_t *pabyValidity = nullptr;
1727
0
    int32_t *panValues = static_cast<int32_t *>(VSI_MALLOC_ALIGNED_AUTO_VERBOSE(
1728
0
        sizeof(int32_t) * (nFeatureCountLimit + 1)));
1729
0
    if (panValues == nullptr)
1730
0
        return false;
1731
0
    psChild->buffers[1] = panValues;
1732
0
    for (size_t iFeat = 0; iFeat < nFeatureCountLimit; ++iFeat)
1733
0
    {
1734
0
        auto &poFeature = apoFeatures[iFeat];
1735
0
        const auto psRawField = poFeature->GetRawFieldRef(i);
1736
0
        if (IsValidField(psRawField))
1737
0
        {
1738
0
            panValues[iFeat] =
1739
0
                psRawField->Date.Hour * 3600000 +
1740
0
                psRawField->Date.Minute * 60000 +
1741
0
                static_cast<int>(psRawField->Date.Second * 1000 + 0.5);
1742
0
        }
1743
0
        else if (bIsNullable)
1744
0
        {
1745
0
            panValues[iFeat] = 0;
1746
0
            ++psChild->null_count;
1747
0
            if (pabyValidity == nullptr)
1748
0
            {
1749
0
                pabyValidity = AllocValidityBitmap(nFeatureCountLimit);
1750
0
                psChild->buffers[0] = pabyValidity;
1751
0
                if (pabyValidity == nullptr)
1752
0
                    return false;
1753
0
            }
1754
0
            UnsetBit(pabyValidity, iFeat);
1755
0
        }
1756
0
        else
1757
0
        {
1758
0
            panValues[iFeat] = 0;
1759
0
        }
1760
0
    }
1761
0
    return true;
1762
0
}
1763
1764
/************************************************************************/
1765
/*                       FillDateTimeArray()                            */
1766
/************************************************************************/
1767
1768
static bool
1769
FillDateTimeArray(struct ArrowArray *psChild,
1770
                  std::deque<std::unique_ptr<OGRFeature>> &apoFeatures,
1771
                  const size_t nFeatureCountLimit, const bool bIsNullable,
1772
                  const int i, int nFieldTZFlag)
1773
0
{
1774
0
    psChild->n_buffers = 2;
1775
0
    psChild->buffers = static_cast<const void **>(CPLCalloc(2, sizeof(void *)));
1776
0
    uint8_t *pabyValidity = nullptr;
1777
0
    int64_t *panValues = static_cast<int64_t *>(VSI_MALLOC_ALIGNED_AUTO_VERBOSE(
1778
0
        sizeof(int64_t) * (nFeatureCountLimit + 1)));
1779
0
    if (panValues == nullptr)
1780
0
        return false;
1781
0
    psChild->buffers[1] = panValues;
1782
0
    struct tm brokenDown;
1783
0
    memset(&brokenDown, 0, sizeof(brokenDown));
1784
0
    for (size_t iFeat = 0; iFeat < nFeatureCountLimit; ++iFeat)
1785
0
    {
1786
0
        auto &poFeature = apoFeatures[iFeat];
1787
0
        const auto psRawField = poFeature->GetRawFieldRef(i);
1788
0
        if (IsValidField(psRawField))
1789
0
        {
1790
0
            brokenDown.tm_year = psRawField->Date.Year - 1900;
1791
0
            brokenDown.tm_mon = psRawField->Date.Month - 1;
1792
0
            brokenDown.tm_mday = psRawField->Date.Day;
1793
0
            brokenDown.tm_hour = psRawField->Date.Hour;
1794
0
            brokenDown.tm_min = psRawField->Date.Minute;
1795
0
            brokenDown.tm_sec = static_cast<int>(psRawField->Date.Second);
1796
0
            auto nVal =
1797
0
                CPLYMDHMSToUnixTime(&brokenDown) * 1000 +
1798
0
                (static_cast<int>(psRawField->Date.Second * 1000 + 0.5) % 1000);
1799
0
            if (nFieldTZFlag >= OGR_TZFLAG_MIXED_TZ &&
1800
0
                psRawField->Date.TZFlag > OGR_TZFLAG_MIXED_TZ)
1801
0
            {
1802
                // Convert for psRawField->Date.TZFlag to UTC
1803
0
                const int TZOffset =
1804
0
                    (psRawField->Date.TZFlag - OGR_TZFLAG_UTC) * 15;
1805
0
                const int TZOffsetMS = TZOffset * 60 * 1000;
1806
0
                nVal -= TZOffsetMS;
1807
0
            }
1808
0
            panValues[iFeat] = nVal;
1809
0
        }
1810
0
        else if (bIsNullable)
1811
0
        {
1812
0
            panValues[iFeat] = 0;
1813
0
            ++psChild->null_count;
1814
0
            if (pabyValidity == nullptr)
1815
0
            {
1816
0
                pabyValidity = AllocValidityBitmap(nFeatureCountLimit);
1817
0
                psChild->buffers[0] = pabyValidity;
1818
0
                if (pabyValidity == nullptr)
1819
0
                    return false;
1820
0
            }
1821
0
            UnsetBit(pabyValidity, iFeat);
1822
0
        }
1823
0
        else
1824
0
        {
1825
0
            panValues[iFeat] = 0;
1826
0
        }
1827
0
    }
1828
0
    return true;
1829
0
}
1830
1831
/************************************************************************/
1832
/*                   FillDateTimeArrayAsString()                        */
1833
/************************************************************************/
1834
1835
static size_t
1836
FillDateTimeArrayAsString(struct ArrowArray *psChild,
1837
                          std::deque<std::unique_ptr<OGRFeature>> &apoFeatures,
1838
                          const size_t nFeatureCountLimit,
1839
                          const bool bIsNullable, const int i,
1840
                          const size_t nMemLimit)
1841
0
{
1842
0
    psChild->n_buffers = 3;
1843
0
    psChild->buffers = static_cast<const void **>(CPLCalloc(3, sizeof(void *)));
1844
0
    uint8_t *pabyValidity = nullptr;
1845
0
    using T = uint32_t;
1846
0
    T *panOffsets = static_cast<T *>(
1847
0
        VSI_MALLOC_ALIGNED_AUTO_VERBOSE(sizeof(T) * (1 + nFeatureCountLimit)));
1848
0
    if (panOffsets == nullptr)
1849
0
        return 0;
1850
0
    psChild->buffers[1] = panOffsets;
1851
1852
0
    size_t nOffset = 0;
1853
0
    size_t nFeatCount = 0;
1854
0
    for (size_t iFeat = 0; iFeat < nFeatureCountLimit; ++iFeat, ++nFeatCount)
1855
0
    {
1856
0
        panOffsets[iFeat] = static_cast<T>(nOffset);
1857
0
        const auto psRawField = apoFeatures[iFeat]->GetRawFieldRef(i);
1858
0
        if (IsValidField(psRawField))
1859
0
        {
1860
0
            size_t nLen = strlen("YYYY-MM-DDTHH:MM:SS");
1861
0
            if (fmodf(psRawField->Date.Second, 1.0f) != 0)
1862
0
                nLen += strlen(".sss");
1863
0
            if (psRawField->Date.TZFlag == OGR_TZFLAG_UTC)
1864
0
                nLen += 1;  // 'Z'
1865
0
            else if (psRawField->Date.TZFlag > OGR_TZFLAG_MIXED_TZ)
1866
0
                nLen += strlen("+hh:mm");
1867
0
            if (nLen > nMemLimit - nOffset)
1868
0
            {
1869
0
                if (nFeatCount == 0)
1870
0
                    return 0;
1871
0
                break;
1872
0
            }
1873
0
            nOffset += static_cast<T>(nLen);
1874
0
        }
1875
0
        else if (bIsNullable)
1876
0
        {
1877
0
            ++psChild->null_count;
1878
0
            if (pabyValidity == nullptr)
1879
0
            {
1880
0
                pabyValidity = AllocValidityBitmap(nFeatureCountLimit);
1881
0
                psChild->buffers[0] = pabyValidity;
1882
0
                if (pabyValidity == nullptr)
1883
0
                    return 0;
1884
0
            }
1885
0
            UnsetBit(pabyValidity, iFeat);
1886
0
        }
1887
0
    }
1888
0
    panOffsets[nFeatCount] = static_cast<T>(nOffset);
1889
1890
0
    char *pachValues =
1891
0
        static_cast<char *>(VSI_MALLOC_ALIGNED_AUTO_VERBOSE(nOffset + 1));
1892
0
    if (pachValues == nullptr)
1893
0
        return 0;
1894
0
    psChild->buffers[2] = pachValues;
1895
1896
0
    nOffset = 0;
1897
0
    char szBuffer[OGR_SIZEOF_ISO8601_DATETIME_BUFFER];
1898
0
    OGRISO8601Format sFormat;
1899
0
    sFormat.ePrecision = OGRISO8601Precision::AUTO;
1900
0
    for (size_t iFeat = 0; iFeat < nFeatCount; ++iFeat)
1901
0
    {
1902
0
        const int nLen =
1903
0
            static_cast<int>(panOffsets[iFeat + 1] - panOffsets[iFeat]);
1904
0
        if (nLen)
1905
0
        {
1906
0
            const auto psRawField = apoFeatures[iFeat]->GetRawFieldRef(i);
1907
0
            int nBufSize = OGRGetISO8601DateTime(psRawField, sFormat, szBuffer);
1908
0
            if (nBufSize)
1909
0
            {
1910
0
                memcpy(pachValues + nOffset, szBuffer,
1911
0
                       std::min(nLen, nBufSize));
1912
0
            }
1913
0
            if (nBufSize < nLen)
1914
0
            {
1915
0
                memset(pachValues + nOffset + nBufSize, 0, nLen - nBufSize);
1916
0
            }
1917
0
            nOffset += nLen;
1918
0
        }
1919
0
    }
1920
1921
0
    return nFeatCount;
1922
0
}
1923
1924
/************************************************************************/
1925
/*                          GetNextArrowArray()                         */
1926
/************************************************************************/
1927
1928
/** Default implementation of the ArrowArrayStream::get_next() callback.
1929
 *
1930
 * To be used by driver implementations that have a custom GetArrowStream()
1931
 * implementation.
1932
 *
1933
 * @since GDAL 3.6
1934
 */
1935
int OGRLayer::GetNextArrowArray(struct ArrowArrayStream *stream,
1936
                                struct ArrowArray *out_array)
1937
0
{
1938
0
    ArrowArrayStreamPrivateDataSharedDataWrapper *poPrivate =
1939
0
        static_cast<ArrowArrayStreamPrivateDataSharedDataWrapper *>(
1940
0
            stream->private_data);
1941
1942
0
    const bool bIncludeFID = CPLTestBool(
1943
0
        m_aosArrowArrayStreamOptions.FetchNameValueDef("INCLUDE_FID", "YES"));
1944
0
    const bool bDateTimeAsString = m_aosArrowArrayStreamOptions.FetchBool(
1945
0
        GAS_OPT_DATETIME_AS_STRING, false);
1946
0
    int nMaxBatchSize = atoi(m_aosArrowArrayStreamOptions.FetchNameValueDef(
1947
0
        "MAX_FEATURES_IN_BATCH", "65536"));
1948
0
    if (nMaxBatchSize <= 0)
1949
0
        nMaxBatchSize = 1;
1950
0
    if (nMaxBatchSize > INT_MAX - 1)
1951
0
        nMaxBatchSize = INT_MAX - 1;
1952
1953
0
    auto &oFeatureQueue =
1954
0
        m_poSharedArrowArrayStreamPrivateData->m_oFeatureQueue;
1955
1956
0
    memset(out_array, 0, sizeof(*out_array));
1957
1958
0
    auto poLayerDefn = GetLayerDefn();
1959
0
    const int nFieldCount = poLayerDefn->GetFieldCount();
1960
0
    const int nGeomFieldCount = poLayerDefn->GetGeomFieldCount();
1961
0
    const int nMaxChildren =
1962
0
        (bIncludeFID ? 1 : 0) + nFieldCount + nGeomFieldCount;
1963
0
    int iSchemaChild = 0;
1964
1965
0
    if (!m_poSharedArrowArrayStreamPrivateData->m_anQueriedFIDs.empty())
1966
0
    {
1967
0
        if (poPrivate->poShared->m_bEOF)
1968
0
        {
1969
0
            return 0;
1970
0
        }
1971
0
        if (m_poSharedArrowArrayStreamPrivateData->m_iQueriedFIDS == 0)
1972
0
        {
1973
0
            CPLDebug("OGR", "Using fast FID filtering");
1974
0
        }
1975
0
        while (
1976
0
            oFeatureQueue.size() < static_cast<size_t>(nMaxBatchSize) &&
1977
0
            m_poSharedArrowArrayStreamPrivateData->m_iQueriedFIDS <
1978
0
                m_poSharedArrowArrayStreamPrivateData->m_anQueriedFIDs.size())
1979
0
        {
1980
0
            const auto nFID =
1981
0
                m_poSharedArrowArrayStreamPrivateData->m_anQueriedFIDs
1982
0
                    [m_poSharedArrowArrayStreamPrivateData->m_iQueriedFIDS];
1983
0
            auto poFeature = std::unique_ptr<OGRFeature>(GetFeature(nFID));
1984
0
            ++m_poSharedArrowArrayStreamPrivateData->m_iQueriedFIDS;
1985
0
            if (poFeature && (m_poFilterGeom == nullptr ||
1986
0
                              FilterGeometry(poFeature->GetGeomFieldRef(
1987
0
                                  m_iGeomFieldFilter))))
1988
0
            {
1989
0
                oFeatureQueue.emplace_back(std::move(poFeature));
1990
0
            }
1991
0
        }
1992
0
        if (m_poSharedArrowArrayStreamPrivateData->m_iQueriedFIDS ==
1993
0
            m_poSharedArrowArrayStreamPrivateData->m_anQueriedFIDs.size())
1994
0
        {
1995
0
            poPrivate->poShared->m_bEOF = true;
1996
0
        }
1997
0
    }
1998
0
    else if (!poPrivate->poShared->m_bEOF)
1999
0
    {
2000
0
        while (oFeatureQueue.size() < static_cast<size_t>(nMaxBatchSize))
2001
0
        {
2002
0
            auto poFeature = std::unique_ptr<OGRFeature>(GetNextFeature());
2003
0
            if (!poFeature)
2004
0
            {
2005
0
                poPrivate->poShared->m_bEOF = true;
2006
0
                break;
2007
0
            }
2008
0
            oFeatureQueue.emplace_back(std::move(poFeature));
2009
0
        }
2010
0
    }
2011
0
    if (oFeatureQueue.empty())
2012
0
    {
2013
0
        return 0;
2014
0
    }
2015
2016
0
    out_array->release = OGRLayerDefaultReleaseArray;
2017
0
    out_array->null_count = 0;
2018
2019
0
    out_array->n_children = nMaxChildren;
2020
0
    out_array->children = static_cast<struct ArrowArray **>(
2021
0
        CPLCalloc(nMaxChildren, sizeof(struct ArrowArray *)));
2022
0
    out_array->release = OGRLayerDefaultReleaseArray;
2023
0
    out_array->n_buffers = 1;
2024
0
    out_array->buffers =
2025
0
        static_cast<const void **>(CPLCalloc(1, sizeof(void *)));
2026
2027
0
    size_t nFeatureCount = oFeatureQueue.size();
2028
0
    const uint32_t nMemLimit = OGRArrowArrayHelper::GetMemLimit();
2029
0
    if (bIncludeFID)
2030
0
    {
2031
0
        out_array->children[iSchemaChild] = static_cast<struct ArrowArray *>(
2032
0
            CPLCalloc(1, sizeof(struct ArrowArray)));
2033
0
        auto psChild = out_array->children[iSchemaChild];
2034
0
        ++iSchemaChild;
2035
0
        psChild->release = OGRLayerDefaultReleaseArray;
2036
0
        psChild->n_buffers = 2;
2037
0
        psChild->buffers =
2038
0
            static_cast<const void **>(CPLCalloc(2, sizeof(void *)));
2039
0
        int64_t *panValues =
2040
0
            static_cast<int64_t *>(VSI_MALLOC_ALIGNED_AUTO_VERBOSE(
2041
0
                sizeof(int64_t) * (oFeatureQueue.size() + 1)));
2042
0
        if (panValues == nullptr)
2043
0
            goto error;
2044
0
        psChild->buffers[1] = panValues;
2045
0
        for (size_t iFeat = 0; iFeat < oFeatureQueue.size(); ++iFeat)
2046
0
        {
2047
0
            panValues[iFeat] = oFeatureQueue[iFeat]->GetFID();
2048
0
        }
2049
0
    }
2050
2051
0
    for (int i = 0; i < nFieldCount; ++i)
2052
0
    {
2053
0
        const auto poFieldDefn = poLayerDefn->GetFieldDefn(i);
2054
0
        if (poFieldDefn->IsIgnored())
2055
0
        {
2056
0
            continue;
2057
0
        }
2058
2059
0
        out_array->children[iSchemaChild] = static_cast<struct ArrowArray *>(
2060
0
            CPLCalloc(1, sizeof(struct ArrowArray)));
2061
0
        auto psChild = out_array->children[iSchemaChild];
2062
0
        ++iSchemaChild;
2063
0
        psChild->release = OGRLayerDefaultReleaseArray;
2064
0
        const bool bIsNullable = CPL_TO_BOOL(poFieldDefn->IsNullable());
2065
0
        const auto eSubType = poFieldDefn->GetSubType();
2066
0
        switch (poFieldDefn->GetType())
2067
0
        {
2068
0
            case OFTInteger:
2069
0
            {
2070
0
                if (eSubType == OFSTBoolean)
2071
0
                {
2072
0
                    if (!FillBoolArray(psChild, oFeatureQueue, nFeatureCount,
2073
0
                                       bIsNullable, &OGRField::Integer, i))
2074
0
                        goto error;
2075
0
                }
2076
0
                else if (eSubType == OFSTInt16)
2077
0
                {
2078
0
                    if (!FillArray<int16_t>(psChild, oFeatureQueue,
2079
0
                                            nFeatureCount, bIsNullable,
2080
0
                                            &OGRField::Integer, i))
2081
0
                        goto error;
2082
0
                }
2083
0
                else
2084
0
                {
2085
0
                    if (!FillArray<int32_t>(psChild, oFeatureQueue,
2086
0
                                            nFeatureCount, bIsNullable,
2087
0
                                            &OGRField::Integer, i))
2088
0
                        goto error;
2089
0
                }
2090
2091
0
                const auto &osDomainName = poFieldDefn->GetDomainName();
2092
0
                if (!osDomainName.empty())
2093
0
                {
2094
0
                    auto poDS = GetDataset();
2095
0
                    if (poDS)
2096
0
                    {
2097
0
                        const auto poFieldDomain =
2098
0
                            poDS->GetFieldDomain(osDomainName);
2099
0
                        if (poFieldDomain &&
2100
0
                            poFieldDomain->GetDomainType() == OFDT_CODED)
2101
0
                        {
2102
0
                            const OGRCodedFieldDomain *poCodedDomain =
2103
0
                                static_cast<const OGRCodedFieldDomain *>(
2104
0
                                    poFieldDomain);
2105
0
                            OGRArrowArrayHelper::FillDict(psChild,
2106
0
                                                          poCodedDomain);
2107
0
                        }
2108
0
                    }
2109
0
                }
2110
2111
0
                break;
2112
0
            }
2113
2114
0
            case OFTInteger64:
2115
0
            {
2116
0
                if (!FillArray<int64_t>(psChild, oFeatureQueue, nFeatureCount,
2117
0
                                        bIsNullable, &OGRField::Integer64, i))
2118
0
                    goto error;
2119
0
                break;
2120
0
            }
2121
2122
0
            case OFTReal:
2123
0
            {
2124
0
                if (eSubType == OFSTFloat32)
2125
0
                {
2126
0
                    if (!FillArray<float>(psChild, oFeatureQueue, nFeatureCount,
2127
0
                                          bIsNullable, &OGRField::Real, i))
2128
0
                        goto error;
2129
0
                }
2130
0
                else
2131
0
                {
2132
0
                    if (!FillArray<double>(psChild, oFeatureQueue,
2133
0
                                           nFeatureCount, bIsNullable,
2134
0
                                           &OGRField::Real, i))
2135
0
                        goto error;
2136
0
                }
2137
0
                break;
2138
0
            }
2139
2140
0
            case OFTString:
2141
0
            case OFTWideString:
2142
0
            {
2143
0
                const size_t nThisFeatureCount = FillStringArray<int32_t>(
2144
0
                    psChild, oFeatureQueue, nFeatureCount, bIsNullable, i,
2145
0
                    nMemLimit);
2146
0
                if (nThisFeatureCount == 0)
2147
0
                {
2148
0
                    goto error_max_mem;
2149
0
                }
2150
0
                if (nThisFeatureCount < nFeatureCount)
2151
0
                    nFeatureCount = nThisFeatureCount;
2152
0
                break;
2153
0
            }
2154
2155
0
            case OFTBinary:
2156
0
            {
2157
0
                const int nWidth = poFieldDefn->GetWidth();
2158
0
                if (nWidth > 0)
2159
0
                {
2160
0
                    if (nFeatureCount > nMemLimit / nWidth)
2161
0
                    {
2162
0
                        nFeatureCount = nMemLimit / nWidth;
2163
0
                        if (nFeatureCount == 0)
2164
0
                            goto error_max_mem;
2165
0
                    }
2166
0
                    if (!FillFixedWidthBinaryArray(psChild, oFeatureQueue,
2167
0
                                                   nFeatureCount, bIsNullable,
2168
0
                                                   nWidth, i))
2169
0
                        goto error;
2170
0
                }
2171
0
                else
2172
0
                {
2173
0
                    const size_t nThisFeatureCount = FillBinaryArray<int32_t>(
2174
0
                        psChild, oFeatureQueue, nFeatureCount, bIsNullable, i,
2175
0
                        nMemLimit);
2176
0
                    if (nThisFeatureCount == 0)
2177
0
                    {
2178
0
                        goto error_max_mem;
2179
0
                    }
2180
0
                    if (nThisFeatureCount < nFeatureCount)
2181
0
                        nFeatureCount = nThisFeatureCount;
2182
0
                }
2183
0
                break;
2184
0
            }
2185
2186
0
            case OFTIntegerList:
2187
0
            {
2188
0
                size_t nThisFeatureCount;
2189
0
                if (eSubType == OFSTBoolean)
2190
0
                {
2191
0
                    nThisFeatureCount =
2192
0
                        FillListArrayBool<int32_t, GetFromIntegerList>(
2193
0
                            psChild, oFeatureQueue, nFeatureCount, bIsNullable,
2194
0
                            i, nMemLimit);
2195
0
                }
2196
0
                else if (eSubType == OFSTInt16)
2197
0
                {
2198
0
                    nThisFeatureCount =
2199
0
                        FillListArray<int32_t, int16_t, GetFromIntegerList>(
2200
0
                            psChild, oFeatureQueue, nFeatureCount, bIsNullable,
2201
0
                            i, nMemLimit);
2202
0
                }
2203
0
                else
2204
0
                {
2205
0
                    nThisFeatureCount =
2206
0
                        FillListArray<int32_t, int32_t, GetFromIntegerList>(
2207
0
                            psChild, oFeatureQueue, nFeatureCount, bIsNullable,
2208
0
                            i, nMemLimit);
2209
0
                }
2210
0
                if (nThisFeatureCount == 0)
2211
0
                {
2212
0
                    goto error_max_mem;
2213
0
                }
2214
0
                if (nThisFeatureCount < nFeatureCount)
2215
0
                    nFeatureCount = nThisFeatureCount;
2216
0
                break;
2217
0
            }
2218
2219
0
            case OFTInteger64List:
2220
0
            {
2221
0
                const size_t nThisFeatureCount =
2222
0
                    FillListArray<int32_t, int64_t, GetFromInteger64List>(
2223
0
                        psChild, oFeatureQueue, nFeatureCount, bIsNullable, i,
2224
0
                        nMemLimit);
2225
0
                if (nThisFeatureCount == 0)
2226
0
                {
2227
0
                    goto error_max_mem;
2228
0
                }
2229
0
                if (nThisFeatureCount < nFeatureCount)
2230
0
                    nFeatureCount = nThisFeatureCount;
2231
0
                break;
2232
0
            }
2233
2234
0
            case OFTRealList:
2235
0
            {
2236
0
                size_t nThisFeatureCount;
2237
0
                if (eSubType == OFSTFloat32)
2238
0
                {
2239
0
                    nThisFeatureCount =
2240
0
                        FillListArray<int32_t, float, GetFromRealList>(
2241
0
                            psChild, oFeatureQueue, nFeatureCount, bIsNullable,
2242
0
                            i, nMemLimit);
2243
0
                }
2244
0
                else
2245
0
                {
2246
0
                    nThisFeatureCount =
2247
0
                        FillListArray<int32_t, double, GetFromRealList>(
2248
0
                            psChild, oFeatureQueue, nFeatureCount, bIsNullable,
2249
0
                            i, nMemLimit);
2250
0
                }
2251
0
                if (nThisFeatureCount == 0)
2252
0
                {
2253
0
                    goto error_max_mem;
2254
0
                }
2255
0
                if (nThisFeatureCount < nFeatureCount)
2256
0
                    nFeatureCount = nThisFeatureCount;
2257
0
                break;
2258
0
            }
2259
2260
0
            case OFTStringList:
2261
0
            case OFTWideStringList:
2262
0
            {
2263
0
                const size_t nThisFeatureCount = FillStringListArray<int32_t>(
2264
0
                    psChild, oFeatureQueue, nFeatureCount, bIsNullable, i,
2265
0
                    nMemLimit);
2266
0
                if (nThisFeatureCount == 0)
2267
0
                {
2268
0
                    goto error_max_mem;
2269
0
                }
2270
0
                if (nThisFeatureCount < nFeatureCount)
2271
0
                    nFeatureCount = nThisFeatureCount;
2272
0
                break;
2273
0
            }
2274
2275
0
            case OFTDate:
2276
0
            {
2277
0
                if (!FillDateArray(psChild, oFeatureQueue, nFeatureCount,
2278
0
                                   bIsNullable, i))
2279
0
                    goto error;
2280
0
                break;
2281
0
            }
2282
2283
0
            case OFTTime:
2284
0
            {
2285
0
                if (!FillTimeArray(psChild, oFeatureQueue, nFeatureCount,
2286
0
                                   bIsNullable, i))
2287
0
                    goto error;
2288
0
                break;
2289
0
            }
2290
2291
0
            case OFTDateTime:
2292
0
            {
2293
0
                if (bDateTimeAsString)
2294
0
                {
2295
0
                    const size_t nThisFeatureCount = FillDateTimeArrayAsString(
2296
0
                        psChild, oFeatureQueue, nFeatureCount, bIsNullable, i,
2297
0
                        nMemLimit);
2298
0
                    if (nThisFeatureCount == 0)
2299
0
                    {
2300
0
                        goto error_max_mem;
2301
0
                    }
2302
0
                    if (nThisFeatureCount < nFeatureCount)
2303
0
                        nFeatureCount = nThisFeatureCount;
2304
0
                }
2305
0
                else
2306
0
                {
2307
0
                    if (!FillDateTimeArray(psChild, oFeatureQueue,
2308
0
                                           nFeatureCount, bIsNullable, i,
2309
0
                                           poFieldDefn->GetTZFlag()))
2310
0
                        goto error;
2311
0
                }
2312
0
                break;
2313
0
            }
2314
0
        }
2315
0
    }
2316
0
    for (int i = 0; i < nGeomFieldCount; ++i)
2317
0
    {
2318
0
        const auto poFieldDefn = poLayerDefn->GetGeomFieldDefn(i);
2319
0
        if (poFieldDefn->IsIgnored())
2320
0
        {
2321
0
            continue;
2322
0
        }
2323
2324
0
        out_array->children[iSchemaChild] = static_cast<struct ArrowArray *>(
2325
0
            CPLCalloc(1, sizeof(struct ArrowArray)));
2326
0
        auto psChild = out_array->children[iSchemaChild];
2327
0
        ++iSchemaChild;
2328
0
        psChild->release = OGRLayerDefaultReleaseArray;
2329
0
        psChild->length = oFeatureQueue.size();
2330
0
        const size_t nThisFeatureCount = FillWKBGeometryArray<int32_t>(
2331
0
            psChild, oFeatureQueue, nFeatureCount, poFieldDefn, i, nMemLimit);
2332
0
        if (nThisFeatureCount == 0)
2333
0
        {
2334
0
            goto error_max_mem;
2335
0
        }
2336
0
        if (nThisFeatureCount < nFeatureCount)
2337
0
            nFeatureCount = nThisFeatureCount;
2338
0
    }
2339
2340
    // Remove consumed features from the queue
2341
0
    if (nFeatureCount == oFeatureQueue.size())
2342
0
        oFeatureQueue.clear();
2343
0
    else
2344
0
    {
2345
0
        for (size_t i = 0; i < nFeatureCount; ++i)
2346
0
        {
2347
0
            oFeatureQueue.pop_front();
2348
0
        }
2349
0
    }
2350
2351
0
    out_array->n_children = iSchemaChild;
2352
0
    out_array->length = nFeatureCount;
2353
0
    for (int i = 0; i < out_array->n_children; ++i)
2354
0
    {
2355
0
        out_array->children[i]->length = nFeatureCount;
2356
0
    }
2357
2358
0
    return 0;
2359
2360
0
error_max_mem:
2361
0
    CPLError(CE_Failure, CPLE_AppDefined,
2362
0
             "Too large feature: not even a single feature can be returned");
2363
0
error:
2364
0
    oFeatureQueue.clear();
2365
0
    poPrivate->poShared->m_bEOF = true;
2366
0
    out_array->release(out_array);
2367
0
    memset(out_array, 0, sizeof(*out_array));
2368
0
    return ENOMEM;
2369
0
}
2370
2371
/************************************************************************/
2372
/*                       StaticGetNextArrowArray()                      */
2373
/************************************************************************/
2374
2375
/** Default implementation of the ArrowArrayStream::get_next() callback.
2376
 *
2377
 * To be used by driver implementations that have a custom GetArrowStream()
2378
 * implementation.
2379
 *
2380
 * @since GDAL 3.6
2381
 */
2382
int OGRLayer::StaticGetNextArrowArray(struct ArrowArrayStream *stream,
2383
                                      struct ArrowArray *out_array)
2384
0
{
2385
0
    auto poLayer = static_cast<ArrowArrayStreamPrivateDataSharedDataWrapper *>(
2386
0
                       stream->private_data)
2387
0
                       ->poShared->m_poLayer;
2388
0
    if (poLayer == nullptr)
2389
0
    {
2390
0
        CPLError(CE_Failure, CPLE_NotSupported,
2391
0
                 "Calling get_next() on a freed OGRLayer is not supported");
2392
0
        return EINVAL;
2393
0
    }
2394
0
    return poLayer->GetNextArrowArray(stream, out_array);
2395
0
}
2396
2397
/************************************************************************/
2398
/*                            ReleaseStream()                           */
2399
/************************************************************************/
2400
2401
/** Release a ArrowArrayStream.
2402
 *
2403
 * To be used by driver implementations that have a custom GetArrowStream()
2404
 * implementation.
2405
 *
2406
 * @param stream Arrow array stream to release.
2407
 * @since GDAL 3.6
2408
 */
2409
void OGRLayer::ReleaseStream(struct ArrowArrayStream *stream)
2410
0
{
2411
0
    assert(stream->release == OGRLayer::ReleaseStream);
2412
0
    ArrowArrayStreamPrivateDataSharedDataWrapper *poPrivate =
2413
0
        static_cast<ArrowArrayStreamPrivateDataSharedDataWrapper *>(
2414
0
            stream->private_data);
2415
0
    poPrivate->poShared->m_bArrowArrayStreamInProgress = false;
2416
0
    poPrivate->poShared->m_bEOF = false;
2417
0
    if (poPrivate->poShared->m_poLayer)
2418
0
        poPrivate->poShared->m_poLayer->ResetReading();
2419
0
    delete poPrivate;
2420
0
    stream->private_data = nullptr;
2421
0
    stream->release = nullptr;
2422
0
}
2423
2424
/************************************************************************/
2425
/*                     GetLastErrorArrowArrayStream()                   */
2426
/************************************************************************/
2427
2428
/** Default implementation of the ArrowArrayStream::get_last_error() callback.
2429
 *
2430
 * To be used by driver implementations that have a custom GetArrowStream()
2431
 * implementation.
2432
 *
2433
 * @since GDAL 3.6
2434
 */
2435
const char *OGRLayer::GetLastErrorArrowArrayStream(struct ArrowArrayStream *)
2436
0
{
2437
0
    const char *pszLastErrorMsg = CPLGetLastErrorMsg();
2438
0
    return pszLastErrorMsg[0] != '\0' ? pszLastErrorMsg : nullptr;
2439
0
}
2440
2441
/************************************************************************/
2442
/*                          GetArrowStream()                            */
2443
/************************************************************************/
2444
2445
/** Get a Arrow C stream.
2446
 *
2447
 * On successful return, and when the stream interfaces is no longer needed, it
2448
 * must must be freed with out_stream->release(out_stream). Please carefully
2449
 * read https://arrow.apache.org/docs/format/CStreamInterface.html for more
2450
 * details on using Arrow C stream.
2451
 *
2452
 * The method may take into account ignored fields set with SetIgnoredFields()
2453
 * (the default implementation does), and should take into account filters set
2454
 * with SetSpatialFilter() and SetAttributeFilter(). Note however that
2455
 * specialized implementations may fallback to the default (slower)
2456
 * implementation when filters are set.
2457
 * Drivers that have a specialized implementation should advertise the
2458
 * OLCFastGetArrowStream capability.
2459
 *
2460
 * There are extra precautions to take into account in a OGR context. Unless
2461
 * otherwise specified by a particular driver implementation, the get_schema(),
2462
 * get_next() and get_last_error() function pointers of the ArrowArrayStream
2463
 * structure should no longer be used after the OGRLayer, from which the
2464
 * ArrowArrayStream structure was initialized, has been destroyed (typically at
2465
 * dataset closing). The reason is that those function pointers will typically
2466
 * point to methods of the OGRLayer instance.
2467
 * However, the ArrowSchema and ArrowArray structures filled from those
2468
 * callbacks can be used and must be released independently from the
2469
 * ArrowArrayStream or the layer.
2470
 *
2471
 * Furthermore, unless otherwise specified by a particular driver
2472
 * implementation, only one ArrowArrayStream can be active at a time on
2473
 * a given layer (that is the last active one must be explicitly released before
2474
 * a next one is asked). Changing filter state, ignored columns, modifying the
2475
 * schema or using ResetReading()/GetNextFeature() while using a
2476
 * ArrowArrayStream is strongly discouraged and may lead to unexpected results.
2477
 * As a rule of thumb, no OGRLayer methods that affect the state of a layer
2478
 * should be called on a layer, while an ArrowArrayStream on it is active.
2479
 *
2480
 * Starting with GDAL 3.8, the ArrowSchema::metadata field filled by the
2481
 * get_schema() callback may be set with the potential following items:
2482
 * <ul>
2483
 * <li>"GDAL:OGR:type": value of OGRFieldDefn::GetType(): (added in 3.11)
2484
 *      Only used for DateTime fields when the DATETIME_AS_STRING=YES option is
2485
 *      specified.</li>
2486
 * <li>"GDAL:OGR:alternative_name": value of
2487
 *     OGRFieldDefn::GetAlternativeNameRef()</li>
2488
 * <li>"GDAL:OGR:comment": value of OGRFieldDefn::GetComment()</li>
2489
 * <li>"GDAL:OGR:default": value of OGRFieldDefn::GetDefault()</li>
2490
 * <li>"GDAL:OGR:subtype": value of OGRFieldDefn::GetSubType()</li>
2491
 * <li>"GDAL:OGR:width": value of OGRFieldDefn::GetWidth() (serialized as a
2492
 *     string)</li>
2493
 * <li>"GDAL:OGR:unique": value of OGRFieldDefn::IsUnique() (serialized as
2494
 *     "true" or "false")</li>
2495
 * <li>"GDAL:OGR:domain_name": value of OGRFieldDefn::GetDomainName()</li>
2496
 * </ul>
2497
 *
2498
 * A potential usage can be:
2499
\code{.cpp}
2500
    struct ArrowArrayStream stream;
2501
    if( !poLayer->GetArrowStream(&stream, nullptr))
2502
    {
2503
        CPLError(CE_Failure, CPLE_AppDefined, "GetArrowStream() failed\n");
2504
        exit(1);
2505
    }
2506
    struct ArrowSchema schema;
2507
    if( stream.get_schema(&stream, &schema) == 0 )
2508
    {
2509
        // Do something useful
2510
        schema.release(schema);
2511
    }
2512
    while( true )
2513
    {
2514
        struct ArrowArray array;
2515
        // Look for an error (get_next() returning a non-zero code), or
2516
        // end of iteration (array.release == nullptr)
2517
        if( stream.get_next(&stream, &array) != 0 ||
2518
            array.release == nullptr )
2519
        {
2520
            break;
2521
        }
2522
        // Do something useful
2523
        array.release(&array);
2524
    }
2525
    stream.release(&stream);
2526
\endcode
2527
 *
2528
 * A full example is available in the
2529
 * <a
2530
href="https://gdal.org/tutorials/vector_api_tut.html#reading-from-ogr-using-the-arrow-c-stream-data-interface">Reading
2531
From OGR using the Arrow C Stream data interface</a> tutorial.
2532
 *
2533
 * Options may be driver specific. The default implementation recognizes the
2534
 * following options:
2535
 * <ul>
2536
 * <li>INCLUDE_FID=YES/NO. Whether to include the FID column. Defaults to YES.
2537
 * </li>
2538
 * <li>MAX_FEATURES_IN_BATCH=integer. Maximum number of features to retrieve in
2539
 *     a ArrowArray batch. Defaults to 65 536.</li>
2540
 * <li>TIMEZONE="unknown", "UTC", "(+|:)HH:MM" or any other value supported by
2541
 *     Arrow. (GDAL >= 3.8)
2542
 *     Override the timezone flag nominally provided by
2543
 *     OGRFieldDefn::GetTZFlag(), and used for the Arrow field timezone
2544
 *     declaration, with a user specified timezone.
2545
 *     Note that datetime values in Arrow arrays are always stored in UTC, and
2546
 *     that the time zone flag used by GDAL to convert to UTC is the one of the
2547
 *     OGRField::Date::TZFlag member at the OGRFeature level. The conversion
2548
 *     to UTC of a OGRField::Date is only done if both the timezone indicated by
2549
 *     OGRField::Date::TZFlag and the one at the OGRFieldDefn level (or set by
2550
 *     this TIMEZONE option) are not unknown.</li>
2551
 * <li>DATETIME_AS_STRING=YES/NO. Defaults to NO. Added in GDAL 3.11.
2552
 *     Whether DateTime fields should be returned as a (normally ISO-8601
2553
 *     formatted) string by drivers. The aim is to be able to handle mixed
2554
 *     timezones (or timezone naive values) in the same column.
2555
 *     All drivers must honour that option, and potentially fallback to the
2556
 *     OGRLayer generic implementation if they cannot (which is the case for the
2557
 *     Arrow, Parquet and ADBC drivers).
2558
 *     When DATETIME_AS_STRING=YES, the TIMEZONE option is ignored.
2559
 * </li>
2560
 * <li>GEOMETRY_METADATA_ENCODING=OGC/GEOARROW (GDAL >= 3.8).
2561
 *     The default is OGC, which will lead to setting
2562
 *     the Arrow geometry column metadata to ARROW:extension:name=ogc.wkb.
2563
 *     If setting to GEOMETRY_METADATA_ENCODING to GEOARROW,
2564
 *     ARROW:extension:name=geoarrow.wkb and
2565
 *     ARROW:extension:metadata={"crs": &lt;projjson CRS representation>&gt; are set.
2566
 * </li>
2567
 * </ul>
2568
 *
2569
 * The Arrow/Parquet drivers recognize the following option:
2570
 * <ul>
2571
 * <li>GEOMETRY_ENCODING=WKB. To force a fallback to the generic implementation
2572
 *     when the native geometry encoding is not WKB. Otherwise the geometry
2573
 *     will be returned with its native Arrow encoding
2574
 *     (possibly using GeoArrow encoding).</li>
2575
 * </ul>
2576
 *
2577
 * @param out_stream Output stream. Must *not* be NULL. The content of the
2578
 *                  structure does not need to be initialized.
2579
 * @param papszOptions NULL terminated list of key=value options.
2580
 * @return true in case of success.
2581
 * @since GDAL 3.6
2582
 */
2583
bool OGRLayer::GetArrowStream(struct ArrowArrayStream *out_stream,
2584
                              CSLConstList papszOptions)
2585
0
{
2586
0
    memset(out_stream, 0, sizeof(*out_stream));
2587
0
    if (m_poSharedArrowArrayStreamPrivateData &&
2588
0
        m_poSharedArrowArrayStreamPrivateData->m_bArrowArrayStreamInProgress)
2589
0
    {
2590
0
        CPLError(CE_Failure, CPLE_AppDefined,
2591
0
                 "An arrow Arrow Stream is in progress on that layer. Only "
2592
0
                 "one at a time is allowed in this implementation.");
2593
0
        return false;
2594
0
    }
2595
0
    m_aosArrowArrayStreamOptions.Assign(CSLDuplicate(papszOptions), true);
2596
2597
0
    out_stream->get_schema = OGRLayer::StaticGetArrowSchema;
2598
0
    out_stream->get_next = OGRLayer::StaticGetNextArrowArray;
2599
0
    out_stream->get_last_error = OGRLayer::GetLastErrorArrowArrayStream;
2600
0
    out_stream->release = OGRLayer::ReleaseStream;
2601
2602
0
    if (m_poSharedArrowArrayStreamPrivateData == nullptr)
2603
0
    {
2604
0
        m_poSharedArrowArrayStreamPrivateData =
2605
0
            std::make_shared<ArrowArrayStreamPrivateData>();
2606
0
        m_poSharedArrowArrayStreamPrivateData->m_poLayer = this;
2607
0
    }
2608
0
    m_poSharedArrowArrayStreamPrivateData->m_bArrowArrayStreamInProgress = true;
2609
2610
    // Special case for "FID = constant", or "FID IN (constant1, ...., constantN)"
2611
0
    m_poSharedArrowArrayStreamPrivateData->m_anQueriedFIDs.clear();
2612
0
    m_poSharedArrowArrayStreamPrivateData->m_iQueriedFIDS = 0;
2613
0
    if (m_poAttrQuery)
2614
0
    {
2615
0
        swq_expr_node *poNode =
2616
0
            static_cast<swq_expr_node *>(m_poAttrQuery->GetSWQExpr());
2617
0
        if (poNode->eNodeType == SNT_OPERATION &&
2618
0
            (poNode->nOperation == SWQ_IN || poNode->nOperation == SWQ_EQ) &&
2619
0
            poNode->papoSubExpr[0]->eNodeType == SNT_COLUMN &&
2620
0
            poNode->papoSubExpr[0]->field_index ==
2621
0
                GetLayerDefn()->GetFieldCount() + SPF_FID &&
2622
0
            TestCapability(OLCRandomRead))
2623
0
        {
2624
0
            std::set<GIntBig> oSetAlreadyListed;
2625
0
            for (int i = 1; i < poNode->nSubExprCount; ++i)
2626
0
            {
2627
0
                if (poNode->papoSubExpr[i]->eNodeType == SNT_CONSTANT &&
2628
0
                    poNode->papoSubExpr[i]->field_type == SWQ_INTEGER64 &&
2629
0
                    oSetAlreadyListed.find(poNode->papoSubExpr[i]->int_value) ==
2630
0
                        oSetAlreadyListed.end())
2631
0
                {
2632
0
                    oSetAlreadyListed.insert(poNode->papoSubExpr[i]->int_value);
2633
0
                    m_poSharedArrowArrayStreamPrivateData->m_anQueriedFIDs
2634
0
                        .push_back(poNode->papoSubExpr[i]->int_value);
2635
0
                }
2636
0
            }
2637
0
        }
2638
0
    }
2639
2640
0
    auto poPrivateData = new ArrowArrayStreamPrivateDataSharedDataWrapper();
2641
0
    poPrivateData->poShared = m_poSharedArrowArrayStreamPrivateData;
2642
0
    out_stream->private_data = poPrivateData;
2643
0
    return true;
2644
0
}
2645
2646
/************************************************************************/
2647
/*                       OGR_L_GetArrowStream()                         */
2648
/************************************************************************/
2649
2650
/** Get a Arrow C stream.
2651
 *
2652
 * On successful return, and when the stream interfaces is no longer needed, it
2653
 * must be freed with out_stream->release(out_stream). Please carefully read
2654
 * https://arrow.apache.org/docs/format/CStreamInterface.html for more details
2655
 * on using Arrow C stream.
2656
 *
2657
 * The method may take into account ignored fields set with SetIgnoredFields()
2658
 * (the default implementation does), and should take into account filters set
2659
 * with SetSpatialFilter() and SetAttributeFilter(). Note however that
2660
 * specialized implementations may fallback to the default (slower)
2661
 * implementation when filters are set.
2662
 * Drivers that have a specialized implementation should
2663
 * advertise the OLCFastGetArrowStream capability.
2664
 *
2665
 * There are extra precautions to take into account in a OGR context. Unless
2666
 * otherwise specified by a particular driver implementation, the get_schema(),
2667
 * get_next() and get_last_error() function pointers of the ArrowArrayStream
2668
 * structure should no longer be used after the OGRLayer, from which the
2669
 * ArrowArrayStream structure was initialized, has been destroyed (typically at
2670
 * dataset closing). The reason is that those function pointers will typically
2671
 * point to methods of the OGRLayer instance.
2672
 * However, the ArrowSchema and ArrowArray structures filled from those
2673
 * callbacks can be used and must be released independently from the
2674
 * ArrowArrayStream or the layer.
2675
 *
2676
 * Furthermore, unless otherwise specified by a particular driver
2677
 * implementation, only one ArrowArrayStream can be active at a time on
2678
 * a given layer (that is the last active one must be explicitly released before
2679
 * a next one is asked). Changing filter state, ignored columns, modifying the
2680
 * schema or using ResetReading()/GetNextFeature() while using a
2681
 * ArrowArrayStream is strongly discouraged and may lead to unexpected results.
2682
 * As a rule of thumb, no OGRLayer methods that affect the state of a layer
2683
 * should be called on a layer, while an ArrowArrayStream on it is active.
2684
 *
2685
 * Starting with GDAL 3.8, the ArrowSchema::metadata field filled by the
2686
 * get_schema() callback may be set with the potential following items:
2687
 * <ul>
2688
 * <li>"GDAL:OGR:type": value of OGRFieldDefn::GetType(): (added in 3.11)
2689
 *      Only used for DateTime fields when the DATETIME_AS_STRING=YES option is
2690
 *      specified.</li>
2691
 * <li>"GDAL:OGR:alternative_name": value of
2692
 *     OGRFieldDefn::GetAlternativeNameRef()</li>
2693
 * <li>"GDAL:OGR:comment": value of OGRFieldDefn::GetComment()</li>
2694
 * <li>"GDAL:OGR:default": value of OGRFieldDefn::GetDefault()</li>
2695
 * <li>"GDAL:OGR:subtype": value of OGRFieldDefn::GetSubType()</li>
2696
 * <li>"GDAL:OGR:width": value of OGRFieldDefn::GetWidth() (serialized as a
2697
 *     string)</li>
2698
 * <li>"GDAL:OGR:unique": value of OGRFieldDefn::IsUnique() (serialized as
2699
 *     "true" or "false")</li>
2700
 * <li>"GDAL:OGR:domain_name": value of OGRFieldDefn::GetDomainName()</li>
2701
 * </ul>
2702
 *
2703
 * A potential usage can be:
2704
\code{.cpp}
2705
    struct ArrowArrayStream stream;
2706
    if( !OGR_L_GetArrowStream(hLayer, &stream, nullptr))
2707
    {
2708
        CPLError(CE_Failure, CPLE_AppDefined,
2709
                 "OGR_L_GetArrowStream() failed\n");
2710
        exit(1);
2711
    }
2712
    struct ArrowSchema schema;
2713
    if( stream.get_schema(&stream, &schema) == 0 )
2714
    {
2715
        // Do something useful
2716
        schema.release(schema);
2717
    }
2718
    while( true )
2719
    {
2720
        struct ArrowArray array;
2721
        // Look for an error (get_next() returning a non-zero code), or
2722
        // end of iteration (array.release == nullptr)
2723
        if( stream.get_next(&stream, &array) != 0 ||
2724
            array.release == nullptr )
2725
        {
2726
            break;
2727
        }
2728
        // Do something useful
2729
        array.release(&array);
2730
    }
2731
    stream.release(&stream);
2732
\endcode
2733
 *
2734
 * A full example is available in the
2735
 * <a
2736
href="https://gdal.org/tutorials/vector_api_tut.html#reading-from-ogr-using-the-arrow-c-stream-data-interface">Reading
2737
From OGR using the Arrow C Stream data interface</a> tutorial.
2738
 *
2739
 * Options may be driver specific. The default implementation recognizes the
2740
 * following options:
2741
 * <ul>
2742
 * <li>INCLUDE_FID=YES/NO. Whether to include the FID column. Defaults to
2743
YES.</li>
2744
 * <li>MAX_FEATURES_IN_BATCH=integer. Maximum number of features to retrieve in
2745
 *     a ArrowArray batch. Defaults to 65 536.</li>
2746
 * <li>TIMEZONE="unknown", "UTC", "(+|:)HH:MM" or any other value supported by
2747
 *     Arrow. (GDAL >= 3.8)
2748
 *     Override the timezone flag nominally provided by
2749
 *     OGRFieldDefn::GetTZFlag(), and used for the Arrow field timezone
2750
 *     declaration, with a user specified timezone.
2751
 *     Note that datetime values in Arrow arrays are always stored in UTC, and
2752
 *     that the time zone flag used by GDAL to convert to UTC is the one of the
2753
 *     OGRField::Date::TZFlag member at the OGRFeature level. The conversion
2754
 *     to UTC of a OGRField::Date is only done if both the timezone indicated by
2755
 *     OGRField::Date::TZFlag and the one at the OGRFieldDefn level (or set by
2756
 *     this TIMEZONE option) are not unknown.</li>
2757
 * <li>DATETIME_AS_STRING=YES/NO. Defaults to NO. Added in GDAL 3.11.
2758
 *     Whether DateTime fields should be returned as a (normally ISO-8601
2759
 *     formatted) string by drivers. The aim is to be able to handle mixed
2760
 *     timezones (or timezone naive values) in the same column.
2761
 *     All drivers must honour that option, and potentially fallback to the
2762
 *     OGRLayer generic implementation if they cannot (which is the case for the
2763
 *     Arrow, Parquet and ADBC drivers).
2764
 *     When DATETIME_AS_STRING=YES, the TIMEZONE option is ignored.
2765
 * </li>
2766
 * <li>GEOMETRY_METADATA_ENCODING=OGC/GEOARROW (GDAL >= 3.8).
2767
 *     The default is OGC, which will lead to setting
2768
 *     the Arrow geometry column metadata to ARROW:extension:name=ogc.wkb.
2769
 *     If setting to GEOMETRY_METADATA_ENCODING to GEOARROW,
2770
 *     ARROW:extension:name=geoarrow.wkb and
2771
 *     ARROW:extension:metadata={"crs": &lt;projjson CRS representation>&gt; are set.
2772
 * </li>
2773
 * </ul>
2774
 *
2775
 * The Arrow/Parquet drivers recognize the following option:
2776
 * <ul>
2777
 * <li>GEOMETRY_ENCODING=WKB. To force a fallback to the generic implementation
2778
 *     when the native geometry encoding is not WKB. Otherwise the geometry
2779
 *     will be returned with its native Arrow encoding
2780
 *     (possibly using GeoArrow encoding).</li>
2781
 * </ul>
2782
 *
2783
 * @param hLayer Layer
2784
 * @param out_stream Output stream. Must *not* be NULL. The content of the
2785
 *                  structure does not need to be initialized.
2786
 * @param papszOptions NULL terminated list of key=value options.
2787
 * @return true in case of success.
2788
 * @since GDAL 3.6
2789
 */
2790
bool OGR_L_GetArrowStream(OGRLayerH hLayer, struct ArrowArrayStream *out_stream,
2791
                          char **papszOptions)
2792
0
{
2793
0
    VALIDATE_POINTER1(hLayer, "OGR_L_GetArrowStream", false);
2794
0
    VALIDATE_POINTER1(out_stream, "OGR_L_GetArrowStream", false);
2795
2796
0
    return OGRLayer::FromHandle(hLayer)->GetArrowStream(out_stream,
2797
0
                                                        papszOptions);
2798
0
}
2799
2800
/************************************************************************/
2801
/*                     OGRParseArrowMetadata()                          */
2802
/************************************************************************/
2803
2804
std::map<std::string, std::string>
2805
OGRParseArrowMetadata(const char *pabyMetadata)
2806
0
{
2807
0
    std::map<std::string, std::string> oMetadata;
2808
0
    int32_t nKVP;
2809
0
    memcpy(&nKVP, pabyMetadata, sizeof(int32_t));
2810
0
    pabyMetadata += sizeof(int32_t);
2811
0
    for (int i = 0; i < nKVP; ++i)
2812
0
    {
2813
0
        int32_t nSizeKey;
2814
0
        memcpy(&nSizeKey, pabyMetadata, sizeof(int32_t));
2815
0
        pabyMetadata += sizeof(int32_t);
2816
0
        std::string osKey;
2817
0
        osKey.assign(pabyMetadata, nSizeKey);
2818
0
        pabyMetadata += nSizeKey;
2819
2820
0
        int32_t nSizeValue;
2821
0
        memcpy(&nSizeValue, pabyMetadata, sizeof(int32_t));
2822
0
        pabyMetadata += sizeof(int32_t);
2823
0
        std::string osValue;
2824
0
        osValue.assign(pabyMetadata, nSizeValue);
2825
0
        pabyMetadata += nSizeValue;
2826
2827
0
        oMetadata[osKey] = std::move(osValue);
2828
0
    }
2829
2830
0
    return oMetadata;
2831
0
}
2832
2833
/************************************************************************/
2834
/*                        ParseDecimalFormat()                          */
2835
/************************************************************************/
2836
2837
static bool ParseDecimalFormat(const char *format, int &nPrecision, int &nScale,
2838
                               int &nWidthInBytes)
2839
0
{
2840
    // d:19,10     ==> decimal128 [precision 19, scale 10]
2841
    // d:19,10,NNN ==> decimal bitwidth = NNN [precision 19, scale 10]
2842
0
    nPrecision = 0;
2843
0
    nScale = 0;
2844
0
    nWidthInBytes = 128 / 8;  // 128 bit
2845
0
    const char *pszFirstComma = strchr(format + 2, ',');
2846
0
    if (pszFirstComma)
2847
0
    {
2848
0
        nPrecision = atoi(format + 2);
2849
0
        nScale = atoi(pszFirstComma + 1);
2850
0
        const char *pszSecondComma = strchr(pszFirstComma + 1, ',');
2851
0
        if (pszSecondComma)
2852
0
        {
2853
0
            const int nWidthInBits = atoi(pszSecondComma + 1);
2854
0
            if ((nWidthInBits % 8) != 0)
2855
0
            {
2856
                // shouldn't happen for well-format schemas
2857
0
                nWidthInBytes = 0;
2858
0
                return false;
2859
0
            }
2860
0
            else
2861
0
            {
2862
0
                nWidthInBytes = nWidthInBits / 8;
2863
0
            }
2864
0
        }
2865
0
    }
2866
0
    else
2867
0
    {
2868
        // shouldn't happen for well-format schemas
2869
0
        nWidthInBytes = 0;
2870
0
        return false;
2871
0
    }
2872
0
    return true;
2873
0
}
2874
2875
/************************************************************************/
2876
/*                   GetErrorIfUnsupportedDecimal()                     */
2877
/************************************************************************/
2878
2879
static const char *GetErrorIfUnsupportedDecimal(int nWidthInBytes,
2880
                                                int nPrecision)
2881
0
{
2882
2883
0
    if (nWidthInBytes != 128 / 8 && nWidthInBytes != 256 / 8)
2884
0
    {
2885
0
        return "For decimal field, only width 128 and 256 are supported";
2886
0
    }
2887
2888
    // precision=19 fits on 64 bits
2889
0
    if (nPrecision <= 0 || nPrecision > 19)
2890
0
    {
2891
0
        return "For decimal field, only precision up to 19 is supported";
2892
0
    }
2893
2894
0
    return nullptr;
2895
0
}
2896
2897
/************************************************************************/
2898
/*                            IsHandledSchema()                         */
2899
/************************************************************************/
2900
2901
static bool IsHandledSchema(bool bTopLevel, const struct ArrowSchema *schema,
2902
                            const std::string &osPrefix, bool bHasAttrQuery,
2903
                            const CPLStringList &aosUsedFields)
2904
0
{
2905
0
    const char *format = schema->format;
2906
0
    if (IsStructure(format))
2907
0
    {
2908
0
        for (int64_t i = 0; i < schema->n_children; ++i)
2909
0
        {
2910
0
            if (!IsHandledSchema(/* bTopLevel = */ false,
2911
0
                                 schema->children[static_cast<size_t>(i)],
2912
0
                                 bTopLevel ? std::string()
2913
0
                                           : osPrefix + schema->name + ".",
2914
0
                                 bHasAttrQuery, aosUsedFields))
2915
0
            {
2916
0
                return false;
2917
0
            }
2918
0
        }
2919
0
        return true;
2920
0
    }
2921
2922
    // Lists or maps
2923
0
    if (IsList(format) || IsLargeList(format) || IsFixedSizeList(format) ||
2924
0
        IsMap(format))
2925
0
    {
2926
0
        if (!IsHandledSchema(/* bTopLevel = */ false, schema->children[0],
2927
0
                             osPrefix, bHasAttrQuery, aosUsedFields))
2928
0
        {
2929
0
            return false;
2930
0
        }
2931
        // For now, we can't filter on lists or maps
2932
0
        if (aosUsedFields.FindString((osPrefix + schema->name).c_str()) >= 0)
2933
0
        {
2934
0
            CPLDebug("OGR",
2935
0
                     "Field %s has unhandled format '%s' for an "
2936
0
                     "attribute to filter on",
2937
0
                     (osPrefix + schema->name).c_str(), format);
2938
0
            return false;
2939
0
        }
2940
0
        return true;
2941
0
    }
2942
2943
0
    const char *const apszHandledFormats[] = {
2944
0
        "b",    // boolean
2945
0
        "c",    // int8
2946
0
        "C",    // uint8
2947
0
        "s",    // int16
2948
0
        "S",    // uint16
2949
0
        "i",    // int32
2950
0
        "I",    // uint32
2951
0
        "l",    // int64
2952
0
        "L",    // uint64
2953
0
        "e",    // float16
2954
0
        "f",    // float32
2955
0
        "g",    // float64,
2956
0
        "z",    // binary
2957
0
        "Z",    // large binary
2958
0
        "u",    // UTF-8 string
2959
0
        "U",    // large UTF-8 string
2960
0
        "tdD",  // date32[days]
2961
0
        "tdm",  // date64[milliseconds]
2962
0
        "tts",  //time32 [seconds]
2963
0
        "ttm",  //time32 [milliseconds]
2964
0
        "ttu",  //time64 [microseconds]
2965
0
        "ttn",  //time64 [nanoseconds]
2966
0
    };
2967
2968
0
    for (const char *pszHandledFormat : apszHandledFormats)
2969
0
    {
2970
0
        if (strcmp(format, pszHandledFormat) == 0)
2971
0
        {
2972
0
            return true;
2973
0
        }
2974
0
    }
2975
2976
0
    if (IsDecimal(format))
2977
0
    {
2978
0
        if (bHasAttrQuery &&
2979
0
            aosUsedFields.FindString((osPrefix + schema->name).c_str()) >= 0)
2980
0
        {
2981
0
            int nPrecision = 0;
2982
0
            int nScale = 0;
2983
0
            int nWidthInBytes = 0;
2984
0
            if (!ParseDecimalFormat(format, nPrecision, nScale, nWidthInBytes))
2985
0
            {
2986
0
                CPLDebug("OGR", "%s",
2987
0
                         (std::string("Invalid field format ") + format +
2988
0
                          " for field " + osPrefix + schema->name)
2989
0
                             .c_str());
2990
0
                return false;
2991
0
            }
2992
2993
0
            const char *pszError =
2994
0
                GetErrorIfUnsupportedDecimal(nWidthInBytes, nPrecision);
2995
0
            if (pszError)
2996
0
            {
2997
0
                CPLDebug("OGR", "%s", pszError);
2998
0
                return false;
2999
0
            }
3000
0
        }
3001
0
        return true;
3002
0
    }
3003
3004
0
    if (IsFixedWidthBinary(format) || IsTimestamp(format))
3005
0
    {
3006
0
        return true;
3007
0
    }
3008
3009
0
    CPLDebug("OGR", "Field %s has unhandled format '%s'",
3010
0
             (osPrefix + schema->name).c_str(), format);
3011
0
    return false;
3012
0
}
3013
3014
/************************************************************************/
3015
/*                  OGRLayer::CanPostFilterArrowArray()                 */
3016
/************************************************************************/
3017
3018
/** Whether the PostFilterArrowArray() can work on the schema to remove
3019
 * rows that aren't selected by the spatial or attribute filter.
3020
 */
3021
bool OGRLayer::CanPostFilterArrowArray(const struct ArrowSchema *schema) const
3022
0
{
3023
0
    if (!IsHandledSchema(
3024
0
            /* bTopLevel=*/true, schema, std::string(),
3025
0
            m_poAttrQuery != nullptr,
3026
0
            m_poAttrQuery ? CPLStringList(m_poAttrQuery->GetUsedFields())
3027
0
                          : CPLStringList()))
3028
0
    {
3029
0
        return false;
3030
0
    }
3031
3032
0
    if (m_poFilterGeom)
3033
0
    {
3034
0
        bool bFound = false;
3035
0
        const char *pszGeomFieldName =
3036
0
            const_cast<OGRLayer *>(this)
3037
0
                ->GetLayerDefn()
3038
0
                ->GetGeomFieldDefn(m_iGeomFieldFilter)
3039
0
                ->GetNameRef();
3040
0
        for (int64_t i = 0; i < schema->n_children; ++i)
3041
0
        {
3042
0
            const auto fieldSchema = schema->children[i];
3043
0
            if (strcmp(fieldSchema->name, pszGeomFieldName) == 0)
3044
0
            {
3045
0
                if (!IsBinary(fieldSchema->format) &&
3046
0
                    !IsLargeBinary(fieldSchema->format))
3047
0
                {
3048
0
                    CPLDebug("OGR", "Geometry field %s has handled format '%s'",
3049
0
                             fieldSchema->name, fieldSchema->format);
3050
0
                    return false;
3051
0
                }
3052
3053
                // Check if ARROW:extension:name = ogc.wkb
3054
0
                const char *pabyMetadata = fieldSchema->metadata;
3055
0
                if (!pabyMetadata)
3056
0
                {
3057
0
                    CPLDebug(
3058
0
                        "OGR",
3059
0
                        "Geometry field %s lacks metadata in its schema field",
3060
0
                        fieldSchema->name);
3061
0
                    return false;
3062
0
                }
3063
3064
0
                const auto oMetadata = OGRParseArrowMetadata(pabyMetadata);
3065
0
                auto oIter = oMetadata.find(ARROW_EXTENSION_NAME_KEY);
3066
0
                if (oIter == oMetadata.end())
3067
0
                {
3068
0
                    CPLDebug("OGR",
3069
0
                             "Geometry field %s lacks "
3070
0
                             "%s metadata "
3071
0
                             "in its schema field",
3072
0
                             fieldSchema->name, ARROW_EXTENSION_NAME_KEY);
3073
0
                    return false;
3074
0
                }
3075
0
                if (oIter->second != EXTENSION_NAME_OGC_WKB &&
3076
0
                    oIter->second != EXTENSION_NAME_GEOARROW_WKB)
3077
0
                {
3078
0
                    CPLDebug("OGR",
3079
0
                             "Geometry field %s has unexpected "
3080
0
                             "%s = '%s' metadata "
3081
0
                             "in its schema field",
3082
0
                             fieldSchema->name, ARROW_EXTENSION_NAME_KEY,
3083
0
                             oIter->second.c_str());
3084
0
                    return false;
3085
0
                }
3086
3087
0
                bFound = true;
3088
0
                break;
3089
0
            }
3090
0
        }
3091
0
        if (!bFound)
3092
0
        {
3093
0
            CPLDebug("OGR", "Cannot find geometry field %s in schema",
3094
0
                     pszGeomFieldName);
3095
0
            return false;
3096
0
        }
3097
0
    }
3098
3099
0
    return true;
3100
0
}
3101
3102
#if 0
3103
/************************************************************************/
3104
/*                      CheckValidityBuffer()                           */
3105
/************************************************************************/
3106
3107
static void CheckValidityBuffer(const struct ArrowArray *array)
3108
{
3109
    if (array->null_count < 0)
3110
        return;
3111
    const uint8_t *pabyValidity =
3112
        static_cast<const uint8_t *>(const_cast<const void *>(array->buffers[0]));
3113
    if( !pabyValidity )
3114
    {
3115
        CPLAssert(array->null_count == 0);
3116
        return;
3117
    }
3118
    size_t null_count = 0;
3119
    const size_t nOffset = static_cast<size_t>(array->offset);
3120
    for(size_t i = 0; i < static_cast<size_t>(array->length); ++i )
3121
    {
3122
        if (!TestBit(pabyValidity, i + nOffset))
3123
            ++ null_count;
3124
    }
3125
    CPLAssert(static_cast<size_t>(array->null_count) == null_count);
3126
}
3127
#endif
3128
3129
/************************************************************************/
3130
/*                    CompactValidityBuffer()                           */
3131
/************************************************************************/
3132
3133
static void CompactValidityBuffer(
3134
    const struct ArrowSchema *, struct ArrowArray *array, size_t iStart,
3135
    const std::vector<bool> &abyValidityFromFilters, size_t nNewLength)
3136
0
{
3137
    // Invalidate null_count as the same validity buffer may be used when
3138
    // scrolling batches, and this creates confusion if we try to set it
3139
    // to different values among the batches
3140
0
    if (array->null_count <= 0)
3141
0
    {
3142
0
        array->null_count = -1;
3143
0
        return;
3144
0
    }
3145
0
    array->null_count = -1;
3146
3147
0
    CPLAssert(static_cast<size_t>(array->length) >=
3148
0
              iStart + abyValidityFromFilters.size());
3149
0
    uint8_t *pabyValidity =
3150
0
        static_cast<uint8_t *>(const_cast<void *>(array->buffers[0]));
3151
0
    const size_t nLength = abyValidityFromFilters.size();
3152
0
    const size_t nOffset = static_cast<size_t>(array->offset);
3153
0
    size_t j = iStart + nOffset;
3154
0
    for (size_t i = 0; i < nLength && j < nNewLength + nOffset; ++i)
3155
0
    {
3156
0
        if (abyValidityFromFilters[i])
3157
0
        {
3158
0
            if (TestBit(pabyValidity, i + iStart + nOffset))
3159
0
                SetBit(pabyValidity, j);
3160
0
            else
3161
0
                UnsetBit(pabyValidity, j);
3162
0
            ++j;
3163
0
        }
3164
0
    }
3165
0
}
3166
3167
/************************************************************************/
3168
/*                       CompactBoolArray()                             */
3169
/************************************************************************/
3170
3171
static void CompactBoolArray(const struct ArrowSchema *schema,
3172
                             struct ArrowArray *array, size_t iStart,
3173
                             const std::vector<bool> &abyValidityFromFilters,
3174
                             size_t nNewLength)
3175
0
{
3176
0
    CPLAssert(array->n_children == 0);
3177
0
    CPLAssert(array->n_buffers == 2);
3178
0
    CPLAssert(static_cast<size_t>(array->length) >=
3179
0
              iStart + abyValidityFromFilters.size());
3180
3181
0
    const size_t nLength = abyValidityFromFilters.size();
3182
0
    const size_t nOffset = static_cast<size_t>(array->offset);
3183
0
    uint8_t *pabyData =
3184
0
        static_cast<uint8_t *>(const_cast<void *>(array->buffers[1]));
3185
0
    size_t j = iStart + nOffset;
3186
0
    for (size_t i = 0; i < nLength; ++i)
3187
0
    {
3188
0
        if (abyValidityFromFilters[i])
3189
0
        {
3190
0
            if (TestBit(pabyData, i + iStart + nOffset))
3191
0
                SetBit(pabyData, j);
3192
0
            else
3193
0
                UnsetBit(pabyData, j);
3194
3195
0
            ++j;
3196
0
        }
3197
0
    }
3198
3199
0
    if (schema->flags & ARROW_FLAG_NULLABLE)
3200
0
        CompactValidityBuffer(schema, array, iStart, abyValidityFromFilters,
3201
0
                              nNewLength);
3202
3203
0
    array->length = nNewLength;
3204
0
}
3205
3206
/************************************************************************/
3207
/*                       CompactPrimitiveArray()                        */
3208
/************************************************************************/
3209
3210
template <class T>
3211
static void CompactPrimitiveArray(
3212
    const struct ArrowSchema *schema, struct ArrowArray *array, size_t iStart,
3213
    const std::vector<bool> &abyValidityFromFilters, size_t nNewLength)
3214
0
{
3215
0
    CPLAssert(array->n_children == 0);
3216
0
    CPLAssert(array->n_buffers == 2);
3217
0
    CPLAssert(static_cast<size_t>(array->length) >=
3218
0
              iStart + abyValidityFromFilters.size());
3219
3220
0
    const size_t nLength = abyValidityFromFilters.size();
3221
0
    const size_t nOffset = static_cast<size_t>(array->offset);
3222
0
    T *paData =
3223
0
        static_cast<T *>(const_cast<void *>(array->buffers[1])) + nOffset;
3224
0
    size_t j = iStart;
3225
0
    for (size_t i = 0; i < nLength; ++i)
3226
0
    {
3227
0
        if (abyValidityFromFilters[i])
3228
0
        {
3229
0
            paData[j] = paData[i + iStart];
3230
0
            ++j;
3231
0
        }
3232
0
    }
3233
3234
0
    if (schema->flags & ARROW_FLAG_NULLABLE)
3235
0
        CompactValidityBuffer(schema, array, iStart, abyValidityFromFilters,
3236
0
                              nNewLength);
3237
3238
0
    array->length = nNewLength;
3239
0
}
Unexecuted instantiation: ogrlayerarrow.cpp:void CompactPrimitiveArray<unsigned char>(ArrowSchema const*, ArrowArray*, unsigned long, std::__1::vector<bool, std::__1::allocator<bool> > const&, unsigned long)
Unexecuted instantiation: ogrlayerarrow.cpp:void CompactPrimitiveArray<unsigned short>(ArrowSchema const*, ArrowArray*, unsigned long, std::__1::vector<bool, std::__1::allocator<bool> > const&, unsigned long)
Unexecuted instantiation: ogrlayerarrow.cpp:void CompactPrimitiveArray<unsigned int>(ArrowSchema const*, ArrowArray*, unsigned long, std::__1::vector<bool, std::__1::allocator<bool> > const&, unsigned long)
Unexecuted instantiation: ogrlayerarrow.cpp:void CompactPrimitiveArray<unsigned long>(ArrowSchema const*, ArrowArray*, unsigned long, std::__1::vector<bool, std::__1::allocator<bool> > const&, unsigned long)
3240
3241
/************************************************************************/
3242
/*                    CompactStringOrBinaryArray()                      */
3243
/************************************************************************/
3244
3245
template <class OffsetType>
3246
static void CompactStringOrBinaryArray(
3247
    const struct ArrowSchema *schema, struct ArrowArray *array, size_t iStart,
3248
    const std::vector<bool> &abyValidityFromFilters, size_t nNewLength)
3249
0
{
3250
0
    CPLAssert(array->n_children == 0);
3251
0
    CPLAssert(array->n_buffers == 3);
3252
0
    CPLAssert(static_cast<size_t>(array->length) >=
3253
0
              iStart + abyValidityFromFilters.size());
3254
3255
0
    const size_t nLength = abyValidityFromFilters.size();
3256
0
    const size_t nOffset = static_cast<size_t>(array->offset);
3257
0
    OffsetType *panOffsets =
3258
0
        static_cast<OffsetType *>(const_cast<void *>(array->buffers[1])) +
3259
0
        nOffset;
3260
0
    GByte *pabyData =
3261
0
        static_cast<GByte *>(const_cast<void *>(array->buffers[2]));
3262
0
    size_t j = iStart;
3263
0
    OffsetType nCurOffset = panOffsets[iStart];
3264
0
    for (size_t i = 0; i < nLength; ++i)
3265
0
    {
3266
0
        if (abyValidityFromFilters[i])
3267
0
        {
3268
0
            const auto nStartOffset = panOffsets[i + iStart];
3269
0
            const auto nEndOffset = panOffsets[i + iStart + 1];
3270
0
            panOffsets[j] = nCurOffset;
3271
0
            const auto nSize = static_cast<size_t>(nEndOffset - nStartOffset);
3272
0
            if (nSize)
3273
0
            {
3274
0
                if (nCurOffset < nStartOffset)
3275
0
                {
3276
0
                    memmove(pabyData + nCurOffset, pabyData + nStartOffset,
3277
0
                            nSize);
3278
0
                }
3279
0
                nCurOffset += static_cast<OffsetType>(nSize);
3280
0
            }
3281
0
            ++j;
3282
0
        }
3283
0
    }
3284
0
    panOffsets[j] = nCurOffset;
3285
3286
0
    if (schema->flags & ARROW_FLAG_NULLABLE)
3287
0
        CompactValidityBuffer(schema, array, iStart, abyValidityFromFilters,
3288
0
                              nNewLength);
3289
3290
0
    array->length = nNewLength;
3291
0
}
Unexecuted instantiation: ogrlayerarrow.cpp:void CompactStringOrBinaryArray<unsigned int>(ArrowSchema const*, ArrowArray*, unsigned long, std::__1::vector<bool, std::__1::allocator<bool> > const&, unsigned long)
Unexecuted instantiation: ogrlayerarrow.cpp:void CompactStringOrBinaryArray<unsigned long>(ArrowSchema const*, ArrowArray*, unsigned long, std::__1::vector<bool, std::__1::allocator<bool> > const&, unsigned long)
3292
3293
/************************************************************************/
3294
/*                    CompactFixedWidthArray()                          */
3295
/************************************************************************/
3296
3297
static void
3298
CompactFixedWidthArray(const struct ArrowSchema *schema,
3299
                       struct ArrowArray *array, int nWidth, size_t iStart,
3300
                       const std::vector<bool> &abyValidityFromFilters,
3301
                       size_t nNewLength)
3302
0
{
3303
0
    CPLAssert(array->n_children == 0);
3304
0
    CPLAssert(array->n_buffers == 2);
3305
0
    CPLAssert(static_cast<size_t>(array->length) >=
3306
0
              iStart + abyValidityFromFilters.size());
3307
3308
0
    const size_t nLength = abyValidityFromFilters.size();
3309
0
    const size_t nOffset = static_cast<size_t>(array->offset);
3310
0
    GByte *pabyData =
3311
0
        static_cast<GByte *>(const_cast<void *>(array->buffers[1]));
3312
0
    size_t nStartOffset = (iStart + nOffset) * nWidth;
3313
0
    size_t nCurOffset = nStartOffset;
3314
0
    for (size_t i = 0; i < nLength; ++i, nStartOffset += nWidth)
3315
0
    {
3316
0
        if (abyValidityFromFilters[i])
3317
0
        {
3318
0
            if (nCurOffset < nStartOffset)
3319
0
            {
3320
0
                memcpy(pabyData + nCurOffset, pabyData + nStartOffset, nWidth);
3321
0
            }
3322
0
            nCurOffset += nWidth;
3323
0
        }
3324
0
    }
3325
3326
0
    if (schema->flags & ARROW_FLAG_NULLABLE)
3327
0
        CompactValidityBuffer(schema, array, iStart, abyValidityFromFilters,
3328
0
                              nNewLength);
3329
3330
0
    array->length = nNewLength;
3331
0
}
3332
3333
/************************************************************************/
3334
/*                       CompactStructArray()                           */
3335
/************************************************************************/
3336
3337
static bool CompactArray(const struct ArrowSchema *schema,
3338
                         struct ArrowArray *array, size_t iStart,
3339
                         const std::vector<bool> &abyValidityFromFilters,
3340
                         size_t nNewLength);
3341
3342
static bool CompactStructArray(const struct ArrowSchema *schema,
3343
                               struct ArrowArray *array, size_t iStart,
3344
                               const std::vector<bool> &abyValidityFromFilters,
3345
                               size_t nNewLength)
3346
0
{
3347
    // The equality might not be strict in the case of when some sub-arrays
3348
    // are fully void !
3349
0
    CPLAssert(array->n_children <= schema->n_children);
3350
0
    for (int64_t iField = 0; iField < array->n_children; ++iField)
3351
0
    {
3352
0
        const auto psChildSchema = schema->children[iField];
3353
0
        const auto psChildArray = array->children[iField];
3354
        // To please Arrow validation...
3355
0
        const size_t nChildNewLength =
3356
0
            static_cast<size_t>(array->offset) + nNewLength;
3357
0
        if (psChildArray->length > array->length)
3358
0
        {
3359
0
            std::vector<bool> abyChildValidity(abyValidityFromFilters);
3360
0
            abyChildValidity.resize(
3361
0
                abyValidityFromFilters.size() +
3362
0
                    static_cast<size_t>(psChildArray->length - array->length),
3363
0
                false);
3364
0
            if (!CompactArray(psChildSchema, psChildArray, iStart,
3365
0
                              abyChildValidity, nChildNewLength))
3366
0
            {
3367
0
                return false;
3368
0
            }
3369
0
        }
3370
0
        else
3371
0
        {
3372
0
            if (!CompactArray(psChildSchema, psChildArray, iStart,
3373
0
                              abyValidityFromFilters, nChildNewLength))
3374
0
            {
3375
0
                return false;
3376
0
            }
3377
0
        }
3378
0
        CPLAssert(psChildArray->length ==
3379
0
                  static_cast<int64_t>(nChildNewLength));
3380
0
    }
3381
3382
0
    if (schema->flags & ARROW_FLAG_NULLABLE)
3383
0
        CompactValidityBuffer(schema, array, iStart, abyValidityFromFilters,
3384
0
                              nNewLength);
3385
3386
0
    array->length = nNewLength;
3387
3388
0
    return true;
3389
0
}
3390
3391
/************************************************************************/
3392
/*                     InvalidateNullCountRec()                         */
3393
/************************************************************************/
3394
3395
static void InvalidateNullCountRec(const struct ArrowSchema *schema,
3396
                                   struct ArrowArray *array)
3397
0
{
3398
0
    if (schema->flags & ARROW_FLAG_NULLABLE)
3399
0
        array->null_count = -1;
3400
0
    for (int i = 0; i < array->n_children; ++i)
3401
0
        InvalidateNullCountRec(schema->children[i], array->children[i]);
3402
0
}
3403
3404
/************************************************************************/
3405
/*                       CompactListArray()                             */
3406
/************************************************************************/
3407
3408
template <class OffsetType>
3409
static bool CompactListArray(const struct ArrowSchema *schema,
3410
                             struct ArrowArray *array, size_t iStart,
3411
                             const std::vector<bool> &abyValidityFromFilters,
3412
                             size_t nNewLength)
3413
0
{
3414
0
    CPLAssert(static_cast<size_t>(array->length) >=
3415
0
              iStart + abyValidityFromFilters.size());
3416
0
    CPLAssert(array->n_children == 1);
3417
0
    CPLAssert(array->n_buffers == 2);
3418
3419
0
    const auto psChildSchema = schema->children[0];
3420
0
    const auto psChildArray = array->children[0];
3421
3422
0
    const size_t nLength = abyValidityFromFilters.size();
3423
0
    const size_t nOffset = static_cast<size_t>(array->offset);
3424
0
    OffsetType *panOffsets =
3425
0
        static_cast<OffsetType *>(const_cast<void *>(array->buffers[1])) +
3426
0
        nOffset;
3427
3428
0
    if (panOffsets[iStart + nLength] > panOffsets[iStart])
3429
0
    {
3430
0
        std::vector<bool> abyChildValidity(
3431
0
            static_cast<size_t>(panOffsets[iStart + nLength] -
3432
0
                                panOffsets[iStart]),
3433
0
            true);
3434
0
        size_t j = iStart;
3435
0
        OffsetType nCurOffset = panOffsets[iStart];
3436
0
        for (size_t i = 0; i < nLength; ++i)
3437
0
        {
3438
0
            if (abyValidityFromFilters[i])
3439
0
            {
3440
0
                const auto nSize =
3441
0
                    panOffsets[i + iStart + 1] - panOffsets[i + iStart];
3442
0
                panOffsets[j] = nCurOffset;
3443
0
                nCurOffset += nSize;
3444
0
                ++j;
3445
0
            }
3446
0
            else
3447
0
            {
3448
0
                const auto nStartOffset = panOffsets[i + iStart];
3449
0
                const auto nEndOffset = panOffsets[i + iStart + 1];
3450
0
                if (nStartOffset != nEndOffset)
3451
0
                {
3452
0
                    if (nStartOffset >=
3453
0
                        panOffsets[iStart] + abyChildValidity.size())
3454
0
                    {
3455
                        // shouldn't happen in sane arrays...
3456
0
                        CPLError(CE_Failure, CPLE_AppDefined,
3457
0
                                 "nStartOffset >= panOffsets[iStart] + "
3458
0
                                 "abyChildValidity.size()");
3459
0
                        return false;
3460
0
                    }
3461
                    // nEndOffset might be equal to abyChildValidity.size()
3462
0
                    if (nEndOffset >
3463
0
                        panOffsets[iStart] + abyChildValidity.size())
3464
0
                    {
3465
                        // shouldn't happen in sane arrays...
3466
0
                        CPLError(CE_Failure, CPLE_AppDefined,
3467
0
                                 "nEndOffset > panOffsets[iStart] + "
3468
0
                                 "abyChildValidity.size()");
3469
0
                        return false;
3470
0
                    }
3471
0
                    for (auto k = nStartOffset - panOffsets[iStart];
3472
0
                         k < nEndOffset - panOffsets[iStart]; ++k)
3473
0
                        abyChildValidity[static_cast<size_t>(k)] = false;
3474
0
                }
3475
0
            }
3476
0
        }
3477
0
        panOffsets[j] = nCurOffset;
3478
0
        const size_t nChildNewLength = static_cast<size_t>(panOffsets[j]);
3479
        // To please Arrow validation
3480
0
        for (; j < iStart + nLength; ++j)
3481
0
            panOffsets[j] = nCurOffset;
3482
3483
0
        if (!CompactArray(psChildSchema, psChildArray,
3484
0
                          static_cast<size_t>(panOffsets[iStart]),
3485
0
                          abyChildValidity, nChildNewLength))
3486
0
            return false;
3487
3488
0
        CPLAssert(psChildArray->length ==
3489
0
                  static_cast<int64_t>(nChildNewLength));
3490
0
    }
3491
0
    else
3492
0
    {
3493
0
        InvalidateNullCountRec(psChildSchema, psChildArray);
3494
0
    }
3495
3496
0
    if (schema->flags & ARROW_FLAG_NULLABLE)
3497
0
        CompactValidityBuffer(schema, array, iStart, abyValidityFromFilters,
3498
0
                              nNewLength);
3499
3500
0
    array->length = nNewLength;
3501
3502
0
    return true;
3503
0
}
Unexecuted instantiation: ogrlayerarrow.cpp:bool CompactListArray<unsigned int>(ArrowSchema const*, ArrowArray*, unsigned long, std::__1::vector<bool, std::__1::allocator<bool> > const&, unsigned long)
Unexecuted instantiation: ogrlayerarrow.cpp:bool CompactListArray<unsigned long>(ArrowSchema const*, ArrowArray*, unsigned long, std::__1::vector<bool, std::__1::allocator<bool> > const&, unsigned long)
3504
3505
/************************************************************************/
3506
/*                     CompactFixedSizeListArray()                      */
3507
/************************************************************************/
3508
3509
static bool
3510
CompactFixedSizeListArray(const struct ArrowSchema *schema,
3511
                          struct ArrowArray *array, size_t N, size_t iStart,
3512
                          const std::vector<bool> &abyValidityFromFilters,
3513
                          size_t nNewLength)
3514
0
{
3515
0
    CPLAssert(static_cast<size_t>(array->length) >=
3516
0
              iStart + abyValidityFromFilters.size());
3517
0
    CPLAssert(array->n_children == 1);
3518
3519
0
    const auto psChildSchema = schema->children[0];
3520
0
    const auto psChildArray = array->children[0];
3521
3522
0
    const size_t nLength = abyValidityFromFilters.size();
3523
0
    const size_t nOffset = static_cast<size_t>(array->offset);
3524
0
    std::vector<bool> abyChildValidity(N * nLength, true);
3525
0
    size_t nChildNewLength = (iStart + nOffset) * N;
3526
0
    size_t nSrcLength = 0;
3527
0
    for (size_t i = 0; i < nLength; ++i)
3528
0
    {
3529
0
        if (abyValidityFromFilters[i])
3530
0
        {
3531
0
            nChildNewLength += N;
3532
0
            nSrcLength++;
3533
0
        }
3534
0
        else
3535
0
        {
3536
0
            const size_t nStartOffset = i * N;
3537
0
            const size_t nEndOffset = (i + 1) * N;
3538
0
            for (size_t k = nStartOffset; k < nEndOffset; ++k)
3539
0
                abyChildValidity[k] = false;
3540
0
        }
3541
0
    }
3542
0
    CPL_IGNORE_RET_VAL(nSrcLength);
3543
0
    CPLAssert(iStart + nSrcLength == nNewLength);
3544
3545
0
    if (!CompactArray(psChildSchema, psChildArray, (iStart + nOffset) * N,
3546
0
                      abyChildValidity, nChildNewLength))
3547
0
        return false;
3548
3549
0
    if (schema->flags & ARROW_FLAG_NULLABLE)
3550
0
        CompactValidityBuffer(schema, array, iStart, abyValidityFromFilters,
3551
0
                              nNewLength);
3552
3553
0
    array->length = nNewLength;
3554
3555
0
    CPLAssert(psChildArray->length >=
3556
0
              static_cast<int64_t>(N) * (array->length + array->offset));
3557
3558
0
    return true;
3559
0
}
3560
3561
/************************************************************************/
3562
/*                       CompactMapArray()                              */
3563
/************************************************************************/
3564
3565
static bool CompactMapArray(const struct ArrowSchema *schema,
3566
                            struct ArrowArray *array, size_t iStart,
3567
                            const std::vector<bool> &abyValidityFromFilters,
3568
                            size_t nNewLength)
3569
0
{
3570
0
    return CompactListArray<uint32_t>(schema, array, iStart,
3571
0
                                      abyValidityFromFilters, nNewLength);
3572
0
}
3573
3574
/************************************************************************/
3575
/*                           CompactArray()                             */
3576
/************************************************************************/
3577
3578
static bool CompactArray(const struct ArrowSchema *schema,
3579
                         struct ArrowArray *array, size_t iStart,
3580
                         const std::vector<bool> &abyValidityFromFilters,
3581
                         size_t nNewLength)
3582
0
{
3583
0
    const char *format = schema->format;
3584
3585
0
    if (IsStructure(format))
3586
0
    {
3587
0
        if (!CompactStructArray(schema, array, iStart, abyValidityFromFilters,
3588
0
                                nNewLength))
3589
0
            return false;
3590
0
    }
3591
0
    else if (IsList(format))
3592
0
    {
3593
0
        if (!CompactListArray<uint32_t>(schema, array, iStart,
3594
0
                                        abyValidityFromFilters, nNewLength))
3595
0
            return false;
3596
0
    }
3597
0
    else if (IsLargeList(format))
3598
0
    {
3599
0
        if (!CompactListArray<uint64_t>(schema, array, iStart,
3600
0
                                        abyValidityFromFilters, nNewLength))
3601
0
            return false;
3602
0
    }
3603
0
    else if (IsMap(format))
3604
0
    {
3605
0
        if (!CompactMapArray(schema, array, iStart, abyValidityFromFilters,
3606
0
                             nNewLength))
3607
0
            return false;
3608
0
    }
3609
0
    else if (IsFixedSizeList(format))
3610
0
    {
3611
0
        const int N = GetFixedSizeList(format);
3612
0
        if (N <= 0)
3613
0
            return false;
3614
0
        if (!CompactFixedSizeListArray(schema, array, static_cast<size_t>(N),
3615
0
                                       iStart, abyValidityFromFilters,
3616
0
                                       nNewLength))
3617
0
            return false;
3618
0
    }
3619
0
    else if (IsBoolean(format))
3620
0
    {
3621
0
        CompactBoolArray(schema, array, iStart, abyValidityFromFilters,
3622
0
                         nNewLength);
3623
0
    }
3624
0
    else if (IsInt8(format) || IsUInt8(format))
3625
0
    {
3626
0
        CompactPrimitiveArray<uint8_t>(schema, array, iStart,
3627
0
                                       abyValidityFromFilters, nNewLength);
3628
0
    }
3629
0
    else if (IsInt16(format) || IsUInt16(format) || IsFloat16(format))
3630
0
    {
3631
0
        CompactPrimitiveArray<uint16_t>(schema, array, iStart,
3632
0
                                        abyValidityFromFilters, nNewLength);
3633
0
    }
3634
0
    else if (IsInt32(format) || IsUInt32(format) || IsFloat32(format) ||
3635
0
             strcmp(format, "tdD") == 0 || strcmp(format, "tts") == 0 ||
3636
0
             strcmp(format, "ttm") == 0)
3637
0
    {
3638
0
        CompactPrimitiveArray<uint32_t>(schema, array, iStart,
3639
0
                                        abyValidityFromFilters, nNewLength);
3640
0
    }
3641
0
    else if (IsInt64(format) || IsUInt64(format) || IsFloat64(format) ||
3642
0
             strcmp(format, "tdm") == 0 || strcmp(format, "ttu") == 0 ||
3643
0
             strcmp(format, "ttn") == 0 || strncmp(format, "ts", 2) == 0)
3644
0
    {
3645
0
        CompactPrimitiveArray<uint64_t>(schema, array, iStart,
3646
0
                                        abyValidityFromFilters, nNewLength);
3647
0
    }
3648
0
    else if (IsString(format) || IsBinary(format))
3649
0
    {
3650
0
        CompactStringOrBinaryArray<uint32_t>(
3651
0
            schema, array, iStart, abyValidityFromFilters, nNewLength);
3652
0
    }
3653
0
    else if (IsLargeString(format) || IsLargeBinary(format))
3654
0
    {
3655
0
        CompactStringOrBinaryArray<uint64_t>(
3656
0
            schema, array, iStart, abyValidityFromFilters, nNewLength);
3657
0
    }
3658
0
    else if (IsFixedWidthBinary(format))
3659
0
    {
3660
0
        const int nWidth = GetFixedWithBinary(format);
3661
0
        CompactFixedWidthArray(schema, array, nWidth, iStart,
3662
0
                               abyValidityFromFilters, nNewLength);
3663
0
    }
3664
0
    else if (IsDecimal(format))
3665
0
    {
3666
0
        int nPrecision = 0;
3667
0
        int nScale = 0;
3668
0
        int nWidthInBytes = 0;
3669
0
        if (!ParseDecimalFormat(format, nPrecision, nScale, nWidthInBytes))
3670
0
        {
3671
0
            CPLError(CE_Failure, CPLE_AppDefined,
3672
0
                     "Unexpected error in PostFilterArrowArray(): unhandled "
3673
0
                     "field format: %s",
3674
0
                     format);
3675
3676
0
            return false;
3677
0
        }
3678
0
        CompactFixedWidthArray(schema, array, nWidthInBytes, iStart,
3679
0
                               abyValidityFromFilters, nNewLength);
3680
0
    }
3681
0
    else
3682
0
    {
3683
0
        CPLError(CE_Failure, CPLE_AppDefined,
3684
0
                 "Unexpected error in CompactArray(): unhandled "
3685
0
                 "field format: %s",
3686
0
                 format);
3687
0
        return false;
3688
0
    }
3689
3690
0
    return true;
3691
0
}
3692
3693
/************************************************************************/
3694
/*                  FillValidityArrayFromWKBArray()                     */
3695
/************************************************************************/
3696
3697
template <class OffsetType>
3698
static size_t
3699
FillValidityArrayFromWKBArray(struct ArrowArray *array, const OGRLayer *poLayer,
3700
                              std::vector<bool> &abyValidityFromFilters)
3701
0
{
3702
0
    const size_t nLength = static_cast<size_t>(array->length);
3703
0
    const uint8_t *pabyValidity =
3704
0
        array->null_count == 0
3705
0
            ? nullptr
3706
0
            : static_cast<const uint8_t *>(array->buffers[0]);
3707
0
    const size_t nOffset = static_cast<size_t>(array->offset);
3708
0
    const OffsetType *panOffsets =
3709
0
        static_cast<const OffsetType *>(array->buffers[1]) + nOffset;
3710
0
    const GByte *pabyData = static_cast<const GByte *>(array->buffers[2]);
3711
0
    OGREnvelope sEnvelope;
3712
0
    abyValidityFromFilters.resize(nLength);
3713
0
    size_t nCountIntersecting = 0;
3714
0
    for (size_t i = 0; i < nLength; ++i)
3715
0
    {
3716
0
        if (!pabyValidity || TestBit(pabyValidity, i + nOffset))
3717
0
        {
3718
0
            const GByte *pabyWKB = pabyData + panOffsets[i];
3719
0
            const size_t nWKBSize =
3720
0
                static_cast<size_t>(panOffsets[i + 1] - panOffsets[i]);
3721
0
            if (poLayer->FilterWKBGeometry(pabyWKB, nWKBSize,
3722
0
                                           /* bEnvelopeAlreadySet=*/false,
3723
0
                                           sEnvelope))
3724
0
            {
3725
0
                abyValidityFromFilters[i] = true;
3726
0
                nCountIntersecting++;
3727
0
            }
3728
0
        }
3729
0
    }
3730
0
    return nCountIntersecting;
3731
0
}
Unexecuted instantiation: ogrlayerarrow.cpp:unsigned long FillValidityArrayFromWKBArray<unsigned int>(ArrowArray*, OGRLayer const*, std::__1::vector<bool, std::__1::allocator<bool> >&)
Unexecuted instantiation: ogrlayerarrow.cpp:unsigned long FillValidityArrayFromWKBArray<unsigned long>(ArrowArray*, OGRLayer const*, std::__1::vector<bool, std::__1::allocator<bool> >&)
3732
3733
/************************************************************************/
3734
/*               ArrowTimestampToOGRDateTime()                          */
3735
/************************************************************************/
3736
3737
static void ArrowTimestampToOGRDateTime(int64_t nTimestamp,
3738
                                        int nInvFactorToSecond,
3739
                                        const char *pszTZ, OGRFeature &oFeature,
3740
                                        int iField)
3741
0
{
3742
0
    double floatingPart = 0;
3743
0
    if (nInvFactorToSecond)
3744
0
    {
3745
0
        floatingPart =
3746
0
            (nTimestamp % nInvFactorToSecond) / double(nInvFactorToSecond);
3747
0
        nTimestamp /= nInvFactorToSecond;
3748
0
    }
3749
0
    int nTZFlag = 0;
3750
0
    const size_t nTZLen = strlen(pszTZ);
3751
0
    if ((nTZLen == 3 && strcmp(pszTZ, "UTC") == 0) ||
3752
0
        (nTZLen == 7 && strcmp(pszTZ, "Etc/UTC") == 0))
3753
0
    {
3754
0
        nTZFlag = 100;
3755
0
    }
3756
0
    else if (nTZLen == 6 && (pszTZ[0] == '+' || pszTZ[0] == '-') &&
3757
0
             pszTZ[3] == ':')
3758
0
    {
3759
0
        int nTZHour = atoi(pszTZ + 1);
3760
0
        int nTZMin = atoi(pszTZ + 4);
3761
0
        if (nTZHour >= 0 && nTZHour <= 14 && nTZMin >= 0 && nTZMin < 60 &&
3762
0
            (nTZMin % 15) == 0)
3763
0
        {
3764
0
            nTZFlag = (nTZHour * 4) + (nTZMin / 15);
3765
0
            if (pszTZ[0] == '+')
3766
0
            {
3767
0
                nTZFlag = 100 + nTZFlag;
3768
0
                nTimestamp += nTZHour * 3600 + nTZMin * 60;
3769
0
            }
3770
0
            else
3771
0
            {
3772
0
                nTZFlag = 100 - nTZFlag;
3773
0
                nTimestamp -= nTZHour * 3600 + nTZMin * 60;
3774
0
            }
3775
0
        }
3776
0
    }
3777
0
    struct tm dt;
3778
0
    CPLUnixTimeToYMDHMS(nTimestamp, &dt);
3779
0
    oFeature.SetField(iField, dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday,
3780
0
                      dt.tm_hour, dt.tm_min,
3781
0
                      static_cast<float>(dt.tm_sec + floatingPart), nTZFlag);
3782
0
}
3783
3784
/************************************************************************/
3785
/*                 BuildMapFieldNameToArrowPath()                       */
3786
/************************************************************************/
3787
3788
static void
3789
BuildMapFieldNameToArrowPath(const struct ArrowSchema *schema,
3790
                             std::map<std::string, std::vector<int>> &oMap,
3791
                             const std::string &osPrefix,
3792
                             std::vector<int> &anArrowPath)
3793
0
{
3794
0
    for (int64_t i = 0; i < schema->n_children; ++i)
3795
0
    {
3796
0
        auto psChild = schema->children[i];
3797
0
        anArrowPath.push_back(static_cast<int>(i));
3798
0
        if (IsStructure(psChild->format))
3799
0
        {
3800
0
            std::string osNewPrefix(osPrefix);
3801
0
            osNewPrefix += psChild->name;
3802
0
            osNewPrefix += ".";
3803
0
            BuildMapFieldNameToArrowPath(psChild, oMap, osNewPrefix,
3804
0
                                         anArrowPath);
3805
0
        }
3806
0
        else
3807
0
        {
3808
0
            oMap[osPrefix + psChild->name] = anArrowPath;
3809
0
        }
3810
0
        anArrowPath.pop_back();
3811
0
    }
3812
0
}
3813
3814
/************************************************************************/
3815
/*                      FillFieldList()                                 */
3816
/************************************************************************/
3817
3818
template <typename ListOffsetType, typename ArrowType,
3819
          typename OGRType = ArrowType>
3820
inline static void FillFieldList(const struct ArrowArray *array,
3821
                                 int iOGRFieldIdx, size_t nOffsettedIndex,
3822
                                 const struct ArrowArray *childArray,
3823
                                 OGRFeature &oFeature)
3824
0
{
3825
0
    const auto panOffsets =
3826
0
        static_cast<const ListOffsetType *>(array->buffers[1]) +
3827
0
        nOffsettedIndex;
3828
0
    std::vector<OGRType> aValues;
3829
0
    const auto *paValues =
3830
0
        static_cast<const ArrowType *>(childArray->buffers[1]);
3831
0
    for (size_t i = static_cast<size_t>(panOffsets[0]);
3832
0
         i < static_cast<size_t>(panOffsets[1]); ++i)
3833
0
    {
3834
0
        aValues.push_back(static_cast<OGRType>(paValues[i]));
3835
0
    }
3836
0
    oFeature.SetField(iOGRFieldIdx, static_cast<int>(aValues.size()),
3837
0
                      aValues.data());
3838
0
}
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldList<unsigned int, signed char, int>(ArrowArray const*, int, unsigned long, ArrowArray const*, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldList<unsigned long, signed char, int>(ArrowArray const*, int, unsigned long, ArrowArray const*, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldList<unsigned int, unsigned char, int>(ArrowArray const*, int, unsigned long, ArrowArray const*, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldList<unsigned long, unsigned char, int>(ArrowArray const*, int, unsigned long, ArrowArray const*, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldList<unsigned int, short, int>(ArrowArray const*, int, unsigned long, ArrowArray const*, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldList<unsigned long, short, int>(ArrowArray const*, int, unsigned long, ArrowArray const*, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldList<unsigned int, unsigned short, int>(ArrowArray const*, int, unsigned long, ArrowArray const*, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldList<unsigned long, unsigned short, int>(ArrowArray const*, int, unsigned long, ArrowArray const*, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldList<unsigned int, int, int>(ArrowArray const*, int, unsigned long, ArrowArray const*, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldList<unsigned long, int, int>(ArrowArray const*, int, unsigned long, ArrowArray const*, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldList<unsigned int, unsigned int, long long>(ArrowArray const*, int, unsigned long, ArrowArray const*, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldList<unsigned long, unsigned int, long long>(ArrowArray const*, int, unsigned long, ArrowArray const*, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldList<unsigned int, long, long long>(ArrowArray const*, int, unsigned long, ArrowArray const*, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldList<unsigned long, long, long long>(ArrowArray const*, int, unsigned long, ArrowArray const*, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldList<unsigned int, unsigned long, double>(ArrowArray const*, int, unsigned long, ArrowArray const*, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldList<unsigned long, unsigned long, double>(ArrowArray const*, int, unsigned long, ArrowArray const*, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldList<unsigned int, float, double>(ArrowArray const*, int, unsigned long, ArrowArray const*, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldList<unsigned long, float, double>(ArrowArray const*, int, unsigned long, ArrowArray const*, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldList<unsigned int, double, double>(ArrowArray const*, int, unsigned long, ArrowArray const*, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldList<unsigned long, double, double>(ArrowArray const*, int, unsigned long, ArrowArray const*, OGRFeature&)
3839
3840
/************************************************************************/
3841
/*                      FillFieldListFromBool()                         */
3842
/************************************************************************/
3843
3844
template <typename ListOffsetType>
3845
inline static void
3846
FillFieldListFromBool(const struct ArrowArray *array, int iOGRFieldIdx,
3847
                      size_t nOffsettedIndex,
3848
                      const struct ArrowArray *childArray, OGRFeature &oFeature)
3849
0
{
3850
0
    const auto panOffsets =
3851
0
        static_cast<const ListOffsetType *>(array->buffers[1]) +
3852
0
        nOffsettedIndex;
3853
0
    std::vector<int> aValues;
3854
0
    const auto *paValues = static_cast<const uint8_t *>(childArray->buffers[1]);
3855
0
    for (size_t i = static_cast<size_t>(panOffsets[0]);
3856
0
         i < static_cast<size_t>(panOffsets[1]); ++i)
3857
0
    {
3858
0
        aValues.push_back(TestBit(paValues, i) ? 1 : 0);
3859
0
    }
3860
0
    oFeature.SetField(iOGRFieldIdx, static_cast<int>(aValues.size()),
3861
0
                      aValues.data());
3862
0
}
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldListFromBool<unsigned int>(ArrowArray const*, int, unsigned long, ArrowArray const*, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldListFromBool<unsigned long>(ArrowArray const*, int, unsigned long, ArrowArray const*, OGRFeature&)
3863
3864
/************************************************************************/
3865
/*                    FillFieldListFromHalfFloat()                      */
3866
/************************************************************************/
3867
3868
template <typename ListOffsetType>
3869
inline static void FillFieldListFromHalfFloat(
3870
    const struct ArrowArray *array, int iOGRFieldIdx, size_t nOffsettedIndex,
3871
    const struct ArrowArray *childArray, OGRFeature &oFeature)
3872
0
{
3873
0
    const auto panOffsets =
3874
0
        static_cast<const ListOffsetType *>(array->buffers[1]) +
3875
0
        nOffsettedIndex;
3876
0
    std::vector<double> aValues;
3877
0
    const auto *paValues =
3878
0
        static_cast<const uint16_t *>(childArray->buffers[1]);
3879
0
    for (size_t i = static_cast<size_t>(panOffsets[0]);
3880
0
         i < static_cast<size_t>(panOffsets[1]); ++i)
3881
0
    {
3882
0
        const auto nFloat16AsUInt32 = CPLHalfToFloat(paValues[i]);
3883
0
        float f;
3884
0
        memcpy(&f, &nFloat16AsUInt32, sizeof(f));
3885
0
        aValues.push_back(f);
3886
0
    }
3887
0
    oFeature.SetField(iOGRFieldIdx, static_cast<int>(aValues.size()),
3888
0
                      aValues.data());
3889
0
}
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldListFromHalfFloat<unsigned int>(ArrowArray const*, int, unsigned long, ArrowArray const*, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldListFromHalfFloat<unsigned long>(ArrowArray const*, int, unsigned long, ArrowArray const*, OGRFeature&)
3890
3891
/************************************************************************/
3892
/*                    FillFieldListFromString()                         */
3893
/************************************************************************/
3894
3895
template <typename ListOffsetType, typename StringOffsetType>
3896
inline static void FillFieldListFromString(const struct ArrowArray *array,
3897
                                           int iOGRFieldIdx,
3898
                                           size_t nOffsettedIndex,
3899
                                           const struct ArrowArray *childArray,
3900
                                           OGRFeature &oFeature)
3901
0
{
3902
0
    const auto panOffsets =
3903
0
        static_cast<const ListOffsetType *>(array->buffers[1]) +
3904
0
        nOffsettedIndex;
3905
0
    CPLStringList aosVals;
3906
0
    const auto panSubOffsets =
3907
0
        static_cast<const StringOffsetType *>(childArray->buffers[1]);
3908
0
    const char *pszValues = static_cast<const char *>(childArray->buffers[2]);
3909
0
    std::string osTmp;
3910
0
    for (size_t i = static_cast<size_t>(panOffsets[0]);
3911
0
         i < static_cast<size_t>(panOffsets[1]); ++i)
3912
0
    {
3913
0
        osTmp.assign(
3914
0
            pszValues + panSubOffsets[i],
3915
0
            static_cast<size_t>(panSubOffsets[i + 1] - panSubOffsets[i]));
3916
0
        aosVals.AddString(osTmp.c_str());
3917
0
    }
3918
0
    oFeature.SetField(iOGRFieldIdx, aosVals.List());
3919
0
}
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldListFromString<unsigned int, unsigned int>(ArrowArray const*, int, unsigned long, ArrowArray const*, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldListFromString<unsigned long, unsigned int>(ArrowArray const*, int, unsigned long, ArrowArray const*, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldListFromString<unsigned int, unsigned long>(ArrowArray const*, int, unsigned long, ArrowArray const*, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldListFromString<unsigned long, unsigned long>(ArrowArray const*, int, unsigned long, ArrowArray const*, OGRFeature&)
3920
3921
/************************************************************************/
3922
/*                         FillFieldFixedSizeList()                     */
3923
/************************************************************************/
3924
3925
template <typename ArrowType, typename OGRType = ArrowType>
3926
inline static void FillFieldFixedSizeList(
3927
    const struct ArrowArray *, int iOGRFieldIdx, size_t nOffsettedIndex,
3928
    const int nItems, const struct ArrowArray *childArray, OGRFeature &oFeature)
3929
0
{
3930
0
    std::vector<OGRType> aValues;
3931
0
    const auto *paValues =
3932
0
        static_cast<const ArrowType *>(childArray->buffers[1]) +
3933
0
        childArray->offset + nOffsettedIndex * nItems;
3934
0
    for (int i = 0; i < nItems; ++i)
3935
0
    {
3936
0
        aValues.push_back(static_cast<OGRType>(paValues[i]));
3937
0
    }
3938
0
    oFeature.SetField(iOGRFieldIdx, static_cast<int>(aValues.size()),
3939
0
                      aValues.data());
3940
0
}
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldFixedSizeList<signed char, int>(ArrowArray const*, int, unsigned long, int, ArrowArray const*, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldFixedSizeList<unsigned char, int>(ArrowArray const*, int, unsigned long, int, ArrowArray const*, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldFixedSizeList<short, int>(ArrowArray const*, int, unsigned long, int, ArrowArray const*, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldFixedSizeList<unsigned short, int>(ArrowArray const*, int, unsigned long, int, ArrowArray const*, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldFixedSizeList<int, int>(ArrowArray const*, int, unsigned long, int, ArrowArray const*, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldFixedSizeList<unsigned int, long long>(ArrowArray const*, int, unsigned long, int, ArrowArray const*, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldFixedSizeList<long, long long>(ArrowArray const*, int, unsigned long, int, ArrowArray const*, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldFixedSizeList<unsigned long, double>(ArrowArray const*, int, unsigned long, int, ArrowArray const*, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldFixedSizeList<float, double>(ArrowArray const*, int, unsigned long, int, ArrowArray const*, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldFixedSizeList<double, double>(ArrowArray const*, int, unsigned long, int, ArrowArray const*, OGRFeature&)
3941
3942
/************************************************************************/
3943
/*                    FillFieldFixedSizeListString()                    */
3944
/************************************************************************/
3945
3946
template <typename StringOffsetType>
3947
inline static void FillFieldFixedSizeListString(
3948
    const struct ArrowArray *, int iOGRFieldIdx, size_t nOffsettedIndex,
3949
    const int nItems, const struct ArrowArray *childArray, OGRFeature &oFeature)
3950
0
{
3951
0
    CPLStringList aosVals;
3952
0
    const auto panSubOffsets =
3953
0
        static_cast<const StringOffsetType *>(childArray->buffers[1]) +
3954
0
        childArray->offset + nOffsettedIndex * nItems;
3955
0
    const char *pszValues = static_cast<const char *>(childArray->buffers[2]);
3956
0
    std::string osTmp;
3957
0
    for (int i = 0; i < nItems; ++i)
3958
0
    {
3959
0
        osTmp.assign(
3960
0
            pszValues + panSubOffsets[i],
3961
0
            static_cast<size_t>(panSubOffsets[i + 1] - panSubOffsets[i]));
3962
0
        aosVals.AddString(osTmp.c_str());
3963
0
    }
3964
0
    oFeature.SetField(iOGRFieldIdx, aosVals.List());
3965
0
}
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldFixedSizeListString<unsigned int>(ArrowArray const*, int, unsigned long, int, ArrowArray const*, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldFixedSizeListString<unsigned long>(ArrowArray const*, int, unsigned long, int, ArrowArray const*, OGRFeature&)
3966
3967
/************************************************************************/
3968
/*                              GetValue()                              */
3969
/************************************************************************/
3970
3971
template <typename ArrowType>
3972
inline static ArrowType GetValue(const struct ArrowArray *array,
3973
                                 size_t iFeature)
3974
0
{
3975
0
    const auto *panValues = static_cast<const ArrowType *>(array->buffers[1]);
3976
0
    return panValues[iFeature + array->offset];
3977
0
}
Unexecuted instantiation: ogrlayerarrow.cpp:unsigned char GetValue<unsigned char>(ArrowArray const*, unsigned long)
Unexecuted instantiation: ogrlayerarrow.cpp:signed char GetValue<signed char>(ArrowArray const*, unsigned long)
Unexecuted instantiation: ogrlayerarrow.cpp:unsigned short GetValue<unsigned short>(ArrowArray const*, unsigned long)
Unexecuted instantiation: ogrlayerarrow.cpp:short GetValue<short>(ArrowArray const*, unsigned long)
Unexecuted instantiation: ogrlayerarrow.cpp:unsigned int GetValue<unsigned int>(ArrowArray const*, unsigned long)
Unexecuted instantiation: ogrlayerarrow.cpp:int GetValue<int>(ArrowArray const*, unsigned long)
Unexecuted instantiation: ogrlayerarrow.cpp:unsigned long GetValue<unsigned long>(ArrowArray const*, unsigned long)
Unexecuted instantiation: ogrlayerarrow.cpp:long GetValue<long>(ArrowArray const*, unsigned long)
Unexecuted instantiation: ogrlayerarrow.cpp:float GetValue<float>(ArrowArray const*, unsigned long)
Unexecuted instantiation: ogrlayerarrow.cpp:double GetValue<double>(ArrowArray const*, unsigned long)
3978
3979
template <> bool GetValue<bool>(const struct ArrowArray *array, size_t iFeature)
3980
0
{
3981
0
    const auto *pabyValues = static_cast<const uint8_t *>(array->buffers[1]);
3982
0
    return TestBit(pabyValues, iFeature + static_cast<size_t>(array->offset));
3983
0
}
3984
3985
/************************************************************************/
3986
/*                          GetValueFloat16()                           */
3987
/************************************************************************/
3988
3989
static float GetValueFloat16(const struct ArrowArray *array, const size_t nIdx)
3990
0
{
3991
0
    const auto *panValues = static_cast<const uint16_t *>(array->buffers[1]);
3992
0
    const auto nFloat16AsUInt32 =
3993
0
        CPLHalfToFloat(panValues[nIdx + array->offset]);
3994
0
    float f;
3995
0
    memcpy(&f, &nFloat16AsUInt32, sizeof(f));
3996
0
    return f;
3997
0
}
3998
3999
/************************************************************************/
4000
/*                          GetValueDecimal()                           */
4001
/************************************************************************/
4002
4003
static double GetValueDecimal(const struct ArrowArray *array,
4004
                              const int nWidthIn64BitWord, const int nScale,
4005
                              const size_t nIdx)
4006
0
{
4007
0
#ifdef CPL_LSB
4008
0
    const auto nIdxIn64BitWord = nIdx * nWidthIn64BitWord;
4009
#else
4010
    const auto nIdxIn64BitWord =
4011
        nIdx * nWidthIn64BitWord + nWidthIn64BitWord - 1;
4012
#endif
4013
0
    const auto *panValues = static_cast<const int64_t *>(array->buffers[1]);
4014
0
    const auto nVal =
4015
0
        panValues[nIdxIn64BitWord + array->offset * nWidthIn64BitWord];
4016
0
    return static_cast<double>(nVal) * std::pow(10.0, -nScale);
4017
0
}
4018
4019
/************************************************************************/
4020
/*                             GetString()                              */
4021
/************************************************************************/
4022
4023
template <class OffsetType>
4024
static std::string GetString(const struct ArrowArray *array, const size_t nIdx)
4025
0
{
4026
0
    const OffsetType *panOffsets =
4027
0
        static_cast<const OffsetType *>(array->buffers[1]) +
4028
0
        static_cast<size_t>(array->offset) + nIdx;
4029
0
    const char *pabyStr = static_cast<const char *>(array->buffers[2]);
4030
0
    std::string osStr;
4031
0
    osStr.assign(pabyStr + static_cast<size_t>(panOffsets[0]),
4032
0
                 static_cast<size_t>(panOffsets[1] - panOffsets[0]));
4033
0
    return osStr;
4034
0
}
Unexecuted instantiation: ogrlayerarrow.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > GetString<unsigned int>(ArrowArray const*, unsigned long)
Unexecuted instantiation: ogrlayerarrow.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > GetString<unsigned long>(ArrowArray const*, unsigned long)
4035
4036
/************************************************************************/
4037
/*                       GetBinaryAsBase64()                            */
4038
/************************************************************************/
4039
4040
template <class OffsetType>
4041
static std::string GetBinaryAsBase64(const struct ArrowArray *array,
4042
                                     const size_t nIdx)
4043
0
{
4044
0
    const OffsetType *panOffsets =
4045
0
        static_cast<const OffsetType *>(array->buffers[1]) +
4046
0
        static_cast<size_t>(array->offset) + nIdx;
4047
0
    const GByte *pabyData = static_cast<const GByte *>(array->buffers[2]);
4048
0
    const size_t nLen = static_cast<size_t>(panOffsets[1] - panOffsets[0]);
4049
0
    if (nLen > static_cast<size_t>(std::numeric_limits<int>::max()))
4050
0
    {
4051
0
        CPLError(CE_Failure, CPLE_AppDefined, "Too large binary");
4052
0
        return std::string();
4053
0
    }
4054
0
    char *pszVal = CPLBase64Encode(
4055
0
        static_cast<int>(nLen), pabyData + static_cast<size_t>(panOffsets[0]));
4056
0
    std::string osStr(pszVal);
4057
0
    CPLFree(pszVal);
4058
0
    return osStr;
4059
0
}
Unexecuted instantiation: ogrlayerarrow.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > GetBinaryAsBase64<unsigned int>(ArrowArray const*, unsigned long)
Unexecuted instantiation: ogrlayerarrow.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > GetBinaryAsBase64<unsigned long>(ArrowArray const*, unsigned long)
4060
4061
/************************************************************************/
4062
/*                   GetValueFixedWithBinaryAsBase64()                  */
4063
/************************************************************************/
4064
4065
static std::string
4066
GetValueFixedWithBinaryAsBase64(const struct ArrowArray *array,
4067
                                const int nWidth, const size_t nIdx)
4068
0
{
4069
0
    const GByte *pabyData = static_cast<const GByte *>(array->buffers[1]);
4070
0
    char *pszVal = CPLBase64Encode(
4071
0
        nWidth,
4072
0
        pabyData + (static_cast<size_t>(array->offset) + nIdx) * nWidth);
4073
0
    std::string osStr(pszVal);
4074
0
    CPLFree(pszVal);
4075
0
    return osStr;
4076
0
}
4077
4078
static CPLJSONObject GetObjectAsJSON(const struct ArrowSchema *schema,
4079
                                     const struct ArrowArray *array,
4080
                                     const size_t nIdx);
4081
4082
/************************************************************************/
4083
/*                               AddToArray()                           */
4084
/************************************************************************/
4085
4086
static void AddToArray(CPLJSONArray &oArray, const struct ArrowSchema *schema,
4087
                       const struct ArrowArray *array, const size_t nIdx)
4088
0
{
4089
0
    if (IsBoolean(schema->format))
4090
0
        oArray.Add(GetValue<bool>(array, nIdx));
4091
0
    else if (IsUInt8(schema->format))
4092
0
        oArray.Add(GetValue<uint8_t>(array, nIdx));
4093
0
    else if (IsInt8(schema->format))
4094
0
        oArray.Add(GetValue<int8_t>(array, nIdx));
4095
0
    else if (IsUInt16(schema->format))
4096
0
        oArray.Add(GetValue<uint16_t>(array, nIdx));
4097
0
    else if (IsInt16(schema->format))
4098
0
        oArray.Add(GetValue<int16_t>(array, nIdx));
4099
0
    else if (IsUInt32(schema->format))
4100
0
        oArray.Add(static_cast<GIntBig>(GetValue<uint32_t>(array, nIdx)));
4101
0
    else if (IsInt32(schema->format))
4102
0
        oArray.Add(GetValue<int32_t>(array, nIdx));
4103
0
    else if (IsUInt64(schema->format))
4104
0
        oArray.Add(GetValue<uint64_t>(array, nIdx));
4105
0
    else if (IsInt64(schema->format))
4106
0
        oArray.Add(static_cast<GIntBig>(GetValue<int64_t>(array, nIdx)));
4107
0
    else if (IsFloat16(schema->format))
4108
0
        oArray.Add(GetValueFloat16(array, nIdx));
4109
0
    else if (IsFloat32(schema->format))
4110
0
        oArray.Add(GetValue<float>(array, nIdx));
4111
0
    else if (IsFloat64(schema->format))
4112
0
        oArray.Add(GetValue<double>(array, nIdx));
4113
0
    else if (IsString(schema->format))
4114
0
        oArray.Add(GetString<uint32_t>(array, nIdx));
4115
0
    else if (IsLargeString(schema->format))
4116
0
        oArray.Add(GetString<uint64_t>(array, nIdx));
4117
0
    else if (IsBinary(schema->format))
4118
0
        oArray.Add(GetBinaryAsBase64<uint32_t>(array, nIdx));
4119
0
    else if (IsLargeBinary(schema->format))
4120
0
        oArray.Add(GetBinaryAsBase64<uint64_t>(array, nIdx));
4121
0
    else if (IsFixedWidthBinary(schema->format))
4122
0
        oArray.Add(GetValueFixedWithBinaryAsBase64(
4123
0
            array, GetFixedWithBinary(schema->format), nIdx));
4124
0
    else if (IsDecimal(schema->format))
4125
0
    {
4126
0
        int nPrecision = 0;
4127
0
        int nScale = 0;
4128
0
        int nWidthInBytes = 0;
4129
0
        const bool bOK = ParseDecimalFormat(schema->format, nPrecision, nScale,
4130
0
                                            nWidthInBytes);
4131
        // Already validated
4132
0
        CPLAssert(bOK);
4133
0
        CPL_IGNORE_RET_VAL(bOK);
4134
0
        oArray.Add(GetValueDecimal(array, nWidthInBytes / 8, nScale, nIdx));
4135
0
    }
4136
0
    else
4137
0
        oArray.Add(GetObjectAsJSON(schema, array, nIdx));
4138
0
}
4139
4140
/************************************************************************/
4141
/*                         GetListAsJSON()                              */
4142
/************************************************************************/
4143
4144
template <class OffsetType>
4145
static CPLJSONArray GetListAsJSON(const struct ArrowSchema *schema,
4146
                                  const struct ArrowArray *array,
4147
                                  const size_t nIdx)
4148
0
{
4149
0
    CPLJSONArray oArray;
4150
0
    const auto panOffsets = static_cast<const OffsetType *>(array->buffers[1]) +
4151
0
                            array->offset + nIdx;
4152
0
    const auto childSchema = schema->children[0];
4153
0
    const auto childArray = array->children[0];
4154
0
    const uint8_t *pabyValidity =
4155
0
        childArray->null_count == 0
4156
0
            ? nullptr
4157
0
            : static_cast<const uint8_t *>(childArray->buffers[0]);
4158
0
    for (size_t k = static_cast<size_t>(panOffsets[0]);
4159
0
         k < static_cast<size_t>(panOffsets[1]); k++)
4160
0
    {
4161
0
        if (!pabyValidity ||
4162
0
            TestBit(pabyValidity, k + static_cast<size_t>(childArray->offset)))
4163
0
        {
4164
0
            AddToArray(oArray, childSchema, childArray, k);
4165
0
        }
4166
0
        else
4167
0
        {
4168
0
            oArray.AddNull();
4169
0
        }
4170
0
    }
4171
0
    return oArray;
4172
0
}
Unexecuted instantiation: ogrlayerarrow.cpp:CPLJSONArray GetListAsJSON<unsigned int>(ArrowSchema const*, ArrowArray const*, unsigned long)
Unexecuted instantiation: ogrlayerarrow.cpp:CPLJSONArray GetListAsJSON<unsigned long>(ArrowSchema const*, ArrowArray const*, unsigned long)
4173
4174
/************************************************************************/
4175
/*                     GetFixedSizeListAsJSON()                         */
4176
/************************************************************************/
4177
4178
static CPLJSONArray GetFixedSizeListAsJSON(const struct ArrowSchema *schema,
4179
                                           const struct ArrowArray *array,
4180
                                           const size_t nIdx)
4181
0
{
4182
0
    CPLJSONArray oArray;
4183
0
    const int nVals = GetFixedSizeList(schema->format);
4184
0
    const auto childSchema = schema->children[0];
4185
0
    const auto childArray = array->children[0];
4186
0
    const uint8_t *pabyValidity =
4187
0
        childArray->null_count == 0
4188
0
            ? nullptr
4189
0
            : static_cast<const uint8_t *>(childArray->buffers[0]);
4190
0
    for (size_t k = nIdx * nVals; k < (nIdx + 1) * nVals; k++)
4191
0
    {
4192
0
        if (!pabyValidity ||
4193
0
            TestBit(pabyValidity, k + static_cast<size_t>(childArray->offset)))
4194
0
        {
4195
0
            AddToArray(oArray, childSchema, childArray, k);
4196
0
        }
4197
0
        else
4198
0
        {
4199
0
            oArray.AddNull();
4200
0
        }
4201
0
    }
4202
0
    return oArray;
4203
0
}
4204
4205
/************************************************************************/
4206
/*                              AddToDict()                             */
4207
/************************************************************************/
4208
4209
static void AddToDict(CPLJSONObject &oDict, const std::string &osKey,
4210
                      const struct ArrowSchema *schema,
4211
                      const struct ArrowArray *array, const size_t nIdx)
4212
0
{
4213
0
    if (IsBoolean(schema->format))
4214
0
        oDict.Add(osKey, GetValue<bool>(array, nIdx));
4215
0
    else if (IsUInt8(schema->format))
4216
0
        oDict.Add(osKey, GetValue<uint8_t>(array, nIdx));
4217
0
    else if (IsInt8(schema->format))
4218
0
        oDict.Add(osKey, GetValue<int8_t>(array, nIdx));
4219
0
    else if (IsUInt16(schema->format))
4220
0
        oDict.Add(osKey, GetValue<uint16_t>(array, nIdx));
4221
0
    else if (IsInt16(schema->format))
4222
0
        oDict.Add(osKey, GetValue<int16_t>(array, nIdx));
4223
0
    else if (IsUInt32(schema->format))
4224
0
        oDict.Add(osKey, static_cast<GIntBig>(GetValue<uint32_t>(array, nIdx)));
4225
0
    else if (IsInt32(schema->format))
4226
0
        oDict.Add(osKey, GetValue<int32_t>(array, nIdx));
4227
0
    else if (IsUInt64(schema->format))
4228
0
        oDict.Add(osKey, GetValue<uint64_t>(array, nIdx));
4229
0
    else if (IsInt64(schema->format))
4230
0
        oDict.Add(osKey, static_cast<GIntBig>(GetValue<int64_t>(array, nIdx)));
4231
0
    else if (IsFloat16(schema->format))
4232
0
        oDict.Add(osKey, GetValueFloat16(array, nIdx));
4233
0
    else if (IsFloat32(schema->format))
4234
0
        oDict.Add(osKey, GetValue<float>(array, nIdx));
4235
0
    else if (IsFloat64(schema->format))
4236
0
        oDict.Add(osKey, GetValue<double>(array, nIdx));
4237
0
    else if (IsString(schema->format))
4238
0
        oDict.Add(osKey, GetString<uint32_t>(array, nIdx));
4239
0
    else if (IsLargeString(schema->format))
4240
0
        oDict.Add(osKey, GetString<uint64_t>(array, nIdx));
4241
0
    else if (IsBinary(schema->format))
4242
0
        oDict.Add(osKey, GetBinaryAsBase64<uint32_t>(array, nIdx));
4243
0
    else if (IsLargeBinary(schema->format))
4244
0
        oDict.Add(osKey, GetBinaryAsBase64<uint64_t>(array, nIdx));
4245
0
    else if (IsFixedWidthBinary(schema->format))
4246
0
        oDict.Add(osKey, GetValueFixedWithBinaryAsBase64(
4247
0
                             array, GetFixedWithBinary(schema->format), nIdx));
4248
0
    else if (IsDecimal(schema->format))
4249
0
    {
4250
0
        int nPrecision = 0;
4251
0
        int nScale = 0;
4252
0
        int nWidthInBytes = 0;
4253
0
        const bool bOK = ParseDecimalFormat(schema->format, nPrecision, nScale,
4254
0
                                            nWidthInBytes);
4255
        // Already validated
4256
0
        CPLAssert(bOK);
4257
0
        CPL_IGNORE_RET_VAL(bOK);
4258
0
        oDict.Add(osKey,
4259
0
                  GetValueDecimal(array, nWidthInBytes / 8, nScale, nIdx));
4260
0
    }
4261
0
    else
4262
0
        oDict.Add(osKey, GetObjectAsJSON(schema, array, nIdx));
4263
0
}
4264
4265
/************************************************************************/
4266
/*                         GetMapAsJSON()                               */
4267
/************************************************************************/
4268
4269
static CPLJSONObject GetMapAsJSON(const struct ArrowSchema *schema,
4270
                                  const struct ArrowArray *array,
4271
                                  const size_t nIdx)
4272
0
{
4273
0
    const auto schemaStruct = schema->children[0];
4274
0
    if (!IsStructure(schemaStruct->format))
4275
0
    {
4276
0
        CPLError(CE_Failure, CPLE_AppDefined,
4277
0
                 "GetMapAsJSON(): !IsStructure(schemaStruct->format))");
4278
0
        return CPLJSONObject();
4279
0
    }
4280
0
    const auto schemaKey = schemaStruct->children[0];
4281
0
    const auto schemaValues = schemaStruct->children[1];
4282
0
    if (!IsString(schemaKey->format))
4283
0
    {
4284
0
        CPLError(CE_Failure, CPLE_AppDefined,
4285
0
                 "GetMapAsJSON(): !IsString(schemaKey->format))");
4286
0
        return CPLJSONObject();
4287
0
    }
4288
0
    const auto arrayKeys = array->children[0]->children[0];
4289
0
    const auto arrayValues = array->children[0]->children[1];
4290
4291
0
    CPLJSONObject oDict;
4292
0
    const auto panOffsets =
4293
0
        static_cast<const uint32_t *>(array->buffers[1]) + array->offset + nIdx;
4294
0
    const uint8_t *pabyValidityKeys =
4295
0
        arrayKeys->null_count == 0
4296
0
            ? nullptr
4297
0
            : static_cast<const uint8_t *>(arrayKeys->buffers[0]);
4298
0
    const uint32_t *panOffsetsKeys =
4299
0
        static_cast<const uint32_t *>(arrayKeys->buffers[1]) +
4300
0
        arrayKeys->offset;
4301
0
    const char *pabyKeys = static_cast<const char *>(arrayKeys->buffers[2]);
4302
0
    const uint8_t *pabyValidityValues =
4303
0
        arrayValues->null_count == 0
4304
0
            ? nullptr
4305
0
            : static_cast<const uint8_t *>(arrayValues->buffers[0]);
4306
0
    for (uint32_t k = panOffsets[0]; k < panOffsets[1]; k++)
4307
0
    {
4308
0
        if (!pabyValidityKeys ||
4309
0
            TestBit(pabyValidityKeys,
4310
0
                    k + static_cast<size_t>(arrayKeys->offset)))
4311
0
        {
4312
0
            std::string osKey;
4313
0
            osKey.assign(pabyKeys + panOffsetsKeys[k],
4314
0
                         panOffsetsKeys[k + 1] - panOffsetsKeys[k]);
4315
4316
0
            if (!pabyValidityValues ||
4317
0
                TestBit(pabyValidityValues,
4318
0
                        k + static_cast<size_t>(arrayValues->offset)))
4319
0
            {
4320
0
                AddToDict(oDict, osKey, schemaValues, arrayValues, k);
4321
0
            }
4322
0
            else
4323
0
            {
4324
0
                oDict.AddNull(osKey);
4325
0
            }
4326
0
        }
4327
0
    }
4328
0
    return oDict;
4329
0
}
4330
4331
/************************************************************************/
4332
/*                        GetStructureAsJSON()                          */
4333
/************************************************************************/
4334
4335
static CPLJSONObject GetStructureAsJSON(const struct ArrowSchema *schema,
4336
                                        const struct ArrowArray *array,
4337
                                        const size_t nIdx)
4338
0
{
4339
0
    CPLJSONObject oDict;
4340
0
    for (int64_t k = 0; k < array->n_children; k++)
4341
0
    {
4342
0
        const uint8_t *pabyValidityValues =
4343
0
            array->children[k]->null_count == 0
4344
0
                ? nullptr
4345
0
                : static_cast<const uint8_t *>(array->children[k]->buffers[0]);
4346
0
        if (!pabyValidityValues ||
4347
0
            TestBit(pabyValidityValues,
4348
0
                    nIdx + static_cast<size_t>(array->children[k]->offset)))
4349
0
        {
4350
0
            AddToDict(oDict, schema->children[k]->name, schema->children[k],
4351
0
                      array->children[k], nIdx);
4352
0
        }
4353
0
        else
4354
0
        {
4355
0
            oDict.AddNull(schema->children[k]->name);
4356
0
        }
4357
0
    }
4358
0
    return oDict;
4359
0
}
4360
4361
/************************************************************************/
4362
/*                        GetObjectAsJSON()                             */
4363
/************************************************************************/
4364
4365
static CPLJSONObject GetObjectAsJSON(const struct ArrowSchema *schema,
4366
                                     const struct ArrowArray *array,
4367
                                     const size_t nIdx)
4368
0
{
4369
0
    if (IsMap(schema->format))
4370
0
        return GetMapAsJSON(schema, array, nIdx);
4371
0
    else if (IsList(schema->format))
4372
0
        return GetListAsJSON<uint32_t>(schema, array, nIdx);
4373
0
    else if (IsLargeList(schema->format))
4374
0
        return GetListAsJSON<uint64_t>(schema, array, nIdx);
4375
0
    else if (IsFixedSizeList(schema->format))
4376
0
        return GetFixedSizeListAsJSON(schema, array, nIdx);
4377
0
    else if (IsStructure(schema->format))
4378
0
        return GetStructureAsJSON(schema, array, nIdx);
4379
0
    else
4380
0
    {
4381
0
        CPLError(CE_Failure, CPLE_AppDefined,
4382
0
                 "GetObjectAsJSON(): unhandled value format: %s",
4383
0
                 schema->format);
4384
0
        return CPLJSONObject();
4385
0
    }
4386
0
}
4387
4388
/************************************************************************/
4389
/*                      SetFieldForOtherFormats()                       */
4390
/************************************************************************/
4391
4392
static bool SetFieldForOtherFormats(OGRFeature &oFeature,
4393
                                    const int iOGRFieldIndex,
4394
                                    const size_t nOffsettedIndex,
4395
                                    const struct ArrowSchema *schema,
4396
                                    const struct ArrowArray *array)
4397
0
{
4398
0
    const char *format = schema->format;
4399
0
    if (IsFloat16(format))
4400
0
    {
4401
0
        oFeature.SetField(
4402
0
            iOGRFieldIndex,
4403
0
            GetValueFloat16(array, nOffsettedIndex -
4404
0
                                       static_cast<size_t>(array->offset)));
4405
0
    }
4406
4407
0
    else if (IsFixedWidthBinary(format))
4408
0
    {
4409
        // Fixed width binary
4410
0
        const int nWidth = GetFixedWithBinary(format);
4411
0
        oFeature.SetField(iOGRFieldIndex, nWidth,
4412
0
                          static_cast<const GByte *>(array->buffers[1]) +
4413
0
                              nOffsettedIndex * nWidth);
4414
0
    }
4415
0
    else if (format[0] == 't' && format[1] == 'd' &&
4416
0
             format[2] == 'D')  // strcmp(format, "tdD") == 0
4417
0
    {
4418
        // date32[days]
4419
        // number of days since Epoch
4420
0
        int64_t timestamp = static_cast<int64_t>(static_cast<const int32_t *>(
4421
0
                                array->buffers[1])[nOffsettedIndex]) *
4422
0
                            3600 * 24;
4423
0
        struct tm dt;
4424
0
        CPLUnixTimeToYMDHMS(timestamp, &dt);
4425
0
        oFeature.SetField(iOGRFieldIndex, dt.tm_year + 1900, dt.tm_mon + 1,
4426
0
                          dt.tm_mday, 0, 0, 0);
4427
0
        return true;
4428
0
    }
4429
0
    else if (format[0] == 't' && format[1] == 'd' &&
4430
0
             format[2] == 'm')  // strcmp(format, "tdm") == 0
4431
0
    {
4432
        // date64[milliseconds]
4433
        // number of milliseconds since Epoch
4434
0
        int64_t timestamp =
4435
0
            static_cast<const int64_t *>(array->buffers[1])[nOffsettedIndex] /
4436
0
            1000;
4437
0
        struct tm dt;
4438
0
        CPLUnixTimeToYMDHMS(timestamp, &dt);
4439
0
        oFeature.SetField(iOGRFieldIndex, dt.tm_year + 1900, dt.tm_mon + 1,
4440
0
                          dt.tm_mday, 0, 0, 0);
4441
0
    }
4442
0
    else if (format[0] == 't' && format[1] == 't' &&
4443
0
             format[2] == 's')  // strcmp(format, "tts") == 0
4444
0
    {
4445
        // time32 [seconds]
4446
0
        int32_t value =
4447
0
            static_cast<const int32_t *>(array->buffers[1])[nOffsettedIndex];
4448
0
        const int nHour = value / 3600;
4449
0
        const int nMinute = (value / 60) % 60;
4450
0
        const int nSecond = value % 60;
4451
0
        oFeature.SetField(iOGRFieldIndex, 0, 0, 0, nHour, nMinute,
4452
0
                          static_cast<float>(nSecond));
4453
0
    }
4454
0
    else if (format[0] == 't' && format[1] == 't' &&
4455
0
             format[2] == 'm')  // strcmp(format, "ttm") == 0
4456
0
    {
4457
        // time32 [milliseconds]
4458
0
        int32_t value =
4459
0
            static_cast<const int32_t *>(array->buffers[1])[nOffsettedIndex];
4460
0
        double floatingPart = (value % 1000) / 1e3;
4461
0
        value /= 1000;
4462
0
        const int nHour = value / 3600;
4463
0
        const int nMinute = (value / 60) % 60;
4464
0
        const int nSecond = value % 60;
4465
0
        oFeature.SetField(iOGRFieldIndex, 0, 0, 0, nHour, nMinute,
4466
0
                          static_cast<float>(nSecond + floatingPart));
4467
0
    }
4468
0
    else if (format[0] == 't' && format[1] == 't' &&
4469
0
             (format[2] == 'u' ||  // time64 [microseconds]
4470
0
              format[2] == 'n'))   // time64 [nanoseconds]
4471
0
    {
4472
0
        oFeature.SetField(iOGRFieldIndex,
4473
0
                          static_cast<GIntBig>(static_cast<const int64_t *>(
4474
0
                              array->buffers[1])[nOffsettedIndex]));
4475
0
    }
4476
0
    else if (IsTimestampSeconds(format))
4477
0
    {
4478
0
        ArrowTimestampToOGRDateTime(
4479
0
            static_cast<const int64_t *>(array->buffers[1])[nOffsettedIndex], 1,
4480
0
            GetTimestampTimezone(format), oFeature, iOGRFieldIndex);
4481
0
    }
4482
0
    else if (IsTimestampMilliseconds(format))
4483
0
    {
4484
0
        ArrowTimestampToOGRDateTime(
4485
0
            static_cast<const int64_t *>(array->buffers[1])[nOffsettedIndex],
4486
0
            1000, GetTimestampTimezone(format), oFeature, iOGRFieldIndex);
4487
0
    }
4488
0
    else if (IsTimestampMicroseconds(format))
4489
0
    {
4490
0
        ArrowTimestampToOGRDateTime(
4491
0
            static_cast<const int64_t *>(array->buffers[1])[nOffsettedIndex],
4492
0
            1000 * 1000, GetTimestampTimezone(format), oFeature,
4493
0
            iOGRFieldIndex);
4494
0
    }
4495
0
    else if (IsTimestampNanoseconds(format))
4496
0
    {
4497
0
        ArrowTimestampToOGRDateTime(
4498
0
            static_cast<const int64_t *>(array->buffers[1])[nOffsettedIndex],
4499
0
            1000 * 1000 * 1000, GetTimestampTimezone(format), oFeature,
4500
0
            iOGRFieldIndex);
4501
0
    }
4502
0
    else if (IsFixedSizeList(format))
4503
0
    {
4504
0
        const int nItems = GetFixedSizeList(format);
4505
0
        const auto childArray = array->children[0];
4506
0
        const char *childFormat = schema->children[0]->format;
4507
0
        if (IsBoolean(childFormat))
4508
0
        {
4509
0
            std::vector<int> aValues;
4510
0
            const auto *paValues =
4511
0
                static_cast<const uint8_t *>(childArray->buffers[1]);
4512
0
            for (int i = 0; i < nItems; ++i)
4513
0
            {
4514
0
                aValues.push_back(
4515
0
                    TestBit(paValues,
4516
0
                            static_cast<size_t>(childArray->offset +
4517
0
                                                nOffsettedIndex * nItems + i))
4518
0
                        ? 1
4519
0
                        : 0);
4520
0
            }
4521
0
            oFeature.SetField(iOGRFieldIndex, static_cast<int>(aValues.size()),
4522
0
                              aValues.data());
4523
0
        }
4524
0
        else if (IsInt8(childFormat))
4525
0
        {
4526
0
            FillFieldFixedSizeList<int8_t, int>(array, iOGRFieldIndex,
4527
0
                                                nOffsettedIndex, nItems,
4528
0
                                                childArray, oFeature);
4529
0
        }
4530
0
        else if (IsUInt8(childFormat))
4531
0
        {
4532
0
            FillFieldFixedSizeList<uint8_t, int>(array, iOGRFieldIndex,
4533
0
                                                 nOffsettedIndex, nItems,
4534
0
                                                 childArray, oFeature);
4535
0
        }
4536
0
        else if (IsInt16(childFormat))
4537
0
        {
4538
0
            FillFieldFixedSizeList<int16_t, int>(array, iOGRFieldIndex,
4539
0
                                                 nOffsettedIndex, nItems,
4540
0
                                                 childArray, oFeature);
4541
0
        }
4542
0
        else if (IsUInt16(childFormat))
4543
0
        {
4544
0
            FillFieldFixedSizeList<uint16_t, int>(array, iOGRFieldIndex,
4545
0
                                                  nOffsettedIndex, nItems,
4546
0
                                                  childArray, oFeature);
4547
0
        }
4548
0
        else if (IsInt32(childFormat))
4549
0
        {
4550
0
            FillFieldFixedSizeList<int32_t, int>(array, iOGRFieldIndex,
4551
0
                                                 nOffsettedIndex, nItems,
4552
0
                                                 childArray, oFeature);
4553
0
        }
4554
0
        else if (IsUInt32(childFormat))
4555
0
        {
4556
0
            FillFieldFixedSizeList<uint32_t, GIntBig>(array, iOGRFieldIndex,
4557
0
                                                      nOffsettedIndex, nItems,
4558
0
                                                      childArray, oFeature);
4559
0
        }
4560
0
        else if (IsInt64(childFormat))
4561
0
        {
4562
0
            FillFieldFixedSizeList<int64_t, GIntBig>(array, iOGRFieldIndex,
4563
0
                                                     nOffsettedIndex, nItems,
4564
0
                                                     childArray, oFeature);
4565
0
        }
4566
0
        else if (IsUInt64(childFormat))
4567
0
        {
4568
0
            FillFieldFixedSizeList<uint64_t, double>(array, iOGRFieldIndex,
4569
0
                                                     nOffsettedIndex, nItems,
4570
0
                                                     childArray, oFeature);
4571
0
        }
4572
0
        else if (IsFloat16(childFormat))
4573
0
        {
4574
0
            std::vector<double> aValues;
4575
0
            for (int i = 0; i < nItems; ++i)
4576
0
            {
4577
0
                aValues.push_back(
4578
0
                    GetValueFloat16(childArray, nOffsettedIndex * nItems + i));
4579
0
            }
4580
0
            oFeature.SetField(iOGRFieldIndex, static_cast<int>(aValues.size()),
4581
0
                              aValues.data());
4582
0
        }
4583
0
        else if (IsFloat32(childFormat))
4584
0
        {
4585
0
            FillFieldFixedSizeList<float, double>(array, iOGRFieldIndex,
4586
0
                                                  nOffsettedIndex, nItems,
4587
0
                                                  childArray, oFeature);
4588
0
        }
4589
0
        else if (IsFloat64(childFormat))
4590
0
        {
4591
0
            FillFieldFixedSizeList<double, double>(array, iOGRFieldIndex,
4592
0
                                                   nOffsettedIndex, nItems,
4593
0
                                                   childArray, oFeature);
4594
0
        }
4595
0
        else if (IsString(childFormat))
4596
0
        {
4597
0
            FillFieldFixedSizeListString<uint32_t>(array, iOGRFieldIndex,
4598
0
                                                   nOffsettedIndex, nItems,
4599
0
                                                   childArray, oFeature);
4600
0
        }
4601
0
        else if (IsLargeString(childFormat))
4602
0
        {
4603
0
            FillFieldFixedSizeListString<uint64_t>(array, iOGRFieldIndex,
4604
0
                                                   nOffsettedIndex, nItems,
4605
0
                                                   childArray, oFeature);
4606
0
        }
4607
0
    }
4608
0
    else if (IsList(format) || IsLargeList(format))
4609
0
    {
4610
0
        const auto childArray = array->children[0];
4611
0
        const char *childFormat = schema->children[0]->format;
4612
0
        if (IsBoolean(childFormat))
4613
0
        {
4614
0
            if (format[1] == ARROW_2ND_LETTER_LIST)
4615
0
                FillFieldListFromBool<uint32_t>(array, iOGRFieldIndex,
4616
0
                                                nOffsettedIndex, childArray,
4617
0
                                                oFeature);
4618
0
            else
4619
0
                FillFieldListFromBool<uint64_t>(array, iOGRFieldIndex,
4620
0
                                                nOffsettedIndex, childArray,
4621
0
                                                oFeature);
4622
0
        }
4623
0
        else if (IsInt8(childFormat))
4624
0
        {
4625
0
            if (format[1] == ARROW_2ND_LETTER_LIST)
4626
0
                FillFieldList<uint32_t, int8_t, int>(array, iOGRFieldIndex,
4627
0
                                                     nOffsettedIndex,
4628
0
                                                     childArray, oFeature);
4629
0
            else
4630
0
                FillFieldList<uint64_t, int8_t, int>(array, iOGRFieldIndex,
4631
0
                                                     nOffsettedIndex,
4632
0
                                                     childArray, oFeature);
4633
0
        }
4634
0
        else if (IsUInt8(childFormat))
4635
0
        {
4636
0
            if (format[1] == ARROW_2ND_LETTER_LIST)
4637
0
                FillFieldList<uint32_t, uint8_t, int>(array, iOGRFieldIndex,
4638
0
                                                      nOffsettedIndex,
4639
0
                                                      childArray, oFeature);
4640
0
            else
4641
0
                FillFieldList<uint64_t, uint8_t, int>(array, iOGRFieldIndex,
4642
0
                                                      nOffsettedIndex,
4643
0
                                                      childArray, oFeature);
4644
0
        }
4645
0
        else if (IsInt16(childFormat))
4646
0
        {
4647
0
            if (format[1] == ARROW_2ND_LETTER_LIST)
4648
0
                FillFieldList<uint32_t, int16_t, int>(array, iOGRFieldIndex,
4649
0
                                                      nOffsettedIndex,
4650
0
                                                      childArray, oFeature);
4651
0
            else
4652
0
                FillFieldList<uint64_t, int16_t, int>(array, iOGRFieldIndex,
4653
0
                                                      nOffsettedIndex,
4654
0
                                                      childArray, oFeature);
4655
0
        }
4656
0
        else if (IsUInt16(childFormat))
4657
0
        {
4658
0
            if (format[1] == ARROW_2ND_LETTER_LIST)
4659
0
                FillFieldList<uint32_t, uint16_t, int>(array, iOGRFieldIndex,
4660
0
                                                       nOffsettedIndex,
4661
0
                                                       childArray, oFeature);
4662
0
            else
4663
0
                FillFieldList<uint64_t, uint16_t, int>(array, iOGRFieldIndex,
4664
0
                                                       nOffsettedIndex,
4665
0
                                                       childArray, oFeature);
4666
0
        }
4667
0
        else if (IsInt32(childFormat))
4668
0
        {
4669
0
            if (format[1] == ARROW_2ND_LETTER_LIST)
4670
0
                FillFieldList<uint32_t, int32_t, int>(array, iOGRFieldIndex,
4671
0
                                                      nOffsettedIndex,
4672
0
                                                      childArray, oFeature);
4673
0
            else
4674
0
                FillFieldList<uint64_t, int32_t, int>(array, iOGRFieldIndex,
4675
0
                                                      nOffsettedIndex,
4676
0
                                                      childArray, oFeature);
4677
0
        }
4678
0
        else if (IsUInt32(childFormat))
4679
0
        {
4680
0
            if (format[1] == ARROW_2ND_LETTER_LIST)
4681
0
                FillFieldList<uint32_t, uint32_t, GIntBig>(
4682
0
                    array, iOGRFieldIndex, nOffsettedIndex, childArray,
4683
0
                    oFeature);
4684
0
            else
4685
0
                FillFieldList<uint64_t, uint32_t, GIntBig>(
4686
0
                    array, iOGRFieldIndex, nOffsettedIndex, childArray,
4687
0
                    oFeature);
4688
0
        }
4689
0
        else if (IsInt64(childFormat))
4690
0
        {
4691
0
            if (format[1] == ARROW_2ND_LETTER_LIST)
4692
0
                FillFieldList<uint32_t, int64_t, GIntBig>(array, iOGRFieldIndex,
4693
0
                                                          nOffsettedIndex,
4694
0
                                                          childArray, oFeature);
4695
0
            else
4696
0
                FillFieldList<uint64_t, int64_t, GIntBig>(array, iOGRFieldIndex,
4697
0
                                                          nOffsettedIndex,
4698
0
                                                          childArray, oFeature);
4699
0
        }
4700
0
        else if (IsUInt64(childFormat))  // (lossy conversion)
4701
0
        {
4702
0
            if (format[1] == ARROW_2ND_LETTER_LIST)
4703
0
                FillFieldList<uint32_t, uint64_t, double>(array, iOGRFieldIndex,
4704
0
                                                          nOffsettedIndex,
4705
0
                                                          childArray, oFeature);
4706
0
            else
4707
0
                FillFieldList<uint64_t, uint64_t, double>(array, iOGRFieldIndex,
4708
0
                                                          nOffsettedIndex,
4709
0
                                                          childArray, oFeature);
4710
0
        }
4711
0
        else if (IsFloat16(childFormat))
4712
0
        {
4713
0
            if (format[1] == ARROW_2ND_LETTER_LIST)
4714
0
                FillFieldListFromHalfFloat<uint32_t>(array, iOGRFieldIndex,
4715
0
                                                     nOffsettedIndex,
4716
0
                                                     childArray, oFeature);
4717
0
            else
4718
0
                FillFieldListFromHalfFloat<uint64_t>(array, iOGRFieldIndex,
4719
0
                                                     nOffsettedIndex,
4720
0
                                                     childArray, oFeature);
4721
0
        }
4722
0
        else if (IsFloat32(childFormat))
4723
0
        {
4724
0
            if (format[1] == ARROW_2ND_LETTER_LIST)
4725
0
                FillFieldList<uint32_t, float, double>(array, iOGRFieldIndex,
4726
0
                                                       nOffsettedIndex,
4727
0
                                                       childArray, oFeature);
4728
0
            else
4729
0
                FillFieldList<uint64_t, float, double>(array, iOGRFieldIndex,
4730
0
                                                       nOffsettedIndex,
4731
0
                                                       childArray, oFeature);
4732
0
        }
4733
0
        else if (IsFloat64(childFormat))
4734
0
        {
4735
0
            if (format[1] == ARROW_2ND_LETTER_LIST)
4736
0
                FillFieldList<uint32_t, double, double>(array, iOGRFieldIndex,
4737
0
                                                        nOffsettedIndex,
4738
0
                                                        childArray, oFeature);
4739
0
            else
4740
0
                FillFieldList<uint64_t, double, double>(array, iOGRFieldIndex,
4741
0
                                                        nOffsettedIndex,
4742
0
                                                        childArray, oFeature);
4743
0
        }
4744
0
        else if (IsString(childFormat))
4745
0
        {
4746
0
            if (format[1] == ARROW_2ND_LETTER_LIST)
4747
0
                FillFieldListFromString<uint32_t, uint32_t>(
4748
0
                    array, iOGRFieldIndex, nOffsettedIndex, childArray,
4749
0
                    oFeature);
4750
0
            else
4751
0
                FillFieldListFromString<uint64_t, uint32_t>(
4752
0
                    array, iOGRFieldIndex, nOffsettedIndex, childArray,
4753
0
                    oFeature);
4754
0
        }
4755
0
        else if (IsLargeString(childFormat))
4756
0
        {
4757
0
            if (format[1] == ARROW_2ND_LETTER_LIST)
4758
0
                FillFieldListFromString<uint32_t, uint64_t>(
4759
0
                    array, iOGRFieldIndex, nOffsettedIndex, childArray,
4760
0
                    oFeature);
4761
0
            else
4762
0
                FillFieldListFromString<uint64_t, uint64_t>(
4763
0
                    array, iOGRFieldIndex, nOffsettedIndex, childArray,
4764
0
                    oFeature);
4765
0
        }
4766
0
        else if (format[1] == ARROW_2ND_LETTER_LIST)
4767
0
        {
4768
0
            const size_t iFeature =
4769
0
                static_cast<size_t>(nOffsettedIndex - array->offset);
4770
0
            oFeature.SetField(iOGRFieldIndex,
4771
0
                              GetListAsJSON<uint32_t>(schema, array, iFeature)
4772
0
                                  .Format(CPLJSONObject::PrettyFormat::Plain)
4773
0
                                  .c_str());
4774
0
        }
4775
0
        else
4776
0
        {
4777
0
            const size_t iFeature =
4778
0
                static_cast<size_t>(nOffsettedIndex - array->offset);
4779
0
            oFeature.SetField(iOGRFieldIndex,
4780
0
                              GetListAsJSON<uint64_t>(schema, array, iFeature)
4781
0
                                  .Format(CPLJSONObject::PrettyFormat::Plain)
4782
0
                                  .c_str());
4783
0
        }
4784
0
    }
4785
0
    else if (IsDecimal(format))
4786
0
    {
4787
0
        int nPrecision = 0;
4788
0
        int nScale = 0;
4789
0
        int nWidthInBytes = 0;
4790
0
        if (!ParseDecimalFormat(format, nPrecision, nScale, nWidthInBytes))
4791
0
        {
4792
0
            CPLAssert(false);
4793
0
        }
4794
4795
        // fits on a int64
4796
0
        CPLAssert(nPrecision <= 19);
4797
        // either 128 or 256 bits
4798
0
        CPLAssert((nWidthInBytes % 8) == 0);
4799
0
        const int nWidthIn64BitWord = nWidthInBytes / 8;
4800
0
        const size_t iFeature =
4801
0
            static_cast<size_t>(nOffsettedIndex - array->offset);
4802
0
        oFeature.SetField(
4803
0
            iOGRFieldIndex,
4804
0
            GetValueDecimal(array, nWidthIn64BitWord, nScale, iFeature));
4805
0
        return true;
4806
0
    }
4807
0
    else if (IsMap(format))
4808
0
    {
4809
0
        const size_t iFeature =
4810
0
            static_cast<size_t>(nOffsettedIndex - array->offset);
4811
0
        oFeature.SetField(iOGRFieldIndex,
4812
0
                          GetMapAsJSON(schema, array, iFeature)
4813
0
                              .Format(CPLJSONObject::PrettyFormat::Plain)
4814
0
                              .c_str());
4815
0
    }
4816
0
    else
4817
0
    {
4818
0
        return false;
4819
0
    }
4820
4821
0
    return true;
4822
0
}
4823
4824
/************************************************************************/
4825
/*                 FillValidityArrayFromAttrQuery()                     */
4826
/************************************************************************/
4827
4828
static size_t FillValidityArrayFromAttrQuery(
4829
    const OGRLayer *poLayer, OGRFeatureQuery *poAttrQuery,
4830
    const struct ArrowSchema *schema, struct ArrowArray *array,
4831
    std::vector<bool> &abyValidityFromFilters, CSLConstList papszOptions)
4832
0
{
4833
0
    size_t nCountIntersecting = 0;
4834
0
    auto poFeatureDefn = const_cast<OGRLayer *>(poLayer)->GetLayerDefn();
4835
0
    OGRFeature oFeature(poFeatureDefn);
4836
4837
0
    std::map<std::string, std::vector<int>> oMapFieldNameToArrowPath;
4838
0
    std::vector<int> anArrowPathTmp;
4839
0
    BuildMapFieldNameToArrowPath(schema, oMapFieldNameToArrowPath,
4840
0
                                 std::string(), anArrowPathTmp);
4841
4842
0
    struct UsedFieldsInfo
4843
0
    {
4844
0
        int iOGRFieldIndex{};
4845
0
        std::vector<int> anArrowPath{};
4846
0
    };
4847
4848
0
    std::vector<UsedFieldsInfo> aoUsedFieldsInfo;
4849
4850
0
    bool bNeedsFID = false;
4851
0
    const CPLStringList aosUsedFields(poAttrQuery->GetUsedFields());
4852
0
    for (int i = 0; i < aosUsedFields.size(); ++i)
4853
0
    {
4854
0
        int iOGRFieldIndex = poFeatureDefn->GetFieldIndex(aosUsedFields[i]);
4855
0
        if (iOGRFieldIndex >= 0)
4856
0
        {
4857
0
            const auto oIter = oMapFieldNameToArrowPath.find(aosUsedFields[i]);
4858
0
            if (oIter != oMapFieldNameToArrowPath.end())
4859
0
            {
4860
0
                UsedFieldsInfo info;
4861
0
                info.iOGRFieldIndex = iOGRFieldIndex;
4862
0
                info.anArrowPath = oIter->second;
4863
0
                aoUsedFieldsInfo.push_back(std::move(info));
4864
0
            }
4865
0
            else
4866
0
            {
4867
0
                CPLError(CE_Failure, CPLE_AppDefined,
4868
0
                         "Cannot find %s in oMapFieldNameToArrowPath",
4869
0
                         aosUsedFields[i]);
4870
0
            }
4871
0
        }
4872
0
        else if (EQUAL(aosUsedFields[i], "FID"))
4873
0
        {
4874
0
            bNeedsFID = true;
4875
0
        }
4876
0
        else
4877
0
        {
4878
0
            CPLDebug("OGR", "Cannot find used field %s", aosUsedFields[i]);
4879
0
        }
4880
0
    }
4881
4882
0
    const size_t nLength = abyValidityFromFilters.size();
4883
4884
0
    GIntBig nBaseSeqFID = -1;
4885
0
    std::vector<int> anArrowPathToFIDColumn;
4886
0
    if (bNeedsFID)
4887
0
    {
4888
        // BASE_SEQUENTIAL_FID is set when there is no Arrow column for the FID
4889
        // and we assume sequential FID numbering
4890
0
        const char *pszBaseSeqFID =
4891
0
            CSLFetchNameValue(papszOptions, "BASE_SEQUENTIAL_FID");
4892
0
        if (pszBaseSeqFID)
4893
0
        {
4894
0
            nBaseSeqFID = CPLAtoGIntBig(pszBaseSeqFID);
4895
4896
            // Optimizimation for "FID = constant"
4897
0
            swq_expr_node *poNode =
4898
0
                static_cast<swq_expr_node *>(poAttrQuery->GetSWQExpr());
4899
0
            if (poNode->eNodeType == SNT_OPERATION &&
4900
0
                poNode->nOperation == SWQ_EQ && poNode->nSubExprCount == 2 &&
4901
0
                poNode->papoSubExpr[0]->eNodeType == SNT_COLUMN &&
4902
0
                poNode->papoSubExpr[1]->eNodeType == SNT_CONSTANT &&
4903
0
                poNode->papoSubExpr[0]->field_index ==
4904
0
                    poFeatureDefn->GetFieldCount() + SPF_FID &&
4905
0
                poNode->papoSubExpr[1]->field_type == SWQ_INTEGER64)
4906
0
            {
4907
0
                if (nBaseSeqFID + static_cast<int64_t>(nLength) <
4908
0
                        poNode->papoSubExpr[1]->int_value ||
4909
0
                    nBaseSeqFID > poNode->papoSubExpr[1]->int_value)
4910
0
                {
4911
0
                    return 0;
4912
0
                }
4913
0
            }
4914
0
        }
4915
0
        else
4916
0
        {
4917
0
            const char *pszFIDColumn =
4918
0
                const_cast<OGRLayer *>(poLayer)->GetFIDColumn();
4919
0
            if (pszFIDColumn && pszFIDColumn[0])
4920
0
            {
4921
0
                const auto oIter = oMapFieldNameToArrowPath.find(pszFIDColumn);
4922
0
                if (oIter != oMapFieldNameToArrowPath.end())
4923
0
                {
4924
0
                    anArrowPathToFIDColumn = oIter->second;
4925
0
                }
4926
0
            }
4927
0
            if (anArrowPathToFIDColumn.empty())
4928
0
            {
4929
0
                CPLError(CE_Failure, CPLE_AppDefined,
4930
0
                         "Filtering on FID requested but cannot associate a "
4931
0
                         "FID with Arrow records");
4932
0
            }
4933
0
        }
4934
0
    }
4935
4936
0
    for (size_t iRow = 0; iRow < nLength; ++iRow)
4937
0
    {
4938
0
        if (!abyValidityFromFilters[iRow])
4939
0
            continue;
4940
4941
0
        if (bNeedsFID)
4942
0
        {
4943
0
            if (nBaseSeqFID >= 0)
4944
0
            {
4945
0
                oFeature.SetFID(nBaseSeqFID + iRow);
4946
0
            }
4947
0
            else if (!anArrowPathToFIDColumn.empty())
4948
0
            {
4949
0
                oFeature.SetFID(OGRNullFID);
4950
4951
0
                const struct ArrowSchema *psSchemaField = schema;
4952
0
                const struct ArrowArray *psArray = array;
4953
0
                bool bSkip = false;
4954
0
                for (size_t i = 0; i < anArrowPathToFIDColumn.size(); ++i)
4955
0
                {
4956
0
                    const int iChild = anArrowPathToFIDColumn[i];
4957
0
                    if (i > 0)
4958
0
                    {
4959
0
                        const uint8_t *pabyValidity =
4960
0
                            psArray->null_count == 0
4961
0
                                ? nullptr
4962
0
                                : static_cast<uint8_t *>(
4963
0
                                      const_cast<void *>(psArray->buffers[0]));
4964
0
                        const size_t nOffsettedIndex =
4965
0
                            static_cast<size_t>(iRow + psArray->offset);
4966
0
                        if (pabyValidity &&
4967
0
                            !TestBit(pabyValidity, nOffsettedIndex))
4968
0
                        {
4969
0
                            bSkip = true;
4970
0
                            break;
4971
0
                        }
4972
0
                    }
4973
4974
0
                    psSchemaField = psSchemaField->children[iChild];
4975
0
                    psArray = psArray->children[iChild];
4976
0
                }
4977
0
                if (bSkip)
4978
0
                    continue;
4979
4980
0
                const char *format = psSchemaField->format;
4981
0
                const uint8_t *pabyValidity =
4982
0
                    psArray->null_count == 0
4983
0
                        ? nullptr
4984
0
                        : static_cast<uint8_t *>(
4985
0
                              const_cast<void *>(psArray->buffers[0]));
4986
0
                const size_t nOffsettedIndex =
4987
0
                    static_cast<size_t>(iRow + psArray->offset);
4988
0
                if (pabyValidity && !TestBit(pabyValidity, nOffsettedIndex))
4989
0
                {
4990
                    // do nothing
4991
0
                }
4992
0
                else if (IsInt32(format))
4993
0
                {
4994
0
                    oFeature.SetFID(static_cast<const int32_t *>(
4995
0
                        psArray->buffers[1])[nOffsettedIndex]);
4996
0
                }
4997
0
                else if (IsInt64(format))
4998
0
                {
4999
0
                    oFeature.SetFID(static_cast<const int64_t *>(
5000
0
                        psArray->buffers[1])[nOffsettedIndex]);
5001
0
                }
5002
0
            }
5003
0
        }
5004
5005
0
        for (const auto &sInfo : aoUsedFieldsInfo)
5006
0
        {
5007
0
            const int iOGRFieldIndex = sInfo.iOGRFieldIndex;
5008
0
            const struct ArrowSchema *psSchemaField = schema;
5009
0
            const struct ArrowArray *psArray = array;
5010
0
            bool bSkip = false;
5011
0
            for (size_t i = 0; i < sInfo.anArrowPath.size(); ++i)
5012
0
            {
5013
0
                const int iChild = sInfo.anArrowPath[i];
5014
0
                if (i > 0)
5015
0
                {
5016
0
                    const uint8_t *pabyValidity =
5017
0
                        psArray->null_count == 0
5018
0
                            ? nullptr
5019
0
                            : static_cast<uint8_t *>(
5020
0
                                  const_cast<void *>(psArray->buffers[0]));
5021
0
                    const size_t nOffsettedIndex =
5022
0
                        static_cast<size_t>(iRow + psArray->offset);
5023
0
                    if (pabyValidity && !TestBit(pabyValidity, nOffsettedIndex))
5024
0
                    {
5025
0
                        bSkip = true;
5026
0
                        oFeature.SetFieldNull(iOGRFieldIndex);
5027
0
                        break;
5028
0
                    }
5029
0
                }
5030
5031
0
                psSchemaField = psSchemaField->children[iChild];
5032
0
                psArray = psArray->children[iChild];
5033
0
            }
5034
0
            if (bSkip)
5035
0
                continue;
5036
5037
0
            const char *format = psSchemaField->format;
5038
0
            const uint8_t *pabyValidity =
5039
0
                psArray->null_count == 0
5040
0
                    ? nullptr
5041
0
                    : static_cast<uint8_t *>(
5042
0
                          const_cast<void *>(psArray->buffers[0]));
5043
0
            const size_t nOffsettedIndex =
5044
0
                static_cast<size_t>(iRow + psArray->offset);
5045
0
            if (pabyValidity && !TestBit(pabyValidity, nOffsettedIndex))
5046
0
            {
5047
0
                oFeature.SetFieldNull(iOGRFieldIndex);
5048
0
            }
5049
0
            else if (IsBoolean(format))
5050
0
            {
5051
0
                oFeature.SetField(
5052
0
                    iOGRFieldIndex,
5053
0
                    TestBit(static_cast<const uint8_t *>(psArray->buffers[1]),
5054
0
                            nOffsettedIndex));
5055
0
            }
5056
0
            else if (IsInt8(format))
5057
0
            {
5058
0
                oFeature.SetField(iOGRFieldIndex,
5059
0
                                  static_cast<const int8_t *>(
5060
0
                                      psArray->buffers[1])[nOffsettedIndex]);
5061
0
            }
5062
0
            else if (IsUInt8(format))
5063
0
            {
5064
0
                oFeature.SetField(iOGRFieldIndex,
5065
0
                                  static_cast<const uint8_t *>(
5066
0
                                      psArray->buffers[1])[nOffsettedIndex]);
5067
0
            }
5068
0
            else if (IsInt16(format))
5069
0
            {
5070
0
                oFeature.SetField(iOGRFieldIndex,
5071
0
                                  static_cast<const int16_t *>(
5072
0
                                      psArray->buffers[1])[nOffsettedIndex]);
5073
0
            }
5074
0
            else if (IsUInt16(format))
5075
0
            {
5076
0
                oFeature.SetField(iOGRFieldIndex,
5077
0
                                  static_cast<const uint16_t *>(
5078
0
                                      psArray->buffers[1])[nOffsettedIndex]);
5079
0
            }
5080
0
            else if (IsInt32(format))
5081
0
            {
5082
0
                oFeature.SetField(iOGRFieldIndex,
5083
0
                                  static_cast<const int32_t *>(
5084
0
                                      psArray->buffers[1])[nOffsettedIndex]);
5085
0
            }
5086
0
            else if (IsUInt32(format))
5087
0
            {
5088
0
                oFeature.SetField(
5089
0
                    iOGRFieldIndex,
5090
0
                    static_cast<GIntBig>(static_cast<const uint32_t *>(
5091
0
                        psArray->buffers[1])[nOffsettedIndex]));
5092
0
            }
5093
0
            else if (IsInt64(format))
5094
0
            {
5095
0
                oFeature.SetField(
5096
0
                    iOGRFieldIndex,
5097
0
                    static_cast<GIntBig>(static_cast<const int64_t *>(
5098
0
                        psArray->buffers[1])[nOffsettedIndex]));
5099
0
            }
5100
0
            else if (IsUInt64(format))
5101
0
            {
5102
0
                oFeature.SetField(
5103
0
                    iOGRFieldIndex,
5104
0
                    static_cast<double>(static_cast<const uint64_t *>(
5105
0
                        psArray->buffers[1])[nOffsettedIndex]));
5106
0
            }
5107
0
            else if (IsFloat32(format))
5108
0
            {
5109
0
                oFeature.SetField(iOGRFieldIndex,
5110
0
                                  static_cast<const float *>(
5111
0
                                      psArray->buffers[1])[nOffsettedIndex]);
5112
0
            }
5113
0
            else if (IsFloat64(format))
5114
0
            {
5115
0
                oFeature.SetField(iOGRFieldIndex,
5116
0
                                  static_cast<const double *>(
5117
0
                                      psArray->buffers[1])[nOffsettedIndex]);
5118
0
            }
5119
0
            else if (IsString(format))
5120
0
            {
5121
0
                const auto nOffset = static_cast<const uint32_t *>(
5122
0
                    psArray->buffers[1])[nOffsettedIndex];
5123
0
                const auto nNextOffset = static_cast<const uint32_t *>(
5124
0
                    psArray->buffers[1])[nOffsettedIndex + 1];
5125
0
                const GByte *pabyData =
5126
0
                    static_cast<const GByte *>(psArray->buffers[2]);
5127
0
                const uint32_t nSize = nNextOffset - nOffset;
5128
0
                CPLAssert(oFeature.GetFieldDefnRef(iOGRFieldIndex)->GetType() ==
5129
0
                          OFTString);
5130
0
                char *pszStr = static_cast<char *>(CPLMalloc(nSize + 1));
5131
0
                memcpy(pszStr, pabyData + nOffset, nSize);
5132
0
                pszStr[nSize] = 0;
5133
0
                OGRField *psField = oFeature.GetRawFieldRef(iOGRFieldIndex);
5134
0
                if (IsValidField(psField))
5135
0
                    CPLFree(psField->String);
5136
0
                psField->String = pszStr;
5137
0
            }
5138
0
            else if (IsLargeString(format))
5139
0
            {
5140
0
                const auto nOffset = static_cast<const uint64_t *>(
5141
0
                    psArray->buffers[1])[nOffsettedIndex];
5142
0
                const auto nNextOffset = static_cast<const uint64_t *>(
5143
0
                    psArray->buffers[1])[nOffsettedIndex + 1];
5144
0
                const GByte *pabyData =
5145
0
                    static_cast<const GByte *>(psArray->buffers[2]);
5146
0
                const size_t nSize = static_cast<size_t>(nNextOffset - nOffset);
5147
0
                char *pszStr = static_cast<char *>(CPLMalloc(nSize + 1));
5148
0
                memcpy(pszStr, pabyData + static_cast<size_t>(nOffset), nSize);
5149
0
                pszStr[nSize] = 0;
5150
0
                OGRField *psField = oFeature.GetRawFieldRef(iOGRFieldIndex);
5151
0
                if (IsValidField(psField))
5152
0
                    CPLFree(psField->String);
5153
0
                psField->String = pszStr;
5154
0
            }
5155
0
            else if (IsBinary(format))
5156
0
            {
5157
0
                const auto nOffset = static_cast<const uint32_t *>(
5158
0
                    psArray->buffers[1])[nOffsettedIndex];
5159
0
                const auto nNextOffset = static_cast<const uint32_t *>(
5160
0
                    psArray->buffers[1])[nOffsettedIndex + 1];
5161
0
                const GByte *pabyData =
5162
0
                    static_cast<const GByte *>(psArray->buffers[2]);
5163
0
                const uint32_t nSize = nNextOffset - nOffset;
5164
0
                if (nSize >
5165
0
                    static_cast<size_t>(std::numeric_limits<int32_t>::max()))
5166
0
                {
5167
0
                    abyValidityFromFilters.clear();
5168
0
                    abyValidityFromFilters.resize(nLength);
5169
0
                    CPLError(CE_Failure, CPLE_AppDefined,
5170
0
                             "Unexpected error in PostFilterArrowArray(): too "
5171
0
                             "large binary");
5172
0
                    return 0;
5173
0
                }
5174
0
                oFeature.SetField(iOGRFieldIndex, static_cast<int>(nSize),
5175
0
                                  pabyData + nOffset);
5176
0
            }
5177
0
            else if (IsLargeBinary(format))
5178
0
            {
5179
0
                const auto nOffset = static_cast<const uint64_t *>(
5180
0
                    psArray->buffers[1])[nOffsettedIndex];
5181
0
                const auto nNextOffset = static_cast<const uint64_t *>(
5182
0
                    psArray->buffers[1])[nOffsettedIndex + 1];
5183
0
                const GByte *pabyData =
5184
0
                    static_cast<const GByte *>(psArray->buffers[2]);
5185
0
                const uint64_t nSize = nNextOffset - nOffset;
5186
0
                if (nSize >
5187
0
                    static_cast<uint64_t>(std::numeric_limits<int32_t>::max()))
5188
0
                {
5189
0
                    abyValidityFromFilters.clear();
5190
0
                    abyValidityFromFilters.resize(nLength);
5191
0
                    CPLError(CE_Failure, CPLE_AppDefined,
5192
0
                             "Unexpected error in PostFilterArrowArray(): too "
5193
0
                             "large binary");
5194
0
                    return 0;
5195
0
                }
5196
0
                oFeature.SetField(iOGRFieldIndex, static_cast<int>(nSize),
5197
0
                                  pabyData + nOffset);
5198
0
            }
5199
0
            else if (!SetFieldForOtherFormats(oFeature, iOGRFieldIndex,
5200
0
                                              nOffsettedIndex, psSchemaField,
5201
0
                                              psArray))
5202
0
            {
5203
0
                abyValidityFromFilters.clear();
5204
0
                abyValidityFromFilters.resize(nLength);
5205
0
                CPLError(
5206
0
                    CE_Failure, CPLE_AppDefined,
5207
0
                    "Unexpected error in PostFilterArrowArray(): unhandled "
5208
0
                    "field format: %s",
5209
0
                    format);
5210
0
                return 0;
5211
0
            }
5212
0
        }
5213
0
        if (poAttrQuery->Evaluate(&oFeature))
5214
0
        {
5215
0
            nCountIntersecting++;
5216
0
        }
5217
0
        else
5218
0
        {
5219
0
            abyValidityFromFilters[iRow] = false;
5220
0
        }
5221
0
    }
5222
0
    return nCountIntersecting;
5223
0
}
5224
5225
/************************************************************************/
5226
/*                  OGRLayer::PostFilterArrowArray()                    */
5227
/************************************************************************/
5228
5229
/** Remove rows that aren't selected by the spatial or attribute filter.
5230
 *
5231
 * Assumes that CanPostFilterArrowArray() has been called and returned true.
5232
 */
5233
void OGRLayer::PostFilterArrowArray(const struct ArrowSchema *schema,
5234
                                    struct ArrowArray *array,
5235
                                    CSLConstList papszOptions) const
5236
0
{
5237
0
    if (!m_poFilterGeom && !m_poAttrQuery)
5238
0
        return;
5239
5240
0
    CPLAssert(schema->n_children == array->n_children);
5241
5242
0
    int64_t iGeomField = -1;
5243
0
    if (m_poFilterGeom)
5244
0
    {
5245
0
        const char *pszGeomFieldName =
5246
0
            const_cast<OGRLayer *>(this)
5247
0
                ->GetLayerDefn()
5248
0
                ->GetGeomFieldDefn(m_iGeomFieldFilter)
5249
0
                ->GetNameRef();
5250
0
        for (int64_t iField = 0; iField < schema->n_children; ++iField)
5251
0
        {
5252
0
            const auto fieldSchema = schema->children[iField];
5253
0
            if (strcmp(fieldSchema->name, pszGeomFieldName) == 0)
5254
0
            {
5255
0
                iGeomField = iField;
5256
0
                break;
5257
0
            }
5258
0
            CPLAssert(array->children[iField]->length ==
5259
0
                      array->children[0]->length);
5260
0
        }
5261
        // Guaranteed if CanPostFilterArrowArray() returned true
5262
0
        CPLAssert(iGeomField >= 0);
5263
0
        CPLAssert(IsBinary(schema->children[iGeomField]->format) ||
5264
0
                  IsLargeBinary(schema->children[iGeomField]->format));
5265
0
        CPLAssert(array->children[iGeomField]->n_buffers == 3);
5266
0
    }
5267
5268
0
    std::vector<bool> abyValidityFromFilters;
5269
0
    const size_t nLength = static_cast<size_t>(array->length);
5270
0
    const size_t nCountIntersectingGeom =
5271
0
        m_poFilterGeom ? (IsBinary(schema->children[iGeomField]->format)
5272
0
                              ? FillValidityArrayFromWKBArray<uint32_t>(
5273
0
                                    array->children[iGeomField], this,
5274
0
                                    abyValidityFromFilters)
5275
0
                              : FillValidityArrayFromWKBArray<uint64_t>(
5276
0
                                    array->children[iGeomField], this,
5277
0
                                    abyValidityFromFilters))
5278
0
                       : nLength;
5279
0
    if (!m_poFilterGeom)
5280
0
        abyValidityFromFilters.resize(nLength, true);
5281
0
    const size_t nCountIntersecting =
5282
0
        m_poAttrQuery && nCountIntersectingGeom > 0
5283
0
            ? FillValidityArrayFromAttrQuery(this, m_poAttrQuery, schema, array,
5284
0
                                             abyValidityFromFilters,
5285
0
                                             papszOptions)
5286
0
        : m_poFilterGeom ? nCountIntersectingGeom
5287
0
                         : nLength;
5288
    // Nothing to do ?
5289
0
    if (nCountIntersecting == nLength)
5290
0
    {
5291
        // CPLDebug("OGR", "All rows match filter");
5292
0
        return;
5293
0
    }
5294
5295
0
    if (nCountIntersecting == 0)
5296
0
    {
5297
0
        array->length = 0;
5298
0
    }
5299
0
    else if (!CompactStructArray(schema, array, 0, abyValidityFromFilters,
5300
0
                                 nCountIntersecting))
5301
0
    {
5302
0
        array->release(array);
5303
0
        memset(array, 0, sizeof(*array));
5304
0
    }
5305
0
}
5306
5307
/************************************************************************/
5308
/*                          OGRCloneArrowArray                          */
5309
/************************************************************************/
5310
5311
static bool OGRCloneArrowArray(const struct ArrowSchema *schema,
5312
                               const struct ArrowArray *src_array,
5313
                               struct ArrowArray *out_array,
5314
                               size_t nParentOffset)
5315
0
{
5316
0
    memset(out_array, 0, sizeof(*out_array));
5317
0
    const size_t nLength =
5318
0
        static_cast<size_t>(src_array->length) - nParentOffset;
5319
0
    out_array->length = nLength;
5320
0
    out_array->null_count = src_array->null_count;
5321
0
    out_array->release = OGRLayerDefaultReleaseArray;
5322
5323
0
    bool bRet = true;
5324
5325
0
    out_array->n_buffers = src_array->n_buffers;
5326
0
    out_array->buffers = static_cast<const void **>(CPLCalloc(
5327
0
        static_cast<size_t>(src_array->n_buffers), sizeof(const void *)));
5328
0
    CPLAssert(static_cast<size_t>(src_array->length) >= nParentOffset);
5329
0
    const char *format = schema->format;
5330
0
    const auto nOffset = static_cast<size_t>(src_array->offset) + nParentOffset;
5331
0
    for (int64_t i = 0; i < src_array->n_buffers; ++i)
5332
0
    {
5333
0
        if (i == 0 || IsBoolean(format))
5334
0
        {
5335
0
            if (i == 1)
5336
0
            {
5337
0
                CPLAssert(src_array->buffers[i]);
5338
0
            }
5339
0
            if (src_array->buffers[i])
5340
0
            {
5341
0
                const size_t nBytes = nLength ? (nLength + 7) / 8 : 1;
5342
0
                uint8_t *CPL_RESTRICT p = static_cast<uint8_t *>(
5343
0
                    VSI_MALLOC_ALIGNED_AUTO_VERBOSE(nBytes));
5344
0
                if (!p)
5345
0
                {
5346
0
                    bRet = false;
5347
0
                    break;
5348
0
                }
5349
0
                const auto *CPL_RESTRICT pSrcArray =
5350
0
                    static_cast<const uint8_t *>(src_array->buffers[i]);
5351
0
                if ((nOffset % 8) != 0)
5352
0
                {
5353
                    // Make sure last byte is fully initialized
5354
0
                    p[nBytes - 1] = 0;
5355
0
                    for (size_t iRow = 0; iRow < nLength; ++iRow)
5356
0
                    {
5357
0
                        if (TestBit(pSrcArray, nOffset + iRow))
5358
0
                            SetBit(p, iRow);
5359
0
                        else
5360
0
                            UnsetBit(p, iRow);
5361
0
                    }
5362
0
                }
5363
0
                else
5364
0
                {
5365
0
                    memcpy(p, pSrcArray + nOffset / 8, nBytes);
5366
0
                }
5367
0
                out_array->buffers[i] = p;
5368
0
            }
5369
0
        }
5370
0
        else if (i == 1)
5371
0
        {
5372
0
            CPLAssert(src_array->buffers[i]);
5373
0
            size_t nEltSize = 0;
5374
0
            size_t nExtraElt = 0;
5375
0
            if (IsUInt8(format) || IsInt8(format))
5376
0
                nEltSize = sizeof(uint8_t);
5377
0
            else if (IsUInt16(format) || IsInt16(format) || IsFloat16(format))
5378
0
                nEltSize = sizeof(uint16_t);
5379
0
            else if (IsUInt32(format) || IsInt32(format) || IsFloat32(format) ||
5380
0
                     strcmp(format, "tdD") == 0 || strcmp(format, "tts") == 0 ||
5381
0
                     strcmp(format, "ttm") == 0)
5382
0
            {
5383
0
                nEltSize = sizeof(uint32_t);
5384
0
            }
5385
0
            else if (IsString(format) || IsBinary(format) || IsList(format) ||
5386
0
                     IsMap(format))
5387
0
            {
5388
0
                nEltSize = sizeof(uint32_t);
5389
0
                nExtraElt = 1;
5390
0
            }
5391
0
            else if (IsUInt64(format) || IsInt64(format) || IsFloat64(format) ||
5392
0
                     strcmp(format, "tdm") == 0 || strcmp(format, "ttu") == 0 ||
5393
0
                     strcmp(format, "ttn") == 0 || IsTimestamp(format))
5394
0
            {
5395
0
                nEltSize = sizeof(uint64_t);
5396
0
            }
5397
0
            else if (IsLargeString(format) || IsLargeBinary(format) ||
5398
0
                     IsLargeList(format))
5399
0
            {
5400
0
                nEltSize = sizeof(uint64_t);
5401
0
                nExtraElt = 1;
5402
0
            }
5403
0
            else if (IsFixedWidthBinary(format))
5404
0
            {
5405
0
                nEltSize = GetFixedWithBinary(format);
5406
0
            }
5407
0
            else if (IsDecimal(format))
5408
0
            {
5409
0
                int nPrecision = 0;
5410
0
                int nScale = 0;
5411
0
                int nWidthInBytes = 0;
5412
0
                if (!ParseDecimalFormat(format, nPrecision, nScale,
5413
0
                                        nWidthInBytes))
5414
0
                {
5415
0
                    CPLError(
5416
0
                        CE_Failure, CPLE_AppDefined,
5417
0
                        "Unexpected error in OGRCloneArrowArray(): unhandled "
5418
0
                        "field format: %s",
5419
0
                        format);
5420
5421
0
                    return false;
5422
0
                }
5423
0
                nEltSize = nWidthInBytes;
5424
0
            }
5425
0
            if (nEltSize)
5426
0
            {
5427
0
                void *p = VSI_MALLOC_ALIGNED_AUTO_VERBOSE(
5428
0
                    nLength ? nEltSize * (nLength + nExtraElt) : 1);
5429
0
                if (!p)
5430
0
                {
5431
0
                    bRet = false;
5432
0
                    break;
5433
0
                }
5434
0
                if (nLength)
5435
0
                {
5436
0
                    if ((IsString(format) || IsBinary(format)) &&
5437
0
                        static_cast<const uint32_t *>(
5438
0
                            src_array->buffers[1])[nOffset] != 0)
5439
0
                    {
5440
0
                        const auto *CPL_RESTRICT pSrcOffsets =
5441
0
                            static_cast<const uint32_t *>(
5442
0
                                src_array->buffers[1]) +
5443
0
                            nOffset;
5444
0
                        const auto nShiftOffset = pSrcOffsets[0];
5445
0
                        auto *CPL_RESTRICT pDstOffsets =
5446
0
                            static_cast<uint32_t *>(p);
5447
0
                        for (size_t iRow = 0; iRow <= nLength; ++iRow)
5448
0
                        {
5449
0
                            pDstOffsets[iRow] =
5450
0
                                pSrcOffsets[iRow] - nShiftOffset;
5451
0
                        }
5452
0
                    }
5453
0
                    else if ((IsLargeString(format) || IsLargeBinary(format)) &&
5454
0
                             static_cast<const uint64_t *>(
5455
0
                                 src_array->buffers[1])[nOffset] != 0)
5456
0
                    {
5457
0
                        const auto *CPL_RESTRICT pSrcOffsets =
5458
0
                            static_cast<const uint64_t *>(
5459
0
                                src_array->buffers[1]) +
5460
0
                            nOffset;
5461
0
                        const auto nShiftOffset = pSrcOffsets[0];
5462
0
                        auto *CPL_RESTRICT pDstOffsets =
5463
0
                            static_cast<uint64_t *>(p);
5464
0
                        for (size_t iRow = 0; iRow <= nLength; ++iRow)
5465
0
                        {
5466
0
                            pDstOffsets[iRow] =
5467
0
                                pSrcOffsets[iRow] - nShiftOffset;
5468
0
                        }
5469
0
                    }
5470
0
                    else
5471
0
                    {
5472
0
                        memcpy(
5473
0
                            p,
5474
0
                            static_cast<const GByte *>(src_array->buffers[i]) +
5475
0
                                nEltSize * nOffset,
5476
0
                            nEltSize * (nLength + nExtraElt));
5477
0
                    }
5478
0
                }
5479
0
                out_array->buffers[i] = p;
5480
0
            }
5481
0
            else
5482
0
            {
5483
0
                CPLError(CE_Failure, CPLE_AppDefined,
5484
0
                         "OGRCloneArrowArray(): unhandled case, array = %s, "
5485
0
                         "format = '%s', i = 1",
5486
0
                         schema->name, format);
5487
0
                bRet = false;
5488
0
                break;
5489
0
            }
5490
0
        }
5491
0
        else if (i == 2)
5492
0
        {
5493
0
            CPLAssert(src_array->buffers[i]);
5494
0
            size_t nSrcCharOffset = 0;
5495
0
            size_t nCharCount = 0;
5496
0
            if (IsString(format) || IsBinary(format))
5497
0
            {
5498
0
                const auto *pSrcOffsets =
5499
0
                    static_cast<const uint32_t *>(src_array->buffers[1]) +
5500
0
                    nOffset;
5501
0
                nSrcCharOffset = pSrcOffsets[0];
5502
0
                nCharCount = pSrcOffsets[nLength] - pSrcOffsets[0];
5503
0
            }
5504
0
            else if (IsLargeString(format) || IsLargeBinary(format))
5505
0
            {
5506
0
                const auto *pSrcOffsets =
5507
0
                    static_cast<const uint64_t *>(src_array->buffers[1]) +
5508
0
                    nOffset;
5509
0
                nSrcCharOffset = static_cast<size_t>(pSrcOffsets[0]);
5510
0
                nCharCount =
5511
0
                    static_cast<size_t>(pSrcOffsets[nLength] - pSrcOffsets[0]);
5512
0
            }
5513
0
            else
5514
0
            {
5515
0
                CPLError(CE_Failure, CPLE_AppDefined,
5516
0
                         "OGRCloneArrowArray(): unhandled case, array = %s, "
5517
0
                         "format = '%s', i = 2",
5518
0
                         schema->name, format);
5519
0
                bRet = false;
5520
0
                break;
5521
0
            }
5522
0
            void *p =
5523
0
                VSI_MALLOC_ALIGNED_AUTO_VERBOSE(nCharCount ? nCharCount : 1);
5524
0
            if (!p)
5525
0
            {
5526
0
                bRet = false;
5527
0
                break;
5528
0
            }
5529
0
            if (nCharCount)
5530
0
            {
5531
0
                memcpy(p,
5532
0
                       static_cast<const GByte *>(src_array->buffers[i]) +
5533
0
                           nSrcCharOffset,
5534
0
                       nCharCount);
5535
0
            }
5536
0
            out_array->buffers[i] = p;
5537
0
        }
5538
0
        else
5539
0
        {
5540
0
            CPLError(CE_Failure, CPLE_AppDefined,
5541
0
                     "OGRCloneArrowArray(): unhandled case, array = %s, format "
5542
0
                     "= '%s', i = 3",
5543
0
                     schema->name, format);
5544
0
            bRet = false;
5545
0
            break;
5546
0
        }
5547
0
    }
5548
5549
0
    if (bRet)
5550
0
    {
5551
0
        out_array->n_children = src_array->n_children;
5552
0
        out_array->children = static_cast<struct ArrowArray **>(
5553
0
            CPLCalloc(static_cast<size_t>(src_array->n_children),
5554
0
                      sizeof(struct ArrowArray *)));
5555
0
        for (int64_t i = 0; i < src_array->n_children; ++i)
5556
0
        {
5557
0
            out_array->children[i] = static_cast<struct ArrowArray *>(
5558
0
                CPLCalloc(1, sizeof(struct ArrowArray)));
5559
0
            if (!OGRCloneArrowArray(schema->children[i], src_array->children[i],
5560
0
                                    out_array->children[i],
5561
0
                                    IsFixedSizeList(format)
5562
0
                                        ? nOffset * GetFixedSizeList(format)
5563
0
                                    : IsStructure(format) ? nOffset
5564
0
                                                          : 0))
5565
0
            {
5566
0
                bRet = false;
5567
0
                break;
5568
0
            }
5569
0
        }
5570
0
    }
5571
5572
0
    if (bRet && src_array->dictionary)
5573
0
    {
5574
0
        out_array->dictionary = static_cast<struct ArrowArray *>(
5575
0
            CPLCalloc(1, sizeof(struct ArrowArray)));
5576
0
        bRet = OGRCloneArrowArray(schema->dictionary, src_array->dictionary,
5577
0
                                  out_array->dictionary, 0);
5578
0
    }
5579
5580
0
    if (!bRet)
5581
0
    {
5582
0
        out_array->release(out_array);
5583
0
        memset(out_array, 0, sizeof(*out_array));
5584
0
    }
5585
0
    return bRet;
5586
0
}
5587
5588
/** Full/deep copy of an array.
5589
 *
5590
 * Renormalize the offset of the array (and its children) to 0.
5591
 *
5592
 * In case of failure, out_array will be let in a released state.
5593
 *
5594
 * @param schema Schema of the array. Must *NOT* be NULL.
5595
 * @param src_array Source array. Must *NOT* be NULL.
5596
 * @param out_array Output array.  Must *NOT* be NULL (but its content may be random)
5597
 * @return true if success.
5598
 */
5599
bool OGRCloneArrowArray(const struct ArrowSchema *schema,
5600
                        const struct ArrowArray *src_array,
5601
                        struct ArrowArray *out_array)
5602
0
{
5603
0
    return OGRCloneArrowArray(schema, src_array, out_array, 0);
5604
0
}
5605
5606
/************************************************************************/
5607
/*                     OGRCloneArrowMetadata()                          */
5608
/************************************************************************/
5609
5610
static void *OGRCloneArrowMetadata(const void *pMetadata)
5611
0
{
5612
0
    if (!pMetadata)
5613
0
        return nullptr;
5614
0
    std::vector<GByte> abyOut;
5615
0
    const GByte *pabyMetadata = static_cast<const GByte *>(pMetadata);
5616
0
    int32_t nKVP;
5617
0
    abyOut.insert(abyOut.end(), pabyMetadata, pabyMetadata + sizeof(int32_t));
5618
0
    memcpy(&nKVP, pabyMetadata, sizeof(int32_t));
5619
0
    pabyMetadata += sizeof(int32_t);
5620
0
    for (int i = 0; i < nKVP; ++i)
5621
0
    {
5622
0
        int32_t nSizeKey;
5623
0
        abyOut.insert(abyOut.end(), pabyMetadata,
5624
0
                      pabyMetadata + sizeof(int32_t));
5625
0
        memcpy(&nSizeKey, pabyMetadata, sizeof(int32_t));
5626
0
        pabyMetadata += sizeof(int32_t);
5627
0
        abyOut.insert(abyOut.end(), pabyMetadata, pabyMetadata + nSizeKey);
5628
0
        pabyMetadata += nSizeKey;
5629
5630
0
        int32_t nSizeValue;
5631
0
        abyOut.insert(abyOut.end(), pabyMetadata,
5632
0
                      pabyMetadata + sizeof(int32_t));
5633
0
        memcpy(&nSizeValue, pabyMetadata, sizeof(int32_t));
5634
0
        pabyMetadata += sizeof(int32_t);
5635
0
        abyOut.insert(abyOut.end(), pabyMetadata, pabyMetadata + nSizeValue);
5636
0
        pabyMetadata += nSizeValue;
5637
0
    }
5638
5639
0
    GByte *pabyOut = static_cast<GByte *>(VSI_MALLOC_VERBOSE(abyOut.size()));
5640
0
    if (pabyOut)
5641
0
        memcpy(pabyOut, abyOut.data(), abyOut.size());
5642
0
    return pabyOut;
5643
0
}
5644
5645
/************************************************************************/
5646
/*                          OGRCloneArrowSchema()                       */
5647
/************************************************************************/
5648
5649
/** Full/deep copy of a schema.
5650
 *
5651
 * In case of failure, out_schema will be let in a released state.
5652
 *
5653
 * @param schema Schema to clone. Must *NOT* be NULL.
5654
 * @param out_schema Output schema.  Must *NOT* be NULL (but its content may be random)
5655
 * @return true if success.
5656
 */
5657
bool OGRCloneArrowSchema(const struct ArrowSchema *schema,
5658
                         struct ArrowSchema *out_schema)
5659
0
{
5660
0
    memset(out_schema, 0, sizeof(*out_schema));
5661
0
    out_schema->release = OGRLayerFullReleaseSchema;
5662
0
    out_schema->format = CPLStrdup(schema->format);
5663
0
    out_schema->name = CPLStrdup(schema->name);
5664
0
    out_schema->metadata = static_cast<const char *>(
5665
0
        const_cast<const void *>(OGRCloneArrowMetadata(schema->metadata)));
5666
0
    out_schema->flags = schema->flags;
5667
0
    if (schema->n_children)
5668
0
    {
5669
0
        out_schema->children =
5670
0
            static_cast<struct ArrowSchema **>(VSI_CALLOC_VERBOSE(
5671
0
                static_cast<int>(schema->n_children), sizeof(ArrowSchema *)));
5672
0
        if (!out_schema->children)
5673
0
        {
5674
0
            out_schema->release(out_schema);
5675
0
            return false;
5676
0
        }
5677
0
        out_schema->n_children = schema->n_children;
5678
0
        for (int i = 0; i < static_cast<int>(schema->n_children); ++i)
5679
0
        {
5680
0
            out_schema->children[i] = static_cast<struct ArrowSchema *>(
5681
0
                CPLMalloc(sizeof(ArrowSchema)));
5682
0
            if (!OGRCloneArrowSchema(schema->children[i],
5683
0
                                     out_schema->children[i]))
5684
0
            {
5685
0
                out_schema->release(out_schema);
5686
0
                return false;
5687
0
            }
5688
0
        }
5689
0
    }
5690
0
    if (schema->dictionary)
5691
0
    {
5692
0
        out_schema->dictionary =
5693
0
            static_cast<struct ArrowSchema *>(CPLMalloc(sizeof(ArrowSchema)));
5694
0
        if (!OGRCloneArrowSchema(schema->dictionary, out_schema->dictionary))
5695
0
        {
5696
0
            out_schema->release(out_schema);
5697
0
            return false;
5698
0
        }
5699
0
    }
5700
0
    return true;
5701
0
}
5702
5703
/************************************************************************/
5704
/*                  OGRLayer::IsArrowSchemaSupported()                  */
5705
/************************************************************************/
5706
5707
const struct
5708
{
5709
    const char *arrowType;
5710
    OGRFieldType eType;
5711
    OGRFieldSubType eSubType;
5712
} gasArrowTypesToOGR[] = {
5713
    {"b", OFTInteger, OFSTBoolean}, {"c", OFTInteger, OFSTInt16},  // Int8
5714
    {"C", OFTInteger, OFSTInt16},                                  // UInt8
5715
    {"s", OFTInteger, OFSTInt16},                                  // Int16
5716
    {"S", OFTInteger, OFSTNone},                                   // UInt16
5717
    {"i", OFTInteger, OFSTNone},                                   // Int32
5718
    {"I", OFTInteger64, OFSTNone},                                 // UInt32
5719
    {"l", OFTInteger64, OFSTNone},                                 // Int64
5720
    {"L", OFTReal, OFSTNone},  // UInt64 (potentially lossy conversion if going through OGRFeature)
5721
    {"e", OFTReal, OFSTFloat32},  // float16
5722
    {"f", OFTReal, OFSTFloat32},  // float32
5723
    {"g", OFTReal, OFSTNone},     // float64
5724
    {"z", OFTBinary, OFSTNone},   // binary
5725
    {"Z", OFTBinary, OFSTNone},  // large binary (will be limited to 32 bit length though if going through OGRFeature!)
5726
    {"u", OFTString, OFSTNone},  // string
5727
    {"U", OFTString, OFSTNone},  // large string
5728
    {"tdD", OFTDate, OFSTNone},  // date32[days]
5729
    {"tdm", OFTDate, OFSTNone},  // date64[milliseconds]
5730
    {"tts", OFTTime, OFSTNone},  // time32 [seconds]
5731
    {"ttm", OFTTime, OFSTNone},  // time32 [milliseconds]
5732
    {"ttu", OFTTime, OFSTNone},  // time64 [microseconds]
5733
    {"ttn", OFTTime, OFSTNone},  // time64 [nanoseconds]
5734
};
5735
5736
const struct
5737
{
5738
    const char arrowLetter;
5739
    OGRFieldType eType;
5740
    OGRFieldSubType eSubType;
5741
} gasListTypes[] = {
5742
    {ARROW_LETTER_BOOLEAN, OFTIntegerList, OFSTBoolean},
5743
    {ARROW_LETTER_INT8, OFTIntegerList, OFSTInt16},
5744
    {ARROW_LETTER_UINT8, OFTIntegerList, OFSTInt16},
5745
    {ARROW_LETTER_INT16, OFTIntegerList, OFSTInt16},
5746
    {ARROW_LETTER_UINT16, OFTIntegerList, OFSTNone},
5747
    {ARROW_LETTER_INT32, OFTIntegerList, OFSTNone},
5748
    {ARROW_LETTER_UINT32, OFTInteger64List, OFSTNone},
5749
    {ARROW_LETTER_INT64, OFTInteger64List, OFSTNone},
5750
    {ARROW_LETTER_UINT64, OFTRealList,
5751
     OFSTNone},  //(potentially lossy conversion if going through OGRFeature)
5752
    {ARROW_LETTER_FLOAT16, OFTRealList, OFSTFloat32},
5753
    {ARROW_LETTER_FLOAT32, OFTRealList, OFSTFloat32},
5754
    {ARROW_LETTER_FLOAT64, OFTRealList, OFSTNone},
5755
    {ARROW_LETTER_STRING, OFTStringList, OFSTNone},
5756
    {ARROW_LETTER_LARGE_STRING, OFTStringList, OFSTNone},
5757
};
5758
5759
static inline bool IsValidDictionaryIndexType(const char *format)
5760
0
{
5761
0
    return (format[0] == ARROW_LETTER_INT8 || format[0] == ARROW_LETTER_UINT8 ||
5762
0
            format[0] == ARROW_LETTER_INT16 ||
5763
0
            format[0] == ARROW_LETTER_UINT16 ||
5764
0
            format[0] == ARROW_LETTER_INT32 ||
5765
0
            format[0] == ARROW_LETTER_UINT32 ||
5766
0
            format[0] == ARROW_LETTER_INT64 ||
5767
0
            format[0] == ARROW_LETTER_UINT64) &&
5768
0
           format[1] == 0;
5769
0
}
5770
5771
static bool IsSupportForJSONObj(const struct ArrowSchema *schema)
5772
0
{
5773
0
    const char *format = schema->format;
5774
0
    if (IsStructure(format))
5775
0
    {
5776
0
        for (int64_t i = 0; i < schema->n_children; ++i)
5777
0
        {
5778
0
            if (!IsSupportForJSONObj(schema->children[i]))
5779
0
                return false;
5780
0
        }
5781
0
        return true;
5782
0
    }
5783
5784
0
    for (const auto &sType : gasListTypes)
5785
0
    {
5786
0
        if (format[0] == sType.arrowLetter && format[1] == 0)
5787
0
        {
5788
0
            return true;
5789
0
        }
5790
0
    }
5791
5792
0
    if (IsBinary(format) || IsLargeBinary(format) || IsFixedWidthBinary(format))
5793
0
        return true;
5794
5795
0
    if (IsDecimal(format))
5796
0
    {
5797
0
        int nPrecision = 0;
5798
0
        int nScale = 0;
5799
0
        int nWidthInBytes = 0;
5800
0
        if (!ParseDecimalFormat(format, nPrecision, nScale, nWidthInBytes))
5801
0
        {
5802
0
            CPLError(CE_Failure, CPLE_AppDefined, "Invalid field format %s",
5803
0
                     format);
5804
0
            return false;
5805
0
        }
5806
5807
0
        return GetErrorIfUnsupportedDecimal(nWidthInBytes, nPrecision) ==
5808
0
               nullptr;
5809
0
    }
5810
5811
0
    if (IsMap(format))
5812
0
    {
5813
0
        return IsStructure(schema->children[0]->format) &&
5814
0
               schema->children[0]->n_children == 2 &&
5815
0
               IsString(schema->children[0]->children[0]->format) &&
5816
0
               IsSupportForJSONObj(schema->children[0]->children[1]);
5817
0
    }
5818
5819
0
    if (IsList(format) || IsLargeList(format) || IsFixedSizeList(format))
5820
0
    {
5821
0
        return IsSupportForJSONObj(schema->children[0]);
5822
0
    }
5823
5824
0
    return false;
5825
0
}
5826
5827
static bool IsArrowSchemaSupportedInternal(const struct ArrowSchema *schema,
5828
                                           const std::string &osFieldPrefix,
5829
                                           std::string &osErrorMsg)
5830
0
{
5831
0
    const auto AppendError = [&osErrorMsg](const std::string &osMsg)
5832
0
    {
5833
0
        if (!osErrorMsg.empty())
5834
0
            osErrorMsg += " ";
5835
0
        osErrorMsg += osMsg;
5836
0
    };
5837
5838
0
    const char *fieldName = schema->name;
5839
0
    const char *format = schema->format;
5840
0
    if (IsStructure(format))
5841
0
    {
5842
0
        bool bRet = true;
5843
0
        const std::string osNewPrefix(osFieldPrefix + fieldName + ".");
5844
0
        for (int64_t i = 0; i < schema->n_children; ++i)
5845
0
        {
5846
0
            if (!IsArrowSchemaSupportedInternal(schema->children[i],
5847
0
                                                osNewPrefix, osErrorMsg))
5848
0
                bRet = false;
5849
0
        }
5850
0
        return bRet;
5851
0
    }
5852
5853
0
    if (schema->dictionary)
5854
0
    {
5855
0
        if (!IsValidDictionaryIndexType(format))
5856
0
        {
5857
0
            AppendError("Dictionary only supported if the parent is of "
5858
0
                        "type [U]Int[8|16|32|64]");
5859
0
            return false;
5860
0
        }
5861
5862
0
        schema = schema->dictionary;
5863
0
        format = schema->format;
5864
0
    }
5865
5866
0
    if (IsList(format) || IsLargeList(format) || IsFixedSizeList(format))
5867
0
    {
5868
        // Only some subtypes supported
5869
0
        const char *childFormat = schema->children[0]->format;
5870
0
        for (const auto &sType : gasListTypes)
5871
0
        {
5872
0
            if (childFormat[0] == sType.arrowLetter && childFormat[1] == 0)
5873
0
            {
5874
0
                return true;
5875
0
            }
5876
0
        }
5877
5878
0
        if (IsDecimal(childFormat))
5879
0
        {
5880
0
            int nPrecision = 0;
5881
0
            int nScale = 0;
5882
0
            int nWidthInBytes = 0;
5883
0
            if (!ParseDecimalFormat(childFormat, nPrecision, nScale,
5884
0
                                    nWidthInBytes))
5885
0
            {
5886
0
                AppendError(std::string("Invalid field format ") + childFormat +
5887
0
                            " for field " + osFieldPrefix + fieldName);
5888
0
                return false;
5889
0
            }
5890
5891
0
            const char *pszError =
5892
0
                GetErrorIfUnsupportedDecimal(nWidthInBytes, nPrecision);
5893
0
            if (pszError)
5894
0
            {
5895
0
                AppendError(pszError);
5896
0
                return false;
5897
0
            }
5898
5899
0
            return true;
5900
0
        }
5901
5902
0
        if (IsSupportForJSONObj(schema))
5903
0
        {
5904
0
            return true;
5905
0
        }
5906
5907
0
        AppendError("Type list for field " + osFieldPrefix + fieldName +
5908
0
                    " is not supported.");
5909
0
        return false;
5910
0
    }
5911
5912
0
    else if (IsMap(format))
5913
0
    {
5914
0
        if (IsSupportForJSONObj(schema))
5915
0
            return true;
5916
5917
0
        AppendError("Type map for field " + osFieldPrefix + fieldName +
5918
0
                    " is not supported.");
5919
0
        return false;
5920
0
    }
5921
0
    else if (IsDecimal(format))
5922
0
    {
5923
0
        int nPrecision = 0;
5924
0
        int nScale = 0;
5925
0
        int nWidthInBytes = 0;
5926
0
        if (!ParseDecimalFormat(format, nPrecision, nScale, nWidthInBytes))
5927
0
        {
5928
0
            AppendError(std::string("Invalid field format ") + format +
5929
0
                        " for field " + osFieldPrefix + fieldName);
5930
0
            return false;
5931
0
        }
5932
5933
0
        const char *pszError =
5934
0
            GetErrorIfUnsupportedDecimal(nWidthInBytes, nPrecision);
5935
0
        if (pszError)
5936
0
        {
5937
0
            AppendError(pszError);
5938
0
            return false;
5939
0
        }
5940
5941
0
        return true;
5942
0
    }
5943
0
    else
5944
0
    {
5945
0
        for (const auto &sType : gasArrowTypesToOGR)
5946
0
        {
5947
0
            if (strcmp(format, sType.arrowType) == 0)
5948
0
            {
5949
0
                return true;
5950
0
            }
5951
0
        }
5952
5953
0
        if (IsFixedWidthBinary(format) || IsTimestamp(format))
5954
0
            return true;
5955
5956
0
        AppendError("Type '" + std::string(format) + "' for field " +
5957
0
                    osFieldPrefix + fieldName + " is not supported.");
5958
0
        return false;
5959
0
    }
5960
0
}
5961
5962
/** Returns whether the provided ArrowSchema is supported for writing.
5963
 *
5964
 * This method exists since not all drivers may support all Arrow data types.
5965
 *
5966
 * The ArrowSchema must be of type struct (format=+s)
5967
 *
5968
 * It is recommended to call this method before calling WriteArrowBatch().
5969
 *
5970
 * This is the same as the C function OGR_L_IsArrowSchemaSupported().
5971
 *
5972
 * @param schema Schema of type struct (format = '+s')
5973
 * @param papszOptions Options (none currently). Null terminated list, or nullptr.
5974
 * @param[out] osErrorMsg Reason of the failure, when this method returns false.
5975
 * @return true if the ArrowSchema is supported for writing.
5976
 * @since 3.8
5977
 */
5978
bool OGRLayer::IsArrowSchemaSupported(const struct ArrowSchema *schema,
5979
                                      CPL_UNUSED CSLConstList papszOptions,
5980
                                      std::string &osErrorMsg) const
5981
0
{
5982
0
    if (!IsStructure(schema->format))
5983
0
    {
5984
0
        osErrorMsg =
5985
0
            "IsArrowSchemaSupported() should be called on a schema that is a "
5986
0
            "struct of fields";
5987
0
        return false;
5988
0
    }
5989
5990
0
    bool bRet = true;
5991
0
    for (int64_t i = 0; i < schema->n_children; ++i)
5992
0
    {
5993
0
        if (!IsArrowSchemaSupportedInternal(schema->children[i], std::string(),
5994
0
                                            osErrorMsg))
5995
0
            bRet = false;
5996
0
    }
5997
0
    return bRet;
5998
0
}
5999
6000
/************************************************************************/
6001
/*                  OGR_L_IsArrowSchemaSupported()                      */
6002
/************************************************************************/
6003
6004
/** Returns whether the provided ArrowSchema is supported for writing.
6005
 *
6006
 * This function exists since not all drivers may support all Arrow data types.
6007
 *
6008
 * The ArrowSchema must be of type struct (format=+s)
6009
 *
6010
 * It is recommended to call this function before calling OGR_L_WriteArrowBatch().
6011
 *
6012
 * This is the same as the C++ method OGRLayer::IsArrowSchemaSupported().
6013
 *
6014
 * @param hLayer Layer.
6015
 * @param schema Schema of type struct (format = '+s')
6016
 * @param papszOptions Options (none currently). Null terminated list, or nullptr.
6017
 * @param[out] ppszErrorMsg nullptr, or pointer to a string that will contain
6018
 * the reason of the failure, when this function returns false.
6019
 * @return true if the ArrowSchema is supported for writing.
6020
 * @since 3.8
6021
 */
6022
bool OGR_L_IsArrowSchemaSupported(OGRLayerH hLayer,
6023
                                  const struct ArrowSchema *schema,
6024
                                  char **papszOptions, char **ppszErrorMsg)
6025
0
{
6026
0
    VALIDATE_POINTER1(hLayer, __func__, false);
6027
0
    VALIDATE_POINTER1(schema, __func__, false);
6028
6029
0
    std::string osErrorMsg;
6030
0
    if (!OGRLayer::FromHandle(hLayer)->IsArrowSchemaSupported(
6031
0
            schema, papszOptions, osErrorMsg))
6032
0
    {
6033
0
        if (ppszErrorMsg)
6034
0
            *ppszErrorMsg = VSIStrdup(osErrorMsg.c_str());
6035
0
        return false;
6036
0
    }
6037
0
    else
6038
0
    {
6039
0
        if (ppszErrorMsg)
6040
0
            *ppszErrorMsg = nullptr;
6041
0
        return true;
6042
0
    }
6043
0
}
6044
6045
/************************************************************************/
6046
/*                     IsKnownCodedFieldDomain()                        */
6047
/************************************************************************/
6048
6049
static bool IsKnownCodedFieldDomain(OGRLayer *poLayer,
6050
                                    const char *arrowMetadata)
6051
0
{
6052
0
    if (arrowMetadata)
6053
0
    {
6054
0
        const auto oMetadata = OGRParseArrowMetadata(arrowMetadata);
6055
0
        for (const auto &oIter : oMetadata)
6056
0
        {
6057
0
            if (oIter.first == MD_GDAL_OGR_DOMAIN_NAME)
6058
0
            {
6059
0
                auto poDS = poLayer->GetDataset();
6060
0
                if (poDS)
6061
0
                {
6062
0
                    const auto poFieldDomain =
6063
0
                        poDS->GetFieldDomain(oIter.second);
6064
0
                    if (poFieldDomain &&
6065
0
                        poFieldDomain->GetDomainType() == OFDT_CODED)
6066
0
                    {
6067
0
                        return true;
6068
0
                    }
6069
0
                }
6070
0
            }
6071
0
        }
6072
0
    }
6073
0
    return false;
6074
0
}
6075
6076
/************************************************************************/
6077
/*                OGRLayer::CreateFieldFromArrowSchema()                */
6078
/************************************************************************/
6079
6080
//! @cond Doxygen_Suppress
6081
bool OGRLayer::CreateFieldFromArrowSchemaInternal(
6082
    const struct ArrowSchema *schema, const std::string &osFieldPrefix,
6083
    CSLConstList papszOptions)
6084
0
{
6085
0
    const char *fieldName = schema->name;
6086
0
    const char *format = schema->format;
6087
0
    if (IsStructure(format))
6088
0
    {
6089
0
        const std::string osNewPrefix(osFieldPrefix + fieldName + ".");
6090
0
        for (int64_t i = 0; i < schema->n_children; ++i)
6091
0
        {
6092
0
            if (!CreateFieldFromArrowSchemaInternal(schema->children[i],
6093
0
                                                    osNewPrefix, papszOptions))
6094
0
                return false;
6095
0
        }
6096
0
        return true;
6097
0
    }
6098
6099
0
    CPLStringList aosNativeTypes;
6100
0
    auto poLayer = const_cast<OGRLayer *>(this);
6101
0
    auto poDS = poLayer->GetDataset();
6102
0
    if (poDS)
6103
0
    {
6104
0
        auto poDriver = poDS->GetDriver();
6105
0
        if (poDriver)
6106
0
        {
6107
0
            const char *pszMetadataItem =
6108
0
                poDriver->GetMetadataItem(GDAL_DMD_CREATIONFIELDDATATYPES);
6109
0
            if (pszMetadataItem)
6110
0
                aosNativeTypes = CSLTokenizeString2(pszMetadataItem, " ", 0);
6111
0
        }
6112
0
    }
6113
6114
0
    if (schema->dictionary &&
6115
0
        !IsKnownCodedFieldDomain(poLayer, schema->metadata))
6116
0
    {
6117
0
        if (!IsValidDictionaryIndexType(format))
6118
0
        {
6119
0
            CPLError(CE_Failure, CPLE_NotSupported,
6120
0
                     "Dictionary only supported if the parent is of "
6121
0
                     "type [U]Int[8|16|32|64]");
6122
0
            return false;
6123
0
        }
6124
6125
0
        schema = schema->dictionary;
6126
0
        format = schema->format;
6127
0
    }
6128
6129
0
    const auto AddField = [this, schema, fieldName, &aosNativeTypes,
6130
0
                           &osFieldPrefix, poDS](OGRFieldType eTypeIn,
6131
0
                                                 OGRFieldSubType eSubTypeIn,
6132
0
                                                 int nWidth, int nPrecision)
6133
0
    {
6134
0
        const char *pszTypeName = OGRFieldDefn::GetFieldTypeName(eTypeIn);
6135
0
        auto eTypeOut = eTypeIn;
6136
0
        auto eSubTypeOut = eSubTypeIn;
6137
0
        if (!aosNativeTypes.empty() &&
6138
0
            aosNativeTypes.FindString(pszTypeName) < 0)
6139
0
        {
6140
0
            eTypeOut = OFTString;
6141
0
            eSubTypeOut =
6142
0
                (eTypeIn == OFTIntegerList || eTypeIn == OFTInteger64List ||
6143
0
                 eTypeIn == OFTRealList || eTypeIn == OFTStringList)
6144
0
                    ? OFSTJSON
6145
0
                    : OFSTNone;
6146
0
        }
6147
6148
0
        const std::string osWantedOGRFieldName = osFieldPrefix + fieldName;
6149
0
        OGRFieldDefn oFieldDefn(osWantedOGRFieldName.c_str(), eTypeOut);
6150
0
        oFieldDefn.SetSubType(eSubTypeOut);
6151
0
        if (eTypeOut == eTypeIn && eSubTypeOut == eSubTypeIn)
6152
0
        {
6153
0
            oFieldDefn.SetWidth(nWidth);
6154
0
            oFieldDefn.SetPrecision(nPrecision);
6155
0
        }
6156
0
        oFieldDefn.SetNullable((schema->flags & ARROW_FLAG_NULLABLE) != 0);
6157
6158
0
        if (schema->metadata)
6159
0
        {
6160
0
            const auto oMetadata = OGRParseArrowMetadata(schema->metadata);
6161
0
            for (const auto &oIter : oMetadata)
6162
0
            {
6163
0
                if (oIter.first == MD_GDAL_OGR_TYPE)
6164
0
                {
6165
0
                    const auto &osType = oIter.second;
6166
0
                    for (auto eType = OFTInteger; eType <= OFTMaxType;)
6167
0
                    {
6168
0
                        if (OGRFieldDefn::GetFieldTypeName(eType) == osType)
6169
0
                        {
6170
0
                            oFieldDefn.SetType(eType);
6171
0
                            break;
6172
0
                        }
6173
0
                        if (eType == OFTMaxType)
6174
0
                            break;
6175
0
                        else
6176
0
                            eType = static_cast<OGRFieldType>(eType + 1);
6177
0
                    }
6178
0
                }
6179
0
                else if (oIter.first == MD_GDAL_OGR_ALTERNATIVE_NAME)
6180
0
                    oFieldDefn.SetAlternativeName(oIter.second.c_str());
6181
0
                else if (oIter.first == MD_GDAL_OGR_COMMENT)
6182
0
                    oFieldDefn.SetComment(oIter.second);
6183
0
                else if (oIter.first == MD_GDAL_OGR_DEFAULT)
6184
0
                    oFieldDefn.SetDefault(oIter.second.c_str());
6185
0
                else if (oIter.first == MD_GDAL_OGR_SUBTYPE)
6186
0
                {
6187
0
                    if (eTypeIn == eTypeOut)
6188
0
                    {
6189
0
                        const auto &osSubType = oIter.second;
6190
0
                        for (auto eSubType = OFSTNone;
6191
0
                             eSubType <= OFSTMaxSubType;)
6192
0
                        {
6193
0
                            if (OGRFieldDefn::GetFieldSubTypeName(eSubType) ==
6194
0
                                osSubType)
6195
0
                            {
6196
0
                                oFieldDefn.SetSubType(eSubType);
6197
0
                                break;
6198
0
                            }
6199
0
                            if (eSubType == OFSTMaxSubType)
6200
0
                                break;
6201
0
                            else
6202
0
                                eSubType =
6203
0
                                    static_cast<OGRFieldSubType>(eSubType + 1);
6204
0
                        }
6205
0
                    }
6206
0
                }
6207
0
                else if (oIter.first == MD_GDAL_OGR_WIDTH)
6208
0
                    oFieldDefn.SetWidth(atoi(oIter.second.c_str()));
6209
0
                else if (oIter.first == MD_GDAL_OGR_UNIQUE)
6210
0
                    oFieldDefn.SetUnique(oIter.second == "true");
6211
0
                else if (oIter.first == MD_GDAL_OGR_DOMAIN_NAME)
6212
0
                {
6213
0
                    if (poDS && poDS->GetFieldDomain(oIter.second))
6214
0
                        oFieldDefn.SetDomainName(oIter.second);
6215
0
                }
6216
0
                else if (oIter.first == ARROW_EXTENSION_NAME_KEY &&
6217
0
                         oIter.second == EXTENSION_NAME_ARROW_JSON)
6218
0
                {
6219
0
                    oFieldDefn.SetSubType(OFSTJSON);
6220
0
                }
6221
0
                else
6222
0
                {
6223
0
                    CPLDebug("OGR", "Unknown field metadata: %s",
6224
0
                             oIter.first.c_str());
6225
0
                }
6226
0
            }
6227
0
        }
6228
0
        auto poLayerDefn = GetLayerDefn();
6229
0
        const int nFieldCountBefore = poLayerDefn->GetFieldCount();
6230
0
        if (CreateField(&oFieldDefn) != OGRERR_NONE ||
6231
0
            nFieldCountBefore + 1 != poLayerDefn->GetFieldCount())
6232
0
        {
6233
0
            return false;
6234
0
        }
6235
0
        const char *pszActualFieldName =
6236
0
            poLayerDefn->GetFieldDefn(nFieldCountBefore)->GetNameRef();
6237
0
        if (pszActualFieldName != osWantedOGRFieldName)
6238
0
        {
6239
0
            m_poPrivate
6240
0
                ->m_oMapArrowFieldNameToOGRFieldName[osWantedOGRFieldName] =
6241
0
                pszActualFieldName;
6242
0
        }
6243
0
        return true;
6244
0
    };
6245
6246
0
    for (const auto &sType : gasArrowTypesToOGR)
6247
0
    {
6248
0
        if (strcmp(format, sType.arrowType) == 0)
6249
0
        {
6250
0
            return AddField(sType.eType, sType.eSubType, 0, 0);
6251
0
        }
6252
0
    }
6253
6254
0
    if (IsMap(format))
6255
0
    {
6256
0
        return AddField(OFTString, OFSTJSON, 0, 0);
6257
0
    }
6258
6259
0
    if (IsTimestamp(format))
6260
0
    {
6261
0
        return AddField(OFTDateTime, OFSTNone, 0, 0);
6262
0
    }
6263
6264
0
    if (IsFixedWidthBinary(format))
6265
0
    {
6266
0
        return AddField(OFTBinary, OFSTNone, GetFixedWithBinary(format), 0);
6267
0
    }
6268
6269
0
    if (IsList(format) || IsLargeList(format) || IsFixedSizeList(format))
6270
0
    {
6271
0
        const char *childFormat = schema->children[0]->format;
6272
0
        for (const auto &sType : gasListTypes)
6273
0
        {
6274
0
            if (childFormat[0] == sType.arrowLetter && childFormat[1] == 0)
6275
0
            {
6276
0
                return AddField(sType.eType, sType.eSubType, 0, 0);
6277
0
            }
6278
0
        }
6279
6280
0
        if (IsDecimal(childFormat))
6281
0
        {
6282
0
            int nPrecision = 0;
6283
0
            int nScale = 0;
6284
0
            int nWidthInBytes = 0;
6285
0
            if (!ParseDecimalFormat(childFormat, nPrecision, nScale,
6286
0
                                    nWidthInBytes))
6287
0
            {
6288
0
                CPLError(CE_Failure, CPLE_AppDefined, "%s",
6289
0
                         (std::string("Invalid field format ") + format +
6290
0
                          " for field " + osFieldPrefix + fieldName)
6291
0
                             .c_str());
6292
0
                return false;
6293
0
            }
6294
6295
0
            const char *pszError =
6296
0
                GetErrorIfUnsupportedDecimal(nWidthInBytes, nPrecision);
6297
0
            if (pszError)
6298
0
            {
6299
0
                CPLError(CE_Failure, CPLE_NotSupported, "%s", pszError);
6300
0
                return false;
6301
0
            }
6302
6303
            // DBF convention: add space for negative sign and decimal separator
6304
0
            return AddField(OFTRealList, OFSTNone, nPrecision + 2, nScale);
6305
0
        }
6306
6307
0
        if (IsSupportForJSONObj(schema->children[0]))
6308
0
        {
6309
0
            return AddField(OFTString, OFSTJSON, 0, 0);
6310
0
        }
6311
6312
0
        CPLError(CE_Failure, CPLE_NotSupported, "%s",
6313
0
                 ("List of type '" + std::string(childFormat) + "' for field " +
6314
0
                  osFieldPrefix + fieldName + " is not supported.")
6315
0
                     .c_str());
6316
0
        return false;
6317
0
    }
6318
6319
0
    if (IsDecimal(format))
6320
0
    {
6321
0
        int nPrecision = 0;
6322
0
        int nScale = 0;
6323
0
        int nWidthInBytes = 0;
6324
0
        if (!ParseDecimalFormat(format, nPrecision, nScale, nWidthInBytes))
6325
0
        {
6326
0
            CPLError(CE_Failure, CPLE_AppDefined, "%s",
6327
0
                     (std::string("Invalid field format ") + format +
6328
0
                      " for field " + osFieldPrefix + fieldName)
6329
0
                         .c_str());
6330
0
            return false;
6331
0
        }
6332
6333
0
        const char *pszError =
6334
0
            GetErrorIfUnsupportedDecimal(nWidthInBytes, nPrecision);
6335
0
        if (pszError)
6336
0
        {
6337
0
            CPLError(CE_Failure, CPLE_NotSupported, "%s", pszError);
6338
0
            return false;
6339
0
        }
6340
6341
        // DBF convention: add space for negative sign and decimal separator
6342
0
        return AddField(OFTReal, OFSTNone, nPrecision + 2, nScale);
6343
0
    }
6344
6345
0
    CPLError(CE_Failure, CPLE_NotSupported, "%s",
6346
0
             ("Type '" + std::string(format) + "' for field " + osFieldPrefix +
6347
0
              fieldName + " is not supported.")
6348
0
                 .c_str());
6349
0
    return false;
6350
0
}
6351
6352
//! @endcond
6353
6354
/** Creates a field from an ArrowSchema.
6355
 *
6356
 * This should only be used for attribute fields. Geometry fields should
6357
 * be created with CreateGeomField(). The FID field should also not be
6358
 * passed with this method.
6359
 *
6360
 * Contrary to the IsArrowSchemaSupported() and WriteArrowBatch() methods, the
6361
 * passed schema must be for an individual field, and thus, is *not* of type
6362
 * struct (format=+s) (unless writing a set of fields grouped together in the
6363
 * same structure).
6364
 *
6365
 * Additional field metadata can be speciffed through the ArrowSchema::metadata
6366
 * field with the potential following items:
6367
 * <ul>
6368
 * <li>"GDAL:OGR:alternative_name": value of
6369
 *     OGRFieldDefn::GetAlternativeNameRef()</li>
6370
 * <li>"GDAL:OGR:comment": value of OGRFieldDefn::GetComment()</li>
6371
 * <li>"GDAL:OGR:default": value of OGRFieldDefn::GetDefault()</li>
6372
 * <li>"GDAL:OGR:subtype": value of OGRFieldDefn::GetSubType()</li>
6373
 * <li>"GDAL:OGR:width": value of OGRFieldDefn::GetWidth() (serialized as a
6374
 *     string)</li>
6375
 * <li>"GDAL:OGR:unique": value of OGRFieldDefn::IsUnique() (serialized as
6376
 *     "true" or "false")</li>
6377
 * <li>"GDAL:OGR:domain_name": value of OGRFieldDefn::GetDomainName()</li>
6378
 * </ul>
6379
 *
6380
 * This method and CreateField() are mutually exclusive in the same session.
6381
 *
6382
 * This method is the same as the C function OGR_L_CreateFieldFromArrowSchema().
6383
 *
6384
 * @param schema Schema of the field to create.
6385
 * @param papszOptions Options (none currently). Null terminated list, or nullptr.
6386
 * @return true in case of success
6387
 * @since 3.8
6388
 */
6389
bool OGRLayer::CreateFieldFromArrowSchema(const struct ArrowSchema *schema,
6390
                                          CSLConstList papszOptions)
6391
0
{
6392
0
    return CreateFieldFromArrowSchemaInternal(schema, std::string(),
6393
0
                                              papszOptions);
6394
0
}
6395
6396
/************************************************************************/
6397
/*                  OGR_L_CreateFieldFromArrowSchema()                  */
6398
/************************************************************************/
6399
6400
/** Creates a field from an ArrowSchema.
6401
 *
6402
 * This should only be used for attribute fields. Geometry fields should
6403
 * be created with CreateGeomField(). The FID field should also not be
6404
 * passed with this method.
6405
 *
6406
 * Contrary to the IsArrowSchemaSupported() and WriteArrowBatch() methods, the
6407
 * passed schema must be for an individual field, and thus, is *not* of type
6408
 * struct (format=+s) (unless writing a set of fields grouped together in the
6409
 * same structure).
6410
 *
6411
 * Additional field metadata can be speciffed through the ArrowSchema::metadata
6412
 * field with the potential following items:
6413
 * <ul>
6414
 * <li>"GDAL:OGR:alternative_name": value of
6415
 *     OGRFieldDefn::GetAlternativeNameRef()</li>
6416
 * <li>"GDAL:OGR:comment": value of OGRFieldDefn::GetComment()</li>
6417
 * <li>"GDAL:OGR:default": value of OGRFieldDefn::GetDefault()</li>
6418
 * <li>"GDAL:OGR:subtype": value of OGRFieldDefn::GetSubType()</li>
6419
 * <li>"GDAL:OGR:width": value of OGRFieldDefn::GetWidth() (serialized as a
6420
 *     string)</li>
6421
 * <li>"GDAL:OGR:unique": value of OGRFieldDefn::IsUnique() (serialized as
6422
 *     "true" or "false")</li>
6423
 * <li>"GDAL:OGR:domain_name": value of OGRFieldDefn::GetDomainName()</li>
6424
 * </ul>
6425
 *
6426
 * This method and CreateField() are mutually exclusive in the same session.
6427
 *
6428
 * This method is the same as the C++ method OGRLayer::CreateFieldFromArrowSchema().
6429
 *
6430
 * @param hLayer Layer.
6431
 * @param schema Schema of the field to create.
6432
 * @param papszOptions Options (none currently). Null terminated list, or nullptr.
6433
 * @return true in case of success
6434
 * @since 3.8
6435
 */
6436
bool OGR_L_CreateFieldFromArrowSchema(OGRLayerH hLayer,
6437
                                      const struct ArrowSchema *schema,
6438
                                      char **papszOptions)
6439
0
{
6440
0
    VALIDATE_POINTER1(hLayer, __func__, false);
6441
0
    VALIDATE_POINTER1(schema, __func__, false);
6442
6443
0
    return OGRLayer::FromHandle(hLayer)->CreateFieldFromArrowSchema(
6444
0
        schema, papszOptions);
6445
0
}
6446
6447
/************************************************************************/
6448
/*                           BuildOGRFieldInfo()                        */
6449
/************************************************************************/
6450
6451
constexpr int FID_COLUMN_SPECIAL_OGR_FIELD_IDX = -2;
6452
6453
struct FieldInfo
6454
{
6455
    std::string osName{};
6456
    int iOGRFieldIdx = -1;
6457
    const char *format = nullptr;
6458
    OGRFieldType eNominalFieldType =
6459
        OFTMaxType;  // OGR data type that would best match the Arrow type
6460
    OGRFieldType eTargetFieldType =
6461
        OFTMaxType;  // actual OGR data type of the layer field
6462
    // OGR data type of the feature passed to FillFeature()
6463
    OGRFieldType eSetFeatureFieldType = OFTMaxType;
6464
    bool bIsGeomCol = false;
6465
    bool bUseDictionary = false;
6466
    bool bUseStringOptim = false;
6467
    int nWidthInBytes = 0;  // only used for decimal fields
6468
    int nPrecision = 0;     // only used for decimal fields
6469
    int nScale = 0;         // only used for decimal fields
6470
};
6471
6472
static bool BuildOGRFieldInfo(
6473
    const struct ArrowSchema *schema, struct ArrowArray *array,
6474
    const OGRFeatureDefn *poFeatureDefn, const std::string &osFieldPrefix,
6475
    const CPLStringList &aosNativeTypes, bool &bFallbackTypesUsed,
6476
    std::vector<FieldInfo> &asFieldInfo, const char *pszFIDName,
6477
    const char *pszGeomFieldName, OGRLayer *poLayer,
6478
    const std::map<std::string, std::string> &oMapArrowFieldNameToOGRFieldName,
6479
    const struct ArrowSchema *&schemaFIDColumn,
6480
    struct ArrowArray *&arrayFIDColumn)
6481
0
{
6482
0
    const char *fieldName = schema->name;
6483
0
    const char *format = schema->format;
6484
0
    if (IsStructure(format))
6485
0
    {
6486
0
        const std::string osNewPrefix(osFieldPrefix + fieldName + ".");
6487
0
        for (int64_t i = 0; i < array->n_children; ++i)
6488
0
        {
6489
0
            if (!BuildOGRFieldInfo(schema->children[i], array->children[i],
6490
0
                                   poFeatureDefn, osNewPrefix, aosNativeTypes,
6491
0
                                   bFallbackTypesUsed, asFieldInfo, pszFIDName,
6492
0
                                   pszGeomFieldName, poLayer,
6493
0
                                   oMapArrowFieldNameToOGRFieldName,
6494
0
                                   schemaFIDColumn, arrayFIDColumn))
6495
0
            {
6496
0
                return false;
6497
0
            }
6498
0
        }
6499
0
        return true;
6500
0
    }
6501
6502
0
    FieldInfo sInfo;
6503
6504
0
    if (schema->dictionary &&
6505
0
        !IsKnownCodedFieldDomain(poLayer, schema->metadata))
6506
0
    {
6507
0
        if (!IsValidDictionaryIndexType(format))
6508
0
        {
6509
0
            CPLError(CE_Failure, CPLE_NotSupported,
6510
0
                     "Dictionary only supported if the parent is of "
6511
0
                     "type [U]Int[8|16|32|64]");
6512
0
            return false;
6513
0
        }
6514
6515
0
        sInfo.bUseDictionary = true;
6516
0
        schema = schema->dictionary;
6517
0
        format = schema->format;
6518
0
        array = array->dictionary;
6519
0
    }
6520
6521
0
    sInfo.osName = osFieldPrefix + fieldName;
6522
0
    sInfo.format = format;
6523
0
    if (pszFIDName && sInfo.osName == pszFIDName)
6524
0
    {
6525
0
        if (IsInt32(format) || IsInt64(format))
6526
0
        {
6527
0
            sInfo.iOGRFieldIdx = FID_COLUMN_SPECIAL_OGR_FIELD_IDX;
6528
0
            schemaFIDColumn = schema;
6529
0
            arrayFIDColumn = array;
6530
0
        }
6531
0
        else
6532
0
        {
6533
0
            CPLError(CE_Failure, CPLE_AppDefined,
6534
0
                     "FID column '%s' should be of Arrow format 'i' "
6535
0
                     "(int32) or 'l' (int64)",
6536
0
                     sInfo.osName.c_str());
6537
0
            return false;
6538
0
        }
6539
0
    }
6540
0
    else
6541
0
    {
6542
0
        const std::string &osExpectedOGRFieldName =
6543
0
            [&oMapArrowFieldNameToOGRFieldName, &sInfo]() -> const std::string &
6544
0
        {
6545
0
            const auto oIter =
6546
0
                oMapArrowFieldNameToOGRFieldName.find(sInfo.osName);
6547
0
            if (oIter != oMapArrowFieldNameToOGRFieldName.end())
6548
0
                return oIter->second;
6549
0
            return sInfo.osName;
6550
0
        }();
6551
0
        sInfo.iOGRFieldIdx =
6552
0
            poFeatureDefn->GetFieldIndex(osExpectedOGRFieldName.c_str());
6553
0
        if (sInfo.iOGRFieldIdx >= 0)
6554
0
        {
6555
0
            bool bTypeOK = false;
6556
0
            const auto eOGRType =
6557
0
                poFeatureDefn->GetFieldDefn(sInfo.iOGRFieldIdx)->GetType();
6558
0
            sInfo.eTargetFieldType = eOGRType;
6559
0
            for (const auto &sType : gasArrowTypesToOGR)
6560
0
            {
6561
0
                if (strcmp(format, sType.arrowType) == 0)
6562
0
                {
6563
0
                    sInfo.bUseStringOptim = sType.eType == OFTString;
6564
0
                    sInfo.eNominalFieldType = sType.eType;
6565
0
                    if (eOGRType == sInfo.eNominalFieldType)
6566
0
                    {
6567
0
                        bTypeOK = true;
6568
0
                        break;
6569
0
                    }
6570
0
                    else if (eOGRType == OFTString)
6571
0
                    {
6572
0
                        bFallbackTypesUsed = true;
6573
0
                        bTypeOK = true;
6574
0
                        break;
6575
0
                    }
6576
0
                    else if (eOGRType == OFTInteger &&
6577
0
                             sType.eType == OFTInteger64)
6578
0
                    {
6579
                        // Potentially lossy.
6580
0
                        CPLDebug("OGR",
6581
0
                                 "For field %s, writing from Arrow array of "
6582
0
                                 "type Int64 into OGR Int32 field. "
6583
0
                                 "Potentially loss conversion can happen",
6584
0
                                 sInfo.osName.c_str());
6585
0
                        bFallbackTypesUsed = true;
6586
0
                        bTypeOK = true;
6587
0
                        break;
6588
0
                    }
6589
0
                    else if (eOGRType == OFTInteger && sType.eType == OFTReal)
6590
0
                    {
6591
                        // Potentially lossy.
6592
0
                        CPLDebug("OGR",
6593
0
                                 "For field %s, writing from Arrow array of "
6594
0
                                 "type Real into OGR Int32 field. "
6595
0
                                 "Potentially loss conversion can happen",
6596
0
                                 sInfo.osName.c_str());
6597
0
                        bFallbackTypesUsed = true;
6598
0
                        bTypeOK = true;
6599
0
                        break;
6600
0
                    }
6601
0
                    else if (eOGRType == OFTInteger64 && sType.eType == OFTReal)
6602
0
                    {
6603
                        // Potentially lossy.
6604
0
                        CPLDebug("OGR",
6605
0
                                 "For field %s, writing from Arrow array of "
6606
0
                                 "type Real into OGR Int64 field. "
6607
0
                                 "Potentially loss conversion can happen",
6608
0
                                 sInfo.osName.c_str());
6609
0
                        bFallbackTypesUsed = true;
6610
0
                        bTypeOK = true;
6611
0
                        break;
6612
0
                    }
6613
0
                    else if (eOGRType == OFTReal && sType.eType == OFTInteger64)
6614
0
                    {
6615
                        // Potentially lossy.
6616
0
                        CPLDebug("OGR",
6617
0
                                 "For field %s, writing from Arrow array of "
6618
0
                                 "type Int64 into OGR Real field. "
6619
0
                                 "Potentially loss conversion can happen",
6620
0
                                 sInfo.osName.c_str());
6621
0
                        bFallbackTypesUsed = true;
6622
0
                        bTypeOK = true;
6623
0
                        break;
6624
0
                    }
6625
0
                    else if ((eOGRType == OFTInteger64 ||
6626
0
                              eOGRType == OFTReal) &&
6627
0
                             sType.eType == OFTInteger)
6628
0
                    {
6629
                        // Non-lossy
6630
0
                        bFallbackTypesUsed = true;
6631
0
                        bTypeOK = true;
6632
0
                        break;
6633
0
                    }
6634
0
                    else if (eOGRType == OFTDateTime &&
6635
0
                             sType.eType == OFTString)
6636
0
                    {
6637
0
                        bFallbackTypesUsed = true;
6638
0
                        bTypeOK = true;
6639
0
                        break;
6640
0
                    }
6641
0
                    else
6642
0
                    {
6643
0
                        CPLError(CE_Failure, CPLE_AppDefined,
6644
0
                                 "For field %s, OGR field type is %s whereas "
6645
0
                                 "Arrow type implies %s",
6646
0
                                 sInfo.osName.c_str(),
6647
0
                                 OGR_GetFieldTypeName(eOGRType),
6648
0
                                 OGR_GetFieldTypeName(sType.eType));
6649
0
                        return false;
6650
0
                    }
6651
0
                }
6652
0
            }
6653
6654
0
            if (!bTypeOK && IsMap(format))
6655
0
            {
6656
0
                sInfo.eNominalFieldType = OFTString;
6657
0
                if (eOGRType == sInfo.eNominalFieldType)
6658
0
                {
6659
0
                    bTypeOK = true;
6660
0
                }
6661
0
                else
6662
0
                {
6663
0
                    CPLError(CE_Failure, CPLE_AppDefined,
6664
0
                             "For field %s, OGR field type is %s whereas "
6665
0
                             "Arrow type implies %s",
6666
0
                             sInfo.osName.c_str(),
6667
0
                             OGR_GetFieldTypeName(eOGRType),
6668
0
                             OGR_GetFieldTypeName(OFTString));
6669
0
                    return false;
6670
0
                }
6671
0
            }
6672
6673
0
            if (!bTypeOK && IsTimestamp(format))
6674
0
            {
6675
0
                sInfo.eNominalFieldType = OFTDateTime;
6676
0
                if (eOGRType == sInfo.eNominalFieldType)
6677
0
                {
6678
0
                    bTypeOK = true;
6679
0
                }
6680
0
                else if (eOGRType == OFTString)
6681
0
                {
6682
0
                    bFallbackTypesUsed = true;
6683
0
                    bTypeOK = true;
6684
0
                }
6685
0
                else
6686
0
                {
6687
0
                    CPLError(CE_Failure, CPLE_AppDefined,
6688
0
                             "For field %s, OGR field type is %s whereas "
6689
0
                             "Arrow type implies %s",
6690
0
                             sInfo.osName.c_str(),
6691
0
                             OGR_GetFieldTypeName(eOGRType),
6692
0
                             OGR_GetFieldTypeName(OFTDateTime));
6693
0
                    return false;
6694
0
                }
6695
0
            }
6696
6697
0
            if (!bTypeOK && IsFixedWidthBinary(format))
6698
0
            {
6699
0
                sInfo.eNominalFieldType = OFTBinary;
6700
0
                if (eOGRType == sInfo.eNominalFieldType)
6701
0
                {
6702
0
                    bTypeOK = true;
6703
0
                }
6704
0
                else if (eOGRType == OFTString)
6705
0
                {
6706
0
                    bFallbackTypesUsed = true;
6707
0
                    bTypeOK = true;
6708
0
                }
6709
0
                else
6710
0
                {
6711
0
                    CPLError(CE_Failure, CPLE_AppDefined,
6712
0
                             "For field %s, OGR field type is %s whereas "
6713
0
                             "Arrow type implies %s",
6714
0
                             sInfo.osName.c_str(),
6715
0
                             OGR_GetFieldTypeName(eOGRType),
6716
0
                             OGR_GetFieldTypeName(OFTBinary));
6717
0
                    return false;
6718
0
                }
6719
0
            }
6720
6721
0
            if (!bTypeOK && (IsList(format) || IsLargeList(format) ||
6722
0
                             IsFixedSizeList(format)))
6723
0
            {
6724
0
                const char *childFormat = schema->children[0]->format;
6725
0
                for (const auto &sType : gasListTypes)
6726
0
                {
6727
0
                    if (childFormat[0] == sType.arrowLetter &&
6728
0
                        childFormat[1] == 0)
6729
0
                    {
6730
0
                        sInfo.eNominalFieldType = sType.eType;
6731
0
                        if (eOGRType == sInfo.eNominalFieldType)
6732
0
                        {
6733
0
                            bTypeOK = true;
6734
0
                            break;
6735
0
                        }
6736
0
                        else if (eOGRType == OFTString)
6737
0
                        {
6738
0
                            bFallbackTypesUsed = true;
6739
0
                            bTypeOK = true;
6740
0
                            break;
6741
0
                        }
6742
0
                        else
6743
0
                        {
6744
0
                            CPLError(CE_Failure, CPLE_AppDefined,
6745
0
                                     "For field %s, OGR field type is %s "
6746
0
                                     "whereas "
6747
0
                                     "Arrow type implies %s",
6748
0
                                     sInfo.osName.c_str(),
6749
0
                                     OGR_GetFieldTypeName(eOGRType),
6750
0
                                     OGR_GetFieldTypeName(sType.eType));
6751
0
                            return false;
6752
0
                        }
6753
0
                    }
6754
0
                }
6755
6756
0
                if (!bTypeOK && IsDecimal(childFormat))
6757
0
                {
6758
0
                    if (!ParseDecimalFormat(childFormat, sInfo.nPrecision,
6759
0
                                            sInfo.nScale, sInfo.nWidthInBytes))
6760
0
                    {
6761
0
                        CPLError(CE_Failure, CPLE_AppDefined, "%s",
6762
0
                                 (std::string("Invalid field format ") +
6763
0
                                  childFormat + " for field " + osFieldPrefix +
6764
0
                                  fieldName)
6765
0
                                     .c_str());
6766
0
                        return false;
6767
0
                    }
6768
6769
0
                    const char *pszError = GetErrorIfUnsupportedDecimal(
6770
0
                        sInfo.nWidthInBytes, sInfo.nPrecision);
6771
0
                    if (pszError)
6772
0
                    {
6773
0
                        CPLError(CE_Failure, CPLE_NotSupported, "%s", pszError);
6774
0
                        return false;
6775
0
                    }
6776
6777
0
                    sInfo.eNominalFieldType = OFTRealList;
6778
0
                    if (eOGRType == sInfo.eNominalFieldType)
6779
0
                    {
6780
0
                        bTypeOK = true;
6781
0
                    }
6782
0
                    else if (eOGRType == OFTString)
6783
0
                    {
6784
0
                        bFallbackTypesUsed = true;
6785
0
                        bTypeOK = true;
6786
0
                    }
6787
0
                    else
6788
0
                    {
6789
0
                        CPLError(CE_Failure, CPLE_AppDefined,
6790
0
                                 "For field %s, OGR field type is %s whereas "
6791
0
                                 "Arrow type implies %s",
6792
0
                                 sInfo.osName.c_str(),
6793
0
                                 OGR_GetFieldTypeName(eOGRType),
6794
0
                                 OGR_GetFieldTypeName(OFTRealList));
6795
0
                        return false;
6796
0
                    }
6797
0
                }
6798
6799
0
                if (!bTypeOK && IsSupportForJSONObj(schema->children[0]))
6800
0
                {
6801
0
                    sInfo.eNominalFieldType = OFTString;
6802
0
                    if (eOGRType == sInfo.eNominalFieldType)
6803
0
                    {
6804
0
                        bTypeOK = true;
6805
0
                    }
6806
0
                    else
6807
0
                    {
6808
0
                        CPLError(CE_Failure, CPLE_AppDefined,
6809
0
                                 "For field %s, OGR field type is %s whereas "
6810
0
                                 "Arrow type implies %s",
6811
0
                                 sInfo.osName.c_str(),
6812
0
                                 OGR_GetFieldTypeName(eOGRType),
6813
0
                                 OGR_GetFieldTypeName(OFTString));
6814
0
                        return false;
6815
0
                    }
6816
0
                }
6817
6818
0
                if (!bTypeOK)
6819
0
                {
6820
0
                    CPLError(CE_Failure, CPLE_NotSupported, "%s",
6821
0
                             ("List of type '" + std::string(childFormat) +
6822
0
                              "' for field " + osFieldPrefix + fieldName +
6823
0
                              " is not supported.")
6824
0
                                 .c_str());
6825
0
                    return false;
6826
0
                }
6827
0
            }
6828
6829
0
            if (!bTypeOK && IsDecimal(format))
6830
0
            {
6831
0
                if (!ParseDecimalFormat(format, sInfo.nPrecision, sInfo.nScale,
6832
0
                                        sInfo.nWidthInBytes))
6833
0
                {
6834
0
                    CPLError(CE_Failure, CPLE_AppDefined, "%s",
6835
0
                             (std::string("Invalid field format ") + format +
6836
0
                              " for field " + osFieldPrefix + fieldName)
6837
0
                                 .c_str());
6838
0
                    return false;
6839
0
                }
6840
6841
0
                const char *pszError = GetErrorIfUnsupportedDecimal(
6842
0
                    sInfo.nWidthInBytes, sInfo.nPrecision);
6843
0
                if (pszError)
6844
0
                {
6845
0
                    CPLError(CE_Failure, CPLE_NotSupported, "%s", pszError);
6846
0
                    return false;
6847
0
                }
6848
6849
0
                sInfo.eNominalFieldType = OFTReal;
6850
0
                if (eOGRType == sInfo.eNominalFieldType)
6851
0
                {
6852
0
                    bTypeOK = true;
6853
0
                }
6854
0
                else if (eOGRType == OFTString)
6855
0
                {
6856
0
                    bFallbackTypesUsed = true;
6857
0
                    bTypeOK = true;
6858
0
                }
6859
0
                else
6860
0
                {
6861
0
                    CPLError(CE_Failure, CPLE_AppDefined,
6862
0
                             "For field %s, OGR field type is %s whereas "
6863
0
                             "Arrow type implies %s",
6864
0
                             sInfo.osName.c_str(),
6865
0
                             OGR_GetFieldTypeName(eOGRType),
6866
0
                             OGR_GetFieldTypeName(OFTReal));
6867
0
                    return false;
6868
0
                }
6869
0
            }
6870
6871
0
            if (!bTypeOK)
6872
0
            {
6873
0
                CPLError(CE_Failure, CPLE_NotSupported, "%s",
6874
0
                         ("Type '" + std::string(format) + "' for field " +
6875
0
                          osFieldPrefix + fieldName + " is not supported.")
6876
0
                             .c_str());
6877
0
                return false;
6878
0
            }
6879
0
        }
6880
0
        else
6881
0
        {
6882
0
            sInfo.iOGRFieldIdx = poFeatureDefn->GetGeomFieldIndex(
6883
0
                osExpectedOGRFieldName.c_str());
6884
0
            if (sInfo.iOGRFieldIdx < 0)
6885
0
            {
6886
0
                if (pszGeomFieldName && pszGeomFieldName == sInfo.osName)
6887
0
                {
6888
0
                    if (poFeatureDefn->GetGeomFieldCount() == 0)
6889
0
                    {
6890
0
                        CPLError(CE_Failure, CPLE_AppDefined,
6891
0
                                 "Cannot find OGR geometry field for Arrow "
6892
0
                                 "array %s",
6893
0
                                 sInfo.osName.c_str());
6894
0
                        return false;
6895
0
                    }
6896
0
                    sInfo.iOGRFieldIdx = 0;
6897
0
                }
6898
0
                else
6899
0
                {
6900
                    // Check if ARROW:extension:name = ogc.wkb or geoarrow.wkb
6901
0
                    const char *pabyMetadata = schema->metadata;
6902
0
                    if (pabyMetadata)
6903
0
                    {
6904
0
                        const auto oMetadata =
6905
0
                            OGRParseArrowMetadata(pabyMetadata);
6906
0
                        auto oIter = oMetadata.find(ARROW_EXTENSION_NAME_KEY);
6907
0
                        if (oIter != oMetadata.end() &&
6908
0
                            (oIter->second == EXTENSION_NAME_OGC_WKB ||
6909
0
                             oIter->second == EXTENSION_NAME_GEOARROW_WKB))
6910
0
                        {
6911
0
                            if (poFeatureDefn->GetGeomFieldCount() == 0)
6912
0
                            {
6913
0
                                CPLError(CE_Failure, CPLE_AppDefined,
6914
0
                                         "Cannot find OGR geometry field "
6915
0
                                         "for Arrow array %s",
6916
0
                                         sInfo.osName.c_str());
6917
0
                                return false;
6918
0
                            }
6919
0
                            sInfo.iOGRFieldIdx = 0;
6920
0
                        }
6921
0
                    }
6922
0
                }
6923
6924
0
                if (sInfo.iOGRFieldIdx < 0)
6925
0
                {
6926
0
                    CPLError(CE_Failure, CPLE_AppDefined,
6927
0
                             "Cannot find OGR field for Arrow array %s",
6928
0
                             sInfo.osName.c_str());
6929
0
                    return false;
6930
0
                }
6931
0
            }
6932
6933
0
            if (!IsBinary(format) && !IsLargeBinary(format))
6934
0
            {
6935
0
                CPLError(CE_Failure, CPLE_AppDefined,
6936
0
                         "Geometry column '%s' should be of Arrow format "
6937
0
                         "'z' (binary) or 'Z' (large binary)",
6938
0
                         sInfo.osName.c_str());
6939
0
                return false;
6940
0
            }
6941
0
            sInfo.bIsGeomCol = true;
6942
0
        }
6943
0
    }
6944
6945
0
    asFieldInfo.emplace_back(std::move(sInfo));
6946
0
    return true;
6947
0
}
6948
6949
/************************************************************************/
6950
/*                           GetUInt64Value()                           */
6951
/************************************************************************/
6952
6953
static inline uint64_t GetUInt64Value(const struct ArrowSchema *schema,
6954
                                      const struct ArrowArray *array,
6955
                                      size_t iFeature)
6956
0
{
6957
0
    uint64_t nVal = 0;
6958
0
    CPLAssert(schema->format[1] == 0);
6959
0
    switch (schema->format[0])
6960
0
    {
6961
0
        case ARROW_LETTER_INT8:
6962
0
            nVal = GetValue<int8_t>(array, iFeature);
6963
0
            break;
6964
0
        case ARROW_LETTER_UINT8:
6965
0
            nVal = GetValue<uint8_t>(array, iFeature);
6966
0
            break;
6967
0
        case ARROW_LETTER_INT16:
6968
0
            nVal = GetValue<int16_t>(array, iFeature);
6969
0
            break;
6970
0
        case ARROW_LETTER_UINT16:
6971
0
            nVal = GetValue<uint16_t>(array, iFeature);
6972
0
            break;
6973
0
        case ARROW_LETTER_INT32:
6974
0
            nVal = GetValue<int32_t>(array, iFeature);
6975
0
            break;
6976
0
        case ARROW_LETTER_UINT32:
6977
0
            nVal = GetValue<uint32_t>(array, iFeature);
6978
0
            break;
6979
0
        case ARROW_LETTER_INT64:
6980
0
            nVal = GetValue<int64_t>(array, iFeature);
6981
0
            break;
6982
0
        case ARROW_LETTER_UINT64:
6983
0
            nVal = GetValue<uint64_t>(array, iFeature);
6984
0
            break;
6985
0
        default:
6986
            // Shouldn't happen given checks in BuildOGRFieldInfo()
6987
0
            CPLAssert(false);
6988
0
            break;
6989
0
    }
6990
0
    return nVal;
6991
0
}
6992
6993
/************************************************************************/
6994
/*                         GetWorkingBufferSize()                       */
6995
/************************************************************************/
6996
6997
static size_t GetWorkingBufferSize(const struct ArrowSchema *schema,
6998
                                   const struct ArrowArray *array,
6999
                                   size_t iFeature, int &iArrowIdxInOut,
7000
                                   const std::vector<FieldInfo> &asFieldInfo)
7001
0
{
7002
0
    const char *fieldName = schema->name;
7003
0
    const char *format = schema->format;
7004
0
    if (IsStructure(format))
7005
0
    {
7006
0
        size_t nRet = 0;
7007
0
        for (int64_t i = 0; i < array->n_children; ++i)
7008
0
        {
7009
0
            nRet += GetWorkingBufferSize(
7010
0
                schema->children[i], array->children[i],
7011
0
                iFeature + static_cast<size_t>(array->offset), iArrowIdxInOut,
7012
0
                asFieldInfo);
7013
0
        }
7014
0
        return nRet;
7015
0
    }
7016
0
    const int iArrowIdx = iArrowIdxInOut;
7017
0
    ++iArrowIdxInOut;
7018
7019
0
    if (!asFieldInfo[iArrowIdx].bUseStringOptim)
7020
0
        return 0;
7021
7022
0
    const uint8_t *pabyValidity =
7023
0
        static_cast<const uint8_t *>(array->buffers[0]);
7024
0
    if (array->null_count != 0 && pabyValidity &&
7025
0
        !TestBit(pabyValidity, static_cast<size_t>(iFeature + array->offset)))
7026
0
    {
7027
        // empty string
7028
0
        return 0;
7029
0
    }
7030
7031
0
    if (asFieldInfo[iArrowIdx].bUseDictionary)
7032
0
    {
7033
0
        const uint64_t nDictIdx = GetUInt64Value(schema, array, iFeature);
7034
0
        const auto dictArray = array->dictionary;
7035
0
        if (nDictIdx >= static_cast<uint64_t>(dictArray->length))
7036
0
        {
7037
0
            CPLError(CE_Failure, CPLE_AppDefined,
7038
0
                     "Feature %" PRIu64
7039
0
                     ", field %s: invalid dictionary index: %" PRIu64,
7040
0
                     static_cast<uint64_t>(iFeature), fieldName, nDictIdx);
7041
0
            return 0;
7042
0
        }
7043
7044
0
        array = dictArray;
7045
0
        schema = schema->dictionary;
7046
0
        format = schema->format;
7047
0
        iFeature = static_cast<size_t>(nDictIdx);
7048
0
    }
7049
7050
0
    if (IsString(format))
7051
0
    {
7052
0
        const auto *panOffsets =
7053
0
            static_cast<const uint32_t *>(array->buffers[1]) + array->offset;
7054
0
        return 1 + (panOffsets[iFeature + 1] - panOffsets[iFeature]);
7055
0
    }
7056
0
    else if (IsLargeString(format))
7057
0
    {
7058
0
        const auto *panOffsets =
7059
0
            static_cast<const uint64_t *>(array->buffers[1]) + array->offset;
7060
0
        return 1 + static_cast<size_t>(panOffsets[iFeature + 1] -
7061
0
                                       panOffsets[iFeature]);
7062
0
    }
7063
0
    return 0;
7064
0
}
7065
7066
/************************************************************************/
7067
/*                              FillField()                             */
7068
/************************************************************************/
7069
7070
template <typename ArrowType, typename OGRType = ArrowType>
7071
inline static void FillField(const struct ArrowArray *array, int iOGRFieldIdx,
7072
                             size_t iFeature, OGRFeature &oFeature)
7073
0
{
7074
0
    const auto *panValues = static_cast<const ArrowType *>(array->buffers[1]);
7075
0
    oFeature.SetFieldSameTypeUnsafe(
7076
0
        iOGRFieldIdx,
7077
0
        static_cast<OGRType>(panValues[iFeature + array->offset]));
7078
0
}
Unexecuted instantiation: ogrlayerarrow.cpp:void FillField<signed char, signed char>(ArrowArray const*, int, unsigned long, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillField<unsigned char, unsigned char>(ArrowArray const*, int, unsigned long, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillField<short, short>(ArrowArray const*, int, unsigned long, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillField<unsigned short, unsigned short>(ArrowArray const*, int, unsigned long, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillField<int, int>(ArrowArray const*, int, unsigned long, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillField<unsigned int, long long>(ArrowArray const*, int, unsigned long, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillField<long, long long>(ArrowArray const*, int, unsigned long, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillField<unsigned long, double>(ArrowArray const*, int, unsigned long, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillField<float, float>(ArrowArray const*, int, unsigned long, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillField<double, double>(ArrowArray const*, int, unsigned long, OGRFeature&)
7079
7080
/************************************************************************/
7081
/*                          FillFieldString()                           */
7082
/************************************************************************/
7083
7084
template <typename OffsetType>
7085
inline static void
7086
FillFieldString(const struct ArrowArray *array, int iOGRFieldIdx,
7087
                size_t iFeature, int iArrowIdx,
7088
                const std::vector<FieldInfo> &asFieldInfo,
7089
                std::string &osWorkingBuffer, OGRFeature &oFeature)
7090
0
{
7091
0
    const auto *panOffsets =
7092
0
        static_cast<const OffsetType *>(array->buffers[1]) + array->offset;
7093
0
    const char *pszStr = static_cast<const char *>(array->buffers[2]);
7094
0
    const size_t nLen =
7095
0
        static_cast<size_t>(panOffsets[iFeature + 1] - panOffsets[iFeature]);
7096
0
    if (asFieldInfo[iArrowIdx].bUseStringOptim)
7097
0
    {
7098
0
        oFeature.SetFieldSameTypeUnsafe(
7099
0
            iOGRFieldIdx, &osWorkingBuffer[0] + osWorkingBuffer.size());
7100
0
        osWorkingBuffer.append(pszStr + panOffsets[iFeature], nLen);
7101
0
        osWorkingBuffer.push_back(0);  // append null character
7102
0
    }
7103
0
    else
7104
0
    {
7105
0
        const std::string osTmp(pszStr, nLen);
7106
0
        oFeature.SetField(iOGRFieldIdx, osTmp.c_str());
7107
0
    }
7108
0
}
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldString<unsigned int>(ArrowArray const*, int, unsigned long, int, std::__1::vector<FieldInfo, std::__1::allocator<FieldInfo> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:void FillFieldString<unsigned long>(ArrowArray const*, int, unsigned long, int, std::__1::vector<FieldInfo, std::__1::allocator<FieldInfo> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, OGRFeature&)
7109
7110
/************************************************************************/
7111
/*                          FillFieldBinary()                           */
7112
/************************************************************************/
7113
7114
template <typename OffsetType>
7115
inline static bool
7116
FillFieldBinary(const struct ArrowArray *array, int iOGRFieldIdx,
7117
                size_t iFeature, int iArrowIdx,
7118
                const std::vector<FieldInfo> &asFieldInfo,
7119
                const std::string &osFieldPrefix, const char *pszFieldName,
7120
                OGRFeature &oFeature)
7121
0
{
7122
0
    const auto *panOffsets =
7123
0
        static_cast<const OffsetType *>(array->buffers[1]) + array->offset;
7124
0
    const GByte *pabyData = static_cast<const GByte *>(array->buffers[2]) +
7125
0
                            static_cast<size_t>(panOffsets[iFeature]);
7126
0
    const size_t nLen =
7127
0
        static_cast<size_t>(panOffsets[iFeature + 1] - panOffsets[iFeature]);
7128
0
    if (asFieldInfo[iArrowIdx].bIsGeomCol)
7129
0
    {
7130
0
        size_t nBytesConsumedOut = 0;
7131
7132
        // Check if we can reuse the existing geometry, to save dynamic memory
7133
        // allocations.
7134
0
        if (nLen >= 5 && pabyData[0] == wkbNDR && pabyData[1] <= wkbTriangle &&
7135
0
            pabyData[2] == 0 && pabyData[3] == 0 && pabyData[4] == 0)
7136
0
        {
7137
0
            const auto poExistingGeom = oFeature.GetGeomFieldRef(iOGRFieldIdx);
7138
0
            if (poExistingGeom &&
7139
0
                poExistingGeom->getGeometryType() == pabyData[1])
7140
0
            {
7141
0
                poExistingGeom->importFromWkb(pabyData, nLen, wkbVariantIso,
7142
0
                                              nBytesConsumedOut);
7143
0
                return true;
7144
0
            }
7145
0
        }
7146
7147
0
        OGRGeometry *poGeometry = nullptr;
7148
0
        OGRGeometryFactory::createFromWkb(pabyData, nullptr, &poGeometry, nLen,
7149
0
                                          wkbVariantIso, nBytesConsumedOut);
7150
0
        oFeature.SetGeomFieldDirectly(iOGRFieldIdx, poGeometry);
7151
0
    }
7152
0
    else
7153
0
    {
7154
0
        if (nLen > static_cast<size_t>(std::numeric_limits<int>::max()))
7155
0
        {
7156
0
            CPLError(CE_Failure, CPLE_NotSupported,
7157
0
                     "Content for field %s%s is too large",
7158
0
                     osFieldPrefix.c_str(), pszFieldName);
7159
0
            return false;
7160
0
        }
7161
0
        oFeature.SetField(iOGRFieldIdx, static_cast<int>(nLen), pabyData);
7162
0
    }
7163
0
    return true;
7164
0
}
Unexecuted instantiation: ogrlayerarrow.cpp:bool FillFieldBinary<unsigned int>(ArrowArray const*, int, unsigned long, int, std::__1::vector<FieldInfo, std::__1::allocator<FieldInfo> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const*, OGRFeature&)
Unexecuted instantiation: ogrlayerarrow.cpp:bool FillFieldBinary<unsigned long>(ArrowArray const*, int, unsigned long, int, std::__1::vector<FieldInfo, std::__1::allocator<FieldInfo> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const*, OGRFeature&)
7165
7166
/************************************************************************/
7167
/*                             FillFeature()                            */
7168
/************************************************************************/
7169
7170
static bool FillFeature(OGRLayer *poLayer, const struct ArrowSchema *schema,
7171
                        const struct ArrowArray *array,
7172
                        const std::string &osFieldPrefix, size_t iFeature,
7173
                        int &iArrowIdxInOut,
7174
                        const std::vector<FieldInfo> &asFieldInfo,
7175
                        OGRFeature &oFeature, std::string &osWorkingBuffer)
7176
7177
0
{
7178
0
    const char *fieldName = schema->name;
7179
0
    const char *format = schema->format;
7180
0
    if (IsStructure(format))
7181
0
    {
7182
0
        const std::string osNewPrefix(osFieldPrefix + fieldName + ".");
7183
0
        for (int64_t i = 0; i < array->n_children; ++i)
7184
0
        {
7185
0
            if (!FillFeature(
7186
0
                    poLayer, schema->children[i], array->children[i],
7187
0
                    osNewPrefix, iFeature + static_cast<size_t>(array->offset),
7188
0
                    iArrowIdxInOut, asFieldInfo, oFeature, osWorkingBuffer))
7189
0
                return false;
7190
0
        }
7191
0
        return true;
7192
0
    }
7193
0
    const int iArrowIdx = iArrowIdxInOut;
7194
0
    ++iArrowIdxInOut;
7195
0
    const int iOGRFieldIdx = asFieldInfo[iArrowIdx].iOGRFieldIdx;
7196
7197
0
    if (asFieldInfo[iArrowIdx].bUseDictionary)
7198
0
    {
7199
0
        format = schema->dictionary->format;
7200
0
    }
7201
7202
0
    if (array->null_count != 0)
7203
0
    {
7204
0
        const uint8_t *pabyValidity =
7205
0
            static_cast<const uint8_t *>(array->buffers[0]);
7206
0
        if (pabyValidity &&
7207
0
            !TestBit(pabyValidity,
7208
0
                     static_cast<size_t>(iFeature + array->offset)))
7209
0
        {
7210
0
            if (iOGRFieldIdx == FID_COLUMN_SPECIAL_OGR_FIELD_IDX)
7211
0
                oFeature.SetFID(OGRNullFID);
7212
0
            else if (asFieldInfo[iArrowIdx].bIsGeomCol)
7213
0
                oFeature.SetGeomFieldDirectly(iOGRFieldIdx, nullptr);
7214
0
            else if (asFieldInfo[iArrowIdx].eSetFeatureFieldType == OFTString)
7215
0
            {
7216
0
                OGRField *psField = oFeature.GetRawFieldRef(iOGRFieldIdx);
7217
0
                if (!asFieldInfo[iArrowIdx].bUseStringOptim)
7218
0
                {
7219
0
                    if (IsValidField(psField))
7220
0
                    {
7221
0
                        CPLFree(psField->String);
7222
0
                        OGR_RawField_SetNull(psField);
7223
0
                    }
7224
0
                }
7225
0
                else
7226
0
                {
7227
0
                    OGR_RawField_SetNull(psField);
7228
0
                }
7229
0
            }
7230
0
            else
7231
0
            {
7232
0
                OGRField *psField = oFeature.GetRawFieldRef(iOGRFieldIdx);
7233
0
                switch (asFieldInfo[iArrowIdx].eSetFeatureFieldType)
7234
0
                {
7235
0
                    case OFTRealList:
7236
0
                    case OFTIntegerList:
7237
0
                    case OFTInteger64List:
7238
0
                        if (IsValidField(psField))
7239
0
                            CPLFree(psField->IntegerList.paList);
7240
0
                        break;
7241
7242
0
                    case OFTStringList:
7243
0
                        if (IsValidField(psField))
7244
0
                            CSLDestroy(psField->StringList.paList);
7245
0
                        break;
7246
7247
0
                    case OFTBinary:
7248
0
                        if (IsValidField(psField))
7249
0
                            CPLFree(psField->Binary.paData);
7250
0
                        break;
7251
7252
0
                    default:
7253
0
                        break;
7254
0
                }
7255
0
                OGR_RawField_SetNull(psField);
7256
0
            }
7257
0
            return true;
7258
0
        }
7259
0
    }
7260
7261
0
    if (asFieldInfo[iArrowIdx].bUseDictionary)
7262
0
    {
7263
0
        const uint64_t nDictIdx = GetUInt64Value(schema, array, iFeature);
7264
0
        auto dictArray = array->dictionary;
7265
0
        if (nDictIdx >= static_cast<uint64_t>(dictArray->length))
7266
0
        {
7267
0
            CPLError(CE_Failure, CPLE_AppDefined,
7268
0
                     "Feature %" PRIu64
7269
0
                     ", field %s: invalid dictionary index: %" PRIu64,
7270
0
                     static_cast<uint64_t>(iFeature),
7271
0
                     (osFieldPrefix + fieldName).c_str(), nDictIdx);
7272
0
            return false;
7273
0
        }
7274
0
        array = dictArray;
7275
0
        schema = schema->dictionary;
7276
0
        iFeature = static_cast<size_t>(nDictIdx);
7277
0
    }
7278
7279
0
    if (IsBoolean(format))
7280
0
    {
7281
0
        const uint8_t *pabyValues =
7282
0
            static_cast<const uint8_t *>(array->buffers[1]);
7283
0
        oFeature.SetFieldSameTypeUnsafe(
7284
0
            iOGRFieldIdx,
7285
0
            TestBit(pabyValues, static_cast<size_t>(iFeature + array->offset))
7286
0
                ? 1
7287
0
                : 0);
7288
0
        return true;
7289
0
    }
7290
0
    else if (IsInt8(format))
7291
0
    {
7292
0
        FillField<int8_t>(array, iOGRFieldIdx, iFeature, oFeature);
7293
0
        return true;
7294
0
    }
7295
0
    else if (IsUInt8(format))
7296
0
    {
7297
0
        FillField<uint8_t>(array, iOGRFieldIdx, iFeature, oFeature);
7298
0
        return true;
7299
0
    }
7300
0
    else if (IsInt16(format))
7301
0
    {
7302
0
        FillField<int16_t>(array, iOGRFieldIdx, iFeature, oFeature);
7303
0
        return true;
7304
0
    }
7305
0
    else if (IsUInt16(format))
7306
0
    {
7307
0
        FillField<uint16_t>(array, iOGRFieldIdx, iFeature, oFeature);
7308
0
        return true;
7309
0
    }
7310
0
    else if (IsInt32(format))
7311
0
    {
7312
0
        if (iOGRFieldIdx == FID_COLUMN_SPECIAL_OGR_FIELD_IDX)
7313
0
        {
7314
0
            const auto *panValues =
7315
0
                static_cast<const int32_t *>(array->buffers[1]);
7316
0
            oFeature.SetFID(panValues[iFeature + array->offset]);
7317
0
        }
7318
0
        else
7319
0
        {
7320
0
            FillField<int32_t>(array, iOGRFieldIdx, iFeature, oFeature);
7321
0
        }
7322
0
        return true;
7323
0
    }
7324
0
    else if (IsUInt32(format))
7325
0
    {
7326
0
        FillField<uint32_t, GIntBig>(array, iOGRFieldIdx, iFeature, oFeature);
7327
0
        return true;
7328
0
    }
7329
0
    else if (IsInt64(format))
7330
0
    {
7331
0
        if (iOGRFieldIdx == FID_COLUMN_SPECIAL_OGR_FIELD_IDX)
7332
0
        {
7333
0
            const auto *panValues =
7334
0
                static_cast<const int64_t *>(array->buffers[1]);
7335
0
            oFeature.SetFID(panValues[iFeature + array->offset]);
7336
0
        }
7337
0
        else
7338
0
        {
7339
0
            FillField<int64_t, GIntBig>(array, iOGRFieldIdx, iFeature,
7340
0
                                        oFeature);
7341
0
        }
7342
0
        return true;
7343
0
    }
7344
0
    else if (IsUInt64(format))
7345
0
    {
7346
0
        FillField<uint64_t, double>(array, iOGRFieldIdx, iFeature, oFeature);
7347
0
        return true;
7348
0
    }
7349
0
    else if (IsFloat32(format))
7350
0
    {
7351
0
        FillField<float>(array, iOGRFieldIdx, iFeature, oFeature);
7352
0
        return true;
7353
0
    }
7354
0
    else if (IsFloat64(format))
7355
0
    {
7356
0
        FillField<double>(array, iOGRFieldIdx, iFeature, oFeature);
7357
0
        return true;
7358
0
    }
7359
0
    else if (IsString(format))
7360
0
    {
7361
0
        FillFieldString<uint32_t>(array, iOGRFieldIdx, iFeature, iArrowIdx,
7362
0
                                  asFieldInfo, osWorkingBuffer, oFeature);
7363
0
        return true;
7364
0
    }
7365
0
    else if (IsLargeString(format))
7366
0
    {
7367
0
        FillFieldString<uint64_t>(array, iOGRFieldIdx, iFeature, iArrowIdx,
7368
0
                                  asFieldInfo, osWorkingBuffer, oFeature);
7369
0
        return true;
7370
0
    }
7371
0
    else if (IsBinary(format))
7372
0
    {
7373
0
        return FillFieldBinary<uint32_t>(array, iOGRFieldIdx, iFeature,
7374
0
                                         iArrowIdx, asFieldInfo, osFieldPrefix,
7375
0
                                         fieldName, oFeature);
7376
0
    }
7377
0
    else if (IsLargeBinary(format))
7378
0
    {
7379
0
        return FillFieldBinary<uint64_t>(array, iOGRFieldIdx, iFeature,
7380
0
                                         iArrowIdx, asFieldInfo, osFieldPrefix,
7381
0
                                         fieldName, oFeature);
7382
0
    }
7383
0
    else if (asFieldInfo[iArrowIdx].nPrecision > 0)
7384
0
    {
7385
        // fits on a int64
7386
0
        CPLAssert(asFieldInfo[iArrowIdx].nPrecision <= 19);
7387
        // either 128 or 256 bits
7388
0
        CPLAssert((asFieldInfo[iArrowIdx].nWidthInBytes % 8) == 0);
7389
0
        const int nWidthIn64BitWord = asFieldInfo[iArrowIdx].nWidthInBytes / 8;
7390
7391
0
        if (IsList(format))
7392
0
        {
7393
0
            const auto panOffsets =
7394
0
                static_cast<const uint32_t *>(array->buffers[1]) +
7395
0
                array->offset;
7396
0
            const auto childArray = array->children[0];
7397
0
            std::vector<double> aValues;
7398
0
            for (auto i = panOffsets[iFeature]; i < panOffsets[iFeature + 1];
7399
0
                 ++i)
7400
0
            {
7401
0
                aValues.push_back(GetValueDecimal(childArray, nWidthIn64BitWord,
7402
0
                                                  asFieldInfo[iArrowIdx].nScale,
7403
0
                                                  i));
7404
0
            }
7405
0
            oFeature.SetField(iOGRFieldIdx, static_cast<int>(aValues.size()),
7406
0
                              aValues.data());
7407
0
            return true;
7408
0
        }
7409
0
        else if (IsLargeList(format))
7410
0
        {
7411
0
            const auto panOffsets =
7412
0
                static_cast<const uint64_t *>(array->buffers[1]) +
7413
0
                array->offset;
7414
0
            const auto childArray = array->children[0];
7415
0
            std::vector<double> aValues;
7416
0
            for (auto i = static_cast<size_t>(panOffsets[iFeature]);
7417
0
                 i < static_cast<size_t>(panOffsets[iFeature + 1]); ++i)
7418
0
            {
7419
0
                aValues.push_back(GetValueDecimal(childArray, nWidthIn64BitWord,
7420
0
                                                  asFieldInfo[iArrowIdx].nScale,
7421
0
                                                  i));
7422
0
            }
7423
0
            oFeature.SetField(iOGRFieldIdx, static_cast<int>(aValues.size()),
7424
0
                              aValues.data());
7425
0
            return true;
7426
0
        }
7427
0
        else if (IsFixedSizeList(format))
7428
0
        {
7429
0
            const int nVals = GetFixedSizeList(format);
7430
0
            const auto childArray = array->children[0];
7431
0
            std::vector<double> aValues;
7432
0
            for (int i = 0; i < nVals; ++i)
7433
0
            {
7434
0
                aValues.push_back(GetValueDecimal(childArray, nWidthIn64BitWord,
7435
0
                                                  asFieldInfo[iArrowIdx].nScale,
7436
0
                                                  iFeature * nVals + i));
7437
0
            }
7438
0
            oFeature.SetField(iOGRFieldIdx, nVals, aValues.data());
7439
0
            return true;
7440
0
        }
7441
7442
0
        CPLAssert(format[0] == ARROW_LETTER_DECIMAL);
7443
7444
0
        oFeature.SetFieldSameTypeUnsafe(
7445
0
            iOGRFieldIdx,
7446
0
            GetValueDecimal(array, nWidthIn64BitWord,
7447
0
                            asFieldInfo[iArrowIdx].nScale, iFeature));
7448
0
        return true;
7449
0
    }
7450
0
    else if (SetFieldForOtherFormats(
7451
0
                 oFeature, iOGRFieldIdx,
7452
0
                 static_cast<size_t>(iFeature + array->offset), schema, array))
7453
0
    {
7454
0
        return true;
7455
0
    }
7456
7457
0
    CPLError(CE_Failure, CPLE_NotSupported, "%s",
7458
0
             ("Type '" + std::string(format) + "' for field " + osFieldPrefix +
7459
0
              fieldName + " is not supported.")
7460
0
                 .c_str());
7461
0
    return false;
7462
0
}
7463
7464
/************************************************************************/
7465
/*                    OGRLayer::WriteArrowBatch()                       */
7466
/************************************************************************/
7467
7468
// clang-format off
7469
/** Writes a batch of rows from an ArrowArray.
7470
 *
7471
 * This is semantically close to calling CreateFeature() with multiple features
7472
 * at once.
7473
 *
7474
 * The ArrowArray must be of type struct (format=+s), and its children generally
7475
 * map to a OGR attribute or geometry field (unless they are struct themselves).
7476
 *
7477
 * Method IsArrowSchemaSupported() can be called to determine if the schema
7478
 * will be supported by WriteArrowBatch().
7479
 *
7480
 * OGR fields for the corresponding children arrays must exist and be of a
7481
 * compatible type. For attribute fields, they should generally be created with
7482
 * CreateFieldFromArrowSchema(). This is strictly required for output drivers
7483
 * Arrow or Parquet, and strongly recommended otherwise. For geometry fields,
7484
 * they should be created either implicitly at CreateLayer() type
7485
 * (if geom_type != wkbNone), or explicitly with CreateGeomField().
7486
 *
7487
 * Starting with GDAL 3.9, some tolerance has been introduced in the base
7488
 * implementation of WriteArrowBatch() for scenarios that involve appending to
7489
 * an already existing output layer when the input Arrow field type and the
7490
 * OGR layer field type are 32/64-bi integers or real number, but do not match
7491
 * exactly, which may cause lossy conversions. The IF_FIELD_NOT_PRESERVED option
7492
 * can be used to control the behavior in case of lossy conversion.
7493
 *
7494
 * Arrays for geometry columns should be of binary or large binary type and
7495
 * contain WKB geometry.
7496
 *
7497
 * Note that the passed array may be set to a released state
7498
 * (array->release==NULL) after this call (not by the base implementation,
7499
 * but in specialized ones such as Parquet or Arrow for example)
7500
 *
7501
 * Supported options of the base implementation are:
7502
 * <ul>
7503
 * <li>FID=name. Name of the FID column in the array. If not provided,
7504
 *     GetFIDColumn() is used to determine it. The special name
7505
 *     OGRLayer::DEFAULT_ARROW_FID_NAME is also recognized if neither FID nor
7506
 *     GetFIDColumn() are set.
7507
 *     The corresponding ArrowArray must be of type int32 (i) or int64 (l).
7508
 *     On input, values of the FID column are used to create the feature.
7509
 *     On output, the values of the FID column may be set with the FID of the
7510
 *     created feature (if the array is not released).
7511
 * </li>
7512
 * <li>IF_FID_NOT_PRESERVED=NOTHING/ERROR/WARNING. Action to perform when the
7513
 *     input FID is not preserved in the output layer. The default is NOTHING.
7514
 *     Setting it to ERROR will cause the function to error out. Setting it
7515
 *     to WARNING will cause the function to emit a warning but continue its
7516
 *     processing.
7517
 * </li>
7518
 * <li>IF_FIELD_NOT_PRESERVED=ERROR/WARNING. (since GDAL 3.9)
7519
 *     Action to perform when the input field value is not preserved in the
7520
 *     output layer.
7521
 *     The default is WARNING, which will cause the function to emit a warning
7522
 *     but continue its processing.
7523
 *     Setting it to ERROR will cause the function to error out if a lossy
7524
 *     conversion is detected.
7525
 * </li>
7526
 * <li>GEOMETRY_NAME=name. Name of the geometry column. If not provided,
7527
 *     GetGeometryColumn() is used. The special name
7528
 *     OGRLayer::DEFAULT_ARROW_GEOMETRY_NAME is also recognized if neither
7529
 *     GEOMETRY_NAME nor GetGeometryColumn() are set.
7530
 *     Geometry columns are also identified if they have
7531
 *     ARROW:extension:name=ogc.wkb as a field metadata.
7532
 *     The corresponding ArrowArray must be of type binary (w) or large
7533
 *     binary (W).
7534
 * </li>
7535
 * </ul>
7536
 *
7537
 * The following example demonstrates how to copy a layer from one format to
7538
 * another one (assuming it has at most a single geometry column):
7539
\code{.py}
7540
    def copy_layer(src_lyr, out_filename, out_format, lcos = {}):
7541
        stream = src_lyr.GetArrowStream()
7542
        schema = stream.GetSchema()
7543
7544
        # If the source layer has a FID column and the output driver supports
7545
        # a FID layer creation option, set it to the source FID column name.
7546
        if src_lyr.GetFIDColumn():
7547
            creationOptions = gdal.GetDriverByName(out_format).GetMetadataItem(
7548
                "DS_LAYER_CREATIONOPTIONLIST"
7549
            )
7550
            if creationOptions and '"FID"' in creationOptions:
7551
                lcos["FID"] = src_lyr.GetFIDColumn()
7552
7553
        with ogr.GetDriverByName(out_format).CreateDataSource(out_filename) as out_ds:
7554
            if src_lyr.GetLayerDefn().GetGeomFieldCount() > 1:
7555
                out_lyr = out_ds.CreateLayer(
7556
                    src_lyr.GetName(), geom_type=ogr.wkbNone, options=lcos
7557
                )
7558
                for i in range(src_lyr.GetLayerDefn().GetGeomFieldCount()):
7559
                    out_lyr.CreateGeomField(src_lyr.GetLayerDefn().GetGeomFieldDefn(i))
7560
            else:
7561
                out_lyr = out_ds.CreateLayer(
7562
                    src_lyr.GetName(),
7563
                    geom_type=src_lyr.GetGeomType(),
7564
                    srs=src_lyr.GetSpatialRef(),
7565
                    options=lcos,
7566
                )
7567
7568
            success, error_msg = out_lyr.IsArrowSchemaSupported(schema)
7569
            assert success, error_msg
7570
7571
            src_geom_field_names = [
7572
                src_lyr.GetLayerDefn().GetGeomFieldDefn(i).GetName()
7573
                for i in range(src_lyr.GetLayerDefn().GetGeomFieldCount())
7574
            ]
7575
            for i in range(schema.GetChildrenCount()):
7576
                # GetArrowStream() may return "OGC_FID" for a unnamed source FID
7577
                # column and "wkb_geometry" for a unnamed source geometry column.
7578
                # Also test GetFIDColumn() and src_geom_field_names if they are
7579
                # named.
7580
                if (
7581
                    schema.GetChild(i).GetName()
7582
                    not in ("OGC_FID", "wkb_geometry", src_lyr.GetFIDColumn())
7583
                    and schema.GetChild(i).GetName() not in src_geom_field_names
7584
                ):
7585
                    out_lyr.CreateFieldFromArrowSchema(schema.GetChild(i))
7586
7587
            write_options = []
7588
            if src_lyr.GetFIDColumn():
7589
                write_options.append("FID=" + src_lyr.GetFIDColumn())
7590
            if (
7591
                src_lyr.GetLayerDefn().GetGeomFieldCount() == 1
7592
                and src_lyr.GetGeometryColumn()
7593
            ):
7594
                write_options.append("GEOMETRY_NAME=" + src_lyr.GetGeometryColumn())
7595
7596
            while True:
7597
                array = stream.GetNextRecordBatch()
7598
                if array is None:
7599
                    break
7600
                out_lyr.WriteArrowBatch(schema, array, write_options)
7601
\endcode
7602
 *
7603
 * This method and CreateFeature() are mutually exclusive in the same session.
7604
 *
7605
 * This method is the same as the C function OGR_L_WriteArrowBatch().
7606
 *
7607
 * @param schema Schema of array
7608
 * @param array Array of type struct. It may be released (array->release==NULL)
7609
 *              after calling this method.
7610
 * @param papszOptions Options. Null terminated list, or nullptr.
7611
 * @return true in case of success
7612
 * @since 3.8
7613
 */
7614
// clang-format on
7615
7616
bool OGRLayer::WriteArrowBatch(const struct ArrowSchema *schema,
7617
                               struct ArrowArray *array,
7618
                               CSLConstList papszOptions)
7619
0
{
7620
0
    const char *format = schema->format;
7621
0
    if (!IsStructure(format))
7622
0
    {
7623
0
        CPLError(CE_Failure, CPLE_AppDefined,
7624
0
                 "WriteArrowBatch() should be called on a schema that is a "
7625
0
                 "struct of fields");
7626
0
        return false;
7627
0
    }
7628
7629
0
    if (schema->n_children != array->n_children)
7630
0
    {
7631
0
        CPLError(CE_Failure, CPLE_AppDefined,
7632
0
                 "WriteArrowBatch(): schema->n_children (%d) != "
7633
0
                 "array->n_children (%d)",
7634
0
                 int(schema->n_children), int(array->n_children));
7635
0
        return false;
7636
0
    }
7637
7638
0
    CPLStringList aosNativeTypes;
7639
0
    auto poDS = const_cast<OGRLayer *>(this)->GetDataset();
7640
0
    if (poDS)
7641
0
    {
7642
0
        auto poDriver = poDS->GetDriver();
7643
0
        if (poDriver)
7644
0
        {
7645
0
            const char *pszMetadataItem =
7646
0
                poDriver->GetMetadataItem(GDAL_DMD_CREATIONFIELDDATATYPES);
7647
0
            if (pszMetadataItem)
7648
0
                aosNativeTypes = CSLTokenizeString2(pszMetadataItem, " ", 0);
7649
0
        }
7650
0
    }
7651
7652
0
    std::vector<FieldInfo> asFieldInfo;
7653
0
    auto poLayerDefn = GetLayerDefn();
7654
0
    const char *pszFIDName =
7655
0
        CSLFetchNameValueDef(papszOptions, "FID", GetFIDColumn());
7656
0
    if (!pszFIDName || pszFIDName[0] == 0)
7657
0
        pszFIDName = DEFAULT_ARROW_FID_NAME;
7658
0
    const bool bErrorIfFIDNotPreserved =
7659
0
        EQUAL(CSLFetchNameValueDef(papszOptions, "IF_FID_NOT_PRESERVED", ""),
7660
0
              "ERROR");
7661
0
    const bool bWarningIfFIDNotPreserved =
7662
0
        EQUAL(CSLFetchNameValueDef(papszOptions, "IF_FID_NOT_PRESERVED", ""),
7663
0
              "WARNING");
7664
0
    const bool bErrorIfFieldNotPreserved =
7665
0
        EQUAL(CSLFetchNameValueDef(papszOptions, "IF_FIELD_NOT_PRESERVED", ""),
7666
0
              "ERROR");
7667
0
    const char *pszGeomFieldName = CSLFetchNameValueDef(
7668
0
        papszOptions, "GEOMETRY_NAME", GetGeometryColumn());
7669
0
    if (!pszGeomFieldName || pszGeomFieldName[0] == 0)
7670
0
        pszGeomFieldName = DEFAULT_ARROW_GEOMETRY_NAME;
7671
0
    const struct ArrowSchema *schemaFIDColumn = nullptr;
7672
0
    struct ArrowArray *arrayFIDColumn = nullptr;
7673
0
    bool bFallbackTypesUsed = false;
7674
0
    for (int64_t i = 0; i < schema->n_children; ++i)
7675
0
    {
7676
0
        if (!BuildOGRFieldInfo(schema->children[i], array->children[i],
7677
0
                               poLayerDefn, std::string(), aosNativeTypes,
7678
0
                               bFallbackTypesUsed, asFieldInfo, pszFIDName,
7679
0
                               pszGeomFieldName, this,
7680
0
                               m_poPrivate->m_oMapArrowFieldNameToOGRFieldName,
7681
0
                               schemaFIDColumn, arrayFIDColumn))
7682
0
        {
7683
0
            return false;
7684
0
        }
7685
0
    }
7686
7687
0
    std::map<int, int> oMapOGRFieldIndexToFieldInfoIndex;
7688
0
    std::vector<bool> abUseStringOptim(poLayerDefn->GetFieldCount(), false);
7689
0
    for (int i = 0; i < static_cast<int>(asFieldInfo.size()); ++i)
7690
0
    {
7691
0
        if (asFieldInfo[i].iOGRFieldIdx >= 0 && !asFieldInfo[i].bIsGeomCol)
7692
0
        {
7693
0
            CPLAssert(oMapOGRFieldIndexToFieldInfoIndex.find(
7694
0
                          asFieldInfo[i].iOGRFieldIdx) ==
7695
0
                      oMapOGRFieldIndexToFieldInfoIndex.end());
7696
0
            oMapOGRFieldIndexToFieldInfoIndex[asFieldInfo[i].iOGRFieldIdx] = i;
7697
0
            abUseStringOptim[asFieldInfo[i].iOGRFieldIdx] =
7698
0
                asFieldInfo[i].bUseStringOptim;
7699
0
        }
7700
0
    }
7701
7702
0
    OGRFeatureDefn oLayerDefnTmp(poLayerDefn->GetName());
7703
7704
0
    struct LayerDefnTmpRefReleaser
7705
0
    {
7706
0
        OGRFeatureDefn &m_oDefn;
7707
7708
0
        explicit LayerDefnTmpRefReleaser(OGRFeatureDefn &oDefn) : m_oDefn(oDefn)
7709
0
        {
7710
0
            m_oDefn.Reference();
7711
0
        }
7712
7713
0
        ~LayerDefnTmpRefReleaser()
7714
0
        {
7715
0
            m_oDefn.Dereference();
7716
0
        }
7717
0
    };
7718
7719
0
    LayerDefnTmpRefReleaser oLayerDefnTmpRefReleaser(oLayerDefnTmp);
7720
7721
0
    std::vector<int> anIdentityFieldMap;
7722
0
    if (bFallbackTypesUsed)
7723
0
    {
7724
0
        oLayerDefnTmp.SetGeomType(wkbNone);
7725
0
        for (int i = 0; i < poLayerDefn->GetFieldCount(); ++i)
7726
0
        {
7727
0
            anIdentityFieldMap.push_back(i);
7728
0
            const auto poSrcFieldDefn = poLayerDefn->GetFieldDefn(i);
7729
0
            const auto oIter = oMapOGRFieldIndexToFieldInfoIndex.find(i);
7730
0
            OGRFieldDefn oFieldDefn(
7731
0
                poSrcFieldDefn->GetNameRef(),
7732
0
                oIter == oMapOGRFieldIndexToFieldInfoIndex.end()
7733
0
                    ? poSrcFieldDefn->GetType()
7734
0
                    : asFieldInfo[oIter->second].eNominalFieldType);
7735
0
            if (oIter != oMapOGRFieldIndexToFieldInfoIndex.end())
7736
0
                asFieldInfo[oIter->second].eSetFeatureFieldType =
7737
0
                    asFieldInfo[oIter->second].eNominalFieldType;
7738
0
            oLayerDefnTmp.AddFieldDefn(&oFieldDefn);
7739
0
        }
7740
0
        for (int i = 0; i < poLayerDefn->GetGeomFieldCount(); ++i)
7741
0
        {
7742
0
            oLayerDefnTmp.AddGeomFieldDefn(poLayerDefn->GetGeomFieldDefn(i));
7743
0
        }
7744
0
    }
7745
0
    else
7746
0
    {
7747
0
        for (auto &sFieldInfo : asFieldInfo)
7748
0
            sFieldInfo.eSetFeatureFieldType = sFieldInfo.eTargetFieldType;
7749
0
    }
7750
7751
0
    struct FeatureCleaner
7752
0
    {
7753
0
        OGRFeature &m_oFeature;
7754
0
        const std::vector<bool> &m_abUseStringOptim;
7755
7756
0
        explicit FeatureCleaner(OGRFeature &oFeature,
7757
0
                                const std::vector<bool> &abUseStringOptim)
7758
0
            : m_oFeature(oFeature), m_abUseStringOptim(abUseStringOptim)
7759
0
        {
7760
0
        }
7761
7762
        // As we set a value that can't be CPLFree()'d in the .String member
7763
        // of string fields, we must take care of manually unsetting it before
7764
        // the destructor of OGRFeature gets called.
7765
0
        ~FeatureCleaner()
7766
0
        {
7767
0
            const auto poLayerDefn = m_oFeature.GetDefnRef();
7768
0
            const int nFieldCount = poLayerDefn->GetFieldCount();
7769
0
            for (int i = 0; i < nFieldCount; ++i)
7770
0
            {
7771
0
                if (m_abUseStringOptim[i])
7772
0
                {
7773
0
                    if (m_oFeature.IsFieldSetAndNotNullUnsafe(i))
7774
0
                        m_oFeature.SetFieldSameTypeUnsafe(
7775
0
                            i, static_cast<char *>(nullptr));
7776
0
                }
7777
0
            }
7778
0
        }
7779
0
    };
7780
7781
0
    OGRFeature oFeature(bFallbackTypesUsed ? &oLayerDefnTmp : poLayerDefn);
7782
0
    FeatureCleaner oCleaner(oFeature, abUseStringOptim);
7783
0
    OGRFeature oFeatureTarget(poLayerDefn);
7784
0
    OGRFeature *const poFeatureTarget =
7785
0
        bFallbackTypesUsed ? &oFeatureTarget : &oFeature;
7786
7787
    // We accumulate the content of all strings in osWorkingBuffer to avoid
7788
    // a few dynamic memory allocations
7789
0
    std::string osWorkingBuffer;
7790
7791
0
    bool bTransactionOK;
7792
0
    {
7793
0
        CPLErrorStateBackuper oBackuper(CPLQuietErrorHandler);
7794
0
        bTransactionOK = StartTransaction() == OGRERR_NONE;
7795
0
    }
7796
7797
0
    const std::string emptyString;
7798
0
    int64_t fidNullCount = 0;
7799
0
    for (size_t iFeature = 0; iFeature < static_cast<size_t>(array->length);
7800
0
         ++iFeature)
7801
0
    {
7802
0
        oFeature.SetFID(OGRNullFID);
7803
7804
0
        int iArrowIdx = 0;
7805
0
        const size_t nWorkingBufferSize = GetWorkingBufferSize(
7806
0
            schema, array, iFeature, iArrowIdx, asFieldInfo);
7807
0
        osWorkingBuffer.clear();
7808
0
        osWorkingBuffer.reserve(nWorkingBufferSize);
7809
0
#ifdef DEBUG
7810
0
        const char *pszWorkingBuffer = osWorkingBuffer.c_str();
7811
0
        CPL_IGNORE_RET_VAL(pszWorkingBuffer);
7812
0
#endif
7813
0
        iArrowIdx = 0;
7814
0
        for (int64_t i = 0; i < schema->n_children; ++i)
7815
0
        {
7816
0
            if (!FillFeature(this, schema->children[i], array->children[i],
7817
0
                             emptyString, iFeature, iArrowIdx, asFieldInfo,
7818
0
                             oFeature, osWorkingBuffer))
7819
0
            {
7820
0
                if (bTransactionOK)
7821
0
                    RollbackTransaction();
7822
0
                return false;
7823
0
            }
7824
0
        }
7825
0
#ifdef DEBUG
7826
        // Check that the buffer didn't get reallocated
7827
0
        CPLAssert(pszWorkingBuffer == osWorkingBuffer.c_str());
7828
0
        CPLAssert(osWorkingBuffer.size() == nWorkingBufferSize);
7829
0
#endif
7830
7831
0
        if (bFallbackTypesUsed)
7832
0
        {
7833
0
            oFeatureTarget.SetFrom(&oFeature, anIdentityFieldMap.data(),
7834
0
                                   /*bForgiving=*/true,
7835
0
                                   /*bUseISO8601ForDateTimeAsString=*/true);
7836
0
            oFeatureTarget.SetFID(oFeature.GetFID());
7837
7838
0
            if (bErrorIfFieldNotPreserved)
7839
0
            {
7840
0
                for (int i = 0; i < poLayerDefn->GetFieldCount(); ++i)
7841
0
                {
7842
0
                    if (!oFeature.IsFieldSetAndNotNullUnsafe(i))
7843
0
                    {
7844
0
                        continue;
7845
0
                    }
7846
0
                    bool bLossyConversion = false;
7847
0
                    const auto eSrcType =
7848
0
                        oLayerDefnTmp.GetFieldDefnUnsafe(i)->GetType();
7849
0
                    const auto eDstType =
7850
0
                        poLayerDefn->GetFieldDefnUnsafe(i)->GetType();
7851
7852
0
                    const auto IsDoubleCastToInt64EqualTInt64 =
7853
0
                        [](double dfVal, int64_t nOtherVal)
7854
0
                    {
7855
                        // Values in the range [INT64_MAX - 1023, INT64_MAX - 1]
7856
                        // get converted to a double that once cast to int64_t
7857
                        // is INT64_MAX + 1, hence the strict < comparison
7858
0
                        return dfVal >=
7859
0
                                   static_cast<double>(
7860
0
                                       std::numeric_limits<int64_t>::min()) &&
7861
0
                               dfVal <
7862
0
                                   static_cast<double>(
7863
0
                                       std::numeric_limits<int64_t>::max()) &&
7864
0
                               static_cast<int64_t>(dfVal) == nOtherVal;
7865
0
                    };
7866
7867
0
                    if (eSrcType == OFTInteger64 && eDstType == OFTInteger &&
7868
0
                        oFeatureTarget.GetFieldAsIntegerUnsafe(i) !=
7869
0
                            oFeature.GetFieldAsInteger64Unsafe(i))
7870
0
                    {
7871
0
                        bLossyConversion = true;
7872
0
                    }
7873
0
                    else if (eSrcType == OFTReal && eDstType == OFTInteger &&
7874
0
                             oFeatureTarget.GetFieldAsIntegerUnsafe(i) !=
7875
0
                                 oFeature.GetFieldAsDoubleUnsafe(i))
7876
0
                    {
7877
0
                        bLossyConversion = true;
7878
0
                    }
7879
0
                    else if (eSrcType == OFTReal && eDstType == OFTInteger64 &&
7880
0
                             static_cast<double>(
7881
0
                                 oFeatureTarget.GetFieldAsInteger64Unsafe(i)) !=
7882
0
                                 oFeature.GetFieldAsDoubleUnsafe(i))
7883
0
                    {
7884
0
                        bLossyConversion = true;
7885
0
                    }
7886
0
                    else if (eSrcType == OFTInteger64 && eDstType == OFTReal &&
7887
0
                             !IsDoubleCastToInt64EqualTInt64(
7888
0
                                 oFeatureTarget.GetFieldAsDoubleUnsafe(i),
7889
0
                                 oFeature.GetFieldAsInteger64Unsafe(i)))
7890
0
                    {
7891
0
                        bLossyConversion = true;
7892
0
                    }
7893
0
                    if (bLossyConversion)
7894
0
                    {
7895
0
                        CPLError(CE_Failure, CPLE_AppDefined,
7896
0
                                 "For feature " CPL_FRMT_GIB
7897
0
                                 ", value of field %s cannot not preserved",
7898
0
                                 oFeatureTarget.GetFID(),
7899
0
                                 oLayerDefnTmp.GetFieldDefn(i)->GetNameRef());
7900
0
                        if (bTransactionOK)
7901
0
                            RollbackTransaction();
7902
0
                        return false;
7903
0
                    }
7904
0
                }
7905
0
            }
7906
0
        }
7907
7908
0
        const auto nInputFID = poFeatureTarget->GetFID();
7909
0
        if (CreateFeature(poFeatureTarget) != OGRERR_NONE)
7910
0
        {
7911
0
            if (bTransactionOK)
7912
0
                RollbackTransaction();
7913
0
            return false;
7914
0
        }
7915
0
        if (nInputFID != OGRNullFID)
7916
0
        {
7917
0
            if (bWarningIfFIDNotPreserved &&
7918
                // cppcheck-suppress knownConditionTrueFalse
7919
0
                poFeatureTarget->GetFID() != nInputFID)
7920
0
            {
7921
0
                CPLError(CE_Warning, CPLE_AppDefined,
7922
0
                         "Feature id " CPL_FRMT_GIB " not preserved",
7923
0
                         nInputFID);
7924
0
            }
7925
0
            else if (bErrorIfFIDNotPreserved &&
7926
                     // cppcheck-suppress knownConditionTrueFalse
7927
0
                     poFeatureTarget->GetFID() != nInputFID)
7928
0
            {
7929
0
                CPLError(CE_Failure, CPLE_AppDefined,
7930
0
                         "Feature id " CPL_FRMT_GIB " not preserved",
7931
0
                         nInputFID);
7932
0
                if (bTransactionOK)
7933
0
                    RollbackTransaction();
7934
0
                return false;
7935
0
            }
7936
0
        }
7937
7938
0
        if (arrayFIDColumn)
7939
0
        {
7940
0
            uint8_t *pabyValidity = static_cast<uint8_t *>(
7941
0
                const_cast<void *>(arrayFIDColumn->buffers[0]));
7942
0
            if (IsInt32(schemaFIDColumn->format))
7943
0
            {
7944
0
                auto *panValues = static_cast<int32_t *>(
7945
0
                    const_cast<void *>(arrayFIDColumn->buffers[1]));
7946
0
                if (poFeatureTarget->GetFID() >
7947
0
                    std::numeric_limits<int32_t>::max())
7948
0
                {
7949
0
                    if (pabyValidity)
7950
0
                    {
7951
0
                        ++fidNullCount;
7952
0
                        UnsetBit(pabyValidity,
7953
0
                                 static_cast<size_t>(iFeature +
7954
0
                                                     arrayFIDColumn->offset));
7955
0
                    }
7956
0
                    CPLError(CE_Warning, CPLE_AppDefined,
7957
0
                             "FID " CPL_FRMT_GIB
7958
0
                             " cannot be stored in FID array of type int32",
7959
0
                             poFeatureTarget->GetFID());
7960
0
                }
7961
0
                else
7962
0
                {
7963
0
                    if (pabyValidity)
7964
0
                    {
7965
0
                        SetBit(pabyValidity,
7966
0
                               static_cast<size_t>(iFeature +
7967
0
                                                   arrayFIDColumn->offset));
7968
0
                    }
7969
0
                    panValues[iFeature + arrayFIDColumn->offset] =
7970
0
                        static_cast<int32_t>(poFeatureTarget->GetFID());
7971
0
                }
7972
0
            }
7973
0
            else if (IsInt64(schemaFIDColumn->format))
7974
0
            {
7975
0
                if (pabyValidity)
7976
0
                {
7977
0
                    SetBit(
7978
0
                        pabyValidity,
7979
0
                        static_cast<size_t>(iFeature + arrayFIDColumn->offset));
7980
0
                }
7981
0
                auto *panValues = static_cast<int64_t *>(
7982
0
                    const_cast<void *>(arrayFIDColumn->buffers[1]));
7983
0
                panValues[iFeature + arrayFIDColumn->offset] =
7984
0
                    poFeatureTarget->GetFID();
7985
0
            }
7986
0
            else
7987
0
            {
7988
0
                CPLAssert(false);
7989
0
            }
7990
0
        }
7991
0
    }
7992
0
    if (arrayFIDColumn && arrayFIDColumn->buffers[0])
7993
0
    {
7994
0
        arrayFIDColumn->null_count = fidNullCount;
7995
0
    }
7996
7997
0
    bool bRet = true;
7998
0
    if (bTransactionOK)
7999
0
        bRet = CommitTransaction() == OGRERR_NONE;
8000
8001
0
    return bRet;
8002
0
}
8003
8004
/************************************************************************/
8005
/*                      OGR_L_WriteArrowBatch()                         */
8006
/************************************************************************/
8007
8008
// clang-format off
8009
/** Writes a batch of rows from an ArrowArray.
8010
 *
8011
 * This is semantically close to calling CreateFeature() with multiple features
8012
 * at once.
8013
 *
8014
 * The ArrowArray must be of type struct (format=+s), and its children generally
8015
 * map to a OGR attribute or geometry field (unless they are struct themselves).
8016
 *
8017
 * Method IsArrowSchemaSupported() can be called to determine if the schema
8018
 * will be supported by WriteArrowBatch().
8019
 *
8020
 * OGR fields for the corresponding children arrays must exist and be of a
8021
 * compatible type. For attribute fields, they should generally be created with
8022
 * CreateFieldFromArrowSchema(). This is strictly required for output drivers
8023
 * Arrow or Parquet, and strongly recommended otherwise. For geometry fields,
8024
 * they should be created either implicitly at CreateLayer() type
8025
 * (if geom_type != wkbNone), or explicitly with CreateGeomField().
8026
 *
8027
 * Starting with GDAL 3.9, some tolerance has been introduced in the base
8028
 * implementation of WriteArrowBatch() for scenarios that involve appending to
8029
 * an already existing output layer when the input Arrow field type and the
8030
 * OGR layer field type are 32/64-bi integers or real number, but do not match
8031
 * exactly, which may cause lossy conversions. The IF_FIELD_NOT_PRESERVED option
8032
 * can be used to control the behavior in case of lossy conversion.
8033
 *
8034
 * Arrays for geometry columns should be of binary or large binary type and
8035
 * contain WKB geometry.
8036
 *
8037
 * Note that the passed array may be set to a released state
8038
 * (array->release==NULL) after this call (not by the base implementation,
8039
 * but in specialized ones such as Parquet or Arrow for example)
8040
 *
8041
 * Supported options of the base implementation are:
8042
 * <ul>
8043
 * <li>FID=name. Name of the FID column in the array. If not provided,
8044
 *     GetFIDColumn() is used to determine it. The special name
8045
 *     OGRLayer::DEFAULT_ARROW_FID_NAME is also recognized if neither FID nor
8046
 *     GetFIDColumn() are set.
8047
 *     The corresponding ArrowArray must be of type int32 (i) or int64 (l).
8048
 *     On input, values of the FID column are used to create the feature.
8049
 *     On output, the values of the FID column may be set with the FID of the
8050
 *     created feature (if the array is not released).
8051
 * </li>
8052
 * <li>IF_FID_NOT_PRESERVED=NOTHING/ERROR/WARNING. Action to perform when the
8053
 *     input FID is not preserved in the output layer. The default is NOTHING.
8054
 *     Setting it to ERROR will cause the function to error out. Setting it
8055
 *     to WARNING will cause the function to emit a warning but continue its
8056
 *     processing.
8057
 * </li>
8058
 * <li>IF_FIELD_NOT_PRESERVED=ERROR/WARNING. (since GDAL 3.9)
8059
 *     Action to perform when the input field value is not preserved in the
8060
 *     output layer.
8061
 *     The default is WARNING, which will cause the function to emit a warning
8062
 *     but continue its processing.
8063
 *     Setting it to ERROR will cause the function to error out if a lossy
8064
 *     conversion is detected.
8065
 * </li>
8066
 * <li>GEOMETRY_NAME=name. Name of the geometry column. If not provided,
8067
 *     GetGeometryColumn() is used. The special name
8068
 *     OGRLayer::DEFAULT_ARROW_GEOMETRY_NAME is also recognized if neither
8069
 *     GEOMETRY_NAME nor GetGeometryColumn() are set.
8070
 *     Geometry columns are also identified if they have
8071
 *     ARROW:extension:name=ogc.wkb as a field metadata.
8072
 *     The corresponding ArrowArray must be of type binary (w) or large
8073
 *     binary (W).
8074
 * </li>
8075
 * </ul>
8076
 *
8077
 * The following example demonstrates how to copy a layer from one format to
8078
 * another one (assuming it has at most a single geometry column):
8079
\code{.py}
8080
    def copy_layer(src_lyr, out_filename, out_format, lcos = {}):
8081
        stream = src_lyr.GetArrowStream()
8082
        schema = stream.GetSchema()
8083
8084
        # If the source layer has a FID column and the output driver supports
8085
        # a FID layer creation option, set it to the source FID column name.
8086
        if src_lyr.GetFIDColumn():
8087
            creationOptions = gdal.GetDriverByName(out_format).GetMetadataItem(
8088
                "DS_LAYER_CREATIONOPTIONLIST"
8089
            )
8090
            if creationOptions and '"FID"' in creationOptions:
8091
                lcos["FID"] = src_lyr.GetFIDColumn()
8092
8093
        with ogr.GetDriverByName(out_format).CreateDataSource(out_filename) as out_ds:
8094
            if src_lyr.GetLayerDefn().GetGeomFieldCount() > 1:
8095
                out_lyr = out_ds.CreateLayer(
8096
                    src_lyr.GetName(), geom_type=ogr.wkbNone, options=lcos
8097
                )
8098
                for i in range(src_lyr.GetLayerDefn().GetGeomFieldCount()):
8099
                    out_lyr.CreateGeomField(src_lyr.GetLayerDefn().GetGeomFieldDefn(i))
8100
            else:
8101
                out_lyr = out_ds.CreateLayer(
8102
                    src_lyr.GetName(),
8103
                    geom_type=src_lyr.GetGeomType(),
8104
                    srs=src_lyr.GetSpatialRef(),
8105
                    options=lcos,
8106
                )
8107
8108
            success, error_msg = out_lyr.IsArrowSchemaSupported(schema)
8109
            assert success, error_msg
8110
8111
            src_geom_field_names = [
8112
                src_lyr.GetLayerDefn().GetGeomFieldDefn(i).GetName()
8113
                for i in range(src_lyr.GetLayerDefn().GetGeomFieldCount())
8114
            ]
8115
            for i in range(schema.GetChildrenCount()):
8116
                # GetArrowStream() may return "OGC_FID" for a unnamed source FID
8117
                # column and "wkb_geometry" for a unnamed source geometry column.
8118
                # Also test GetFIDColumn() and src_geom_field_names if they are
8119
                # named.
8120
                if (
8121
                    schema.GetChild(i).GetName()
8122
                    not in ("OGC_FID", "wkb_geometry", src_lyr.GetFIDColumn())
8123
                    and schema.GetChild(i).GetName() not in src_geom_field_names
8124
                ):
8125
                    out_lyr.CreateFieldFromArrowSchema(schema.GetChild(i))
8126
8127
            write_options = []
8128
            if src_lyr.GetFIDColumn():
8129
                write_options.append("FID=" + src_lyr.GetFIDColumn())
8130
            if (
8131
                src_lyr.GetLayerDefn().GetGeomFieldCount() == 1
8132
                and src_lyr.GetGeometryColumn()
8133
            ):
8134
                write_options.append("GEOMETRY_NAME=" + src_lyr.GetGeometryColumn())
8135
8136
            while True:
8137
                array = stream.GetNextRecordBatch()
8138
                if array is None:
8139
                    break
8140
                out_lyr.WriteArrowBatch(schema, array, write_options)
8141
\endcode
8142
 *
8143
 * This method and CreateFeature() are mutually exclusive in the same session.
8144
 *
8145
 * This method is the same as the C++ method OGRLayer::WriteArrowBatch().
8146
 *
8147
 * @param hLayer Layer.
8148
 * @param schema Schema of array.
8149
 * @param array Array of type struct. It may be released (array->release==NULL)
8150
 *              after calling this method.
8151
 * @param papszOptions Options. Null terminated list, or nullptr.
8152
 * @return true in case of success
8153
 * @since 3.8
8154
 */
8155
// clang-format on
8156
8157
bool OGR_L_WriteArrowBatch(OGRLayerH hLayer, const struct ArrowSchema *schema,
8158
                           struct ArrowArray *array, char **papszOptions)
8159
0
{
8160
0
    VALIDATE_POINTER1(hLayer, __func__, false);
8161
0
    VALIDATE_POINTER1(schema, __func__, false);
8162
0
    VALIDATE_POINTER1(array, __func__, false);
8163
8164
0
    return OGRLayer::FromHandle(hLayer)->WriteArrowBatch(schema, array,
8165
0
                                                         papszOptions);
8166
0
}