Line data Source code
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
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 14461 : void SetParent(FileGDBTable *poParent)
121 : {
122 14461 : m_poParent = poParent;
123 14461 : }
124 :
125 305265 : const std::string &GetName() const
126 : {
127 305265 : return m_osName;
128 : }
129 :
130 23415 : const std::string &GetAlias() const
131 : {
132 23415 : return m_osAlias;
133 : }
134 :
135 377716 : FileGDBFieldType GetType() const
136 : {
137 377716 : return m_eType;
138 : }
139 :
140 152869 : bool IsNullable() const
141 : {
142 152869 : return m_bNullable;
143 : }
144 :
145 19230 : bool IsRequired() const
146 : {
147 19230 : return m_bRequired;
148 : }
149 :
150 19230 : bool IsEditable() const
151 : {
152 19230 : return m_bEditable;
153 : }
154 :
155 8988 : int GetMaxWidth() const
156 : {
157 8988 : return m_nMaxWidth;
158 : }
159 :
160 23657 : const OGRField *GetDefault() const
161 : {
162 23657 : return &m_sDefault;
163 : }
164 :
165 2 : void SetHighPrecision()
166 : {
167 2 : m_bHighPrecision = true;
168 2 : }
169 :
170 12006 : bool IsHighPrecision() const
171 : {
172 12006 : return m_bHighPrecision;
173 : }
174 :
175 : int HasIndex();
176 : FileGDBIndex *GetIndex();
177 : };
178 :
179 : /************************************************************************/
180 : /* FileGDBGeomField */
181 : /************************************************************************/
182 :
183 6341 : class FileGDBGeomField : 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 : virtual ~FileGDBGeomField();
220 :
221 2859 : const std::string &GetWKT() const
222 : {
223 2859 : return m_osWKT;
224 : }
225 :
226 13266 : double GetXMin() const
227 : {
228 13266 : return m_dfXMin;
229 : }
230 :
231 7022 : double GetYMin() const
232 : {
233 7022 : return m_dfYMin;
234 : }
235 :
236 4047 : double GetZMin() const
237 : {
238 4047 : return m_dfZMin;
239 : } // only valid for m_bGeomTypeHasZ
240 :
241 25 : double GetMMin() const
242 : {
243 25 : return m_dfMMin;
244 : } // only valid for m_bGeomTypeHasM
245 :
246 7022 : double GetXMax() const
247 : {
248 7022 : return m_dfXMax;
249 : }
250 :
251 7022 : double GetYMax() const
252 : {
253 7022 : return m_dfYMax;
254 : }
255 :
256 4041 : double GetZMax() const
257 : {
258 4041 : return m_dfZMax;
259 : } // only valid for m_bGeomTypeHasZ
260 :
261 25 : double GetMMax() const
262 : {
263 25 : return m_dfMMax;
264 : } // 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 1806 : int HasZOriginScaleTolerance() const
272 : {
273 1806 : return m_bHasZOriginScaleTolerance;
274 : }
275 :
276 1806 : int HasMOriginScaleTolerance() const
277 : {
278 1806 : return m_bHasMOriginScaleTolerance;
279 : }
280 :
281 65762 : double GetXOrigin() const
282 : {
283 65762 : return m_dfXOrigin;
284 : }
285 :
286 65762 : double GetYOrigin() const
287 : {
288 65762 : return m_dfYOrigin;
289 : }
290 :
291 130307 : double GetXYScale() const
292 : {
293 130307 : return m_dfXYScale;
294 : }
295 :
296 1773 : double GetXYTolerance() const
297 : {
298 1773 : return m_dfXYTolerance;
299 : }
300 :
301 22634 : double GetZOrigin() const
302 : {
303 22634 : return m_dfZOrigin;
304 : }
305 :
306 5895 : double GetZScale() const
307 : {
308 5895 : return m_dfZScale;
309 : }
310 :
311 1773 : double GetZTolerance() const
312 : {
313 1773 : return m_dfZTolerance;
314 : }
315 :
316 : void SetZOriginScaleTolerance(double dfZOrigin, double dfZScale,
317 : double dfZTolerance);
318 :
319 2919 : double GetMOrigin() const
320 : {
321 2919 : return m_dfMOrigin;
322 : }
323 :
324 2209 : double GetMScale() const
325 : {
326 2209 : return m_dfMScale;
327 : }
328 :
329 1773 : double GetMTolerance() const
330 : {
331 1773 : return m_dfMTolerance;
332 : }
333 :
334 : void SetMOriginScaleTolerance(double dfMOrigin, double dfMScale,
335 : double dfMTolerance);
336 :
337 1209 : const std::vector<double> &GetSpatialIndexGridResolution() const
338 : {
339 1209 : return m_adfSpatialIndexGridResolution;
340 : }
341 : };
342 :
343 : /************************************************************************/
344 : /* FileGDBRasterField */
345 : /************************************************************************/
346 :
347 6 : class FileGDBRasterField : 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 3 : explicit FileGDBRasterField(FileGDBTable *poParentIn)
369 3 : : FileGDBGeomField(poParentIn)
370 : {
371 3 : }
372 :
373 : virtual ~FileGDBRasterField();
374 :
375 : const std::string &GetRasterColumnName() const
376 : {
377 : return m_osRasterColumnName;
378 : }
379 :
380 1 : Type GetRasterType() const
381 : {
382 1 : return m_eRasterType;
383 : }
384 : };
385 :
386 : /************************************************************************/
387 : /* FileGDBIndex */
388 : /************************************************************************/
389 :
390 1246 : class FileGDBIndex
391 : {
392 : friend class FileGDBTable;
393 : std::string m_osIndexName{};
394 : std::string m_osExpression{};
395 :
396 : public:
397 1246 : FileGDBIndex() = default;
398 :
399 : ~FileGDBIndex();
400 :
401 1503 : const std::string &GetIndexName() const
402 : {
403 1503 : return m_osIndexName;
404 : }
405 :
406 1181 : const std::string &GetExpression() const
407 : {
408 1181 : return m_osExpression;
409 : }
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 45 : explicit WholeFileRewriter(FileGDBTable &oTable) : m_oTable(oTable)
555 : {
556 45 : }
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 194 : bool IsFileGDBV9() const
613 : {
614 194 : return m_bIsV9;
615 : }
616 :
617 1690 : const std::string &GetFilename() const
618 : {
619 1690 : return m_osFilename;
620 : }
621 :
622 5414 : FileGDBTableGeometryType GetGeometryType() const
623 : {
624 5414 : return m_eTableGeomType;
625 : }
626 :
627 127 : bool GetGeomTypeHasZ() const
628 : {
629 127 : return m_bGeomTypeHasZ;
630 : }
631 :
632 127 : bool GetGeomTypeHasM() const
633 : {
634 127 : return m_bGeomTypeHasM;
635 : }
636 :
637 4087 : int64_t GetValidRecordCount() const
638 : {
639 4087 : return m_nValidRecordCount;
640 : }
641 :
642 1606080 : int64_t GetTotalRecordCount() const
643 : {
644 1606080 : return m_nTotalRecordCount;
645 : }
646 :
647 240161 : int GetFieldCount() const
648 : {
649 240161 : return static_cast<int>(m_apoFields.size());
650 : }
651 :
652 56625 : FileGDBField *GetField(int i) const
653 : {
654 56625 : return m_apoFields[i].get();
655 : }
656 :
657 1107 : int GetGeomFieldIdx() const
658 : {
659 1107 : return m_iGeomField;
660 : }
661 :
662 2065 : const FileGDBGeomField *GetGeomField() const
663 : {
664 4129 : return (m_iGeomField >= 0) ? cpl::down_cast<FileGDBGeomField *>(
665 2064 : m_apoFields[m_iGeomField].get())
666 2065 : : nullptr;
667 : }
668 :
669 173487 : int GetObjectIdFieldIdx() const
670 : {
671 173487 : return m_iObjectIdField;
672 : }
673 :
674 : int GetFieldIdx(const std::string &osName) const;
675 :
676 : int GetIndexCount();
677 :
678 : const FileGDBIndex *GetIndex(int i) const
679 : {
680 : return m_apoIndexes[i].get();
681 : }
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 1004 : bool CanUseIndices() const
688 : {
689 1004 : return m_bReliableObjectID;
690 : }
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 28322 : int HasDeletedFeaturesListed() const
703 : {
704 28322 : return m_bHasDeletedFeaturesListed;
705 : }
706 :
707 : /* Next call to SelectRow() or GetFieldValue() invalidates previously
708 : * returned values */
709 : bool SelectRow(int64_t iRow);
710 : int64_t GetAndSelectNextNonEmptyRow(int64_t iRow);
711 :
712 1781160 : int HasGotError() const
713 : {
714 1781160 : return m_bError;
715 : }
716 :
717 38559 : int64_t GetCurRow() const
718 : {
719 38559 : return m_nCurRow;
720 : }
721 :
722 0 : bool IsCurRowDeleted() const
723 : {
724 0 : return m_bIsDeleted;
725 : }
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 27589 : const std::vector<double> &GetSpatialIndexGridResolution() const
735 : {
736 27589 : return m_adfSpatialIndexGridResolution;
737 : }
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
782 : {
783 : public:
784 891 : virtual ~FileGDBIterator()
785 891 : {
786 891 : }
787 :
788 : virtual FileGDBTable *GetTable() = 0;
789 : virtual void Reset() = 0;
790 : virtual int64_t GetNextRowSortedByFID() = 0;
791 : virtual int64_t GetRowCount();
792 :
793 : /* Only available on a BuildIsNotNull() iterator */
794 : virtual const OGRField *GetMinValue(int &eOutOGRFieldType);
795 : virtual const OGRField *GetMaxValue(int &eOutOGRFieldType);
796 : /* will reset the iterator */
797 : virtual bool GetMinMaxSumCount(double &dfMin, double &dfMax, double &dfSum,
798 : int &nCount);
799 :
800 : /* Only available on a BuildIsNotNull() or Build() iterator */
801 : virtual int64_t GetNextRowSortedByValue();
802 :
803 : static FileGDBIterator *Build(FileGDBTable *poParent, int nFieldIdx,
804 : int bAscending, FileGDBSQLOp op,
805 : OGRFieldType eOGRFieldType,
806 : const OGRField *psValue);
807 : static FileGDBIterator *BuildIsNotNull(FileGDBTable *poParent,
808 : int nFieldIdx, int bAscending);
809 : static FileGDBIterator *BuildNot(FileGDBIterator *poIterBase);
810 : static FileGDBIterator *BuildAnd(FileGDBIterator *poIter1,
811 : FileGDBIterator *poIter2,
812 : bool bTakeOwnershipOfIterators);
813 : static FileGDBIterator *BuildOr(FileGDBIterator *poIter1,
814 : FileGDBIterator *poIter2,
815 : int bIteratorAreExclusive = FALSE);
816 : };
817 :
818 : /************************************************************************/
819 : /* FileGDBSpatialIndexIterator */
820 : /************************************************************************/
821 :
822 361 : class FileGDBSpatialIndexIterator : virtual public FileGDBIterator
823 : {
824 : public:
825 : virtual bool SetEnvelope(const OGREnvelope &sFilterEnvelope) = 0;
826 :
827 : ~FileGDBSpatialIndexIterator() override;
828 :
829 : static FileGDBSpatialIndexIterator *
830 : Build(FileGDBTable *poParent, const OGREnvelope &sFilterEnvelope);
831 : };
832 :
833 : /************************************************************************/
834 : /* FileGDBOGRGeometryConverter */
835 : /************************************************************************/
836 :
837 968 : class FileGDBOGRGeometryConverter
838 : {
839 : public:
840 : virtual ~FileGDBOGRGeometryConverter();
841 :
842 : virtual OGRGeometry *GetAsGeometry(const OGRField *psField) = 0;
843 :
844 : static FileGDBOGRGeometryConverter *
845 : BuildConverter(const FileGDBGeomField *poGeomField);
846 : static OGRwkbGeometryType
847 : GetGeometryTypeFromESRI(const char *pszESRIGeometryType);
848 : };
849 :
850 : int FileGDBDoubleDateToOGRDate(double dfVal, bool bHighPrecision,
851 : OGRField *psField);
852 : int FileGDBDoubleTimeToOGRTime(double dfVal, OGRField *psField);
853 : int FileGDBDateTimeWithOffsetToOGRDate(double dfVal, int16_t nUTCOffset,
854 : OGRField *psField);
855 :
856 : } /* namespace OpenFileGDB */
857 :
858 : #endif /* ndef FILEGDBTABLE_H_INCLUDED */
|