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