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