Coverage Report

Created: 2026-05-16 08:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/ogr/ogrsf_frmts/openfilegdb/filegdbtable.h
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  OpenGIS Simple Features Reference Implementation
4
 * Purpose:  Implements reading of FileGDB tables
5
 * Author:   Even Rouault, <even dot rouault at spatialys.com>
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2014, Even Rouault <even dot rouault at spatialys.com>
9
 *
10
 * SPDX-License-Identifier: MIT
11
 ****************************************************************************/
12
13
#ifndef FILEGDBTABLE_H_INCLUDED
14
#define FILEGDBTABLE_H_INCLUDED
15
16
#include "ogr_core.h"
17
#include "cpl_progress.h"
18
#include "cpl_vsi.h"
19
#include "ogr_geometry.h"
20
21
#include <limits>
22
#include <string>
23
#include <vector>
24
25
namespace OpenFileGDB
26
{
27
constexpr uint64_t OFFSET_MINUS_ONE = static_cast<uint64_t>(-1);
28
constexpr int MAX_CAR_COUNT_INDEXED_STR = 80;
29
30
/************************************************************************/
31
/*                       FileGDBTableGeometryType                       */
32
/************************************************************************/
33
34
/* FGTGT = (F)ile(G)DB(T)able(G)eometry(T)ype */
35
typedef enum
36
{
37
    FGTGT_NONE = 0,
38
    FGTGT_POINT = 1,
39
    FGTGT_MULTIPOINT = 2,
40
    FGTGT_LINE = 3,
41
    FGTGT_POLYGON = 4,
42
    FGTGT_MULTIPATCH = 9
43
} FileGDBTableGeometryType;
44
45
/************************************************************************/
46
/*                           FileGDBFieldType                           */
47
/************************************************************************/
48
49
/* FGFT = (F)ile(G)DB(F)ield(T)ype */
50
typedef enum
51
{
52
    FGFT_UNDEFINED = -1,
53
    FGFT_INT16 = 0,
54
    FGFT_INT32 = 1,
55
    FGFT_FLOAT32 = 2,
56
    FGFT_FLOAT64 = 3,
57
    FGFT_STRING = 4,
58
    FGFT_DATETIME = 5,
59
    FGFT_OBJECTID = 6,
60
    FGFT_GEOMETRY = 7,
61
    FGFT_BINARY = 8,
62
    FGFT_RASTER = 9,
63
    FGFT_GUID = 10,
64
    FGFT_GLOBALID = 11,
65
    FGFT_XML = 12,
66
    FGFT_INT64 = 13,                 // added in ArcGIS Pro 3.2
67
    FGFT_DATE = 14,                  // added in ArcGIS Pro 3.2
68
    FGFT_TIME = 15,                  // added in ArcGIS Pro 3.2
69
    FGFT_DATETIME_WITH_OFFSET = 16,  // added in ArcGIS Pro 3.2
70
} FileGDBFieldType;
71
72
/************************************************************************/
73
/*                             FileGDBField                             */
74
/************************************************************************/
75
76
class FileGDBTable;
77
class FileGDBIndex;
78
79
class FileGDBField /* non final */
80
{
81
    friend class FileGDBTable;
82
83
    FileGDBTable *m_poParent = nullptr;
84
85
    std::string m_osName{};
86
    std::string m_osAlias{};
87
    FileGDBFieldType m_eType = FGFT_UNDEFINED;
88
89
    bool m_bNullable = false;  // Bit 1 of flag field
90
    bool m_bRequired =
91
        false;  // Bit 2 of flag field. Set for ObjectID, geometry field and Shape_Area/Shape_Length
92
    bool m_bEditable = false;       // Bit 3 of flag field.
93
    bool m_bHighPrecision = false;  // for FGFT_DATETIME
94
    bool m_bReadAsDouble =
95
        false;           // used by FileGDBTable::CreateAttributeIndex()
96
    int m_nMaxWidth = 0; /* for string */
97
98
    OGRField m_sDefault{};
99
100
    FileGDBIndex *m_poIndex = nullptr;
101
102
    FileGDBField(const FileGDBField &) = delete;
103
    FileGDBField &operator=(const FileGDBField &) = delete;
104
105
  public:
106
    static const OGRField UNSET_FIELD;
107
    static constexpr int BIT_NULLABLE = 0;
108
    static constexpr int BIT_REQUIRED = 1;
109
    static constexpr int BIT_EDITABLE = 2;
110
    static constexpr int MASK_NULLABLE = 1 << BIT_NULLABLE;
111
    static constexpr int MASK_REQUIRED = 1 << BIT_REQUIRED;
112
    static constexpr int MASK_EDITABLE = 1 << BIT_EDITABLE;
113
114
    explicit FileGDBField(FileGDBTable *m_poParent);
115
    FileGDBField(const std::string &osName, const std::string &osAlias,
116
                 FileGDBFieldType eType, bool bNullable, bool bRequired,
117
                 bool bEditable, int nMaxWidth, const OGRField &sDefault);
118
    virtual ~FileGDBField();
119
120
    void SetParent(FileGDBTable *poParent)
121
83.5k
    {
122
83.5k
        m_poParent = poParent;
123
83.5k
    }
124
125
    const std::string &GetName() const
126
93.3M
    {
127
93.3M
        return m_osName;
128
93.3M
    }
129
130
    const std::string &GetAlias() const
131
1.91M
    {
132
1.91M
        return m_osAlias;
133
1.91M
    }
134
135
    FileGDBFieldType GetType() const
136
16.4M
    {
137
16.4M
        return m_eType;
138
16.4M
    }
139
140
    bool IsNullable() const
141
6.62M
    {
142
6.62M
        return m_bNullable;
143
6.62M
    }
144
145
    bool IsRequired() const
146
1.88M
    {
147
1.88M
        return m_bRequired;
148
1.88M
    }
149
150
    bool IsEditable() const
151
1.88M
    {
152
1.88M
        return m_bEditable;
153
1.88M
    }
154
155
    int GetMaxWidth() const
156
1.87M
    {
157
1.87M
        return m_nMaxWidth;
158
1.87M
    }
159
160
    const OGRField *GetDefault() const
161
1.92M
    {
162
1.92M
        return &m_sDefault;
163
1.92M
    }
164
165
    void SetHighPrecision()
166
0
    {
167
0
        m_bHighPrecision = true;
168
0
    }
169
170
    bool IsHighPrecision() const
171
1.77M
    {
172
1.77M
        return m_bHighPrecision;
173
1.77M
    }
174
175
    int HasIndex();
176
    FileGDBIndex *GetIndex();
177
};
178
179
/************************************************************************/
180
/*                           FileGDBGeomField                           */
181
/************************************************************************/
182
183
class FileGDBGeomField /* non final */ : public FileGDBField
184
{
185
    friend class FileGDBTable;
186
187
    static const double ESRI_NAN;
188
189
    std::string m_osWKT{};
190
    int m_bHasZOriginScaleTolerance = 0;
191
    int m_bHasMOriginScaleTolerance = 0;
192
    double m_dfXOrigin = 0;
193
    double m_dfYOrigin = 0;
194
    double m_dfXYScale = 0;
195
    double m_dfMOrigin = 0;
196
    double m_dfMScale = 0;
197
    double m_dfZOrigin = 0;
198
    double m_dfZScale = 0;
199
    double m_dfXYTolerance = 0;
200
    double m_dfMTolerance = 0;
201
    double m_dfZTolerance = 0;
202
    double m_dfXMin = ESRI_NAN;
203
    double m_dfYMin = ESRI_NAN;
204
    double m_dfZMin = ESRI_NAN;
205
    double m_dfMMin = ESRI_NAN;
206
    double m_dfXMax = ESRI_NAN;
207
    double m_dfYMax = ESRI_NAN;
208
    double m_dfZMax = ESRI_NAN;
209
    double m_dfMMax = ESRI_NAN;
210
    std::vector<double> m_adfSpatialIndexGridResolution{};
211
212
  public:
213
    explicit FileGDBGeomField(FileGDBTable *m_poParent);
214
    FileGDBGeomField(const std::string &osName, const std::string &osAlias,
215
                     bool bNullable, const std::string &osWKT, double dfXOrigin,
216
                     double dfYOrigin, double dfXYScale, double dfXYTolerance,
217
                     const std::vector<double> &adfSpatialIndexGridResolution);
218
219
    ~FileGDBGeomField() override;
220
221
    const std::string &GetWKT() const
222
34.2k
    {
223
34.2k
        return m_osWKT;
224
34.2k
    }
225
226
    double GetXMin() const
227
11.1k
    {
228
11.1k
        return m_dfXMin;
229
11.1k
    }
230
231
    double GetYMin() const
232
10.5k
    {
233
10.5k
        return m_dfYMin;
234
10.5k
    }
235
236
    double GetZMin() const
237
1.70k
    {
238
1.70k
        return m_dfZMin;
239
1.70k
    }  // only valid for m_bGeomTypeHasZ
240
241
    double GetMMin() const
242
0
    {
243
0
        return m_dfMMin;
244
0
    }  // only valid for m_bGeomTypeHasM
245
246
    double GetXMax() const
247
10.5k
    {
248
10.5k
        return m_dfXMax;
249
10.5k
    }
250
251
    double GetYMax() const
252
10.5k
    {
253
10.5k
        return m_dfYMax;
254
10.5k
    }
255
256
    double GetZMax() const
257
1.70k
    {
258
1.70k
        return m_dfZMax;
259
1.70k
    }  // only valid for m_bGeomTypeHasZ
260
261
    double GetMMax() const
262
0
    {
263
0
        return m_dfMMax;
264
0
    }  // only valid for m_bGeomTypeHasM
265
266
    void SetXYMinMax(double dfXMin, double dfYMin, double dfXMax,
267
                     double dfYMax);
268
    void SetZMinMax(double dfZMin, double dfZMax);
269
    void SetMMinMax(double dfMMin, double dfMMax);
270
271
    int HasZOriginScaleTolerance() const
272
11.0k
    {
273
11.0k
        return m_bHasZOriginScaleTolerance;
274
11.0k
    }
275
276
    int HasMOriginScaleTolerance() const
277
11.0k
    {
278
11.0k
        return m_bHasMOriginScaleTolerance;
279
11.0k
    }
280
281
    double GetXOrigin() const
282
2.27M
    {
283
2.27M
        return m_dfXOrigin;
284
2.27M
    }
285
286
    double GetYOrigin() const
287
2.27M
    {
288
2.27M
        return m_dfYOrigin;
289
2.27M
    }
290
291
    double GetXYScale() const
292
4.51M
    {
293
4.51M
        return m_dfXYScale;
294
4.51M
    }
295
296
    double GetXYTolerance() const
297
34.7k
    {
298
34.7k
        return m_dfXYTolerance;
299
34.7k
    }
300
301
    double GetZOrigin() const
302
517k
    {
303
517k
        return m_dfZOrigin;
304
517k
    }
305
306
    double GetZScale() const
307
132k
    {
308
132k
        return m_dfZScale;
309
132k
    }
310
311
    double GetZTolerance() const
312
34.7k
    {
313
34.7k
        return m_dfZTolerance;
314
34.7k
    }
315
316
    void SetZOriginScaleTolerance(double dfZOrigin, double dfZScale,
317
                                  double dfZTolerance);
318
319
    double GetMOrigin() const
320
693k
    {
321
693k
        return m_dfMOrigin;
322
693k
    }
323
324
    double GetMScale() const
325
143k
    {
326
143k
        return m_dfMScale;
327
143k
    }
328
329
    double GetMTolerance() const
330
34.7k
    {
331
34.7k
        return m_dfMTolerance;
332
34.7k
    }
333
334
    void SetMOriginScaleTolerance(double dfMOrigin, double dfMScale,
335
                                  double dfMTolerance);
336
337
    const std::vector<double> &GetSpatialIndexGridResolution() const
338
6.67k
    {
339
6.67k
        return m_adfSpatialIndexGridResolution;
340
6.67k
    }
341
};
342
343
/************************************************************************/
344
/*                          FileGDBRasterField                          */
345
/************************************************************************/
346
347
class FileGDBRasterField final : public FileGDBGeomField
348
{
349
  public:
350
    enum class Type
351
    {
352
        EXTERNAL,
353
        MANAGED,
354
        INLINE,
355
    };
356
357
  private:
358
    friend class FileGDBTable;
359
360
    std::string m_osRasterColumnName{};
361
362
    Type m_eRasterType = Type::EXTERNAL;
363
364
    FileGDBRasterField(const FileGDBRasterField &) = delete;
365
    FileGDBRasterField &operator=(const FileGDBRasterField &) = delete;
366
367
  public:
368
    explicit FileGDBRasterField(FileGDBTable *poParentIn)
369
875
        : FileGDBGeomField(poParentIn)
370
875
    {
371
875
    }
372
373
    ~FileGDBRasterField() override;
374
375
    const std::string &GetRasterColumnName() const
376
0
    {
377
0
        return m_osRasterColumnName;
378
0
    }
379
380
    Type GetRasterType() const
381
1.21M
    {
382
1.21M
        return m_eRasterType;
383
1.21M
    }
384
};
385
386
/************************************************************************/
387
/*                             FileGDBIndex                             */
388
/************************************************************************/
389
390
class FileGDBIndex
391
{
392
    friend class FileGDBTable;
393
    std::string m_osIndexName{};
394
    std::string m_osExpression{};
395
396
  public:
397
7.32k
    FileGDBIndex() = default;
398
399
    ~FileGDBIndex();
400
401
    const std::string &GetIndexName() const
402
9.59k
    {
403
9.59k
        return m_osIndexName;
404
9.59k
    }
405
406
    const std::string &GetExpression() const
407
9.38k
    {
408
9.38k
        return m_osExpression;
409
9.38k
    }
410
411
    std::string GetFieldName() const;
412
    int GetMaxWidthInBytes(const FileGDBTable *poTable) const;
413
414
    static std::string
415
    GetFieldNameFromExpression(const std::string &osExpression);
416
};
417
418
/************************************************************************/
419
/*                             FileGDBTable                             */
420
/************************************************************************/
421
422
class FileGDBTable
423
{
424
    VSILFILE *m_fpTable = nullptr;
425
    VSILFILE *m_fpTableX = nullptr;
426
427
    enum class GDBTableVersion
428
    {
429
        V3 = 3,  // 32-bit object id
430
        V4 = 4,  // 64-bit object id (ince ArcGIS Pro 3.2)
431
    };
432
    GDBTableVersion m_eGDBTableVersion = GDBTableVersion::V3;
433
    vsi_l_offset m_nFileSize = 0; /* only read when needed */
434
    bool m_bUpdate = false;
435
    bool m_bReliableObjectID = true;  // can be set to false on some V4 files
436
437
    //! This flag is set when we detect that a corruption of m_nHeaderBufferMaxSize
438
    // prior to fix needs to  fdf39012788b1110b3bf0ae6b8422a528f0ae8b6 to be
439
    // repaired
440
    bool m_bHasWarnedAboutHeaderRepair = false;
441
442
    std::string m_osFilename{};
443
    std::string m_osFilenameWithLayerName{};
444
    bool m_bIsV9 = false;
445
    std::vector<std::unique_ptr<FileGDBField>> m_apoFields{};
446
    int m_iObjectIdField = -1;
447
448
    int m_bHasReadGDBIndexes = FALSE;
449
    std::vector<std::unique_ptr<FileGDBIndex>> m_apoIndexes{};
450
451
    int m_nHasSpatialIndex = -1;
452
453
    bool m_bDirtyHeader = false;
454
    bool m_bDirtyFieldDescriptors = false;
455
    bool m_bDirtyIndices = false;
456
    bool m_bDirtyGdbIndexesFile = false;
457
458
    uint32_t m_nHeaderBufferMaxSize = 0;
459
    GUIntBig m_nOffsetFieldDesc = 0;
460
    GUInt32 m_nFieldDescLength = 0;
461
    bool m_bDirtyGeomFieldBBox = false;
462
    bool m_bDirtyGeomFieldSpatialIndexGridRes = false;
463
    uint32_t m_nGeomFieldBBoxSubOffset =
464
        0;  // offset of geometry field bounding box
465
            // relative to m_nOffsetFieldDesc
466
    uint32_t m_nGeomFieldSpatialIndexGridResSubOffset =
467
        0;  // offset of geometry field spatial index grid resolution
468
            // relative to m_nOffsetFieldDesc
469
470
    GUInt32 m_nTablxOffsetSize =
471
        0;  // 4 (4 GB limit), 5 (1 TB limit), 6 (256 TB limit)
472
    std::vector<vsi_l_offset>
473
        m_anFeatureOffsets{}; /* MSb set marks deleted feature. Only used when
474
                                 no .gdbtablx file */
475
476
    uint64_t m_nOffsetTableXTrailer = 0;
477
    uint64_t m_n1024BlocksPresent = 0;
478
    std::vector<GByte> m_abyTablXBlockMap{};
479
    int m_nCountBlocksBeforeIBlockIdx = 0;   /* optimization */
480
    int m_nCountBlocksBeforeIBlockValue = 0; /* optimization */
481
    bool m_bDirtyTableXHeader = false;
482
    bool m_bDirtyTableXTrailer = false;
483
484
    int m_nHasFreeList = -1;
485
    bool m_bFreelistCanBeDeleted = false;
486
487
    char m_achGUIDBuffer[32 + 6 + 1]{0};
488
    int m_nChSaved = -1;
489
490
    int m_bError = FALSE;
491
    int64_t m_nCurRow = -1;
492
    int m_bHasDeletedFeaturesListed = FALSE;
493
    bool m_bIsDeleted = false;
494
    int m_nLastCol = -1;
495
    GByte *m_pabyIterVals = nullptr;
496
    int m_iAccNullable = 0;
497
    GUInt32 m_nRowBlobLength = 0;
498
    OGRField m_sCurField{};
499
500
    FileGDBTableGeometryType m_eTableGeomType = FGTGT_NONE;
501
    bool m_bGeomTypeHasZ = false;
502
    bool m_bGeomTypeHasM = false;
503
    bool m_bStringsAreUTF8 = true;  // if false, UTF16
504
    std::string m_osTempString{};   // used as a temporary to store strings
505
                                    // recoded from UTF16 to UTF8
506
    int64_t m_nValidRecordCount = 0;
507
    int64_t m_nTotalRecordCount = 0;
508
    int m_iGeomField = -1;
509
    int m_nCountNullableFields = 0;
510
    unsigned m_nNullableFieldsSizeInBytes = 0;
511
512
    std::vector<double> m_adfSpatialIndexGridResolution{};
513
514
    GUInt32 m_nRowBufferMaxSize = 0;
515
    std::vector<GByte> m_abyBuffer{};
516
    std::vector<GByte> m_abyGeomBuffer{};
517
    std::vector<GByte> m_abyCurvePart{};
518
    std::vector<uint32_t> m_anNumberPointsPerPart{};
519
    std::vector<double> m_adfX{};
520
    std::vector<double> m_adfY{};
521
    std::vector<double> m_adfZ{};
522
    std::vector<double> m_adfM{};
523
524
    std::string m_osCacheRasterFieldPath{};
525
526
    GUIntBig m_nFilterXMin = 0, m_nFilterXMax = 0, m_nFilterYMin = 0,
527
             m_nFilterYMax = 0;
528
529
    class WholeFileRewriter
530
    {
531
        FileGDBTable &m_oTable;
532
        bool m_bModifyInPlace = false;
533
        std::string m_osGdbTablx{};
534
        std::string m_osBackupValidFilename{};
535
        std::string m_osBackupGdbTable{};
536
        std::string m_osBackupGdbTablx{};
537
        std::string m_osTmpGdbTable{};
538
        std::string m_osTmpGdbTablx{};
539
        bool m_bOldDirtyIndices = false;
540
        uint64_t m_nOldFileSize = 0;
541
        uint64_t m_nOldOffsetFieldDesc = 0;
542
        uint32_t m_nOldFieldDescLength = 0;
543
        bool m_bIsInit = false;
544
545
        WholeFileRewriter(const WholeFileRewriter &) = delete;
546
        WholeFileRewriter &operator=(const WholeFileRewriter &) = delete;
547
548
      public:
549
        VSILFILE *m_fpOldGdbtable = nullptr;
550
        VSILFILE *m_fpOldGdbtablx = nullptr;
551
        VSILFILE *m_fpTable = nullptr;
552
        VSILFILE *m_fpTableX = nullptr;
553
554
559
        explicit WholeFileRewriter(FileGDBTable &oTable) : m_oTable(oTable)
555
559
        {
556
559
        }
557
558
        ~WholeFileRewriter();
559
560
        bool Begin();
561
        bool Commit();
562
        void Rollback();
563
    };
564
565
    bool WriteHeader(VSILFILE *fpTable);
566
    bool WriteHeaderX(VSILFILE *fpTableX);
567
568
    bool ReadTableXHeaderV3();
569
    bool ReadTableXHeaderV4();
570
    int IsLikelyFeatureAtOffset(vsi_l_offset nOffset, GUInt32 *pnSize,
571
                                int *pbDeletedRecord);
572
    bool GuessFeatureLocations();
573
    bool WriteFieldDescriptors(VSILFILE *fpTable);
574
    bool SeekIntoTableXForNewFeature(int nObjectID);
575
    uint64_t ReadFeatureOffset(const GByte *pabyBuffer);
576
    void WriteFeatureOffset(uint64_t nFeatureOffset, GByte *pabyBuffer);
577
    bool WriteFeatureOffset(uint64_t nFeatureOffset);
578
    bool EncodeFeature(const std::vector<OGRField> &asRawFields,
579
                       const OGRGeometry *poGeom, int iSkipField);
580
    bool EncodeGeometry(const FileGDBGeomField *poGeomField,
581
                        const OGRGeometry *poGeom);
582
    bool RewriteTableToAddLastAddedField();
583
    void CreateGdbIndexesFile();
584
    void RemoveIndices();
585
    void RefreshIndices();
586
    bool CreateAttributeIndex(const FileGDBIndex *poIndex);
587
    uint64_t GetOffsetOfFreeAreaFromFreeList(uint32_t nSize);
588
    void AddEntryToFreelist(uint64_t nOffset, uint32_t nSize);
589
590
    FileGDBTable(const FileGDBTable &) = delete;
591
    FileGDBTable &operator=(const FileGDBTable &) = delete;
592
593
  public:
594
    FileGDBTable();
595
    ~FileGDBTable();
596
597
    bool Open(const char *pszFilename, bool bUpdate,
598
              const char *pszLayerName = nullptr);
599
600
    bool Create(const char *pszFilename, int nTablxOffsetSize,
601
                FileGDBTableGeometryType eTableGeomType, bool bGeomTypeHasZ,
602
                bool bGeomTypeHasM);
603
    bool SetTextUTF16();
604
605
    bool Sync(VSILFILE *fpTable = nullptr, VSILFILE *fpTableX = nullptr);
606
    bool Repack(GDALProgressFunc pfnProgress, void *pProgressData);
607
    void RecomputeExtent();
608
609
    //! Object should no longer be used after Close()
610
    void Close();
611
612
    bool IsFileGDBV9() const
613
0
    {
614
0
        return m_bIsV9;
615
0
    }
616
617
    const std::string &GetFilename() const
618
0
    {
619
0
        return m_osFilename;
620
0
    }
621
622
    FileGDBTableGeometryType GetGeometryType() const
623
43.7k
    {
624
43.7k
        return m_eTableGeomType;
625
43.7k
    }
626
627
    bool GetGeomTypeHasZ() const
628
6.42k
    {
629
6.42k
        return m_bGeomTypeHasZ;
630
6.42k
    }
631
632
    bool GetGeomTypeHasM() const
633
6.42k
    {
634
6.42k
        return m_bGeomTypeHasM;
635
6.42k
    }
636
637
    int64_t GetValidRecordCount() const
638
6.34k
    {
639
6.34k
        return m_nValidRecordCount;
640
6.34k
    }
641
642
    int64_t GetTotalRecordCount() const
643
1.82M
    {
644
1.82M
        return m_nTotalRecordCount;
645
1.82M
    }
646
647
    int GetFieldCount() const
648
3.83M
    {
649
3.83M
        return static_cast<int>(m_apoFields.size());
650
3.83M
    }
651
652
    FileGDBField *GetField(int i) const
653
6.08M
    {
654
6.08M
        return m_apoFields[i].get();
655
6.08M
    }
656
657
    int GetGeomFieldIdx() const
658
11.4k
    {
659
11.4k
        return m_iGeomField;
660
11.4k
    }
661
662
    const FileGDBGeomField *GetGeomField() const
663
35.0k
    {
664
35.0k
        return (m_iGeomField >= 0) ? cpl::down_cast<FileGDBGeomField *>(
665
35.0k
                                         m_apoFields[m_iGeomField].get())
666
35.0k
                                   : nullptr;
667
35.0k
    }
668
669
    int GetObjectIdFieldIdx() const
670
927k
    {
671
927k
        return m_iObjectIdField;
672
927k
    }
673
674
    int GetFieldIdx(const std::string &osName) const;
675
676
    int GetIndexCount();
677
678
    const FileGDBIndex *GetIndex(int i) const
679
0
    {
680
0
        return m_apoIndexes[i].get();
681
0
    }
682
683
    /** Return if we can use attribute or spatial indices.
684
     * This can be false for some sparse tables with 64-bit ObjectID since
685
     * the format of the sparse bitmap isn't fully understood yet.
686
     */
687
    bool CanUseIndices() const
688
6.68k
    {
689
6.68k
        return m_bReliableObjectID;
690
6.68k
    }
691
692
    bool HasSpatialIndex();
693
    bool CreateIndex(const std::string &osIndexName,
694
                     const std::string &osExpression);
695
    void ComputeOptimalSpatialIndexGridResolution();
696
    bool CreateSpatialIndex();
697
698
    vsi_l_offset
699
    GetOffsetInTableForRow(int64_t iRow,
700
                           vsi_l_offset *pnOffsetInTableX = nullptr);
701
702
    int HasDeletedFeaturesListed() const
703
191k
    {
704
191k
        return m_bHasDeletedFeaturesListed;
705
191k
    }
706
707
    /* Next call to SelectRow() or GetFieldValue() invalidates previously
708
     * returned values */
709
    bool SelectRow(int64_t iRow, bool bWarnOnlyOnDeletedRows = false);
710
    int64_t GetAndSelectNextNonEmptyRow(int64_t iRow);
711
712
    int HasGotError() const
713
2.67M
    {
714
2.67M
        return m_bError;
715
2.67M
    }
716
717
    int64_t GetCurRow() const
718
182k
    {
719
182k
        return m_nCurRow;
720
182k
    }
721
722
    bool IsCurRowDeleted() const
723
0
    {
724
0
        return m_bIsDeleted;
725
0
    }
726
727
    const OGRField *GetFieldValue(int iCol);
728
    std::vector<OGRField> GetAllFieldValues();
729
    void FreeAllFieldValues(std::vector<OGRField> &asFields);
730
731
    int GetFeatureExtent(const OGRField *psGeomField,
732
                         OGREnvelope *psOutFeatureEnvelope);
733
734
    const std::vector<double> &GetSpatialIndexGridResolution() const
735
0
    {
736
0
        return m_adfSpatialIndexGridResolution;
737
0
    }
738
739
    void InstallFilterEnvelope(const OGREnvelope *psFilterEnvelope);
740
    int DoesGeometryIntersectsFilterEnvelope(const OGRField *psGeomField);
741
742
    void GetMinMaxProjYForSpatialIndex(double &dfYMin, double &dfYMax) const;
743
744
    bool CreateField(std::unique_ptr<FileGDBField> &&psField);
745
    bool DeleteField(int iField);
746
    bool AlterField(int iField, const std::string &osName,
747
                    const std::string &osAlias, FileGDBFieldType eType,
748
                    bool bNullable, int nMaxWidth, const OGRField &sDefault);
749
    bool AlterGeomField(const std::string &osName, const std::string &osAlias,
750
                        bool bNullable, const std::string &osWKT);
751
752
    bool CreateFeature(const std::vector<OGRField> &asRawFields,
753
                       const OGRGeometry *poGeom, int *pnFID = nullptr);
754
    bool UpdateFeature(int64_t nFID, const std::vector<OGRField> &asRawFields,
755
                       const OGRGeometry *poGeom);
756
    bool DeleteFeature(int64_t nFID);
757
758
    bool CheckFreeListConsistency();
759
    void DeleteFreeList();
760
};
761
762
/************************************************************************/
763
/*                             FileGDBSQLOp                             */
764
/************************************************************************/
765
766
typedef enum
767
{
768
    FGSO_ISNOTNULL,
769
    FGSO_LT,
770
    FGSO_LE,
771
    FGSO_EQ,
772
    FGSO_GE,
773
    FGSO_GT,
774
    FGSO_ILIKE
775
} FileGDBSQLOp;
776
777
/************************************************************************/
778
/*                           FileGDBIterator                            */
779
/************************************************************************/
780
781
class FileGDBIterator /* non final */
782
{
783
  public:
784
0
    virtual ~FileGDBIterator() = default;
785
786
    virtual FileGDBTable *GetTable() = 0;
787
    virtual void Reset() = 0;
788
    virtual int64_t GetNextRowSortedByFID() = 0;
789
    virtual int64_t GetRowCount();
790
791
    /* Only available on a BuildIsNotNull() iterator */
792
    virtual const OGRField *GetMinValue(int &eOutOGRFieldType);
793
    virtual const OGRField *GetMaxValue(int &eOutOGRFieldType);
794
    /* will reset the iterator */
795
    virtual bool GetMinMaxSumCount(double &dfMin, double &dfMax, double &dfSum,
796
                                   int &nCount);
797
798
    /* Only available on a BuildIsNotNull() or Build() iterator */
799
    virtual int64_t GetNextRowSortedByValue();
800
801
    static FileGDBIterator *Build(FileGDBTable *poParent, int nFieldIdx,
802
                                  int bAscending, FileGDBSQLOp op,
803
                                  OGRFieldType eOGRFieldType,
804
                                  const OGRField *psValue);
805
    static FileGDBIterator *BuildIsNotNull(FileGDBTable *poParent,
806
                                           int nFieldIdx, int bAscending);
807
    static FileGDBIterator *BuildNot(FileGDBIterator *poIterBase);
808
    static FileGDBIterator *BuildAnd(FileGDBIterator *poIter1,
809
                                     FileGDBIterator *poIter2,
810
                                     bool bTakeOwnershipOfIterators);
811
    static FileGDBIterator *BuildOr(FileGDBIterator *poIter1,
812
                                    FileGDBIterator *poIter2,
813
                                    int bIteratorAreExclusive = FALSE);
814
};
815
816
/************************************************************************/
817
/*                     FileGDBSpatialIndexIterator                      */
818
/************************************************************************/
819
820
class FileGDBSpatialIndexIterator /* non final */
821
    : virtual public FileGDBIterator
822
{
823
  public:
824
    virtual bool SetEnvelope(const OGREnvelope &sFilterEnvelope) = 0;
825
826
    ~FileGDBSpatialIndexIterator() override;
827
828
    static FileGDBSpatialIndexIterator *
829
    Build(FileGDBTable *poParent, const OGREnvelope &sFilterEnvelope);
830
};
831
832
/************************************************************************/
833
/*                     FileGDBOGRGeometryConverter                      */
834
/************************************************************************/
835
836
class FileGDBOGRGeometryConverter /* non final */
837
{
838
  public:
839
    virtual ~FileGDBOGRGeometryConverter();
840
841
    virtual OGRGeometry *GetAsGeometry(const OGRField *psField) = 0;
842
843
    static FileGDBOGRGeometryConverter *
844
    BuildConverter(const FileGDBGeomField *poGeomField);
845
    static OGRwkbGeometryType
846
    GetGeometryTypeFromESRI(const char *pszESRIGeometryType);
847
};
848
849
int FileGDBDoubleDateToOGRDate(double dfVal, bool bHighPrecision,
850
                               OGRField *psField);
851
int FileGDBDoubleTimeToOGRTime(double dfVal, OGRField *psField);
852
int FileGDBDateTimeWithOffsetToOGRDate(double dfVal, int16_t nUTCOffset,
853
                                       OGRField *psField);
854
855
} /* namespace OpenFileGDB */
856
857
#endif /* ndef FILEGDBTABLE_H_INCLUDED */