Coverage Report

Created: 2025-11-16 06:25

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