Coverage Report

Created: 2026-04-01 06:20

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