Coverage Report

Created: 2026-02-14 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/gcore/gdaldataset.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  GDAL Core
4
 * Purpose:  Base class for raster file formats.
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 1998, 2003, Frank Warmerdam
9
 * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13
14
#include "cpl_port.h"
15
16
#include <array>
17
#include <cassert>
18
#include <climits>
19
#include <cmath>
20
#include <cstdarg>
21
#include <cstdio>
22
#include <cstdlib>
23
#include <cstring>
24
#include <algorithm>
25
#include <limits>
26
#include <map>
27
#include <mutex>
28
#include <new>
29
#include <set>
30
#include <string>
31
#include <type_traits>
32
#include <utility>
33
34
#include "cpl_conv.h"
35
#include "cpl_cpu_features.h"
36
#include "cpl_error.h"
37
#include "cpl_hash_set.h"
38
#include "cpl_multiproc.h"
39
#include "cpl_progress.h"
40
#include "cpl_string.h"
41
#include "cpl_vsi.h"
42
#include "cpl_vsi_error.h"
43
44
#include "gdal.h"
45
#include "gdal_alg.h"
46
#include "gdal_abstractbandblockcache.h"
47
#include "gdalantirecursion.h"
48
#include "gdal_dataset.h"
49
#include "gdal_matrix.hpp"
50
51
#ifdef CAN_DETECT_AVX2_FMA_AT_RUNTIME
52
#include "gdal_matrix_avx2_fma.h"
53
#endif
54
55
#include "gdalsubdatasetinfo.h"
56
#include "gdal_thread_pool.h"
57
#include "gdal_typetraits.h"
58
59
#include "ogr_api.h"
60
#include "ogr_attrind.h"
61
#include "ogr_core.h"
62
#include "ogr_feature.h"
63
#include "ogr_featurestyle.h"
64
#include "ogr_gensql.h"
65
#include "ogr_geometry.h"
66
#include "ogr_p.h"
67
#include "ogr_spatialref.h"
68
#include "ogr_srs_api.h"
69
#include "ograpispy.h"
70
#include "ogrsf_frmts.h"
71
#include "ogrunionlayer.h"
72
#include "ogr_swq.h"
73
#include "memmultidim.h"
74
#include "gdalmultidim_priv.h"
75
76
#include "../frmts/derived/derivedlist.h"
77
78
#ifdef SQLITE_ENABLED
79
#include "../sqlite/ogrsqliteexecutesql.h"
80
#endif
81
82
#ifdef HAVE_OPENMP
83
#include <omp.h>
84
#endif
85
86
extern const swq_field_type SpecialFieldTypes[SPECIAL_FIELD_COUNT];
87
88
enum class GDALAllowReadWriteMutexState
89
{
90
    RW_MUTEX_STATE_UNKNOWN,
91
    RW_MUTEX_STATE_ALLOWED,
92
    RW_MUTEX_STATE_DISABLED
93
};
94
95
const GIntBig TOTAL_FEATURES_NOT_INIT = -2;
96
const GIntBig TOTAL_FEATURES_UNKNOWN = -1;
97
98
class GDALDataset::Private
99
{
100
    CPL_DISALLOW_COPY_ASSIGN(Private)
101
102
  public:
103
    CPLMutex *hMutex = nullptr;
104
    std::map<GIntBig, int> oMapThreadToMutexTakenCount{};
105
#ifdef DEBUG_EXTRA
106
    std::map<GIntBig, int> oMapThreadToMutexTakenCountSaved{};
107
#endif
108
    GDALAllowReadWriteMutexState eStateReadWriteMutex =
109
        GDALAllowReadWriteMutexState::RW_MUTEX_STATE_UNKNOWN;
110
    int nCurrentLayerIdx = 0;
111
    int nLayerCount = -1;
112
    GIntBig nFeatureReadInLayer = 0;
113
    GIntBig nFeatureReadInDataset = 0;
114
    GIntBig nTotalFeaturesInLayer = TOTAL_FEATURES_NOT_INIT;
115
    GIntBig nTotalFeatures = TOTAL_FEATURES_NOT_INIT;
116
    OGRLayer *poCurrentLayer = nullptr;
117
118
    std::mutex m_oMutexWKT{};
119
120
    char *m_pszWKTCached = nullptr;
121
    OGRSpatialReference *m_poSRSCached = nullptr;
122
    char *m_pszWKTGCPCached = nullptr;
123
    OGRSpatialReference *m_poSRSGCPCached = nullptr;
124
125
    GDALDataset *poParentDataset = nullptr;
126
127
    bool m_bOverviewsEnabled = true;
128
129
    std::vector<int>
130
        m_anBandMap{};  // used by RasterIO(). Values are 1, 2, etc.
131
132
0
    Private() = default;
133
};
134
135
struct SharedDatasetCtxt
136
{
137
    // PID of the thread that mark the dataset as shared
138
    // This may not be the actual PID, but the responsiblePID.
139
    GIntBig nPID;
140
    char *pszDescription;
141
    char *pszConcatenatedOpenOptions;
142
    int nOpenFlags;
143
144
    GDALDataset *poDS;
145
};
146
147
// Set of datasets opened as shared datasets (with GDALOpenShared)
148
// The values in the set are of type SharedDatasetCtxt.
149
static CPLHashSet *phSharedDatasetSet = nullptr;
150
151
// Set of all datasets created in the constructor of GDALDataset.
152
// In the case of a shared dataset, memorize the PID of the thread
153
// that marked the dataset as shared, so that we can remove it from
154
// the phSharedDatasetSet in the destructor of the dataset, even
155
// if GDALClose is called from a different thread.
156
static std::map<GDALDataset *, GIntBig> *poAllDatasetMap = nullptr;
157
158
static CPLMutex *hDLMutex = nullptr;
159
160
// Static array of all datasets. Used by GDALGetOpenDatasets.
161
// Not thread-safe. See GDALGetOpenDatasets.
162
static GDALDataset **ppDatasets = nullptr;
163
164
static unsigned long GDALSharedDatasetHashFunc(const void *elt)
165
0
{
166
0
    const SharedDatasetCtxt *psStruct =
167
0
        static_cast<const SharedDatasetCtxt *>(elt);
168
0
    return static_cast<unsigned long>(
169
0
        CPLHashSetHashStr(psStruct->pszDescription) ^
170
0
        CPLHashSetHashStr(psStruct->pszConcatenatedOpenOptions) ^
171
0
        psStruct->nOpenFlags ^ psStruct->nPID);
172
0
}
173
174
static int GDALSharedDatasetEqualFunc(const void *elt1, const void *elt2)
175
0
{
176
0
    const SharedDatasetCtxt *psStruct1 =
177
0
        static_cast<const SharedDatasetCtxt *>(elt1);
178
0
    const SharedDatasetCtxt *psStruct2 =
179
0
        static_cast<const SharedDatasetCtxt *>(elt2);
180
0
    return strcmp(psStruct1->pszDescription, psStruct2->pszDescription) == 0 &&
181
0
           strcmp(psStruct1->pszConcatenatedOpenOptions,
182
0
                  psStruct2->pszConcatenatedOpenOptions) == 0 &&
183
0
           psStruct1->nPID == psStruct2->nPID &&
184
0
           psStruct1->nOpenFlags == psStruct2->nOpenFlags;
185
0
}
186
187
static void GDALSharedDatasetFreeFunc(void *elt)
188
0
{
189
0
    SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(elt);
190
0
    CPLFree(psStruct->pszDescription);
191
0
    CPLFree(psStruct->pszConcatenatedOpenOptions);
192
0
    CPLFree(psStruct);
193
0
}
194
195
static std::string
196
GDALSharedDatasetConcatenateOpenOptions(CSLConstList papszOpenOptions)
197
0
{
198
0
    std::string osStr;
199
0
    for (const char *pszOption : cpl::Iterate(papszOpenOptions))
200
0
        osStr += pszOption;
201
0
    return osStr;
202
0
}
203
204
/************************************************************************/
205
/*    Functions shared between gdalproxypool.cpp and gdaldataset.cpp    */
206
/************************************************************************/
207
208
// The open-shared mutex must be used by the ProxyPool too.
209
CPLMutex **GDALGetphDLMutex()
210
0
{
211
0
    return &hDLMutex;
212
0
}
213
214
// The current thread will act in the behalf of the thread of PID
215
// responsiblePID.
216
void GDALSetResponsiblePIDForCurrentThread(GIntBig responsiblePID)
217
0
{
218
0
    GIntBig *pResponsiblePID =
219
0
        static_cast<GIntBig *>(CPLGetTLS(CTLS_RESPONSIBLEPID));
220
0
    if (pResponsiblePID == nullptr)
221
0
    {
222
0
        pResponsiblePID = static_cast<GIntBig *>(CPLMalloc(sizeof(GIntBig)));
223
0
        CPLSetTLS(CTLS_RESPONSIBLEPID, pResponsiblePID, TRUE);
224
0
    }
225
0
    *pResponsiblePID = responsiblePID;
226
0
}
227
228
// Get the PID of the thread that the current thread will act in the behalf of
229
// By default : the current thread acts in the behalf of itself.
230
GIntBig GDALGetResponsiblePIDForCurrentThread()
231
0
{
232
0
    GIntBig *pResponsiblePID =
233
0
        static_cast<GIntBig *>(CPLGetTLS(CTLS_RESPONSIBLEPID));
234
0
    if (pResponsiblePID == nullptr)
235
0
        return CPLGetPID();
236
0
    return *pResponsiblePID;
237
0
}
238
239
/************************************************************************/
240
/* ==================================================================== */
241
/*                             GDALDataset                              */
242
/* ==================================================================== */
243
/************************************************************************/
244
245
/**
246
 * \class GDALDataset "gdal_priv.h"
247
 *
248
 * A dataset encapsulating one or more raster bands.  Details are further
249
 * discussed in the <a href="https://gdal.org/user/raster_data_model.html">GDAL
250
 * Raster Data Model</a>.
251
 *
252
 * Use GDALOpen() or GDALOpenShared() to create a GDALDataset for a named file,
253
 * or GDALDriver::Create() or GDALDriver::CreateCopy() to create a new
254
 * dataset.
255
 */
256
257
/************************************************************************/
258
/*                            GDALDataset()                             */
259
/************************************************************************/
260
261
//! @cond Doxygen_Suppress
262
GDALDataset::GDALDataset()
263
0
    : GDALDataset(CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
264
0
{
265
0
}
266
267
GDALDataset::GDALDataset(int bForceCachedIOIn)
268
0
    : bForceCachedIO(CPL_TO_BOOL(bForceCachedIOIn)),
269
0
      m_poPrivate(new (std::nothrow) GDALDataset::Private)
270
0
{
271
0
}
272
273
//! @endcond
274
275
/************************************************************************/
276
/*                            ~GDALDataset()                            */
277
/************************************************************************/
278
279
/**
280
 * \brief Destroy an open GDALDataset.
281
 *
282
 * This is the accepted method of closing a GDAL dataset and deallocating
283
 * all resources associated with it.
284
 *
285
 * Equivalent of the C callable GDALClose().  Except that GDALClose() first
286
 * decrements the reference count, and then closes only if it has dropped to
287
 * zero.
288
 *
289
 * For Windows users, it is not recommended to use the delete operator on the
290
 * dataset object because of known issues when allocating and freeing memory
291
 * across module boundaries. Calling GDALClose() is then a better option.
292
 */
293
294
GDALDataset::~GDALDataset()
295
296
0
{
297
    // we don't want to report destruction of datasets that
298
    // were never really open or meant as internal
299
0
    if (!bIsInternal && (nBands != 0 || !EQUAL(GetDescription(), "")))
300
0
    {
301
0
        if (CPLGetPID() != GDALGetResponsiblePIDForCurrentThread())
302
0
            CPLDebug("GDAL",
303
0
                     "GDALClose(%s, this=%p) (pid=%d, responsiblePID=%d)",
304
0
                     GetDescription(), this, static_cast<int>(CPLGetPID()),
305
0
                     static_cast<int>(GDALGetResponsiblePIDForCurrentThread()));
306
0
        else
307
0
            CPLDebug("GDAL", "GDALClose(%s, this=%p)", GetDescription(), this);
308
0
    }
309
310
0
    GDALDataset::Close();
311
312
    /* -------------------------------------------------------------------- */
313
    /*      Remove dataset from the "open" dataset list.                    */
314
    /* -------------------------------------------------------------------- */
315
0
    if (!bIsInternal)
316
0
    {
317
0
        CPLMutexHolderD(&hDLMutex);
318
0
        if (poAllDatasetMap)
319
0
        {
320
0
            std::map<GDALDataset *, GIntBig>::iterator oIter =
321
0
                poAllDatasetMap->find(this);
322
0
            CPLAssert(oIter != poAllDatasetMap->end());
323
324
0
            UnregisterFromSharedDataset();
325
326
0
            poAllDatasetMap->erase(oIter);
327
328
0
            if (poAllDatasetMap->empty())
329
0
            {
330
0
                delete poAllDatasetMap;
331
0
                poAllDatasetMap = nullptr;
332
0
                if (phSharedDatasetSet)
333
0
                {
334
0
                    CPLHashSetDestroy(phSharedDatasetSet);
335
0
                }
336
0
                phSharedDatasetSet = nullptr;
337
0
                CPLFree(ppDatasets);
338
0
                ppDatasets = nullptr;
339
0
            }
340
0
        }
341
0
    }
342
343
    /* -------------------------------------------------------------------- */
344
    /*      Destroy the raster bands if they exist.                         */
345
    /* -------------------------------------------------------------------- */
346
0
    for (int i = 0; i < nBands && papoBands != nullptr; ++i)
347
0
    {
348
0
        if (papoBands[i] != nullptr)
349
0
            delete papoBands[i];
350
0
        papoBands[i] = nullptr;
351
0
    }
352
353
0
    CPLFree(papoBands);
354
355
0
    if (m_poStyleTable)
356
0
    {
357
0
        delete m_poStyleTable;
358
0
        m_poStyleTable = nullptr;
359
0
    }
360
361
0
    if (m_poPrivate != nullptr)
362
0
    {
363
0
        if (m_poPrivate->hMutex != nullptr)
364
0
            CPLDestroyMutex(m_poPrivate->hMutex);
365
366
0
#if defined(__COVERITY__) || defined(DEBUG)
367
        // Not needed since at destruction there is no risk of concurrent use.
368
0
        std::lock_guard oLock(m_poPrivate->m_oMutexWKT);
369
0
#endif
370
0
        CPLFree(m_poPrivate->m_pszWKTCached);
371
0
        if (m_poPrivate->m_poSRSCached)
372
0
        {
373
0
            m_poPrivate->m_poSRSCached->Release();
374
0
        }
375
0
        CPLFree(m_poPrivate->m_pszWKTGCPCached);
376
0
        if (m_poPrivate->m_poSRSGCPCached)
377
0
        {
378
0
            m_poPrivate->m_poSRSGCPCached->Release();
379
0
        }
380
0
    }
381
382
0
    delete m_poPrivate;
383
384
0
    CSLDestroy(papszOpenOptions);
385
0
}
386
387
/************************************************************************/
388
/*                               Close()                                */
389
/************************************************************************/
390
391
/** Do final cleanup before a dataset is destroyed.
392
 *
393
 * This method is typically called by GDALClose() or the destructor of a
394
 * GDALDataset subclass. It might also be called by C++ users before
395
 * destroying a dataset. It should not be called on a shared dataset whose
396
 * reference count is greater than one.
397
 *
398
 * It gives a last chance to the closing process to return an error code if
399
 * something goes wrong, in particular in creation / update scenarios where
400
 * file write or network communication might occur when finalizing the dataset.
401
 *
402
 * Implementations should be robust to this method to be called several times
403
 * (on subsequent calls, it should do nothing and return CE_None).
404
 * Once it has been called, no other method than Close() or the dataset
405
 * destructor should be called. RasterBand or OGRLayer owned by the dataset
406
 * should be assumed as no longer being valid.
407
 *
408
 * If a driver implements this method, it must also call it from its
409
 * dataset destructor.
410
 *
411
 * Starting with GDAL 3.13, this function may report progress if a progress
412
 * callback if provided in the pfnProgress argument and if the dataset returns
413
 * true for GDALDataset::GetCloseReportsProgress()
414
 *
415
 * This is the equivalent of C function GDALDatasetRunCloseWithoutDestroying()
416
 * or GDALDatasetRunCloseWithoutDestroyingEx()
417
 *
418
 * A typical implementation might look as the following
419
 * \code{.cpp}
420
 *
421
 *  MyDataset::~MyDataset()
422
 *  {
423
 *     try
424
 *     {
425
 *         MyDataset::Close();
426
 *     }
427
 *     catch (const std::exception &exc)
428
 *     {
429
 *         // If Close() can throw exception
430
 *         CPLError(CE_Failure, CPLE_AppDefined,
431
 *                  "Exception thrown in MyDataset::Close(): %s",
432
 *                  exc.what());
433
 *     }
434
 *     catch (...)
435
 *     {
436
 *         // If Close() can throw exception
437
 *         CPLError(CE_Failure, CPLE_AppDefined,
438
 *                  "Exception thrown in MyDataset::Close()");
439
 *     }
440
 *  }
441
 *
442
 *  CPLErr MyDataset::Close(GDALProgressFunc pfnProgress, void* pProgressData)
443
 *  {
444
 *      CPLErr eErr = CE_None;
445
 *      if( nOpenFlags != OPEN_FLAGS_CLOSED )
446
 *      {
447
 *          eErr = MyDataset::FlushCache(true);
448
 *
449
 *          // Do something driver specific
450
 *          if (m_fpImage)
451
 *          {
452
 *              if( VSIFCloseL(m_fpImage) != 0 )
453
 *              {
454
 *                  CPLError(CE_Failure, CPLE_FileIO, "VSIFCloseL() failed");
455
 *                  eErr = CE_Failure;
456
 *              }
457
 *          }
458
 *
459
 *          // Call parent Close() implementation.
460
 *          eErr = GDAL::Combine(eErr, MyParentDatasetClass::Close());
461
 *      }
462
 *      return eErr;
463
 *  }
464
 * \endcode
465
 *
466
 * @param pfnProgress (since GDAL 3.13) Progress callback, or nullptr
467
 * @param pProgressData (since GDAL 3.13) User data of progress callback, or nullptr
468
 * @return CE_None if no error
469
 *
470
 * @since GDAL 3.7
471
 */
472
CPLErr GDALDataset::Close(GDALProgressFunc pfnProgress, void *pProgressData)
473
0
{
474
0
    (void)pfnProgress;
475
0
    (void)pProgressData;
476
477
0
    if (nOpenFlags != OPEN_FLAGS_CLOSED)
478
0
    {
479
        // Call UnregisterFromSharedDataset() before altering nOpenFlags
480
0
        UnregisterFromSharedDataset();
481
482
0
        nOpenFlags = OPEN_FLAGS_CLOSED;
483
0
    }
484
485
0
    if (IsMarkedSuppressOnClose())
486
0
    {
487
0
        if (poDriver == nullptr ||
488
            // Someone issuing Create("foo.tif") on a
489
            // memory driver doesn't expect files with those names to be deleted
490
            // on a file system...
491
            // This is somewhat messy. Ideally there should be a way for the
492
            // driver to overload the default behavior
493
0
            (!EQUAL(poDriver->GetDescription(), "MEM") &&
494
0
             !EQUAL(poDriver->GetDescription(), "Memory")))
495
0
        {
496
0
            if (VSIUnlink(GetDescription()) == 0)
497
0
                UnMarkSuppressOnClose();
498
0
        }
499
0
    }
500
501
0
    return CE_None;
502
0
}
503
504
/************************************************************************/
505
/*                GDALDatasetRunCloseWithoutDestroying()                */
506
/************************************************************************/
507
508
/** Run the Close() method, without running destruction of the object.
509
 *
510
 * This ensures that content that should be written to file is written and
511
 * that all file descriptors are closed.
512
 *
513
 * Note that this is different from GDALClose() which also destroys
514
 * the underlying C++ object. GDALClose() or GDALReleaseDataset() are actually
515
 * the only functions that can be safely called on the dataset handle after
516
 * this function has been called.
517
 *
518
 * Most users want to use GDALClose() or GDALReleaseDataset() rather than
519
 * this function.
520
 *
521
 * This function is equivalent to the C++ method GDALDataset:Close()
522
 *
523
 * @param hDS dataset handle.
524
 * @return CE_None if no error
525
 *
526
 * @since GDAL 3.12
527
 * @see GDALClose(), GDALDatasetRunCloseWithoutDestroyingEx()
528
 */
529
CPLErr GDALDatasetRunCloseWithoutDestroying(GDALDatasetH hDS)
530
0
{
531
0
    VALIDATE_POINTER1(hDS, __func__, CE_Failure);
532
0
    return GDALDataset::FromHandle(hDS)->Close();
533
0
}
534
535
/************************************************************************/
536
/*               GDALDatasetRunCloseWithoutDestroyingEx()               */
537
/************************************************************************/
538
539
/** Run the Close() method, without running destruction of the object.
540
 *
541
 * This ensures that content that should be written to file is written and
542
 * that all file descriptors are closed.
543
 *
544
 * Note that this is different from GDALClose() which also destroys
545
 * the underlying C++ object. GDALClose() or GDALReleaseDataset() are actually
546
 * the only functions that can be safely called on the dataset handle after
547
 * this function has been called.
548
 *
549
 * Most users want to use GDALClose() or GDALReleaseDataset() rather than
550
 * this function.
551
 *
552
 * This function may report progress if a progress
553
 * callback if provided in the pfnProgress argument and if the dataset returns
554
 * true for GDALDataset::GetCloseReportsProgress()
555
 *
556
 * This function is equivalent to the C++ method GDALDataset:Close()
557
 *
558
 * @param hDS dataset handle.
559
 * @param pfnProgress Progress callback, or nullptr
560
 * @param pProgressData User data of progress callback, or nullptr
561
 *
562
 * @return CE_None if no error
563
 *
564
 * @since GDAL 3.13
565
 * @see GDALClose()
566
 */
567
CPLErr GDALDatasetRunCloseWithoutDestroyingEx(GDALDatasetH hDS,
568
                                              GDALProgressFunc pfnProgress,
569
                                              void *pProgressData)
570
0
{
571
0
    VALIDATE_POINTER1(hDS, __func__, CE_Failure);
572
0
    return GDALDataset::FromHandle(hDS)->Close(pfnProgress, pProgressData);
573
0
}
574
575
/************************************************************************/
576
/*                      GetCloseReportsProgress()                       */
577
/************************************************************************/
578
579
/** Returns whether the Close() operation will report progress / is a potential
580
 * lengthy operation.
581
 *
582
 * At time of writing, only the COG driver will return true, if the dataset
583
 * has been created through the GDALDriver::Create() interface.
584
 *
585
 * This method is equivalent to the C function GDALDatasetGetCloseReportsProgress()
586
 *
587
 * @return true if the Close() operation will report progress
588
 * @since GDAL 3.13
589
 * @see Close()
590
 */
591
bool GDALDataset::GetCloseReportsProgress() const
592
0
{
593
0
    return false;
594
0
}
595
596
/************************************************************************/
597
/*                 GDALDatasetGetCloseReportsProgress()                 */
598
/************************************************************************/
599
600
/** Returns whether the Close() operation will report progress / is a potential
601
 * lengthy operation.
602
 *
603
 * This function is equivalent to the C++ method GDALDataset::GetCloseReportsProgress()
604
 *
605
 * @param hDS dataset handle.
606
 * @return CE_None if no error
607
 *
608
 * @return true if the Close() operation will report progress
609
 * @since GDAL 3.13
610
 * @see GDALClose()
611
 */
612
bool GDALDatasetGetCloseReportsProgress(GDALDatasetH hDS)
613
0
{
614
0
    VALIDATE_POINTER1(hDS, __func__, false);
615
0
    return GDALDataset::FromHandle(hDS)->GetCloseReportsProgress();
616
0
}
617
618
/************************************************************************/
619
/*                  CanReopenWithCurrentDescription()                   */
620
/************************************************************************/
621
622
/** Returns whether, once this dataset is closed, it can be re-opened with
623
 * Open() using the current value of GetDescription()
624
 *
625
 * The default implementation returns true. Some drivers, like MVT in Create()
626
 * mode, can return false. Some drivers return true, but the re-opened dataset
627
 * may be opened by another driver (e.g. the COG driver will return true, but
628
 * the driver used for re-opening is GTiff).
629
 *
630
 * @return true if the dataset can be re-opened using the value as
631
 *         GetDescription() as connection string for Open()
632
 * @since GDAL 3.13
633
 */
634
bool GDALDataset::CanReopenWithCurrentDescription() const
635
0
{
636
0
    return true;
637
0
}
638
639
/************************************************************************/
640
/*                    UnregisterFromSharedDataset()                     */
641
/************************************************************************/
642
643
void GDALDataset::UnregisterFromSharedDataset()
644
0
{
645
0
    if (!(!bIsInternal && bShared && poAllDatasetMap && phSharedDatasetSet))
646
0
        return;
647
648
0
    CPLMutexHolderD(&hDLMutex);
649
650
0
    std::map<GDALDataset *, GIntBig>::iterator oIter =
651
0
        poAllDatasetMap->find(this);
652
0
    CPLAssert(oIter != poAllDatasetMap->end());
653
0
    const GIntBig nPIDCreatorForShared = oIter->second;
654
0
    bShared = false;
655
0
    SharedDatasetCtxt sStruct;
656
0
    sStruct.nPID = nPIDCreatorForShared;
657
0
    sStruct.nOpenFlags = nOpenFlags & ~GDAL_OF_SHARED;
658
0
    sStruct.pszDescription = const_cast<char *>(GetDescription());
659
0
    std::string osConcatenatedOpenOptions =
660
0
        GDALSharedDatasetConcatenateOpenOptions(papszOpenOptions);
661
0
    sStruct.pszConcatenatedOpenOptions = &osConcatenatedOpenOptions[0];
662
0
    sStruct.poDS = nullptr;
663
0
    SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(
664
0
        CPLHashSetLookup(phSharedDatasetSet, &sStruct));
665
0
    if (psStruct && psStruct->poDS == this)
666
0
    {
667
0
        CPLHashSetRemove(phSharedDatasetSet, psStruct);
668
0
    }
669
0
    else
670
0
    {
671
0
        CPLDebug("GDAL",
672
0
                 "Should not happen. Cannot find %s, "
673
0
                 "this=%p in phSharedDatasetSet",
674
0
                 GetDescription(), this);
675
0
    }
676
0
}
677
678
/************************************************************************/
679
/*                        AddToDatasetOpenList()                        */
680
/************************************************************************/
681
682
void GDALDataset::AddToDatasetOpenList()
683
0
{
684
    /* -------------------------------------------------------------------- */
685
    /*      Add this dataset to the open dataset list.                      */
686
    /* -------------------------------------------------------------------- */
687
0
    bIsInternal = false;
688
689
0
    CPLMutexHolderD(&hDLMutex);
690
691
0
    if (poAllDatasetMap == nullptr)
692
0
        poAllDatasetMap = new std::map<GDALDataset *, GIntBig>;
693
0
    (*poAllDatasetMap)[this] = -1;
694
0
}
695
696
/************************************************************************/
697
/*                             FlushCache()                             */
698
/************************************************************************/
699
700
/**
701
 * \brief Flush all write cached data to disk.
702
 *
703
 * Any raster (or other GDAL) data written via GDAL calls, but buffered
704
 * internally will be written to disk.
705
 *
706
 * The default implementation of this method just calls the FlushCache() method
707
 * on each of the raster bands and the SyncToDisk() method
708
 * on each of the layers.  Conceptually, calling FlushCache() on a dataset
709
 * should include any work that might be accomplished by calling SyncToDisk()
710
 * on layers in that dataset.
711
 *
712
 * Using this method does not prevent use from calling GDALClose()
713
 * to properly close a dataset and ensure that important data not addressed
714
 * by FlushCache() is written in the file.
715
 *
716
 * This method is the same as the C function GDALFlushCache().
717
 *
718
 * @param bAtClosing Whether this is called from a GDALDataset destructor
719
 * @return CE_None in case of success (note: return value added in GDAL 3.7)
720
 */
721
722
CPLErr GDALDataset::FlushCache(bool bAtClosing)
723
724
0
{
725
0
    CPLErr eErr = CE_None;
726
    // This sometimes happens if a dataset is destroyed before completely
727
    // built.
728
729
0
    if (papoBands)
730
0
    {
731
0
        for (int i = 0; i < nBands; ++i)
732
0
        {
733
0
            if (papoBands[i])
734
0
            {
735
0
                if (papoBands[i]->FlushCache(bAtClosing) != CE_None)
736
0
                    eErr = CE_Failure;
737
0
            }
738
0
        }
739
0
    }
740
741
0
    const int nLayers = GetLayerCount();
742
    // cppcheck-suppress knownConditionTrueFalse
743
0
    if (nLayers > 0)
744
0
    {
745
0
        CPLMutexHolderD(m_poPrivate ? &(m_poPrivate->hMutex) : nullptr);
746
0
        for (int i = 0; i < nLayers; ++i)
747
0
        {
748
0
            OGRLayer *poLayer = GetLayer(i);
749
750
0
            if (poLayer)
751
0
            {
752
0
                if (poLayer->SyncToDisk() != OGRERR_NONE)
753
0
                    eErr = CE_Failure;
754
0
            }
755
0
        }
756
0
    }
757
758
0
    return eErr;
759
0
}
760
761
/************************************************************************/
762
/*                           GDALFlushCache()                           */
763
/************************************************************************/
764
765
/**
766
 * \brief Flush all write cached data to disk.
767
 *
768
 * @see GDALDataset::FlushCache().
769
 * @return CE_None in case of success (note: return value added in GDAL 3.7)
770
 */
771
772
CPLErr CPL_STDCALL GDALFlushCache(GDALDatasetH hDS)
773
774
0
{
775
0
    VALIDATE_POINTER1(hDS, "GDALFlushCache", CE_Failure);
776
777
0
    return GDALDataset::FromHandle(hDS)->FlushCache(false);
778
0
}
779
780
/************************************************************************/
781
/*                             DropCache()                              */
782
/************************************************************************/
783
784
/**
785
* \brief Drop all write cached data
786
*
787
* This method is the same as the C function GDALDropCache().
788
*
789
* @return CE_None in case of success
790
* @since 3.9
791
*/
792
793
CPLErr GDALDataset::DropCache()
794
795
0
{
796
0
    CPLErr eErr = CE_None;
797
798
0
    if (papoBands)
799
0
    {
800
0
        for (int i = 0; i < nBands; ++i)
801
0
        {
802
0
            if (papoBands[i])
803
0
            {
804
0
                if (papoBands[i]->DropCache() != CE_None)
805
0
                    eErr = CE_Failure;
806
0
            }
807
0
        }
808
0
    }
809
810
0
    return eErr;
811
0
}
812
813
/************************************************************************/
814
/*                           GDALDropCache()                            */
815
/************************************************************************/
816
817
/**
818
* \brief Drop all write cached data
819
*
820
* @see GDALDataset::DropCache().
821
* @return CE_None in case of success
822
* @since 3.9
823
*/
824
825
CPLErr CPL_STDCALL GDALDropCache(GDALDatasetH hDS)
826
827
0
{
828
0
    VALIDATE_POINTER1(hDS, "GDALDropCache", CE_Failure);
829
830
0
    return GDALDataset::FromHandle(hDS)->DropCache();
831
0
}
832
833
/************************************************************************/
834
/*                        GetEstimatedRAMUsage()                        */
835
/************************************************************************/
836
837
/**
838
 * \brief Return the intrinsic RAM usage of this dataset.
839
 *
840
 * The returned value should take into account caches in the underlying driver
841
 * and decoding library, but not the usage related to the GDAL block cache.
842
 *
843
 * At time of writing, this method is only implemented in the JP2OpenJPEG
844
 * driver. For single-tiled JPEG2000 images, the decoding of the image,
845
 * even partially, involves allocating at least
846
 * width * height * number_of_bands * sizeof(uint32_t) bytes inside the libopenjp2
847
 * library.
848
 *
849
 * This method is used by the GDALDatasetPool class, itself used by the GDAL VRT
850
 * driver, to determine how long a dataset in the pool must be kept open, given
851
 * the RAM usage of the dataset with respect to the usable total RAM.
852
 *
853
 * @since GDAL 3.7
854
 * @return RAM usage in bytes, or -1 if unknown (the default implementation
855
 * returns -1)
856
 */
857
858
GIntBig GDALDataset::GetEstimatedRAMUsage()
859
0
{
860
0
    return -1;
861
0
}
862
863
/************************************************************************/
864
/*                        BlockBasedFlushCache()                        */
865
/*                                                                      */
866
/*      This helper method can be called by the                         */
867
/*      GDALDataset::FlushCache() for particular drivers to ensure      */
868
/*      that buffers will be flushed in a manner suitable for pixel     */
869
/*      interleaved (by block) IO.  That is, if all the bands have      */
870
/*      the same size blocks then a given block will be flushed for     */
871
/*      all bands before proceeding to the next block.                  */
872
/************************************************************************/
873
874
//! @cond Doxygen_Suppress
875
CPLErr GDALDataset::BlockBasedFlushCache(bool bAtClosing)
876
877
0
{
878
0
    GDALRasterBand *poBand1 = GetRasterBand(1);
879
0
    if (poBand1 == nullptr || (IsMarkedSuppressOnClose() && bAtClosing))
880
0
    {
881
0
        return GDALDataset::FlushCache(bAtClosing);
882
0
    }
883
884
0
    int nBlockXSize = 0;
885
0
    int nBlockYSize = 0;
886
0
    poBand1->GetBlockSize(&nBlockXSize, &nBlockYSize);
887
888
    /* -------------------------------------------------------------------- */
889
    /*      Verify that all bands match.                                    */
890
    /* -------------------------------------------------------------------- */
891
0
    for (int iBand = 1; iBand < nBands; ++iBand)
892
0
    {
893
0
        GDALRasterBand *poBand = GetRasterBand(iBand + 1);
894
895
0
        int nThisBlockXSize, nThisBlockYSize;
896
0
        poBand->GetBlockSize(&nThisBlockXSize, &nThisBlockYSize);
897
0
        if (nThisBlockXSize != nBlockXSize && nThisBlockYSize != nBlockYSize)
898
0
        {
899
0
            return GDALDataset::FlushCache(bAtClosing);
900
0
        }
901
0
    }
902
903
    /* -------------------------------------------------------------------- */
904
    /*      Now flush writable data.                                        */
905
    /* -------------------------------------------------------------------- */
906
0
    for (int iY = 0; iY < poBand1->nBlocksPerColumn; ++iY)
907
0
    {
908
0
        for (int iX = 0; iX < poBand1->nBlocksPerRow; ++iX)
909
0
        {
910
0
            for (int iBand = 0; iBand < nBands; ++iBand)
911
0
            {
912
0
                const CPLErr eErr = papoBands[iBand]->FlushBlock(iX, iY);
913
914
0
                if (eErr != CE_None)
915
0
                    return CE_Failure;
916
0
            }
917
0
        }
918
0
    }
919
0
    return CE_None;
920
0
}
921
922
/************************************************************************/
923
/*                          RasterInitialize()                          */
924
/*                                                                      */
925
/*      Initialize raster size                                          */
926
/************************************************************************/
927
928
void GDALDataset::RasterInitialize(int nXSize, int nYSize)
929
930
0
{
931
0
    CPLAssert(nXSize > 0 && nYSize > 0);
932
933
0
    nRasterXSize = nXSize;
934
0
    nRasterYSize = nYSize;
935
0
}
936
937
//! @endcond
938
939
/************************************************************************/
940
/*                              AddBand()                               */
941
/************************************************************************/
942
943
/**
944
 * \fn GDALDataset::AddBand(GDALDataType, char**)
945
 * \brief Add a band to a dataset.
946
 *
947
 * This method will add a new band to the dataset if the underlying format
948
 * supports this action.  Most formats do not.
949
 *
950
 * Note that the new GDALRasterBand is not returned.  It may be fetched
951
 * after successful completion of the method by calling
952
 * GDALDataset::GetRasterBand(GDALDataset::GetRasterCount()) as the newest
953
 * band will always be the last band.
954
 *
955
 * @param eType the data type of the pixels in the new band.
956
 *
957
 * @param papszOptions a list of NAME=VALUE option strings.  The supported
958
 * options are format specific.  NULL may be passed by default.
959
 *
960
 * @return CE_None on success or CE_Failure on failure.
961
 */
962
963
CPLErr GDALDataset::AddBand(CPL_UNUSED GDALDataType eType,
964
                            CPL_UNUSED CSLConstList papszOptions)
965
966
0
{
967
0
    ReportError(CE_Failure, CPLE_NotSupported,
968
0
                "Dataset does not support the AddBand() method.");
969
970
0
    return CE_Failure;
971
0
}
972
973
/************************************************************************/
974
/*                            GDALAddBand()                             */
975
/************************************************************************/
976
977
/**
978
 * \brief Add a band to a dataset.
979
 *
980
 * @see GDALDataset::AddBand().
981
 */
982
983
CPLErr CPL_STDCALL GDALAddBand(GDALDatasetH hDataset, GDALDataType eType,
984
                               CSLConstList papszOptions)
985
986
0
{
987
0
    VALIDATE_POINTER1(hDataset, "GDALAddBand", CE_Failure);
988
989
0
    return GDALDataset::FromHandle(hDataset)->AddBand(
990
0
        eType, const_cast<char **>(papszOptions));
991
0
}
992
993
/************************************************************************/
994
/*                              SetBand()                               */
995
/************************************************************************/
996
997
//! @cond Doxygen_Suppress
998
/**  Set a band in the band array, updating the band count, and array size
999
 * appropriately.
1000
 *
1001
 * @param nNewBand new band number (indexing starts at 1)
1002
 * @param poBand band object.
1003
 */
1004
1005
void GDALDataset::SetBand(int nNewBand, GDALRasterBand *poBand)
1006
1007
0
{
1008
    /* -------------------------------------------------------------------- */
1009
    /*      Do we need to grow the bands list?                              */
1010
    /* -------------------------------------------------------------------- */
1011
0
    if (nBands < nNewBand || papoBands == nullptr)
1012
0
    {
1013
0
        GDALRasterBand **papoNewBands = nullptr;
1014
1015
0
        if (papoBands == nullptr)
1016
0
            papoNewBands = static_cast<GDALRasterBand **>(VSICalloc(
1017
0
                sizeof(GDALRasterBand *), std::max(nNewBand, nBands)));
1018
0
        else
1019
0
            papoNewBands = static_cast<GDALRasterBand **>(
1020
0
                VSIRealloc(papoBands, sizeof(GDALRasterBand *) *
1021
0
                                          std::max(nNewBand, nBands)));
1022
0
        if (papoNewBands == nullptr)
1023
0
        {
1024
0
            ReportError(CE_Failure, CPLE_OutOfMemory,
1025
0
                        "Cannot allocate band array");
1026
0
            return;
1027
0
        }
1028
1029
0
        papoBands = papoNewBands;
1030
1031
0
        for (int i = nBands; i < nNewBand; ++i)
1032
0
            papoBands[i] = nullptr;
1033
1034
0
        nBands = std::max(nBands, nNewBand);
1035
1036
0
        if (m_poPrivate)
1037
0
        {
1038
0
            for (int i = static_cast<int>(m_poPrivate->m_anBandMap.size());
1039
0
                 i < nBands; ++i)
1040
0
            {
1041
0
                m_poPrivate->m_anBandMap.push_back(i + 1);
1042
0
            }
1043
0
        }
1044
0
    }
1045
1046
    /* -------------------------------------------------------------------- */
1047
    /*      Set the band.  Resetting the band is currently not permitted.   */
1048
    /* -------------------------------------------------------------------- */
1049
0
    if (papoBands[nNewBand - 1] != nullptr)
1050
0
    {
1051
0
        ReportError(CE_Failure, CPLE_NotSupported,
1052
0
                    "Cannot set band %d as it is already set", nNewBand);
1053
0
        return;
1054
0
    }
1055
1056
0
    papoBands[nNewBand - 1] = poBand;
1057
1058
    /* -------------------------------------------------------------------- */
1059
    /*      Set back reference information on the raster band.  Note        */
1060
    /*      that the GDALDataset is a friend of the GDALRasterBand          */
1061
    /*      specifically to allow this.                                     */
1062
    /* -------------------------------------------------------------------- */
1063
0
    poBand->nBand = nNewBand;
1064
0
    poBand->poDS = this;
1065
0
    poBand->nRasterXSize = nRasterXSize;
1066
0
    poBand->nRasterYSize = nRasterYSize;
1067
0
    poBand->eAccess = eAccess;  // Default access to be same as dataset.
1068
0
}
1069
1070
//! @endcond
1071
1072
/************************************************************************/
1073
/*                              SetBand()                               */
1074
/************************************************************************/
1075
1076
//! @cond Doxygen_Suppress
1077
/**  Set a band in the band array, updating the band count, and array size
1078
 * appropriately.
1079
 *
1080
 * @param nNewBand new band number (indexing starts at 1)
1081
 * @param poBand band object.
1082
 */
1083
1084
void GDALDataset::SetBand(int nNewBand, std::unique_ptr<GDALRasterBand> poBand)
1085
0
{
1086
0
    SetBand(nNewBand, poBand.release());
1087
0
}
1088
1089
//! @endcond
1090
1091
/************************************************************************/
1092
/*                           GetRasterXSize()                           */
1093
/************************************************************************/
1094
1095
/**
1096
1097
 \brief Fetch raster width in pixels.
1098
1099
 Equivalent of the C function GDALGetRasterXSize().
1100
1101
 @return the width in pixels of raster bands in this GDALDataset.
1102
1103
*/
1104
1105
int GDALDataset::GetRasterXSize() const
1106
0
{
1107
0
    return nRasterXSize;
1108
0
}
1109
1110
/************************************************************************/
1111
/*                         GDALGetRasterXSize()                         */
1112
/************************************************************************/
1113
1114
/**
1115
 * \brief Fetch raster width in pixels.
1116
 *
1117
 * @see GDALDataset::GetRasterXSize().
1118
 */
1119
1120
int CPL_STDCALL GDALGetRasterXSize(GDALDatasetH hDataset)
1121
1122
0
{
1123
0
    VALIDATE_POINTER1(hDataset, "GDALGetRasterXSize", 0);
1124
1125
0
    return GDALDataset::FromHandle(hDataset)->GetRasterXSize();
1126
0
}
1127
1128
/************************************************************************/
1129
/*                           GetRasterYSize()                           */
1130
/************************************************************************/
1131
1132
/**
1133
1134
 \brief Fetch raster height in pixels.
1135
1136
 Equivalent of the C function GDALGetRasterYSize().
1137
1138
 @return the height in pixels of raster bands in this GDALDataset.
1139
1140
*/
1141
1142
int GDALDataset::GetRasterYSize() const
1143
0
{
1144
0
    return nRasterYSize;
1145
0
}
1146
1147
/************************************************************************/
1148
/*                         GDALGetRasterYSize()                         */
1149
/************************************************************************/
1150
1151
/**
1152
 * \brief Fetch raster height in pixels.
1153
 *
1154
 * @see GDALDataset::GetRasterYSize().
1155
 */
1156
1157
int CPL_STDCALL GDALGetRasterYSize(GDALDatasetH hDataset)
1158
1159
0
{
1160
0
    VALIDATE_POINTER1(hDataset, "GDALGetRasterYSize", 0);
1161
1162
0
    return GDALDataset::FromHandle(hDataset)->GetRasterYSize();
1163
0
}
1164
1165
/************************************************************************/
1166
/*                           GetRasterBand()                            */
1167
/************************************************************************/
1168
1169
/**
1170
1171
 \brief Fetch a band object for a dataset.
1172
1173
 See GetBands() for a C++ iterator version of this method.
1174
1175
 Equivalent of the C function GDALGetRasterBand().
1176
1177
 @param nBandId the index number of the band to fetch, from 1 to
1178
                GetRasterCount().
1179
1180
 @return the nBandId th band object
1181
1182
*/
1183
1184
GDALRasterBand *GDALDataset::GetRasterBand(int nBandId)
1185
1186
0
{
1187
0
    if (papoBands)
1188
0
    {
1189
0
        if (nBandId < 1 || nBandId > nBands)
1190
0
        {
1191
0
            ReportError(CE_Failure, CPLE_IllegalArg,
1192
0
                        "GDALDataset::GetRasterBand(%d) - Illegal band #\n",
1193
0
                        nBandId);
1194
0
            return nullptr;
1195
0
        }
1196
1197
0
        return papoBands[nBandId - 1];
1198
0
    }
1199
0
    return nullptr;
1200
0
}
1201
1202
/************************************************************************/
1203
/*                           GetRasterBand()                            */
1204
/************************************************************************/
1205
1206
/**
1207
1208
 \brief Fetch a band object for a dataset.
1209
1210
 See GetBands() for a C++ iterator version of this method.
1211
1212
 Equivalent of the C function GDALGetRasterBand().
1213
1214
 @param nBandId the index number of the band to fetch, from 1 to
1215
                GetRasterCount().
1216
1217
 @return the nBandId th band object
1218
1219
*/
1220
1221
const GDALRasterBand *GDALDataset::GetRasterBand(int nBandId) const
1222
1223
0
{
1224
0
    if (papoBands)
1225
0
    {
1226
0
        if (nBandId < 1 || nBandId > nBands)
1227
0
        {
1228
0
            ReportError(CE_Failure, CPLE_IllegalArg,
1229
0
                        "GDALDataset::GetRasterBand(%d) - Illegal band #\n",
1230
0
                        nBandId);
1231
0
            return nullptr;
1232
0
        }
1233
1234
0
        return papoBands[nBandId - 1];
1235
0
    }
1236
0
    return nullptr;
1237
0
}
1238
1239
/************************************************************************/
1240
/*                         GDALGetRasterBand()                          */
1241
/************************************************************************/
1242
1243
/**
1244
 * \brief Fetch a band object for a dataset.
1245
 * @see GDALDataset::GetRasterBand().
1246
 */
1247
1248
GDALRasterBandH CPL_STDCALL GDALGetRasterBand(GDALDatasetH hDS, int nBandId)
1249
1250
0
{
1251
0
    VALIDATE_POINTER1(hDS, "GDALGetRasterBand", nullptr);
1252
1253
0
    return GDALRasterBand::ToHandle(
1254
0
        GDALDataset::FromHandle(hDS)->GetRasterBand(nBandId));
1255
0
}
1256
1257
/************************************************************************/
1258
/*                           GetRasterCount()                           */
1259
/************************************************************************/
1260
1261
/**
1262
 * \brief Fetch the number of raster bands on this dataset.
1263
 *
1264
 * Same as the C function GDALGetRasterCount().
1265
 *
1266
 * @return the number of raster bands.
1267
 */
1268
1269
int GDALDataset::GetRasterCount() const
1270
0
{
1271
0
    return papoBands ? nBands : 0;
1272
0
}
1273
1274
/************************************************************************/
1275
/*                         GDALGetRasterCount()                         */
1276
/************************************************************************/
1277
1278
/**
1279
 * \brief Fetch the number of raster bands on this dataset.
1280
 *
1281
 * @see GDALDataset::GetRasterCount().
1282
 */
1283
1284
int CPL_STDCALL GDALGetRasterCount(GDALDatasetH hDS)
1285
1286
0
{
1287
0
    VALIDATE_POINTER1(hDS, "GDALGetRasterCount", 0);
1288
1289
0
    return GDALDataset::FromHandle(hDS)->GetRasterCount();
1290
0
}
1291
1292
/************************************************************************/
1293
/*                          GetProjectionRef()                          */
1294
/************************************************************************/
1295
1296
/**
1297
 * \brief Fetch the projection definition string for this dataset.
1298
 *
1299
 * Same as the C function GDALGetProjectionRef().
1300
 *
1301
 * The returned string defines the projection coordinate system of the
1302
 * image in OpenGIS WKT format.  It should be suitable for use with the
1303
 * OGRSpatialReference class.
1304
 *
1305
 * When a projection definition is not available an empty (but not NULL)
1306
 * string is returned.
1307
 *
1308
 * \note Starting with GDAL 3.0, this is a compatibility layer around
1309
 * GetSpatialRef()
1310
 *
1311
 * @return a pointer to an internal projection reference string.  It should
1312
 * not be altered, freed or expected to last for long.
1313
 *
1314
 * @see https://gdal.org/tutorials/osr_api_tut.html
1315
 */
1316
1317
const char *GDALDataset::GetProjectionRef() const
1318
0
{
1319
0
    const auto poSRS = GetSpatialRef();
1320
0
    if (!poSRS || !m_poPrivate)
1321
0
    {
1322
0
        return "";
1323
0
    }
1324
0
    char *pszWKT = nullptr;
1325
0
    poSRS->exportToWkt(&pszWKT);
1326
0
    if (!pszWKT)
1327
0
    {
1328
0
        return "";
1329
0
    }
1330
1331
    // If called on a thread-safe dataset, we might be called by several
1332
    // threads, so make sure our accesses to m_pszWKTCached are protected
1333
    // by a mutex.
1334
0
    std::lock_guard oLock(m_poPrivate->m_oMutexWKT);
1335
0
    if (m_poPrivate->m_pszWKTCached &&
1336
0
        strcmp(pszWKT, m_poPrivate->m_pszWKTCached) == 0)
1337
0
    {
1338
0
        CPLFree(pszWKT);
1339
0
        return m_poPrivate->m_pszWKTCached;
1340
0
    }
1341
0
    CPLFree(m_poPrivate->m_pszWKTCached);
1342
0
    m_poPrivate->m_pszWKTCached = pszWKT;
1343
0
    return m_poPrivate->m_pszWKTCached;
1344
0
}
1345
1346
/************************************************************************/
1347
/*                           GetSpatialRef()                            */
1348
/************************************************************************/
1349
1350
static thread_local int tlsEnableLayersInGetSpatialRefCounter = 0;
1351
1352
/**
1353
 * \brief Fetch the spatial reference for this dataset.
1354
 *
1355
 * Same as the C function GDALGetSpatialRef().
1356
 *
1357
 * When a projection definition is not available, null is returned. If used on
1358
 * a dataset where there are GCPs and not a geotransform, this method returns
1359
 * null. Use GetGCPSpatialRef() instead.
1360
 *
1361
 * Since GDAL 3.12, the default implementation of this method will iterate over
1362
 * vector layers and return their SRS if all geometry columns of all layers use
1363
 * the same SRS, or nullptr otherwise.
1364
 *
1365
 * @since GDAL 3.0
1366
 *
1367
 * @return a pointer to an internal object. It should not be altered or freed.
1368
 * Its lifetime will be the one of the dataset object.
1369
 *
1370
 * @see https://gdal.org/tutorials/osr_api_tut.html
1371
 */
1372
1373
const OGRSpatialReference *GDALDataset::GetSpatialRef() const
1374
0
{
1375
0
    if (tlsEnableLayersInGetSpatialRefCounter == 0)
1376
0
        return GetSpatialRefVectorOnly();
1377
0
    return nullptr;
1378
0
}
1379
1380
/************************************************************************/
1381
/*                      GetSpatialRefVectorOnly()                       */
1382
/************************************************************************/
1383
1384
/**
1385
 * \brief Fetch the spatial reference for this dataset (only for vector layers)
1386
 *
1387
 * The default implementation of this method will iterate over
1388
 * vector layers and return their SRS if all geometry columns of all layers use
1389
 * the same SRS, or nullptr otherwise.
1390
 *
1391
 * @since GDAL 3.12
1392
 *
1393
 * @return a pointer to an internal object. It should not be altered or freed.
1394
 * Its lifetime will be the one of the dataset object.
1395
 */
1396
1397
const OGRSpatialReference *GDALDataset::GetSpatialRefVectorOnly() const
1398
0
{
1399
0
    bool bInit = false;
1400
0
    const OGRSpatialReference *poGlobalSRS = nullptr;
1401
0
    for (const OGRLayer *poLayer : GetLayers())
1402
0
    {
1403
0
        for (const auto *poGeomFieldDefn :
1404
0
             poLayer->GetLayerDefn()->GetGeomFields())
1405
0
        {
1406
0
            const auto *poSRS = poGeomFieldDefn->GetSpatialRef();
1407
0
            if (!bInit)
1408
0
            {
1409
0
                bInit = true;
1410
0
                poGlobalSRS = poSRS;
1411
0
            }
1412
0
            else if ((poSRS && !poGlobalSRS) || (!poSRS && poGlobalSRS) ||
1413
0
                     (poSRS && poGlobalSRS && !poSRS->IsSame(poGlobalSRS)))
1414
0
            {
1415
0
                CPLDebug("GDAL",
1416
0
                         "Not all geometry fields or layers have the same CRS");
1417
0
                return nullptr;
1418
0
            }
1419
0
        }
1420
0
    }
1421
0
    return poGlobalSRS;
1422
0
}
1423
1424
/************************************************************************/
1425
/*                      GetSpatialRefRasterOnly()                       */
1426
/************************************************************************/
1427
1428
/**
1429
 * \brief Fetch the spatial reference for this dataset (ignoring vector layers)
1430
 *
1431
 * @since GDAL 3.12
1432
 *
1433
 * @return a pointer to an internal object. It should not be altered or freed.
1434
 * Its lifetime will be the one of the dataset object.
1435
 */
1436
1437
const OGRSpatialReference *GDALDataset::GetSpatialRefRasterOnly() const
1438
0
{
1439
0
    ++tlsEnableLayersInGetSpatialRefCounter;
1440
0
    const auto poRet = GetSpatialRef();
1441
0
    --tlsEnableLayersInGetSpatialRefCounter;
1442
0
    return poRet;
1443
0
}
1444
1445
/************************************************************************/
1446
/*                         GDALGetSpatialRef()                          */
1447
/************************************************************************/
1448
1449
/**
1450
 * \brief Fetch the spatial reference for this dataset.
1451
 *
1452
 * Same as the C++ method GDALDataset::GetSpatialRef()
1453
 *
1454
 * @since GDAL 3.0
1455
 *
1456
 * @see GDALDataset::GetSpatialRef()
1457
 */
1458
1459
OGRSpatialReferenceH GDALGetSpatialRef(GDALDatasetH hDS)
1460
1461
0
{
1462
0
    VALIDATE_POINTER1(hDS, "GDALGetSpatialRef", nullptr);
1463
1464
0
    return OGRSpatialReference::ToHandle(const_cast<OGRSpatialReference *>(
1465
0
        GDALDataset::FromHandle(hDS)->GetSpatialRef()));
1466
0
}
1467
1468
/************************************************************************/
1469
/*                        GDALGetProjectionRef()                        */
1470
/************************************************************************/
1471
1472
/**
1473
 * \brief Fetch the projection definition string for this dataset.
1474
 *
1475
 * @see GDALDataset::GetProjectionRef()
1476
 */
1477
1478
const char *CPL_STDCALL GDALGetProjectionRef(GDALDatasetH hDS)
1479
1480
0
{
1481
0
    VALIDATE_POINTER1(hDS, "GDALGetProjectionRef", nullptr);
1482
1483
0
    return GDALDataset::FromHandle(hDS)->GetProjectionRef();
1484
0
}
1485
1486
/************************************************************************/
1487
/*                           SetProjection()                            */
1488
/************************************************************************/
1489
1490
/**
1491
 * \brief Set the projection reference string for this dataset.
1492
 *
1493
 * The string should be in OGC WKT or PROJ.4 format.  An error may occur
1494
 * because of incorrectly specified projection strings, because the dataset
1495
 * is not writable, or because the dataset does not support the indicated
1496
 * projection.  Many formats do not support writing projections.
1497
 *
1498
 * This method is the same as the C GDALSetProjection() function.
1499
 *
1500
 * \note Startig with GDAL 3.0, this is a compatibility layer around
1501
 * SetSpatialRef()
1502
1503
 * @param pszProjection projection reference string.
1504
 *
1505
 * @return CE_Failure if an error occurs, otherwise CE_None.
1506
 */
1507
1508
CPLErr GDALDataset::SetProjection(const char *pszProjection)
1509
0
{
1510
0
    if (pszProjection && pszProjection[0] != '\0')
1511
0
    {
1512
0
        OGRSpatialReference oSRS;
1513
0
        oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1514
0
        if (oSRS.SetFromUserInput(pszProjection) != OGRERR_NONE)
1515
0
        {
1516
0
            return CE_Failure;
1517
0
        }
1518
0
        return SetSpatialRef(&oSRS);
1519
0
    }
1520
0
    else
1521
0
    {
1522
0
        return SetSpatialRef(nullptr);
1523
0
    }
1524
0
}
1525
1526
/************************************************************************/
1527
/*                           SetSpatialRef()                            */
1528
/************************************************************************/
1529
1530
/**
1531
 * \brief Set the spatial reference system for this dataset.
1532
 *
1533
 * An error may occur because the dataset
1534
 * is not writable, or because the dataset does not support the indicated
1535
 * projection. Many formats do not support writing projections.
1536
 *
1537
 * This method is the same as the C GDALSetSpatialRef() function.
1538
 *
1539
 * @since GDAL 3.0
1540
1541
 * @param poSRS spatial reference system object. nullptr can potentially be
1542
 * passed for drivers that support unsetting the SRS.
1543
 *
1544
 * @return CE_Failure if an error occurs, otherwise CE_None.
1545
 */
1546
1547
CPLErr GDALDataset::SetSpatialRef(CPL_UNUSED const OGRSpatialReference *poSRS)
1548
0
{
1549
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1550
0
        ReportError(CE_Failure, CPLE_NotSupported,
1551
0
                    "Dataset does not support the SetSpatialRef() method.");
1552
0
    return CE_Failure;
1553
0
}
1554
1555
/************************************************************************/
1556
/*                         GDALSetSpatialRef()                          */
1557
/************************************************************************/
1558
1559
/**
1560
 * \brief Set the spatial reference system for this dataset.
1561
 *
1562
 * @since GDAL 3.0
1563
 *
1564
 * @see GDALDataset::SetSpatialRef()
1565
 */
1566
1567
CPLErr GDALSetSpatialRef(GDALDatasetH hDS, OGRSpatialReferenceH hSRS)
1568
1569
0
{
1570
0
    VALIDATE_POINTER1(hDS, "GDALSetSpatialRef", CE_Failure);
1571
1572
0
    return GDALDataset::FromHandle(hDS)->SetSpatialRef(
1573
0
        OGRSpatialReference::FromHandle(hSRS));
1574
0
}
1575
1576
/************************************************************************/
1577
/*                         GDALSetProjection()                          */
1578
/************************************************************************/
1579
1580
/**
1581
 * \brief Set the projection reference string for this dataset.
1582
 *
1583
 * @see GDALDataset::SetProjection()
1584
 */
1585
1586
CPLErr CPL_STDCALL GDALSetProjection(GDALDatasetH hDS,
1587
                                     const char *pszProjection)
1588
1589
0
{
1590
0
    VALIDATE_POINTER1(hDS, "GDALSetProjection", CE_Failure);
1591
1592
0
    return GDALDataset::FromHandle(hDS)->SetProjection(pszProjection);
1593
0
}
1594
1595
/************************************************************************/
1596
/*                          GetGeoTransform()                           */
1597
/************************************************************************/
1598
1599
/**
1600
 * \brief Fetch the affine transformation coefficients.
1601
 *
1602
 * Fetches the coefficients for transforming between pixel/line (P,L) raster
1603
 * space, and projection coordinates (Xp,Yp) space.
1604
 *
1605
 * \code
1606
 *   Xp = gt.xorig + P*gt.xscale + L*gt.xrot;
1607
 *   Yp = gt.yorig + P*padfTransform[4] + L*gt.yscale;
1608
 * \endcode
1609
 *
1610
 * In a north up image, gt.xscale is the pixel width, and
1611
 * gt.yscale is the pixel height.  The upper left corner of the
1612
 * upper left pixel is at position (gt.xorig,gt.yorig).
1613
 *
1614
 * The default transform is (0,1,0,0,0,1) and should be returned even when
1615
 * a CE_Failure error is returned, such as for formats that don't support
1616
 * transformation to projection coordinates.
1617
 *
1618
 * This method does the same thing as the C GDALGetGeoTransform() function.
1619
 *
1620
 * @param gt an existing six double buffer into which the
1621
 * transformation will be placed.
1622
 *
1623
 * @return CE_None on success, or CE_Failure if no transform can be fetched.
1624
 *
1625
 * @since 3.12
1626
 */
1627
1628
CPLErr GDALDataset::GetGeoTransform(GDALGeoTransform &gt) const
1629
1630
0
{
1631
0
    gt = GDALGeoTransform();
1632
1633
0
    return CE_Failure;
1634
0
}
1635
1636
/************************************************************************/
1637
/*                          GetGeoTransform()                           */
1638
/************************************************************************/
1639
1640
/**
1641
 * \brief Fetch the affine transformation coefficients.
1642
 *
1643
 * Fetches the coefficients for transforming between pixel/line (P,L) raster
1644
 * space, and projection coordinates (Xp,Yp) space.
1645
 *
1646
 * \code
1647
 *   Xp = padfTransform[0] + P*padfTransform[1] + L*padfTransform[2];
1648
 *   Yp = padfTransform[3] + P*padfTransform[4] + L*padfTransform[5];
1649
 * \endcode
1650
 *
1651
 * In a north up image, padfTransform[1] is the pixel width, and
1652
 * padfTransform[5] is the pixel height.  The upper left corner of the
1653
 * upper left pixel is at position (padfTransform[0],padfTransform[3]).
1654
 *
1655
 * The default transform is (0,1,0,0,0,1) and should be returned even when
1656
 * a CE_Failure error is returned, such as for formats that don't support
1657
 * transformation to projection coordinates.
1658
 *
1659
 * This method does the same thing as the C GDALGetGeoTransform() function.
1660
 *
1661
 * @param padfTransform an existing six double buffer into which the
1662
 * transformation will be placed.
1663
 *
1664
 * @return CE_None on success, or CE_Failure if no transform can be fetched.
1665
 *
1666
 * @deprecated since 3.12. Use GetGeoTransform(GDALGeoTransform&) instead
1667
 */
1668
1669
CPLErr GDALDataset::GetGeoTransform(double *padfTransform) const
1670
1671
0
{
1672
0
    return GetGeoTransform(
1673
0
        *reinterpret_cast<GDALGeoTransform *>(padfTransform));
1674
0
}
1675
1676
/************************************************************************/
1677
/*                        GDALGetGeoTransform()                         */
1678
/************************************************************************/
1679
1680
/**
1681
 * \brief Fetch the affine transformation coefficients.
1682
 *
1683
 * @see GDALDataset::GetGeoTransform()
1684
 */
1685
1686
CPLErr CPL_STDCALL GDALGetGeoTransform(GDALDatasetH hDS, double *padfTransform)
1687
1688
0
{
1689
0
    VALIDATE_POINTER1(hDS, "GDALGetGeoTransform", CE_Failure);
1690
1691
0
    return GDALDataset::FromHandle(hDS)->GetGeoTransform(
1692
0
        *reinterpret_cast<GDALGeoTransform *>(padfTransform));
1693
0
}
1694
1695
/************************************************************************/
1696
/*                          SetGeoTransform()                           */
1697
/************************************************************************/
1698
1699
/**
1700
 * \fn GDALDataset::SetGeoTransform(const GDALGeoTransform&)
1701
 * \brief Set the affine transformation coefficients.
1702
 *
1703
 * See GetGeoTransform() for details on the meaning of the padfTransform
1704
 * coefficients.
1705
 *
1706
 * This method does the same thing as the C GDALSetGeoTransform() function.
1707
 *
1708
 * @param gt the transformation coefficients to be written with the dataset.
1709
 *
1710
 * @return CE_None on success, or CE_Failure if this transform cannot be
1711
 * written.
1712
 *
1713
 * @since 3.12
1714
 */
1715
1716
CPLErr GDALDataset::SetGeoTransform(CPL_UNUSED const GDALGeoTransform &gt)
1717
1718
0
{
1719
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1720
0
        ReportError(CE_Failure, CPLE_NotSupported,
1721
0
                    "SetGeoTransform() not supported for this dataset.");
1722
1723
0
    return CE_Failure;
1724
0
}
1725
1726
/************************************************************************/
1727
/*                          SetGeoTransform()                           */
1728
/************************************************************************/
1729
1730
/**
1731
 * \brief Set the affine transformation coefficients.
1732
 *
1733
 * See GetGeoTransform() for details on the meaning of the padfTransform
1734
 * coefficients.
1735
 *
1736
 * This method does the same thing as the C GDALSetGeoTransform() function.
1737
 *
1738
 * @param padfTransform a six double buffer containing the transformation
1739
 * coefficients to be written with the dataset.
1740
 *
1741
 * @return CE_None on success, or CE_Failure if this transform cannot be
1742
 * written.
1743
 *
1744
 * @deprecated since 3.12. Use SetGeoTransform(const GDALGeoTransform&) instead
1745
 */
1746
CPLErr GDALDataset::SetGeoTransform(const double *padfTransform)
1747
1748
0
{
1749
0
    return SetGeoTransform(
1750
0
        *reinterpret_cast<const GDALGeoTransform *>(padfTransform));
1751
0
}
1752
1753
/************************************************************************/
1754
/*                        GDALSetGeoTransform()                         */
1755
/************************************************************************/
1756
1757
/**
1758
 * \brief Set the affine transformation coefficients.
1759
 *
1760
 * @see GDALDataset::SetGeoTransform()
1761
 */
1762
1763
CPLErr CPL_STDCALL GDALSetGeoTransform(GDALDatasetH hDS,
1764
                                       const double *padfTransform)
1765
1766
0
{
1767
0
    VALIDATE_POINTER1(hDS, "GDALSetGeoTransform", CE_Failure);
1768
0
    VALIDATE_POINTER1(padfTransform, "GDALSetGeoTransform", CE_Failure);
1769
1770
0
    return GDALDataset::FromHandle(hDS)->SetGeoTransform(
1771
0
        *reinterpret_cast<const GDALGeoTransform *>(padfTransform));
1772
0
}
1773
1774
/************************************************************************/
1775
/*                         GetInternalHandle()                          */
1776
/************************************************************************/
1777
1778
/**
1779
 * \fn GDALDataset::GetInternalHandle(const char*)
1780
 * \brief Fetch a format specific internally meaningful handle.
1781
 *
1782
 * This method is the same as the C GDALGetInternalHandle() method.
1783
 *
1784
 * @param pszHandleName the handle name desired.  The meaningful names
1785
 * will be specific to the file format.
1786
 *
1787
 * @return the desired handle value, or NULL if not recognized/supported.
1788
 */
1789
1790
void *GDALDataset::GetInternalHandle(CPL_UNUSED const char *pszHandleName)
1791
1792
0
{
1793
0
    return nullptr;
1794
0
}
1795
1796
/************************************************************************/
1797
/*                       GDALGetInternalHandle()                        */
1798
/************************************************************************/
1799
1800
/**
1801
 * \brief Fetch a format specific internally meaningful handle.
1802
 *
1803
 * @see GDALDataset::GetInternalHandle()
1804
 */
1805
1806
void *CPL_STDCALL GDALGetInternalHandle(GDALDatasetH hDS,
1807
                                        const char *pszRequest)
1808
1809
0
{
1810
0
    VALIDATE_POINTER1(hDS, "GDALGetInternalHandle", nullptr);
1811
1812
0
    return GDALDataset::FromHandle(hDS)->GetInternalHandle(pszRequest);
1813
0
}
1814
1815
/************************************************************************/
1816
/*                             GetDriver()                              */
1817
/************************************************************************/
1818
1819
/**
1820
 * \brief Fetch the driver to which this dataset relates.
1821
 *
1822
 * This method is the same as the C GDALGetDatasetDriver() function.
1823
 *
1824
 * @return the driver on which the dataset was created with GDALOpen() or
1825
 * GDALCreate().
1826
 */
1827
1828
GDALDriver *GDALDataset::GetDriver()
1829
0
{
1830
0
    return poDriver;
1831
0
}
1832
1833
/************************************************************************/
1834
/*                        GDALGetDatasetDriver()                        */
1835
/************************************************************************/
1836
1837
/**
1838
 * \brief Fetch the driver to which this dataset relates.
1839
 *
1840
 * @see GDALDataset::GetDriver()
1841
 */
1842
1843
GDALDriverH CPL_STDCALL GDALGetDatasetDriver(GDALDatasetH hDataset)
1844
1845
0
{
1846
0
    VALIDATE_POINTER1(hDataset, "GDALGetDatasetDriver", nullptr);
1847
1848
0
    return static_cast<GDALDriverH>(
1849
0
        GDALDataset::FromHandle(hDataset)->GetDriver());
1850
0
}
1851
1852
/************************************************************************/
1853
/*                             Reference()                              */
1854
/************************************************************************/
1855
1856
/**
1857
 * \brief Add one to dataset reference count.
1858
 *
1859
 * The reference is one after instantiation.
1860
 *
1861
 * This method is the same as the C GDALReferenceDataset() function.
1862
 *
1863
 * @return the post-increment reference count.
1864
 */
1865
1866
int GDALDataset::Reference()
1867
0
{
1868
0
    return ++nRefCount;
1869
0
}
1870
1871
/************************************************************************/
1872
/*                        GDALReferenceDataset()                        */
1873
/************************************************************************/
1874
1875
/**
1876
 * \brief Add one to dataset reference count.
1877
 *
1878
 * @see GDALDataset::Reference()
1879
 */
1880
1881
int CPL_STDCALL GDALReferenceDataset(GDALDatasetH hDataset)
1882
1883
0
{
1884
0
    VALIDATE_POINTER1(hDataset, "GDALReferenceDataset", 0);
1885
1886
0
    return GDALDataset::FromHandle(hDataset)->Reference();
1887
0
}
1888
1889
/************************************************************************/
1890
/*                            Dereference()                             */
1891
/************************************************************************/
1892
1893
/**
1894
 * \brief Subtract one from dataset reference count.
1895
 *
1896
 * The reference is one after instantiation.  Generally when the reference
1897
 * count has dropped to zero the dataset may be safely deleted (closed).
1898
 *
1899
 * This method is the same as the C GDALDereferenceDataset() function.
1900
 *
1901
 * @return the post-decrement reference count.
1902
 */
1903
1904
int GDALDataset::Dereference()
1905
0
{
1906
0
    return --nRefCount;
1907
0
}
1908
1909
/************************************************************************/
1910
/*                       GDALDereferenceDataset()                       */
1911
/************************************************************************/
1912
1913
/**
1914
 * \brief Subtract one from dataset reference count.
1915
 *
1916
 * @see GDALDataset::Dereference()
1917
 */
1918
1919
int CPL_STDCALL GDALDereferenceDataset(GDALDatasetH hDataset)
1920
1921
0
{
1922
0
    VALIDATE_POINTER1(hDataset, "GDALDereferenceDataset", 0);
1923
1924
0
    return GDALDataset::FromHandle(hDataset)->Dereference();
1925
0
}
1926
1927
/************************************************************************/
1928
/*                             ReleaseRef()                             */
1929
/************************************************************************/
1930
1931
/**
1932
 * \brief Drop a reference to this object, and destroy if no longer referenced.
1933
 * @return TRUE if the object has been destroyed.
1934
 */
1935
1936
int GDALDataset::ReleaseRef()
1937
1938
0
{
1939
0
    if (Dereference() <= 0)
1940
0
    {
1941
0
        nRefCount = 1;
1942
0
        delete this;
1943
0
        return TRUE;
1944
0
    }
1945
0
    return FALSE;
1946
0
}
1947
1948
/************************************************************************/
1949
/*                         GDALReleaseDataset()                         */
1950
/************************************************************************/
1951
1952
/**
1953
 * \brief Drop a reference to this object, and destroy if no longer referenced.
1954
 *
1955
 * @see GDALDataset::ReleaseRef()
1956
 */
1957
1958
int CPL_STDCALL GDALReleaseDataset(GDALDatasetH hDataset)
1959
1960
0
{
1961
0
    VALIDATE_POINTER1(hDataset, "GDALReleaseDataset", 0);
1962
1963
0
    return GDALDataset::FromHandle(hDataset)->ReleaseRef();
1964
0
}
1965
1966
/************************************************************************/
1967
/*                             GetShared()                              */
1968
/************************************************************************/
1969
1970
/**
1971
 * \brief Returns shared flag.
1972
 *
1973
 * @return TRUE if the GDALDataset is available for sharing, or FALSE if not.
1974
 */
1975
1976
int GDALDataset::GetShared() const
1977
0
{
1978
0
    return bShared;
1979
0
}
1980
1981
/************************************************************************/
1982
/*                            MarkAsShared()                            */
1983
/************************************************************************/
1984
1985
/**
1986
 * \brief Mark this dataset as available for sharing.
1987
 */
1988
1989
void GDALDataset::MarkAsShared()
1990
1991
0
{
1992
0
    CPLAssert(!bShared);
1993
1994
0
    bShared = true;
1995
0
    if (bIsInternal)
1996
0
        return;
1997
1998
0
    GIntBig nPID = GDALGetResponsiblePIDForCurrentThread();
1999
2000
    // Insert the dataset in the set of shared opened datasets.
2001
0
    CPLMutexHolderD(&hDLMutex);
2002
0
    if (phSharedDatasetSet == nullptr)
2003
0
        phSharedDatasetSet =
2004
0
            CPLHashSetNew(GDALSharedDatasetHashFunc, GDALSharedDatasetEqualFunc,
2005
0
                          GDALSharedDatasetFreeFunc);
2006
2007
0
    SharedDatasetCtxt *psStruct =
2008
0
        static_cast<SharedDatasetCtxt *>(CPLMalloc(sizeof(SharedDatasetCtxt)));
2009
0
    psStruct->poDS = this;
2010
0
    psStruct->nPID = nPID;
2011
0
    psStruct->nOpenFlags = nOpenFlags & ~GDAL_OF_SHARED;
2012
0
    psStruct->pszDescription = CPLStrdup(GetDescription());
2013
0
    std::string osConcatenatedOpenOptions =
2014
0
        GDALSharedDatasetConcatenateOpenOptions(papszOpenOptions);
2015
0
    psStruct->pszConcatenatedOpenOptions =
2016
0
        CPLStrdup(osConcatenatedOpenOptions.c_str());
2017
0
    if (CPLHashSetLookup(phSharedDatasetSet, psStruct) != nullptr)
2018
0
    {
2019
0
        GDALSharedDatasetFreeFunc(psStruct);
2020
0
        ReportError(CE_Failure, CPLE_AppDefined,
2021
0
                    "An existing shared dataset already has this description. "
2022
0
                    "This should not happen.");
2023
0
    }
2024
0
    else
2025
0
    {
2026
0
        CPLHashSetInsert(phSharedDatasetSet, psStruct);
2027
2028
0
        (*poAllDatasetMap)[this] = nPID;
2029
0
    }
2030
0
}
2031
2032
/************************************************************************/
2033
/*                        MarkSuppressOnClose()                         */
2034
/************************************************************************/
2035
2036
/** Set that the dataset must be deleted on close.
2037
 *
2038
 * This is the same as C function GDALDatasetMarkSuppressOnClose()
2039
 */
2040
void GDALDataset::MarkSuppressOnClose()
2041
0
{
2042
0
    bSuppressOnClose = true;
2043
0
}
2044
2045
/************************************************************************/
2046
/*                   GDALDatasetMarkSuppressOnClose()                   */
2047
/************************************************************************/
2048
2049
/** Set that the dataset must be deleted on close.
2050
 *
2051
 * This is the same as C++ method GDALDataset::MarkSuppressOnClose()
2052
 *
2053
 * @since GDAL 3.12
2054
 */
2055
2056
void GDALDatasetMarkSuppressOnClose(GDALDatasetH hDS)
2057
0
{
2058
0
    VALIDATE_POINTER0(hDS, "GDALDatasetMarkSuppressOnClose");
2059
2060
0
    return GDALDataset::FromHandle(hDS)->MarkSuppressOnClose();
2061
0
}
2062
2063
/************************************************************************/
2064
/*                       UnMarkSuppressOnClose()                        */
2065
/************************************************************************/
2066
2067
/** Remove the flag requesting the dataset to be deleted on close. */
2068
void GDALDataset::UnMarkSuppressOnClose()
2069
0
{
2070
0
    bSuppressOnClose = false;
2071
0
}
2072
2073
/************************************************************************/
2074
/*                       CleanupPostFileClosing()                       */
2075
/************************************************************************/
2076
2077
/** This method should be called by driver implementations in their destructor,
2078
 * after having closed all files, but before having freed resources that
2079
 * are needed for their GetFileList() implementation.
2080
 * This is used to implement MarkSuppressOnClose behavior.
2081
 */
2082
void GDALDataset::CleanupPostFileClosing()
2083
0
{
2084
0
    if (IsMarkedSuppressOnClose())
2085
0
    {
2086
0
        char **papszFileList = GetFileList();
2087
0
        for (int i = 0; papszFileList && papszFileList[i]; ++i)
2088
0
            VSIUnlink(papszFileList[i]);
2089
0
        CSLDestroy(papszFileList);
2090
0
    }
2091
0
}
2092
2093
/************************************************************************/
2094
/*                            GetGCPCount()                             */
2095
/************************************************************************/
2096
2097
/**
2098
 * \brief Get number of GCPs.
2099
 *
2100
 * This method is the same as the C function GDALGetGCPCount().
2101
 *
2102
 * @return number of GCPs for this dataset.  Zero if there are none.
2103
 */
2104
2105
int GDALDataset::GetGCPCount()
2106
0
{
2107
0
    return 0;
2108
0
}
2109
2110
/************************************************************************/
2111
/*                          GDALGetGCPCount()                           */
2112
/************************************************************************/
2113
2114
/**
2115
 * \brief Get number of GCPs.
2116
 *
2117
 * @see GDALDataset::GetGCPCount()
2118
 */
2119
2120
int CPL_STDCALL GDALGetGCPCount(GDALDatasetH hDS)
2121
2122
0
{
2123
0
    VALIDATE_POINTER1(hDS, "GDALGetGCPCount", 0);
2124
2125
0
    return GDALDataset::FromHandle(hDS)->GetGCPCount();
2126
0
}
2127
2128
/************************************************************************/
2129
/*                          GetGCPProjection()                          */
2130
/************************************************************************/
2131
2132
/**
2133
 * \brief Get output projection for GCPs.
2134
 *
2135
 * This method is the same as the C function GDALGetGCPProjection().
2136
 *
2137
 * The projection string follows the normal rules from GetProjectionRef().
2138
 *
2139
 * \note Starting with GDAL 3.0, this is a compatibility layer around
2140
 * GetGCPSpatialRef()
2141
 *
2142
 * @return internal projection string or "" if there are no GCPs.
2143
 *  It should not be altered, freed or expected to last for long.
2144
 */
2145
2146
const char *GDALDataset::GetGCPProjection() const
2147
0
{
2148
0
    const auto poSRS = GetGCPSpatialRef();
2149
0
    if (!poSRS || !m_poPrivate)
2150
0
    {
2151
0
        return "";
2152
0
    }
2153
0
    char *pszWKT = nullptr;
2154
0
    poSRS->exportToWkt(&pszWKT);
2155
0
    if (!pszWKT)
2156
0
    {
2157
0
        return "";
2158
0
    }
2159
2160
    // If called on a thread-safe dataset, we might be called by several
2161
    // threads, so make sure our accesses to m_pszWKTCached are protected
2162
    // by a mutex.
2163
0
    std::lock_guard oLock(m_poPrivate->m_oMutexWKT);
2164
0
    if (m_poPrivate->m_pszWKTGCPCached &&
2165
0
        strcmp(pszWKT, m_poPrivate->m_pszWKTGCPCached) == 0)
2166
0
    {
2167
0
        CPLFree(pszWKT);
2168
0
        return m_poPrivate->m_pszWKTGCPCached;
2169
0
    }
2170
0
    CPLFree(m_poPrivate->m_pszWKTGCPCached);
2171
0
    m_poPrivate->m_pszWKTGCPCached = pszWKT;
2172
0
    return m_poPrivate->m_pszWKTGCPCached;
2173
0
}
2174
2175
/************************************************************************/
2176
/*                          GetGCPSpatialRef()                          */
2177
/************************************************************************/
2178
2179
/**
2180
 * \brief Get output spatial reference system for GCPs.
2181
 *
2182
 * Same as the C function GDALGetGCPSpatialRef().
2183
 *
2184
 * When a SRS is not available, null is returned. If used on
2185
 * a dataset where there is a geotransform, and not GCPs, this method returns
2186
 * null. Use GetSpatialRef() instead.
2187
 *
2188
 * @since GDAL 3.0
2189
 *
2190
 * @return a pointer to an internal object. It should not be altered or freed.
2191
 * Its lifetime will be the one of the dataset object, or until the next
2192
 * call to this method.
2193
 */
2194
2195
const OGRSpatialReference *GDALDataset::GetGCPSpatialRef() const
2196
0
{
2197
0
    return nullptr;
2198
0
}
2199
2200
/************************************************************************/
2201
/*                        GDALGetGCPSpatialRef()                        */
2202
/************************************************************************/
2203
2204
/**
2205
 * \brief Get output spatial reference system for GCPs.
2206
 *
2207
 * @since GDAL 3.0
2208
 *
2209
 * @see GDALDataset::GetGCPSpatialRef()
2210
 */
2211
2212
OGRSpatialReferenceH GDALGetGCPSpatialRef(GDALDatasetH hDS)
2213
2214
0
{
2215
0
    VALIDATE_POINTER1(hDS, "GDALGetGCPSpatialRef", nullptr);
2216
2217
0
    return OGRSpatialReference::ToHandle(const_cast<OGRSpatialReference *>(
2218
0
        GDALDataset::FromHandle(hDS)->GetGCPSpatialRef()));
2219
0
}
2220
2221
/************************************************************************/
2222
/*                        GDALGetGCPProjection()                        */
2223
/************************************************************************/
2224
2225
/**
2226
 * \brief Get output projection for GCPs.
2227
 *
2228
 * @see GDALDataset::GetGCPProjection()
2229
 */
2230
2231
const char *CPL_STDCALL GDALGetGCPProjection(GDALDatasetH hDS)
2232
2233
0
{
2234
0
    VALIDATE_POINTER1(hDS, "GDALGetGCPProjection", nullptr);
2235
2236
0
    return GDALDataset::FromHandle(hDS)->GetGCPProjection();
2237
0
}
2238
2239
/************************************************************************/
2240
/*                              GetGCPs()                               */
2241
/************************************************************************/
2242
2243
/**
2244
 * \brief Fetch GCPs.
2245
 *
2246
 * This method is the same as the C function GDALGetGCPs().
2247
 *
2248
 * @return pointer to internal GCP structure list.  It should not be modified,
2249
 * and may change on the next GDAL call.
2250
 */
2251
2252
const GDAL_GCP *GDALDataset::GetGCPs()
2253
0
{
2254
0
    return nullptr;
2255
0
}
2256
2257
/************************************************************************/
2258
/*                            GDALGetGCPs()                             */
2259
/************************************************************************/
2260
2261
/**
2262
 * \brief Fetch GCPs.
2263
 *
2264
 * @see GDALDataset::GetGCPs()
2265
 */
2266
2267
const GDAL_GCP *CPL_STDCALL GDALGetGCPs(GDALDatasetH hDS)
2268
2269
0
{
2270
0
    VALIDATE_POINTER1(hDS, "GDALGetGCPs", nullptr);
2271
2272
0
    return GDALDataset::FromHandle(hDS)->GetGCPs();
2273
0
}
2274
2275
/************************************************************************/
2276
/*                              SetGCPs()                               */
2277
/************************************************************************/
2278
2279
/**
2280
 * \brief Assign GCPs.
2281
 *
2282
 * This method is the same as the C function GDALSetGCPs().
2283
 *
2284
 * This method assigns the passed set of GCPs to this dataset, as well as
2285
 * setting their coordinate system.  Internally copies are made of the
2286
 * coordinate system and list of points, so the caller remains responsible for
2287
 * deallocating these arguments if appropriate.
2288
 *
2289
 * Most formats do not support setting of GCPs, even formats that can
2290
 * handle GCPs.  These formats will return CE_Failure.
2291
 *
2292
 * \note Startig with GDAL 3.0, this is a compatibility layer around
2293
 * SetGCPs(int, const GDAL_GCP*, const char*)
2294
 *
2295
 * @param nGCPCount number of GCPs being assigned.
2296
 *
2297
 * @param pasGCPList array of GCP structures being assign (nGCPCount in array).
2298
 *
2299
 * @param pszGCPProjection the new OGC WKT coordinate system to assign for the
2300
 * GCP output coordinates.  This parameter should be "" if no output coordinate
2301
 * system is known.
2302
 *
2303
 * @return CE_None on success, CE_Failure on failure (including if action is
2304
 * not supported for this format).
2305
 */
2306
2307
CPLErr GDALDataset::SetGCPs(int nGCPCount, const GDAL_GCP *pasGCPList,
2308
                            const char *pszGCPProjection)
2309
2310
0
{
2311
0
    if (pszGCPProjection && pszGCPProjection[0] != '\0')
2312
0
    {
2313
0
        OGRSpatialReference oSRS;
2314
0
        oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
2315
0
        if (oSRS.importFromWkt(pszGCPProjection) != OGRERR_NONE)
2316
0
        {
2317
0
            return CE_Failure;
2318
0
        }
2319
0
        return SetGCPs(nGCPCount, pasGCPList, &oSRS);
2320
0
    }
2321
0
    else
2322
0
    {
2323
0
        return SetGCPs(nGCPCount, pasGCPList,
2324
0
                       static_cast<const OGRSpatialReference *>(nullptr));
2325
0
    }
2326
0
}
2327
2328
/************************************************************************/
2329
/*                              SetGCPs()                               */
2330
/************************************************************************/
2331
2332
/**
2333
 * \brief Assign GCPs.
2334
 *
2335
 * This method is the same as the C function GDALSetGCPs().
2336
 *
2337
 * This method assigns the passed set of GCPs to this dataset, as well as
2338
 * setting their coordinate system.  Internally copies are made of the
2339
 * coordinate system and list of points, so the caller remains responsible for
2340
 * deallocating these arguments if appropriate.
2341
 *
2342
 * Most formats do not support setting of GCPs, even formats that can
2343
 * handle GCPs.  These formats will return CE_Failure.
2344
 *
2345
 * @since GDAL 3.0
2346
 *
2347
 * @param nGCPCount number of GCPs being assigned.
2348
 *
2349
 * @param pasGCPList array of GCP structures being assign (nGCPCount in array).
2350
 *
2351
 * @param poGCP_SRS the new coordinate reference system to assign for the
2352
 * GCP output coordinates.  This parameter should be null if no output
2353
 * coordinate system is known.
2354
 *
2355
 * @return CE_None on success, CE_Failure on failure (including if action is
2356
 * not supported for this format).
2357
 */
2358
2359
CPLErr GDALDataset::SetGCPs(CPL_UNUSED int nGCPCount,
2360
                            CPL_UNUSED const GDAL_GCP *pasGCPList,
2361
                            CPL_UNUSED const OGRSpatialReference *poGCP_SRS)
2362
2363
0
{
2364
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2365
0
        ReportError(CE_Failure, CPLE_NotSupported,
2366
0
                    "Dataset does not support the SetGCPs() method.");
2367
2368
0
    return CE_Failure;
2369
0
}
2370
2371
/************************************************************************/
2372
/*                            GDALSetGCPs()                             */
2373
/************************************************************************/
2374
2375
/**
2376
 * \brief Assign GCPs.
2377
 *
2378
 * @see GDALDataset::SetGCPs(int, const GDAL_GCP*, const char*)
2379
 */
2380
2381
CPLErr CPL_STDCALL GDALSetGCPs(GDALDatasetH hDS, int nGCPCount,
2382
                               const GDAL_GCP *pasGCPList,
2383
                               const char *pszGCPProjection)
2384
2385
0
{
2386
0
    VALIDATE_POINTER1(hDS, "GDALSetGCPs", CE_Failure);
2387
2388
0
    return GDALDataset::FromHandle(hDS)->SetGCPs(nGCPCount, pasGCPList,
2389
0
                                                 pszGCPProjection);
2390
0
}
2391
2392
/************************************************************************/
2393
/*                            GDALSetGCPs2()                            */
2394
/************************************************************************/
2395
2396
/**
2397
 * \brief Assign GCPs.
2398
 *
2399
 * @since GDAL 3.0
2400
 * @see GDALDataset::SetGCPs(int, const GDAL_GCP*, const OGRSpatialReference*)
2401
 */
2402
2403
CPLErr GDALSetGCPs2(GDALDatasetH hDS, int nGCPCount, const GDAL_GCP *pasGCPList,
2404
                    OGRSpatialReferenceH hSRS)
2405
2406
0
{
2407
0
    VALIDATE_POINTER1(hDS, "GDALSetGCPs2", CE_Failure);
2408
2409
0
    return GDALDataset::FromHandle(hDS)->SetGCPs(
2410
0
        nGCPCount, pasGCPList, OGRSpatialReference::FromHandle(hSRS));
2411
0
}
2412
2413
/************************************************************************/
2414
/*                           BuildOverviews()                           */
2415
/************************************************************************/
2416
2417
/**
2418
 * \brief Build raster overview(s)
2419
 *
2420
 * If the operation is not supported for the indicated dataset, then
2421
 * CE_Failure is returned, and CPLGetLastErrorNo() will return
2422
 * CPLE_NotSupported.
2423
 *
2424
 * Depending on the actual file format, all overviews level can be also
2425
 * deleted by specifying nOverviews == 0. This works at least for external
2426
 * overviews (.ovr), TIFF internal overviews, etc.
2427
 *
2428
 * Starting with GDAL 3.2, the GDAL_NUM_THREADS configuration option can be set
2429
 * to "ALL_CPUS" or a integer value to specify the number of threads to use for
2430
 * overview computation.
2431
 *
2432
 * This method is the same as the C function GDALBuildOverviewsEx().
2433
 *
2434
 * @param pszResampling one of "AVERAGE", "AVERAGE_MAGPHASE", "RMS",
2435
 * "BILINEAR", "CUBIC", "CUBICSPLINE", "GAUSS", "LANCZOS", "MODE", "NEAREST",
2436
 * or "NONE" controlling the downsampling method applied.
2437
 * @param nOverviews number of overviews to build, or 0 to clean overviews.
2438
 * @param panOverviewList the list of overview decimation factors (positive
2439
 *                        integers, normally larger or equal to 2) to build, or
2440
 *                        NULL if nOverviews == 0.
2441
 * @param nListBands number of bands to build overviews for in panBandList.
2442
 * Build for all bands if this is 0.
2443
 * @param panBandList list of band numbers.
2444
 * @param pfnProgress a function to call to report progress, or NULL.
2445
 * @param pProgressData application data to pass to the progress function.
2446
 * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
2447
 *                     key=value pairs, or NULL.
2448
 *                     Possible keys are the ones returned by
2449
 *                     GetDriver()->GetMetadataItem(GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST)
2450
 *
2451
 * @return CE_None on success or CE_Failure if the operation doesn't work.
2452
 *
2453
 * For example, to build overview level 2, 4 and 8 on all bands the following
2454
 * call could be made:
2455
 * \code{.cpp}
2456
 *   int       anOverviewList[3] = { 2, 4, 8 };
2457
 *
2458
 *   poDataset->BuildOverviews( "NEAREST", 3, anOverviewList, 0, nullptr,
2459
 *                              GDALDummyProgress, nullptr );
2460
 * \endcode
2461
 *
2462
 * @see GDALRegenerateOverviewsEx()
2463
 */
2464
2465
CPLErr GDALDataset::BuildOverviews(const char *pszResampling, int nOverviews,
2466
                                   const int *panOverviewList, int nListBands,
2467
                                   const int *panBandList,
2468
                                   GDALProgressFunc pfnProgress,
2469
                                   void *pProgressData,
2470
                                   CSLConstList papszOptions)
2471
0
{
2472
0
    int *panAllBandList = nullptr;
2473
2474
0
    CPLStringList aosOptions(papszOptions);
2475
0
    if (poDriver && !aosOptions.empty())
2476
0
    {
2477
0
        const char *pszOptionList =
2478
0
            poDriver->GetMetadataItem(GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST);
2479
0
        if (pszOptionList)
2480
0
        {
2481
            // For backwards compatibility
2482
0
            if (const char *opt = aosOptions.FetchNameValue("USE_RRD"))
2483
0
            {
2484
0
                if (strstr(pszOptionList, "<Value>RRD</Value>") &&
2485
0
                    aosOptions.FetchNameValue("LOCATION") == nullptr)
2486
0
                {
2487
0
                    if (CPLTestBool(opt))
2488
0
                        aosOptions.SetNameValue("LOCATION", "RRD");
2489
0
                    aosOptions.SetNameValue("USE_RRD", nullptr);
2490
0
                }
2491
0
            }
2492
0
            if (const char *opt =
2493
0
                    aosOptions.FetchNameValue("VRT_VIRTUAL_OVERVIEWS"))
2494
0
            {
2495
0
                if (strstr(pszOptionList, "VIRTUAL"))
2496
0
                {
2497
0
                    aosOptions.SetNameValue("VIRTUAL", opt);
2498
0
                    aosOptions.SetNameValue("VRT_VIRTUAL_OVERVIEWS", nullptr);
2499
0
                }
2500
0
            }
2501
2502
0
            for (const auto &[pszKey, pszValue] :
2503
0
                 cpl::IterateNameValue(papszOptions))
2504
0
            {
2505
0
                if (cpl::ends_with(std::string_view(pszKey), "_OVERVIEW"))
2506
0
                {
2507
0
                    aosOptions.SetNameValue(
2508
0
                        std::string(pszKey)
2509
0
                            .substr(0, strlen(pszKey) - strlen("_OVERVIEW"))
2510
0
                            .c_str(),
2511
0
                        pszValue);
2512
0
                    aosOptions.SetNameValue(pszKey, nullptr);
2513
0
                }
2514
0
            }
2515
2516
0
            CPLString osDriver;
2517
0
            osDriver.Printf("driver %s", poDriver->GetDescription());
2518
0
            GDALValidateOptions(pszOptionList, aosOptions.List(),
2519
0
                                "overview creation option", osDriver);
2520
0
        }
2521
0
    }
2522
2523
0
    if (nListBands == 0)
2524
0
    {
2525
0
        nListBands = GetRasterCount();
2526
0
        panAllBandList =
2527
0
            static_cast<int *>(CPLMalloc(sizeof(int) * nListBands));
2528
0
        for (int i = 0; i < nListBands; ++i)
2529
0
            panAllBandList[i] = i + 1;
2530
2531
0
        panBandList = panAllBandList;
2532
0
    }
2533
2534
0
    if (pfnProgress == nullptr)
2535
0
        pfnProgress = GDALDummyProgress;
2536
2537
0
    for (int i = 0; i < nOverviews; ++i)
2538
0
    {
2539
0
        if (panOverviewList[i] <= 0)
2540
0
        {
2541
0
            CPLError(CE_Failure, CPLE_IllegalArg,
2542
0
                     "panOverviewList[%d] = %d is invalid. It must be a "
2543
0
                     "positive value",
2544
0
                     i, panOverviewList[i]);
2545
0
            CPLFree(panAllBandList);
2546
0
            return CE_Failure;
2547
0
        }
2548
0
    }
2549
2550
0
    const CPLErr eErr = IBuildOverviews(
2551
0
        pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
2552
0
        pfnProgress, pProgressData, aosOptions.List());
2553
2554
0
    if (panAllBandList != nullptr)
2555
0
        CPLFree(panAllBandList);
2556
2557
0
    return eErr;
2558
0
}
2559
2560
/************************************************************************/
2561
/*                         GDALBuildOverviews()                         */
2562
/************************************************************************/
2563
2564
/**
2565
 * \brief Build raster overview(s)
2566
 *
2567
 * @see GDALDataset::BuildOverviews() and GDALBuildOverviews()
2568
 */
2569
2570
CPLErr CPL_STDCALL GDALBuildOverviews(GDALDatasetH hDataset,
2571
                                      const char *pszResampling, int nOverviews,
2572
                                      const int *panOverviewList,
2573
                                      int nListBands, const int *panBandList,
2574
                                      GDALProgressFunc pfnProgress,
2575
                                      void *pProgressData)
2576
2577
0
{
2578
0
    VALIDATE_POINTER1(hDataset, "GDALBuildOverviews", CE_Failure);
2579
2580
0
    return GDALDataset::FromHandle(hDataset)->BuildOverviews(
2581
0
        pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
2582
0
        pfnProgress, pProgressData, nullptr);
2583
0
}
2584
2585
/************************************************************************/
2586
/*                         GDALBuildOverviews()                         */
2587
/************************************************************************/
2588
2589
/**
2590
 * \brief Build raster overview(s)
2591
 *
2592
 * @see GDALDataset::BuildOverviews()
2593
 * @since GDAL 3.6
2594
 */
2595
2596
CPLErr CPL_STDCALL
2597
GDALBuildOverviewsEx(GDALDatasetH hDataset, const char *pszResampling,
2598
                     int nOverviews, const int *panOverviewList, int nListBands,
2599
                     const int *panBandList, GDALProgressFunc pfnProgress,
2600
                     void *pProgressData, CSLConstList papszOptions)
2601
2602
0
{
2603
0
    VALIDATE_POINTER1(hDataset, "GDALBuildOverviews", CE_Failure);
2604
2605
0
    return GDALDataset::FromHandle(hDataset)->BuildOverviews(
2606
0
        pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
2607
0
        pfnProgress, pProgressData, papszOptions);
2608
0
}
2609
2610
/************************************************************************/
2611
/*                          IBuildOverviews()                           */
2612
/*                                                                      */
2613
/*      Default implementation.                                         */
2614
/************************************************************************/
2615
2616
//! @cond Doxygen_Suppress
2617
CPLErr GDALDataset::IBuildOverviews(const char *pszResampling, int nOverviews,
2618
                                    const int *panOverviewList, int nListBands,
2619
                                    const int *panBandList,
2620
                                    GDALProgressFunc pfnProgress,
2621
                                    void *pProgressData,
2622
                                    CSLConstList papszOptions)
2623
2624
0
{
2625
0
    if (oOvManager.IsInitialized())
2626
0
        return oOvManager.BuildOverviews(
2627
0
            nullptr, pszResampling, nOverviews, panOverviewList, nListBands,
2628
0
            panBandList, pfnProgress, pProgressData, papszOptions);
2629
0
    else
2630
0
    {
2631
0
        ReportError(CE_Failure, CPLE_NotSupported,
2632
0
                    "BuildOverviews() not supported for this dataset.");
2633
2634
0
        return CE_Failure;
2635
0
    }
2636
0
}
2637
2638
//! @endcond
2639
2640
/************************************************************************/
2641
/*                            AddOverviews()                            */
2642
/*                                                                      */
2643
/*      Default implementation.                                         */
2644
/************************************************************************/
2645
2646
/**
2647
 * \brief Add overview from existing dataset(s)
2648
 *
2649
 * This function creates new overview levels or refresh existing one from
2650
 * the list of provided overview datasets.
2651
 * Source overviews may come from any GDAL supported format, provided they
2652
 * have the same number of bands and geospatial extent than the target
2653
 * dataset.
2654
 *
2655
 * If the operation is not supported for the indicated dataset, then
2656
 * CE_Failure is returned, and CPLGetLastErrorNo() will return
2657
 * CPLE_NotSupported.
2658
 *
2659
 * At time of writing, this method is only implemented for internal overviews
2660
 * of GeoTIFF datasets and external overviews in GeoTIFF format.
2661
 *
2662
 * @param apoSrcOvrDS Vector of source overviews.
2663
 * @param pfnProgress a function to call to report progress, or NULL.
2664
 * @param pProgressData application data to pass to the progress function.
2665
 * @param papszOptions NULL terminated list of options as
2666
 *                     key=value pairs, or NULL. Possible keys are the
2667
 *                     ones returned by
2668
 *                     GetDriver()->GetMetadataItem(GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST)
2669
 *
2670
 * @return CE_None on success or CE_Failure if the operation doesn't work.
2671
 * @since 3.12
2672
 */
2673
CPLErr GDALDataset::AddOverviews(const std::vector<GDALDataset *> &apoSrcOvrDS,
2674
                                 GDALProgressFunc pfnProgress,
2675
                                 void *pProgressData, CSLConstList papszOptions)
2676
0
{
2677
0
    if (oOvManager.IsInitialized())
2678
0
    {
2679
0
        return oOvManager.AddOverviews(nullptr, apoSrcOvrDS, pfnProgress,
2680
0
                                       pProgressData, papszOptions);
2681
0
    }
2682
0
    else
2683
0
    {
2684
0
        ReportError(CE_Failure, CPLE_NotSupported,
2685
0
                    "AddOverviews() not supported for this dataset.");
2686
0
        return CE_Failure;
2687
0
    }
2688
0
}
2689
2690
/************************************************************************/
2691
/*                             IRasterIO()                              */
2692
/*                                                                      */
2693
/*      The default implementation of IRasterIO() is, in the general    */
2694
/*      case to pass the request off to each band objects rasterio      */
2695
/*      methods with appropriate arguments. In some cases, it might     */
2696
/*      choose instead the BlockBasedRasterIO() implementation.         */
2697
/************************************************************************/
2698
2699
//! @cond Doxygen_Suppress
2700
CPLErr GDALDataset::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
2701
                              int nXSize, int nYSize, void *pData,
2702
                              int nBufXSize, int nBufYSize,
2703
                              GDALDataType eBufType, int nBandCount,
2704
                              BANDMAP_TYPE panBandMap, GSpacing nPixelSpace,
2705
                              GSpacing nLineSpace, GSpacing nBandSpace,
2706
                              GDALRasterIOExtraArg *psExtraArg)
2707
2708
0
{
2709
0
    const char *pszInterleave = nullptr;
2710
2711
0
    CPLAssert(nullptr != pData);
2712
2713
0
    const bool bHasSubpixelShift =
2714
0
        psExtraArg->bFloatingPointWindowValidity &&
2715
0
        psExtraArg->eResampleAlg != GRIORA_NearestNeighbour &&
2716
0
        (nXOff != psExtraArg->dfXOff || nYOff != psExtraArg->dfYOff);
2717
2718
0
    if (!bHasSubpixelShift && nXSize == nBufXSize && nYSize == nBufYSize &&
2719
0
        nBandCount > 1 &&
2720
0
        (pszInterleave = GetMetadataItem("INTERLEAVE", "IMAGE_STRUCTURE")) !=
2721
0
            nullptr &&
2722
0
        EQUAL(pszInterleave, "PIXEL"))
2723
0
    {
2724
0
        return BlockBasedRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
2725
0
                                  nBufXSize, nBufYSize, eBufType, nBandCount,
2726
0
                                  panBandMap, nPixelSpace, nLineSpace,
2727
0
                                  nBandSpace, psExtraArg);
2728
0
    }
2729
2730
0
    if (eRWFlag == GF_Read &&
2731
0
        (psExtraArg->eResampleAlg == GRIORA_Cubic ||
2732
0
         psExtraArg->eResampleAlg == GRIORA_CubicSpline ||
2733
0
         psExtraArg->eResampleAlg == GRIORA_Bilinear ||
2734
0
         psExtraArg->eResampleAlg == GRIORA_Lanczos) &&
2735
0
        !(nXSize == nBufXSize && nYSize == nBufYSize) && nBandCount > 1)
2736
0
    {
2737
0
        if (nBufXSize < nXSize && nBufYSize < nYSize && AreOverviewsEnabled())
2738
0
        {
2739
0
            int bTried = FALSE;
2740
0
            const CPLErr eErr = TryOverviewRasterIO(
2741
0
                eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
2742
0
                nBufYSize, eBufType, nBandCount, panBandMap, nPixelSpace,
2743
0
                nLineSpace, nBandSpace, psExtraArg, &bTried);
2744
0
            if (bTried)
2745
0
                return eErr;
2746
0
        }
2747
2748
0
        GDALDataType eFirstBandDT = GDT_Unknown;
2749
0
        int nFirstMaskFlags = 0;
2750
0
        GDALRasterBand *poFirstMaskBand = nullptr;
2751
0
        int nOKBands = 0;
2752
2753
        // Check if bands share the same mask band
2754
0
        for (int i = 0; i < nBandCount; ++i)
2755
0
        {
2756
0
            GDALRasterBand *poBand = GetRasterBand(panBandMap[i]);
2757
0
            if ((nBufXSize < nXSize || nBufYSize < nYSize) &&
2758
0
                poBand->GetOverviewCount())
2759
0
            {
2760
                // Could be improved to select the appropriate overview.
2761
0
                break;
2762
0
            }
2763
0
            if (poBand->GetColorTable() != nullptr)
2764
0
            {
2765
0
                break;
2766
0
            }
2767
0
            const GDALDataType eDT = poBand->GetRasterDataType();
2768
0
            if (GDALDataTypeIsComplex(eDT))
2769
0
            {
2770
0
                break;
2771
0
            }
2772
0
            if (i == 0)
2773
0
            {
2774
0
                eFirstBandDT = eDT;
2775
0
                nFirstMaskFlags = poBand->GetMaskFlags();
2776
0
                if (nFirstMaskFlags == GMF_NODATA)
2777
0
                {
2778
                    // The dataset-level resampling code is not ready for nodata
2779
                    // Fallback to band-level resampling
2780
0
                    break;
2781
0
                }
2782
0
                poFirstMaskBand = poBand->GetMaskBand();
2783
0
            }
2784
0
            else
2785
0
            {
2786
0
                if (eDT != eFirstBandDT)
2787
0
                {
2788
0
                    break;
2789
0
                }
2790
0
                int nMaskFlags = poBand->GetMaskFlags();
2791
0
                if (nMaskFlags == GMF_NODATA)
2792
0
                {
2793
                    // The dataset-level resampling code is not ready for nodata
2794
                    // Fallback to band-level resampling
2795
0
                    break;
2796
0
                }
2797
0
                GDALRasterBand *poMaskBand = poBand->GetMaskBand();
2798
0
                if (nFirstMaskFlags == GMF_ALL_VALID &&
2799
0
                    nMaskFlags == GMF_ALL_VALID)
2800
0
                {
2801
                    // Ok.
2802
0
                }
2803
0
                else if (poFirstMaskBand == poMaskBand)
2804
0
                {
2805
                    // Ok.
2806
0
                }
2807
0
                else
2808
0
                {
2809
0
                    break;
2810
0
                }
2811
0
            }
2812
2813
0
            ++nOKBands;
2814
0
        }
2815
2816
0
        GDALProgressFunc pfnProgressGlobal = psExtraArg->pfnProgress;
2817
0
        void *pProgressDataGlobal = psExtraArg->pProgressData;
2818
2819
0
        CPLErr eErr = CE_None;
2820
0
        if (nOKBands > 0)
2821
0
        {
2822
0
            if (nOKBands < nBandCount)
2823
0
            {
2824
0
                psExtraArg->pfnProgress = GDALScaledProgress;
2825
0
                psExtraArg->pProgressData = GDALCreateScaledProgress(
2826
0
                    0.0, static_cast<double>(nOKBands) / nBandCount,
2827
0
                    pfnProgressGlobal, pProgressDataGlobal);
2828
0
                if (psExtraArg->pProgressData == nullptr)
2829
0
                    psExtraArg->pfnProgress = nullptr;
2830
0
            }
2831
2832
0
            eErr = RasterIOResampled(eRWFlag, nXOff, nYOff, nXSize, nYSize,
2833
0
                                     pData, nBufXSize, nBufYSize, eBufType,
2834
0
                                     nOKBands, panBandMap, nPixelSpace,
2835
0
                                     nLineSpace, nBandSpace, psExtraArg);
2836
2837
0
            if (nOKBands < nBandCount)
2838
0
            {
2839
0
                GDALDestroyScaledProgress(psExtraArg->pProgressData);
2840
0
            }
2841
0
        }
2842
0
        if (eErr == CE_None && nOKBands < nBandCount)
2843
0
        {
2844
0
            if (nOKBands > 0)
2845
0
            {
2846
0
                psExtraArg->pfnProgress = GDALScaledProgress;
2847
0
                psExtraArg->pProgressData = GDALCreateScaledProgress(
2848
0
                    static_cast<double>(nOKBands) / nBandCount, 1.0,
2849
0
                    pfnProgressGlobal, pProgressDataGlobal);
2850
0
                if (psExtraArg->pProgressData == nullptr)
2851
0
                    psExtraArg->pfnProgress = nullptr;
2852
0
            }
2853
0
            eErr = BandBasedRasterIO(
2854
0
                eRWFlag, nXOff, nYOff, nXSize, nYSize,
2855
0
                static_cast<GByte *>(pData) + nBandSpace * nOKBands, nBufXSize,
2856
0
                nBufYSize, eBufType, nBandCount - nOKBands,
2857
0
                panBandMap + nOKBands, nPixelSpace, nLineSpace, nBandSpace,
2858
0
                psExtraArg);
2859
0
            if (nOKBands > 0)
2860
0
            {
2861
0
                GDALDestroyScaledProgress(psExtraArg->pProgressData);
2862
0
            }
2863
0
        }
2864
2865
0
        psExtraArg->pfnProgress = pfnProgressGlobal;
2866
0
        psExtraArg->pProgressData = pProgressDataGlobal;
2867
2868
0
        return eErr;
2869
0
    }
2870
2871
0
    return BandBasedRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
2872
0
                             nBufXSize, nBufYSize, eBufType, nBandCount,
2873
0
                             panBandMap, nPixelSpace, nLineSpace, nBandSpace,
2874
0
                             psExtraArg);
2875
0
}
2876
2877
//! @endcond
2878
2879
/************************************************************************/
2880
/*                         BandBasedRasterIO()                          */
2881
/*                                                                      */
2882
/*      Pass the request off to each band objects rasterio methods with */
2883
/*      appropriate arguments.                                          */
2884
/************************************************************************/
2885
2886
//! @cond Doxygen_Suppress
2887
CPLErr GDALDataset::BandBasedRasterIO(
2888
    GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
2889
    void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
2890
    int nBandCount, const int *panBandMap, GSpacing nPixelSpace,
2891
    GSpacing nLineSpace, GSpacing nBandSpace, GDALRasterIOExtraArg *psExtraArg)
2892
2893
0
{
2894
0
    int iBandIndex;
2895
0
    CPLErr eErr = CE_None;
2896
2897
0
    GDALProgressFunc pfnProgressGlobal = psExtraArg->pfnProgress;
2898
0
    void *pProgressDataGlobal = psExtraArg->pProgressData;
2899
2900
0
    for (iBandIndex = 0; iBandIndex < nBandCount && eErr == CE_None;
2901
0
         ++iBandIndex)
2902
0
    {
2903
0
        GDALRasterBand *poBand = GetRasterBand(panBandMap[iBandIndex]);
2904
2905
0
        if (poBand == nullptr)
2906
0
        {
2907
0
            eErr = CE_Failure;
2908
0
            break;
2909
0
        }
2910
2911
0
        GByte *pabyBandData =
2912
0
            static_cast<GByte *>(pData) + iBandIndex * nBandSpace;
2913
2914
0
        if (nBandCount > 1)
2915
0
        {
2916
0
            psExtraArg->pfnProgress = GDALScaledProgress;
2917
0
            psExtraArg->pProgressData = GDALCreateScaledProgress(
2918
0
                1.0 * iBandIndex / nBandCount,
2919
0
                1.0 * (iBandIndex + 1) / nBandCount, pfnProgressGlobal,
2920
0
                pProgressDataGlobal);
2921
0
            if (psExtraArg->pProgressData == nullptr)
2922
0
                psExtraArg->pfnProgress = nullptr;
2923
0
        }
2924
2925
0
        eErr = poBand->IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
2926
0
                                 pabyBandData, nBufXSize, nBufYSize, eBufType,
2927
0
                                 nPixelSpace, nLineSpace, psExtraArg);
2928
2929
0
        if (nBandCount > 1)
2930
0
            GDALDestroyScaledProgress(psExtraArg->pProgressData);
2931
0
    }
2932
2933
0
    psExtraArg->pfnProgress = pfnProgressGlobal;
2934
0
    psExtraArg->pProgressData = pProgressDataGlobal;
2935
2936
0
    return eErr;
2937
0
}
2938
2939
//! @endcond
2940
2941
/************************************************************************/
2942
/*               ValidateRasterIOOrAdviseReadParameters()               */
2943
/************************************************************************/
2944
2945
//! @cond Doxygen_Suppress
2946
CPLErr GDALDataset::ValidateRasterIOOrAdviseReadParameters(
2947
    const char *pszCallingFunc, int *pbStopProcessingOnCENone, int nXOff,
2948
    int nYOff, int nXSize, int nYSize, int nBufXSize, int nBufYSize,
2949
    int nBandCount, const int *panBandMap)
2950
0
{
2951
2952
    /* -------------------------------------------------------------------- */
2953
    /*      Some size values are "noop".  Lets just return to avoid         */
2954
    /*      stressing lower level functions.                                */
2955
    /* -------------------------------------------------------------------- */
2956
0
    if (nXSize < 1 || nYSize < 1 || nBufXSize < 1 || nBufYSize < 1)
2957
0
    {
2958
0
        CPLDebug("GDAL",
2959
0
                 "%s skipped for odd window or buffer size.\n"
2960
0
                 "  Window = (%d,%d)x%dx%d\n"
2961
0
                 "  Buffer = %dx%d",
2962
0
                 pszCallingFunc, nXOff, nYOff, nXSize, nYSize, nBufXSize,
2963
0
                 nBufYSize);
2964
2965
0
        *pbStopProcessingOnCENone = TRUE;
2966
0
        return CE_None;
2967
0
    }
2968
2969
0
    CPLErr eErr = CE_None;
2970
0
    *pbStopProcessingOnCENone = FALSE;
2971
2972
0
    if (nXOff < 0 || nXSize > nRasterXSize - nXOff || nYOff < 0 ||
2973
0
        nYSize > nRasterYSize - nYOff)
2974
0
    {
2975
0
        ReportError(CE_Failure, CPLE_IllegalArg,
2976
0
                    "Access window out of range in %s.  Requested "
2977
0
                    "(%d,%d) of size %dx%d on raster of %dx%d.",
2978
0
                    pszCallingFunc, nXOff, nYOff, nXSize, nYSize, nRasterXSize,
2979
0
                    nRasterYSize);
2980
0
        eErr = CE_Failure;
2981
0
    }
2982
2983
0
    if (panBandMap == nullptr && nBandCount > GetRasterCount())
2984
0
    {
2985
0
        ReportError(CE_Failure, CPLE_IllegalArg,
2986
0
                    "%s: nBandCount cannot be greater than %d", pszCallingFunc,
2987
0
                    GetRasterCount());
2988
0
        eErr = CE_Failure;
2989
0
    }
2990
2991
0
    for (int i = 0; i < nBandCount && eErr == CE_None; ++i)
2992
0
    {
2993
0
        int iBand = (panBandMap != nullptr) ? panBandMap[i] : i + 1;
2994
0
        if (iBand < 1 || iBand > GetRasterCount())
2995
0
        {
2996
0
            ReportError(
2997
0
                CE_Failure, CPLE_IllegalArg,
2998
0
                "%s: panBandMap[%d] = %d, this band does not exist on dataset.",
2999
0
                pszCallingFunc, i, iBand);
3000
0
            eErr = CE_Failure;
3001
0
        }
3002
3003
0
        if (eErr == CE_None && GetRasterBand(iBand) == nullptr)
3004
0
        {
3005
0
            ReportError(
3006
0
                CE_Failure, CPLE_IllegalArg,
3007
0
                "%s: panBandMap[%d]=%d, this band should exist but is NULL!",
3008
0
                pszCallingFunc, i, iBand);
3009
0
            eErr = CE_Failure;
3010
0
        }
3011
0
    }
3012
3013
0
    return eErr;
3014
0
}
3015
3016
//! @endcond
3017
3018
/************************************************************************/
3019
/*                              RasterIO()                              */
3020
/************************************************************************/
3021
3022
/**
3023
 * \brief Read/write a region of image data from multiple bands.
3024
 *
3025
 * This method allows reading a region of one or more GDALRasterBands from
3026
 * this dataset into a buffer,  or writing data from a buffer into a region
3027
 * of the GDALRasterBands.  It automatically takes care of data type
3028
 * translation if the data type (eBufType) of the buffer is different than
3029
 * that of the GDALRasterBand.
3030
 * The method also takes care of image decimation / replication if the
3031
 * buffer size (nBufXSize x nBufYSize) is different than the size of the
3032
 * region being accessed (nXSize x nYSize).
3033
 *
3034
 * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
3035
 * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
3036
 * nXOff + nXSize <= GetRasterXSize() and nYOff + nYSize <= GetRasterYSize().
3037
 * If reads larger than the raster space are wished, GDALTranslate() might be used.
3038
 * Or use nLineSpace and a possibly shifted pData value.
3039
 *
3040
 * The nPixelSpace, nLineSpace and nBandSpace parameters allow reading into or
3041
 * writing from various organization of buffers.
3042
 *
3043
 * Some formats may efficiently implement decimation into a buffer by
3044
 * reading from lower resolution overview images. The logic of the default
3045
 * implementation in the base class GDALRasterBand is the following one. It
3046
 * computes a target_downscaling_factor from the window of interest and buffer
3047
 * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
3048
 * It then walks through overviews and will select the first one whose
3049
 * downscaling factor is greater than target_downscaling_factor / 1.2.
3050
 *
3051
 * Let's assume we have overviews at downscaling factors 2, 4 and 8.
3052
 * The relationship between target_downscaling_factor and the select overview
3053
 * level is the following one:
3054
 *
3055
 * target_downscaling_factor  | selected_overview
3056
 * -------------------------  | -----------------
3057
 * ]0,       2 / 1.2]         | full resolution band
3058
 * ]2 / 1.2, 4 / 1.2]         | 2x downsampled band
3059
 * ]4 / 1.2, 8 / 1.2]         | 4x downsampled band
3060
 * ]8 / 1.2, infinity[        | 8x downsampled band
3061
 *
3062
 * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
3063
 * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
3064
 * option. Also note that starting with GDAL 3.9, when the resampling algorithm
3065
 * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
3066
 * this oversampling threshold defaults to 1. Consequently if there are overviews
3067
 * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
3068
 * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
3069
 *
3070
 * For highest performance full resolution data access, read and write
3071
 * on "block boundaries" as returned by GetBlockSize(), or use the
3072
 * ReadBlock() and WriteBlock() methods.
3073
 *
3074
 * This method is the same as the C GDALDatasetRasterIO() or
3075
 * GDALDatasetRasterIOEx() functions.
3076
 *
3077
 * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
3078
 * write a region of data.
3079
 *
3080
 * @param nXOff The pixel offset to the top left corner of the region
3081
 * of the band to be accessed.  This would be zero to start from the left side.
3082
 *
3083
 * @param nYOff The line offset to the top left corner of the region
3084
 * of the band to be accessed.  This would be zero to start from the top.
3085
 *
3086
 * @param nXSize The width of the region of the band to be accessed in pixels.
3087
 *
3088
 * @param nYSize The height of the region of the band to be accessed in lines.
3089
 *
3090
 * @param pData The buffer into which the data should be read, or from which
3091
 * it should be written.  This buffer must contain at least
3092
 * nBufXSize * nBufYSize * nBandCount words of type eBufType.  It is organized
3093
 * in left to right,top to bottom pixel order.  Spacing is controlled by the
3094
 * nPixelSpace, and nLineSpace parameters.
3095
 * Note that even with eRWFlag==GF_Write, the content of the buffer might be
3096
 * temporarily modified during the execution of this method (and eventually
3097
 * restored back to its original content), so it is not safe to use a buffer
3098
 * stored in a read-only section of the calling program.
3099
 *
3100
 * @param nBufXSize the width of the buffer image into which the desired region
3101
 * is to be read, or from which it is to be written.
3102
 *
3103
 * @param nBufYSize the height of the buffer image into which the desired
3104
 * region is to be read, or from which it is to be written.
3105
 *
3106
 * @param eBufType the type of the pixel values in the pData data buffer. The
3107
 * pixel values will automatically be translated to/from the GDALRasterBand
3108
 * data type as needed. Most driver implementations will use GDALCopyWords64()
3109
 * to perform data type translation.
3110
 *
3111
 * @param nBandCount the number of bands being read or written.
3112
 *
3113
 * @param panBandMap the list of nBandCount band numbers being read/written.
3114
 * Note band numbers are 1 based. This may be NULL to select the first
3115
 * nBandCount bands. (Note: before GDAL 3.10, argument type was "int*", and
3116
 * not "const int*")
3117
 *
3118
 * @param nPixelSpace The byte offset from the start of one pixel value in
3119
 * pData to the start of the next pixel value within a scanline. If defaulted
3120
 * (0) the size of the datatype eBufType is used.
3121
 *
3122
 * @param nLineSpace The byte offset from the start of one scanline in
3123
 * pData to the start of the next. If defaulted (0) the size of the datatype
3124
 * eBufType * nBufXSize is used.
3125
 *
3126
 * @param nBandSpace the byte offset from the start of one bands data to the
3127
 * start of the next. If defaulted (0) the value will be
3128
 * nLineSpace * nBufYSize implying band sequential organization
3129
 * of the data buffer.
3130
 *
3131
 * @param psExtraArg pointer to a GDALRasterIOExtraArg
3132
 * structure with additional arguments to specify resampling and progress
3133
 * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
3134
 * configuration option can also be defined to override the default resampling
3135
 * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
3136
 *
3137
 * @return CE_Failure if the access fails, otherwise CE_None.
3138
 */
3139
3140
CPLErr GDALDataset::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
3141
                             int nXSize, int nYSize, void *pData, int nBufXSize,
3142
                             int nBufYSize, GDALDataType eBufType,
3143
                             int nBandCount, const int *panBandMap,
3144
                             GSpacing nPixelSpace, GSpacing nLineSpace,
3145
                             GSpacing nBandSpace,
3146
                             GDALRasterIOExtraArg *psExtraArg)
3147
3148
0
{
3149
0
    GDALRasterIOExtraArg sExtraArg;
3150
0
    if (psExtraArg == nullptr)
3151
0
    {
3152
0
        INIT_RASTERIO_EXTRA_ARG(sExtraArg);
3153
3154
        // 4 below inits are not strictly needed but make Coverity Scan
3155
        // happy
3156
0
        sExtraArg.dfXOff = nXOff;
3157
0
        sExtraArg.dfYOff = nYOff;
3158
0
        sExtraArg.dfXSize = nXSize;
3159
0
        sExtraArg.dfYSize = nYSize;
3160
3161
0
        psExtraArg = &sExtraArg;
3162
0
    }
3163
0
    else if (CPL_UNLIKELY(psExtraArg->nVersion >
3164
0
                          RASTERIO_EXTRA_ARG_CURRENT_VERSION))
3165
0
    {
3166
0
        ReportError(CE_Failure, CPLE_AppDefined,
3167
0
                    "Unhandled version of GDALRasterIOExtraArg");
3168
0
        return CE_Failure;
3169
0
    }
3170
3171
0
    GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
3172
0
                                       nBufYSize);
3173
3174
0
    if (CPL_UNLIKELY(nullptr == pData))
3175
0
    {
3176
0
        ReportError(CE_Failure, CPLE_AppDefined,
3177
0
                    "The buffer into which the data should be read is null");
3178
0
        return CE_Failure;
3179
0
    }
3180
3181
    /* -------------------------------------------------------------------- */
3182
    /*      Do some validation of parameters.                               */
3183
    /* -------------------------------------------------------------------- */
3184
3185
0
    if (CPL_UNLIKELY(eRWFlag != GF_Read && eRWFlag != GF_Write))
3186
0
    {
3187
0
        ReportError(
3188
0
            CE_Failure, CPLE_IllegalArg,
3189
0
            "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
3190
0
            eRWFlag);
3191
0
        return CE_Failure;
3192
0
    }
3193
3194
0
    if (eRWFlag == GF_Write)
3195
0
    {
3196
0
        if (CPL_UNLIKELY(eAccess != GA_Update))
3197
0
        {
3198
0
            ReportError(CE_Failure, CPLE_AppDefined,
3199
0
                        "Write operation not permitted on dataset opened "
3200
0
                        "in read-only mode");
3201
0
            return CE_Failure;
3202
0
        }
3203
0
    }
3204
3205
0
    int bStopProcessing = FALSE;
3206
0
    CPLErr eErr = ValidateRasterIOOrAdviseReadParameters(
3207
0
        "RasterIO()", &bStopProcessing, nXOff, nYOff, nXSize, nYSize, nBufXSize,
3208
0
        nBufYSize, nBandCount, panBandMap);
3209
0
    if (eErr != CE_None || bStopProcessing)
3210
0
        return eErr;
3211
0
    if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
3212
0
    {
3213
0
        ReportError(CE_Failure, CPLE_AppDefined,
3214
0
                    "Illegal GDT_Unknown/GDT_TypeCount argument");
3215
0
        return CE_Failure;
3216
0
    }
3217
3218
    /* -------------------------------------------------------------------- */
3219
    /*      If pixel and line spacing are defaulted assign reasonable      */
3220
    /*      value assuming a packed buffer.                                 */
3221
    /* -------------------------------------------------------------------- */
3222
0
    if (nPixelSpace == 0)
3223
0
        nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
3224
3225
0
    if (nLineSpace == 0)
3226
0
    {
3227
0
        nLineSpace = nPixelSpace * nBufXSize;
3228
0
    }
3229
3230
0
    if (nBandSpace == 0 && nBandCount > 1)
3231
0
    {
3232
0
        nBandSpace = nLineSpace * nBufYSize;
3233
0
    }
3234
3235
0
    if (panBandMap == nullptr)
3236
0
    {
3237
0
        if (!m_poPrivate)
3238
0
            return CE_Failure;
3239
0
        CPLAssert(static_cast<int>(m_poPrivate->m_anBandMap.size()) == nBands);
3240
0
        panBandMap = m_poPrivate->m_anBandMap.data();
3241
0
    }
3242
3243
0
    int bCallLeaveReadWrite = EnterReadWrite(eRWFlag);
3244
3245
    /* -------------------------------------------------------------------- */
3246
    /*      We are being forced to use cached IO instead of a driver        */
3247
    /*      specific implementation.                                        */
3248
    /* -------------------------------------------------------------------- */
3249
0
    if (bForceCachedIO)
3250
0
    {
3251
0
        eErr = BlockBasedRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3252
0
                                  nBufXSize, nBufYSize, eBufType, nBandCount,
3253
0
                                  panBandMap, nPixelSpace, nLineSpace,
3254
0
                                  nBandSpace, psExtraArg);
3255
0
    }
3256
3257
    /* -------------------------------------------------------------------- */
3258
    /*      Call the format specific function.                              */
3259
    /* -------------------------------------------------------------------- */
3260
0
    else
3261
0
    {
3262
0
        eErr = IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3263
0
                         nBufXSize, nBufYSize, eBufType, nBandCount,
3264
                         // TODO: remove this const_cast once IRasterIO()
3265
                         // takes a const int*
3266
0
                         const_cast<int *>(panBandMap), nPixelSpace, nLineSpace,
3267
0
                         nBandSpace, psExtraArg);
3268
0
    }
3269
3270
0
    if (bCallLeaveReadWrite)
3271
0
        LeaveReadWrite();
3272
3273
0
    return eErr;
3274
0
}
3275
3276
/************************************************************************/
3277
/*                        GDALDatasetRasterIO()                         */
3278
/************************************************************************/
3279
3280
/**
3281
 * \brief Read/write a region of image data from multiple bands.
3282
 *
3283
 * Use GDALDatasetRasterIOEx() if 64 bit spacings or extra arguments (resampling
3284
 * resolution, progress callback, etc. are needed)
3285
 *
3286
 * Note: before GDAL 3.10, panBandMap type was "int*", and not "const int*"
3287
 *
3288
 * @see GDALDataset::RasterIO()
3289
 */
3290
3291
CPLErr CPL_STDCALL GDALDatasetRasterIO(GDALDatasetH hDS, GDALRWFlag eRWFlag,
3292
                                       int nXOff, int nYOff, int nXSize,
3293
                                       int nYSize, void *pData, int nBufXSize,
3294
                                       int nBufYSize, GDALDataType eBufType,
3295
                                       int nBandCount, const int *panBandMap,
3296
                                       int nPixelSpace, int nLineSpace,
3297
                                       int nBandSpace)
3298
3299
0
{
3300
0
    VALIDATE_POINTER1(hDS, "GDALDatasetRasterIO", CE_Failure);
3301
3302
0
    GDALDataset *poDS = GDALDataset::FromHandle(hDS);
3303
3304
0
    return poDS->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3305
0
                          nBufXSize, nBufYSize, eBufType, nBandCount,
3306
0
                          panBandMap, nPixelSpace, nLineSpace, nBandSpace,
3307
0
                          nullptr);
3308
0
}
3309
3310
/************************************************************************/
3311
/*                       GDALDatasetRasterIOEx()                        */
3312
/************************************************************************/
3313
3314
/**
3315
 * \brief Read/write a region of image data from multiple bands.
3316
 *
3317
 * Note: before GDAL 3.10, panBandMap type was "int*", and not "const int*"
3318
 *
3319
 * @see GDALDataset::RasterIO()
3320
 */
3321
3322
CPLErr CPL_STDCALL GDALDatasetRasterIOEx(
3323
    GDALDatasetH hDS, GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize,
3324
    int nYSize, void *pData, int nBufXSize, int nBufYSize,
3325
    GDALDataType eBufType, int nBandCount, const int *panBandMap,
3326
    GSpacing nPixelSpace, GSpacing nLineSpace, GSpacing nBandSpace,
3327
    GDALRasterIOExtraArg *psExtraArg)
3328
3329
0
{
3330
0
    VALIDATE_POINTER1(hDS, "GDALDatasetRasterIOEx", CE_Failure);
3331
3332
0
    GDALDataset *poDS = GDALDataset::FromHandle(hDS);
3333
3334
0
    return poDS->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
3335
0
                          nBufXSize, nBufYSize, eBufType, nBandCount,
3336
0
                          panBandMap, nPixelSpace, nLineSpace, nBandSpace,
3337
0
                          psExtraArg);
3338
0
}
3339
3340
/************************************************************************/
3341
/*                          GetOpenDatasets()                           */
3342
/************************************************************************/
3343
3344
/**
3345
 * \brief Fetch all open GDAL dataset handles.
3346
 *
3347
 * This method is the same as the C function GDALGetOpenDatasets().
3348
 *
3349
 * NOTE: This method is not thread safe.  The returned list may change
3350
 * at any time and it should not be freed.
3351
 *
3352
 * @param pnCount integer into which to place the count of dataset pointers
3353
 * being returned.
3354
 *
3355
 * @return a pointer to an array of dataset handles.
3356
 */
3357
3358
GDALDataset **GDALDataset::GetOpenDatasets(int *pnCount)
3359
3360
0
{
3361
0
    CPLMutexHolderD(&hDLMutex);
3362
3363
0
    if (poAllDatasetMap == nullptr)
3364
0
    {
3365
0
        *pnCount = 0;
3366
0
        return nullptr;
3367
0
    }
3368
3369
0
    *pnCount = static_cast<int>(poAllDatasetMap->size());
3370
0
    ppDatasets = static_cast<GDALDataset **>(
3371
0
        CPLRealloc(ppDatasets, (*pnCount) * sizeof(GDALDataset *)));
3372
0
    std::map<GDALDataset *, GIntBig>::iterator oIter = poAllDatasetMap->begin();
3373
0
    for (int i = 0; oIter != poAllDatasetMap->end(); ++oIter, ++i)
3374
0
        ppDatasets[i] = oIter->first;
3375
0
    return ppDatasets;
3376
0
}
3377
3378
/************************************************************************/
3379
/*                        GDALGetOpenDatasets()                         */
3380
/************************************************************************/
3381
3382
/**
3383
 * \brief Fetch all open GDAL dataset handles.
3384
 *
3385
 * @see GDALDataset::GetOpenDatasets()
3386
 */
3387
3388
void CPL_STDCALL GDALGetOpenDatasets(GDALDatasetH **ppahDSList, int *pnCount)
3389
3390
0
{
3391
0
    VALIDATE_POINTER0(ppahDSList, "GDALGetOpenDatasets");
3392
0
    VALIDATE_POINTER0(pnCount, "GDALGetOpenDatasets");
3393
3394
0
    *ppahDSList =
3395
0
        reinterpret_cast<GDALDatasetH *>(GDALDataset::GetOpenDatasets(pnCount));
3396
0
}
3397
3398
/************************************************************************/
3399
/*                     GDALCleanOpenDatasetsList()                      */
3400
/************************************************************************/
3401
3402
// Useful when called from the child of a fork(), to avoid closing
3403
// the datasets of the parent at the child termination.
3404
void GDALNullifyOpenDatasetsList()
3405
0
{
3406
0
    poAllDatasetMap = nullptr;
3407
0
    phSharedDatasetSet = nullptr;
3408
0
    ppDatasets = nullptr;
3409
0
    hDLMutex = nullptr;
3410
0
}
3411
3412
/************************************************************************/
3413
/*                           GDALGetAccess()                            */
3414
/************************************************************************/
3415
3416
/**
3417
 * \brief Return access flag
3418
 *
3419
 * @see GDALDataset::GetAccess()
3420
 */
3421
3422
int CPL_STDCALL GDALGetAccess(GDALDatasetH hDS)
3423
0
{
3424
0
    VALIDATE_POINTER1(hDS, "GDALGetAccess", 0);
3425
3426
0
    return GDALDataset::FromHandle(hDS)->GetAccess();
3427
0
}
3428
3429
/************************************************************************/
3430
/*                             AdviseRead()                             */
3431
/************************************************************************/
3432
3433
/**
3434
 * \brief Advise driver of upcoming read requests.
3435
 *
3436
 * Some GDAL drivers operate more efficiently if they know in advance what
3437
 * set of upcoming read requests will be made.  The AdviseRead() method allows
3438
 * an application to notify the driver of the region and bands of interest,
3439
 * and at what resolution the region will be read.
3440
 *
3441
 * Many drivers just ignore the AdviseRead() call, but it can dramatically
3442
 * accelerate access via some drivers.
3443
 *
3444
 * Depending on call paths, drivers might receive several calls to
3445
 * AdviseRead() with the same parameters.
3446
 *
3447
 * @param nXOff The pixel offset to the top left corner of the region
3448
 * of the band to be accessed.  This would be zero to start from the left side.
3449
 *
3450
 * @param nYOff The line offset to the top left corner of the region
3451
 * of the band to be accessed.  This would be zero to start from the top.
3452
 *
3453
 * @param nXSize The width of the region of the band to be accessed in pixels.
3454
 *
3455
 * @param nYSize The height of the region of the band to be accessed in lines.
3456
 *
3457
 * @param nBufXSize the width of the buffer image into which the desired region
3458
 * is to be read, or from which it is to be written.
3459
 *
3460
 * @param nBufYSize the height of the buffer image into which the desired
3461
 * region is to be read, or from which it is to be written.
3462
 *
3463
 * @param eBufType the type of the pixel values in the pData data buffer.  The
3464
 * pixel values will automatically be translated to/from the GDALRasterBand
3465
 * data type as needed.
3466
 *
3467
 * @param nBandCount the number of bands being read or written.
3468
 *
3469
 * @param panBandMap the list of nBandCount band numbers being read/written.
3470
 * Note band numbers are 1 based.   This may be NULL to select the first
3471
 * nBandCount bands.
3472
 *
3473
 * @param papszOptions a list of name=value strings with special control
3474
 * options.  Normally this is NULL.
3475
 *
3476
 * @return CE_Failure if the request is invalid and CE_None if it works or
3477
 * is ignored.
3478
 */
3479
3480
CPLErr GDALDataset::AdviseRead(int nXOff, int nYOff, int nXSize, int nYSize,
3481
                               int nBufXSize, int nBufYSize,
3482
                               GDALDataType eBufType, int nBandCount,
3483
                               int *panBandMap, CSLConstList papszOptions)
3484
3485
0
{
3486
    /* -------------------------------------------------------------------- */
3487
    /*      Do some validation of parameters.                               */
3488
    /* -------------------------------------------------------------------- */
3489
0
    int bStopProcessing = FALSE;
3490
0
    CPLErr eErr = ValidateRasterIOOrAdviseReadParameters(
3491
0
        "AdviseRead()", &bStopProcessing, nXOff, nYOff, nXSize, nYSize,
3492
0
        nBufXSize, nBufYSize, nBandCount, panBandMap);
3493
0
    if (eErr != CE_None || bStopProcessing)
3494
0
        return eErr;
3495
3496
0
    for (int iBand = 0; iBand < nBandCount; ++iBand)
3497
0
    {
3498
0
        GDALRasterBand *poBand = nullptr;
3499
3500
0
        if (panBandMap == nullptr)
3501
0
            poBand = GetRasterBand(iBand + 1);
3502
0
        else
3503
0
            poBand = GetRasterBand(panBandMap[iBand]);
3504
3505
0
        if (poBand == nullptr)
3506
0
            return CE_Failure;
3507
3508
0
        eErr = poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
3509
0
                                  nBufYSize, eBufType, papszOptions);
3510
3511
0
        if (eErr != CE_None)
3512
0
            return eErr;
3513
0
    }
3514
3515
0
    return CE_None;
3516
0
}
3517
3518
/************************************************************************/
3519
/*                       GDALDatasetAdviseRead()                        */
3520
/************************************************************************/
3521
3522
/**
3523
 * \brief Advise driver of upcoming read requests.
3524
 *
3525
 * @see GDALDataset::AdviseRead()
3526
 */
3527
CPLErr CPL_STDCALL GDALDatasetAdviseRead(GDALDatasetH hDS, int nXOff, int nYOff,
3528
                                         int nXSize, int nYSize, int nBufXSize,
3529
                                         int nBufYSize, GDALDataType eDT,
3530
                                         int nBandCount, int *panBandMap,
3531
                                         CSLConstList papszOptions)
3532
3533
0
{
3534
0
    VALIDATE_POINTER1(hDS, "GDALDatasetAdviseRead", CE_Failure);
3535
3536
0
    return GDALDataset::FromHandle(hDS)->AdviseRead(
3537
0
        nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, eDT, nBandCount,
3538
0
        panBandMap, const_cast<char **>(papszOptions));
3539
0
}
3540
3541
/************************************************************************/
3542
/*                       GDALAntiRecursionStruct                        */
3543
/************************************************************************/
3544
3545
// Prevent infinite recursion.
3546
struct GDALAntiRecursionStruct
3547
{
3548
    struct DatasetContext
3549
    {
3550
        std::string osFilename;
3551
        int nOpenFlags;
3552
        std::string osAllowedDrivers;
3553
3554
        DatasetContext(const std::string &osFilenameIn, int nOpenFlagsIn,
3555
                       const std::string &osAllowedDriversIn)
3556
0
            : osFilename(osFilenameIn), nOpenFlags(nOpenFlagsIn),
3557
0
              osAllowedDrivers(osAllowedDriversIn)
3558
0
        {
3559
0
        }
3560
    };
3561
3562
    struct DatasetContextCompare
3563
    {
3564
        bool operator()(const DatasetContext &lhs,
3565
                        const DatasetContext &rhs) const
3566
0
        {
3567
0
            return lhs.osFilename < rhs.osFilename ||
3568
0
                   (lhs.osFilename == rhs.osFilename &&
3569
0
                    (lhs.nOpenFlags < rhs.nOpenFlags ||
3570
0
                     (lhs.nOpenFlags == rhs.nOpenFlags &&
3571
0
                      lhs.osAllowedDrivers < rhs.osAllowedDrivers)));
3572
0
        }
3573
    };
3574
3575
    ~GDALAntiRecursionStruct()
3576
0
    {
3577
0
        CPLAssert(aosDatasetNamesWithFlags.empty());
3578
0
        CPLAssert(nRecLevel == 0);
3579
0
        CPLAssert(m_oMapDepth.empty());
3580
0
    }
3581
3582
    std::set<DatasetContext, DatasetContextCompare> aosDatasetNamesWithFlags{};
3583
    int nRecLevel = 0;
3584
    std::map<std::string, int> m_oMapDepth{};
3585
};
3586
3587
#ifdef _WIN32
3588
// Currently thread_local and C++ objects don't work well with DLL on Windows
3589
static void FreeAntiRecursionOpen(void *pData)
3590
{
3591
    delete static_cast<GDALAntiRecursionStruct *>(pData);
3592
}
3593
3594
static GDALAntiRecursionStruct &GetAntiRecursionOpen()
3595
{
3596
    static GDALAntiRecursionStruct dummy;
3597
    int bMemoryErrorOccurred = false;
3598
    void *pData =
3599
        CPLGetTLSEx(CTLS_GDALOPEN_ANTIRECURSION, &bMemoryErrorOccurred);
3600
    if (bMemoryErrorOccurred)
3601
    {
3602
        return dummy;
3603
    }
3604
    if (pData == nullptr)
3605
    {
3606
        auto pAntiRecursion = new GDALAntiRecursionStruct();
3607
        CPLSetTLSWithFreeFuncEx(CTLS_GDALOPEN_ANTIRECURSION, pAntiRecursion,
3608
                                FreeAntiRecursionOpen, &bMemoryErrorOccurred);
3609
        if (bMemoryErrorOccurred)
3610
        {
3611
            delete pAntiRecursion;
3612
            return dummy;
3613
        }
3614
        return *pAntiRecursion;
3615
    }
3616
    return *static_cast<GDALAntiRecursionStruct *>(pData);
3617
}
3618
#else
3619
static thread_local GDALAntiRecursionStruct g_tls_antiRecursion;
3620
3621
static GDALAntiRecursionStruct &GetAntiRecursionOpen()
3622
0
{
3623
0
    return g_tls_antiRecursion;
3624
0
}
3625
#endif
3626
3627
//! @cond Doxygen_Suppress
3628
GDALAntiRecursionGuard::GDALAntiRecursionGuard(const std::string &osIdentifier)
3629
0
    : m_psAntiRecursionStruct(&GetAntiRecursionOpen()),
3630
0
      m_osIdentifier(osIdentifier),
3631
0
      m_nDepth(++m_psAntiRecursionStruct->m_oMapDepth[m_osIdentifier])
3632
0
{
3633
0
    CPLAssert(!osIdentifier.empty());
3634
0
}
3635
3636
GDALAntiRecursionGuard::GDALAntiRecursionGuard(
3637
    const GDALAntiRecursionGuard &other, const std::string &osIdentifier)
3638
0
    : m_psAntiRecursionStruct(other.m_psAntiRecursionStruct),
3639
0
      m_osIdentifier(osIdentifier.empty()
3640
0
                         ? osIdentifier
3641
0
                         : other.m_osIdentifier + osIdentifier),
3642
0
      m_nDepth(m_osIdentifier.empty()
3643
0
                   ? 0
3644
0
                   : ++m_psAntiRecursionStruct->m_oMapDepth[m_osIdentifier])
3645
0
{
3646
0
}
3647
3648
GDALAntiRecursionGuard::~GDALAntiRecursionGuard()
3649
0
{
3650
0
    if (!m_osIdentifier.empty())
3651
0
    {
3652
0
        auto oIter = m_psAntiRecursionStruct->m_oMapDepth.find(m_osIdentifier);
3653
0
        CPLAssert(oIter != m_psAntiRecursionStruct->m_oMapDepth.end());
3654
0
        if (--(oIter->second) == 0)
3655
0
            m_psAntiRecursionStruct->m_oMapDepth.erase(oIter);
3656
0
    }
3657
0
}
3658
3659
//! @endcond
3660
3661
/************************************************************************/
3662
/*                            GetFileList()                             */
3663
/************************************************************************/
3664
3665
/**
3666
 * \brief Fetch files forming dataset.
3667
 *
3668
 * Returns a list of files believed to be part of this dataset.  If it returns
3669
 * an empty list of files it means there is believed to be no local file
3670
 * system files associated with the dataset (for instance a virtual dataset).
3671
 * The returned file list is owned by the caller and should be deallocated
3672
 * with CSLDestroy().
3673
 *
3674
 * The returned filenames will normally be relative or absolute paths
3675
 * depending on the path used to originally open the dataset.  The strings
3676
 * will be UTF-8 encoded.
3677
 *
3678
 * This method is the same as the C GDALGetFileList() function.
3679
 *
3680
 * @return NULL or a NULL terminated array of file names.
3681
 */
3682
3683
char **GDALDataset::GetFileList()
3684
3685
0
{
3686
0
    CPLString osMainFilename = GetDescription();
3687
0
    VSIStatBufL sStat;
3688
3689
0
    GDALAntiRecursionStruct &sAntiRecursion = GetAntiRecursionOpen();
3690
0
    GDALAntiRecursionStruct::DatasetContext datasetCtxt(osMainFilename, 0,
3691
0
                                                        std::string());
3692
0
    auto &aosDatasetList = sAntiRecursion.aosDatasetNamesWithFlags;
3693
0
    if (cpl::contains(aosDatasetList, datasetCtxt))
3694
0
        return nullptr;
3695
3696
    /* -------------------------------------------------------------------- */
3697
    /*      Is the main filename even a real filesystem object?             */
3698
    /* -------------------------------------------------------------------- */
3699
0
    int bMainFileReal =
3700
0
        VSIStatExL(osMainFilename, &sStat, VSI_STAT_EXISTS_FLAG) == 0;
3701
3702
    /* -------------------------------------------------------------------- */
3703
    /*      Form new list.                                                  */
3704
    /* -------------------------------------------------------------------- */
3705
0
    char **papszList = nullptr;
3706
3707
0
    if (bMainFileReal)
3708
0
        papszList = CSLAddString(papszList, osMainFilename);
3709
3710
0
    if (sAntiRecursion.nRecLevel == 100)
3711
0
    {
3712
0
        CPLError(CE_Failure, CPLE_AppDefined,
3713
0
                 "GetFileList() called with too many recursion levels");
3714
0
        return papszList;
3715
0
    }
3716
0
    ++sAntiRecursion.nRecLevel;
3717
3718
    /* -------------------------------------------------------------------- */
3719
    /*      Do we have a known overview file?                               */
3720
    /* -------------------------------------------------------------------- */
3721
0
    if (oOvManager.IsInitialized() && oOvManager.poODS != nullptr)
3722
0
    {
3723
0
        auto iter = aosDatasetList.insert(datasetCtxt).first;
3724
0
        char **papszOvrList = oOvManager.poODS->GetFileList();
3725
0
        papszList = CSLInsertStrings(papszList, -1, papszOvrList);
3726
0
        CSLDestroy(papszOvrList);
3727
0
        aosDatasetList.erase(iter);
3728
0
    }
3729
3730
    /* -------------------------------------------------------------------- */
3731
    /*      Do we have a known mask file?                                   */
3732
    /* -------------------------------------------------------------------- */
3733
0
    if (oOvManager.HaveMaskFile())
3734
0
    {
3735
0
        auto iter = aosDatasetList.insert(std::move(datasetCtxt)).first;
3736
0
        for (const char *pszFile :
3737
0
             CPLStringList(oOvManager.poMaskDS->GetFileList()))
3738
0
        {
3739
0
            if (CSLFindString(papszList, pszFile) < 0)
3740
0
                papszList = CSLAddString(papszList, pszFile);
3741
0
        }
3742
0
        aosDatasetList.erase(iter);
3743
0
    }
3744
3745
0
    --sAntiRecursion.nRecLevel;
3746
3747
0
    return papszList;
3748
0
}
3749
3750
/************************************************************************/
3751
/*                          GDALGetFileList()                           */
3752
/************************************************************************/
3753
3754
/**
3755
 * \brief Fetch files forming dataset.
3756
 *
3757
 * @see GDALDataset::GetFileList()
3758
 */
3759
3760
char **CPL_STDCALL GDALGetFileList(GDALDatasetH hDS)
3761
3762
0
{
3763
0
    VALIDATE_POINTER1(hDS, "GDALGetFileList", nullptr);
3764
3765
0
    return GDALDataset::FromHandle(hDS)->GetFileList();
3766
0
}
3767
3768
/************************************************************************/
3769
/*                           CreateMaskBand()                           */
3770
/************************************************************************/
3771
3772
/**
3773
 * \brief Adds a mask band to the dataset
3774
 *
3775
 * The default implementation of the CreateMaskBand() method is implemented
3776
 * based on similar rules to the .ovr handling implemented using the
3777
 * GDALDefaultOverviews object. A TIFF file with the extension .msk will
3778
 * be created with the same basename as the original file, and it will have
3779
 * one band.
3780
 * The mask images will be deflate compressed tiled images with the same
3781
 * block size as the original image if possible.
3782
 * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
3783
 * level, where xx matches the band number of a band of the main dataset. The
3784
 * value of those items will be the one of the nFlagsIn parameter.
3785
 *
3786
 * Note that if you got a mask band with a previous call to GetMaskBand(), it
3787
 * might be invalidated by CreateMaskBand(). So you have to call GetMaskBand()
3788
 * again.
3789
 *
3790
 *
3791
 * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
3792
 *                 GMF_PER_DATASET will be always set, even if not explicitly
3793
 *                 specified.
3794
 * @return CE_None on success or CE_Failure on an error.
3795
 *
3796
 * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
3797
 * @see GDALRasterBand::CreateMaskBand()
3798
 *
3799
 */
3800
CPLErr GDALDataset::CreateMaskBand(int nFlagsIn)
3801
3802
0
{
3803
0
    if (oOvManager.IsInitialized())
3804
0
    {
3805
0
        CPLErr eErr = oOvManager.CreateMaskBand(nFlagsIn, -1);
3806
0
        if (eErr != CE_None)
3807
0
            return eErr;
3808
3809
        // Invalidate existing raster band masks.
3810
0
        for (int i = 0; i < nBands; ++i)
3811
0
        {
3812
0
            GDALRasterBand *poBand = papoBands[i];
3813
0
            poBand->poMask.reset();
3814
0
        }
3815
3816
0
        return CE_None;
3817
0
    }
3818
3819
0
    ReportError(CE_Failure, CPLE_NotSupported,
3820
0
                "CreateMaskBand() not supported for this dataset.");
3821
3822
0
    return CE_Failure;
3823
0
}
3824
3825
/************************************************************************/
3826
/*                     GDALCreateDatasetMaskBand()                      */
3827
/************************************************************************/
3828
3829
/**
3830
 * \brief Adds a mask band to the dataset
3831
 * @see GDALDataset::CreateMaskBand()
3832
 */
3833
CPLErr CPL_STDCALL GDALCreateDatasetMaskBand(GDALDatasetH hDS, int nFlags)
3834
3835
0
{
3836
0
    VALIDATE_POINTER1(hDS, "GDALCreateDatasetMaskBand", CE_Failure);
3837
3838
0
    return GDALDataset::FromHandle(hDS)->CreateMaskBand(nFlags);
3839
0
}
3840
3841
/************************************************************************/
3842
/*                              GDALOpen()                              */
3843
/************************************************************************/
3844
3845
/**
3846
 * \brief Open a raster file as a GDALDataset.
3847
 *
3848
 * This function will try to open the passed file, or virtual dataset
3849
 * name by invoking the Open method of each registered GDALDriver in turn.
3850
 * The first successful open will result in a returned dataset.  If all
3851
 * drivers fail then NULL is returned and an error is issued.
3852
 *
3853
 * Several recommendations :
3854
 * <ul>
3855
 * <li>If you open a dataset object with GA_Update access, it is not recommended
3856
 * to open a new dataset on the same underlying file.</li>
3857
 * <li>The returned dataset should only be accessed by one thread at a time. If
3858
 * you want to use it from different threads, you must add all necessary code
3859
 * (mutexes, etc.)  to avoid concurrent use of the object. (Some drivers, such
3860
 * as GeoTIFF, maintain internal state variables that are updated each time a
3861
 * new block is read, thus preventing concurrent use.) </li>
3862
 * </ul>
3863
 *
3864
 * For drivers supporting the VSI virtual file API, it is possible to open a
3865
 * file in a .zip archive (see VSIInstallZipFileHandler()), in a
3866
 * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
3867
 * server (see VSIInstallCurlFileHandler())
3868
 *
3869
 * \sa GDALOpenShared()
3870
 * \sa GDALOpenEx()
3871
 *
3872
 * @param pszFilename the name of the file to access.  In the case of
3873
 * exotic drivers this may not refer to a physical file, but instead contain
3874
 * information for the driver on how to access a dataset.  It should be in UTF-8
3875
 * encoding.
3876
 *
3877
 * @param eAccess the desired access, either GA_Update or GA_ReadOnly.  Many
3878
 * drivers support only read only access.
3879
 *
3880
 * @return A GDALDatasetH handle or NULL on failure.  For C++ applications
3881
 * this handle can be cast to a GDALDataset *.
3882
 */
3883
3884
GDALDatasetH CPL_STDCALL GDALOpen(const char *pszFilename, GDALAccess eAccess)
3885
3886
0
{
3887
0
    const int nUpdateFlag = eAccess == GA_Update ? GDAL_OF_UPDATE : 0;
3888
0
    const int nOpenFlags = GDAL_OF_RASTER | nUpdateFlag | GDAL_OF_VERBOSE_ERROR;
3889
0
    GDALDatasetH hDataset =
3890
0
        GDALOpenEx(pszFilename, nOpenFlags, nullptr, nullptr, nullptr);
3891
0
    return hDataset;
3892
0
}
3893
3894
/************************************************************************/
3895
/*                            GetSharedDS()                             */
3896
/************************************************************************/
3897
3898
static GDALDataset *GetSharedDS(const char *pszFilename,
3899
                                unsigned int nOpenFlags,
3900
                                const char *const *papszOpenOptions)
3901
0
{
3902
0
    CPLMutexHolderD(&hDLMutex);
3903
3904
0
    if (phSharedDatasetSet != nullptr)
3905
0
    {
3906
0
        const GIntBig nThisPID = GDALGetResponsiblePIDForCurrentThread();
3907
0
        SharedDatasetCtxt sStruct;
3908
3909
0
        sStruct.nPID = nThisPID;
3910
0
        sStruct.pszDescription = const_cast<char *>(pszFilename);
3911
0
        sStruct.nOpenFlags = nOpenFlags & ~GDAL_OF_SHARED;
3912
0
        std::string osConcatenatedOpenOptions =
3913
0
            GDALSharedDatasetConcatenateOpenOptions(papszOpenOptions);
3914
0
        sStruct.pszConcatenatedOpenOptions = &osConcatenatedOpenOptions[0];
3915
0
        sStruct.poDS = nullptr;
3916
0
        SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(
3917
0
            CPLHashSetLookup(phSharedDatasetSet, &sStruct));
3918
0
        if (psStruct == nullptr && (nOpenFlags & GDAL_OF_UPDATE) == 0)
3919
0
        {
3920
0
            sStruct.nOpenFlags |= GDAL_OF_UPDATE;
3921
0
            psStruct = static_cast<SharedDatasetCtxt *>(
3922
0
                CPLHashSetLookup(phSharedDatasetSet, &sStruct));
3923
0
        }
3924
0
        if (psStruct)
3925
0
        {
3926
0
            return psStruct->poDS;
3927
0
        }
3928
0
    }
3929
0
    return nullptr;
3930
0
}
3931
3932
/************************************************************************/
3933
/*                             GDALOpenEx()                             */
3934
/************************************************************************/
3935
3936
/**
3937
 * \brief Open a raster or vector file as a GDALDataset.
3938
 *
3939
 * This function will try to open the passed file, or virtual dataset
3940
 * name by invoking the Open method of each registered GDALDriver in turn.
3941
 * The first successful open will result in a returned dataset.  If all
3942
 * drivers fail then NULL is returned and an error is issued.
3943
 *
3944
 * Several recommendations :
3945
 * <ul>
3946
 * <li>If you open a dataset object with GDAL_OF_UPDATE access, it is not
3947
 * recommended to open a new dataset on the same underlying file.</li>
3948
 * <li>The returned dataset should only be accessed by one thread at a time. If
3949
 * you want to use it from different threads, you must add all necessary code
3950
 * (mutexes, etc.)  to avoid concurrent use of the object. (Some drivers, such
3951
 * as GeoTIFF, maintain internal state variables that are updated each time a
3952
 * new block is read, thus preventing concurrent use.) </li>
3953
 * </ul>
3954
 *
3955
 * For drivers supporting the VSI virtual file API, it is possible to open a
3956
 * file in a .zip archive (see VSIInstallZipFileHandler()), in a
3957
 * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
3958
 * server (see VSIInstallCurlFileHandler())
3959
 *
3960
 * In order to reduce the need for searches through the operating system
3961
 * file system machinery, it is possible to give an optional list of files with
3962
 * the papszSiblingFiles parameter.
3963
 * This is the list of all files at the same level in the file system as the
3964
 * target file, including the target file. The filenames must not include any
3965
 * path components, are essentially just the output of VSIReadDir() on the
3966
 * parent directory. If the target object does not have filesystem semantics
3967
 * then the file list should be NULL.
3968
 *
3969
 * @param pszFilename the name of the file to access.  In the case of
3970
 * exotic drivers this may not refer to a physical file, but instead contain
3971
 * information for the driver on how to access a dataset.  It should be in UTF-8
3972
 * encoding.
3973
 *
3974
 * @param nOpenFlags a combination of GDAL_OF_ flags that may be combined
3975
 * through logical or operator.
3976
 * <ul>
3977
 * <li>Driver kind:
3978
 *   <ul>
3979
 *     <li>GDAL_OF_RASTER for raster drivers,</li>
3980
 *     <li>GDAL_OF_MULTIDIM_RASTER for multidimensional raster drivers,</li>
3981
 *     <li>GDAL_OF_VECTOR for vector drivers,</li>
3982
 *     <li>GDAL_OF_GNM for Geographic Network Model drivers.</li>
3983
 *    </ul>
3984
 * GDAL_OF_RASTER and GDAL_OF_MULTIDIM_RASTER are generally mutually
3985
 * exclusive. If none of the value is specified, GDAL_OF_RASTER | GDAL_OF_VECTOR
3986
 * | GDAL_OF_GNM is implied.
3987
 * </li>
3988
 * <li>Access mode: GDAL_OF_READONLY (exclusive)or GDAL_OF_UPDATE.
3989
 * </li>
3990
 * <li>Shared mode: GDAL_OF_SHARED. If set,
3991
 * it allows the sharing of GDALDataset handles for a dataset with other callers
3992
 * that have set GDAL_OF_SHARED. In particular, GDALOpenEx() will first consult
3993
 * its list of currently open and shared GDALDataset's, and if the
3994
 * GetDescription() name for one exactly matches the pszFilename passed to
3995
 * GDALOpenEx() it will be referenced and returned, if GDALOpenEx() is called
3996
 * from the same thread.
3997
 * </li>
3998
 * <li>Thread safe mode: GDAL_OF_THREAD_SAFE (added in 3.10).
3999
 * This must be use in combination with GDAL_OF_RASTER, and is mutually
4000
 * exclusive with GDAL_OF_UPDATE, GDAL_OF_VECTOR, GDAL_OF_MULTIDIM_RASTER or
4001
 * GDAL_OF_GNM.
4002
 * </li>
4003
 * <li>Verbose error: GDAL_OF_VERBOSE_ERROR. If set,
4004
 * a failed attempt to open the file will lead to an error message to be
4005
 * reported.
4006
 * </li>
4007
 * </ul>
4008
 *
4009
 * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
4010
 * terminated list of strings with the driver short names that must be
4011
 * considered.
4012
 * Starting with GDAL 3.13, a string starting with the dash (-) character
4013
 * followed by the driver short name can be used to exclude a driver.
4014
 *
4015
 * @param papszOpenOptions NULL, or a NULL terminated list of strings with open
4016
 * options passed to candidate drivers. An option exists for all drivers,
4017
 * OVERVIEW_LEVEL=level, to select a particular overview level of a dataset.
4018
 * The level index starts at 0. The level number can be suffixed by "only" to
4019
 * specify that only this overview level must be visible, and not sub-levels.
4020
 * Open options are validated by default, and a warning is emitted in case the
4021
 * option is not recognized. In some scenarios, it might be not desirable (e.g.
4022
 * when not knowing which driver will open the file), so the special open option
4023
 * VALIDATE_OPEN_OPTIONS can be set to NO to avoid such warnings. Alternatively,
4024
 * that it may not cause a warning if the driver doesn't declare this option.
4025
 * Starting with GDAL 3.3, OVERVIEW_LEVEL=NONE is supported to indicate that
4026
 * no overviews should be exposed.
4027
 *
4028
 * @param papszSiblingFiles NULL, or a NULL terminated list of strings that are
4029
 * filenames that are auxiliary to the main filename. If NULL is passed, a
4030
 * probing of the file system will be done.
4031
 *
4032
 * @return A GDALDatasetH handle or NULL on failure.  For C++ applications
4033
 * this handle can be cast to a GDALDataset *.
4034
 *
4035
 */
4036
4037
GDALDatasetH CPL_STDCALL GDALOpenEx(const char *pszFilename,
4038
                                    unsigned int nOpenFlags,
4039
                                    const char *const *papszAllowedDrivers,
4040
                                    const char *const *papszOpenOptions,
4041
                                    const char *const *papszSiblingFiles)
4042
0
{
4043
0
    VALIDATE_POINTER1(pszFilename, "GDALOpen", nullptr);
4044
4045
    // Do some sanity checks on incompatible flags with thread-safe mode.
4046
0
    if ((nOpenFlags & GDAL_OF_THREAD_SAFE) != 0)
4047
0
    {
4048
0
        const struct
4049
0
        {
4050
0
            int nFlag;
4051
0
            const char *pszFlagName;
4052
0
        } asFlags[] = {
4053
0
            {GDAL_OF_UPDATE, "GDAL_OF_UPDATE"},
4054
0
            {GDAL_OF_VECTOR, "GDAL_OF_VECTOR"},
4055
0
            {GDAL_OF_MULTIDIM_RASTER, "GDAL_OF_MULTIDIM_RASTER"},
4056
0
            {GDAL_OF_GNM, "GDAL_OF_GNM"},
4057
0
        };
4058
4059
0
        for (const auto &asFlag : asFlags)
4060
0
        {
4061
0
            if ((nOpenFlags & asFlag.nFlag) != 0)
4062
0
            {
4063
0
                CPLError(CE_Failure, CPLE_IllegalArg,
4064
0
                         "GDAL_OF_THREAD_SAFE and %s are mutually "
4065
0
                         "exclusive",
4066
0
                         asFlag.pszFlagName);
4067
0
                return nullptr;
4068
0
            }
4069
0
        }
4070
0
    }
4071
4072
    // If no driver kind is specified, assume all are to be probed.
4073
0
    if ((nOpenFlags & GDAL_OF_KIND_MASK) == 0)
4074
0
        nOpenFlags |= GDAL_OF_KIND_MASK & ~GDAL_OF_MULTIDIM_RASTER;
4075
4076
    /* -------------------------------------------------------------------- */
4077
    /*      In case of shared dataset, first scan the existing list to see  */
4078
    /*      if it could already contain the requested dataset.              */
4079
    /* -------------------------------------------------------------------- */
4080
0
    if (nOpenFlags & GDAL_OF_SHARED)
4081
0
    {
4082
0
        if (nOpenFlags & GDAL_OF_INTERNAL)
4083
0
        {
4084
0
            CPLError(CE_Failure, CPLE_IllegalArg,
4085
0
                     "GDAL_OF_SHARED and GDAL_OF_INTERNAL are exclusive");
4086
0
            return nullptr;
4087
0
        }
4088
4089
0
        auto poSharedDS =
4090
0
            GetSharedDS(pszFilename, nOpenFlags, papszOpenOptions);
4091
0
        if (poSharedDS)
4092
0
        {
4093
0
            poSharedDS->Reference();
4094
0
            return poSharedDS;
4095
0
        }
4096
0
    }
4097
4098
0
    CPLErrorReset();
4099
0
    VSIErrorReset();
4100
4101
    // Build GDALOpenInfo just now to avoid useless file stat'ing if a
4102
    // shared dataset was asked before.
4103
0
    GDALOpenInfo oOpenInfo(pszFilename, nOpenFlags, papszSiblingFiles);
4104
4105
0
    return GDALDataset::Open(&oOpenInfo, papszAllowedDrivers, papszOpenOptions)
4106
0
        .release();
4107
0
}
4108
4109
/************************************************************************/
4110
/*                         GDALDataset::Open()                          */
4111
/************************************************************************/
4112
4113
/**
4114
 * \brief Open a raster or vector file as a GDALDataset.
4115
 *
4116
 * This function will use the passed open info on each registered GDALDriver in
4117
 * turn.
4118
 * The first successful open will result in a returned dataset.  If all
4119
 * drivers fail then NULL is returned and an error is issued.
4120
 *
4121
 * Several recommendations :
4122
 * <ul>
4123
 * <li>If you open a dataset object with GDAL_OF_UPDATE access, it is not
4124
 * recommended to open a new dataset on the same underlying file.</li>
4125
 * <li>The returned dataset should only be accessed by one thread at a time. If
4126
 * you want to use it from different threads, you must add all necessary code
4127
 * (mutexes, etc.)  to avoid concurrent use of the object. (Some drivers, such
4128
 * as GeoTIFF, maintain internal state variables that are updated each time a
4129
 * new block is read, thus preventing concurrent use.) </li>
4130
 * </ul>
4131
 *
4132
 * For drivers supporting the VSI virtual file API, it is possible to open a
4133
 * file in a .zip archive (see VSIInstallZipFileHandler()), in a
4134
 * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
4135
 * server (see VSIInstallCurlFileHandler())
4136
 *
4137
 * @param poOpenInfo a pointer to an open info instance. Must NOT be NULL,
4138
 * and the GDAL_OF_SHARED flag must NOT be set in poOpenInfo->nOpenFlags.
4139
 * If shared dataset is needed, use GDALOpenEx() or the other variant of
4140
 * GDALDataset::Open()
4141
 *
4142
 * @param papszAllowedDrivers NULL to consider all candidate drivers, or a NULL
4143
 * terminated list of strings with the driver short names that must be
4144
 * considered.
4145
 * Starting with GDAL 3.13, a string starting with the dash (-) character
4146
 * followed by the driver short name can be used to exclude a driver.
4147
 *
4148
 * @param papszOpenOptions NULL, or a NULL terminated list of strings with open
4149
 * options passed to candidate drivers. An option exists for all drivers,
4150
 * OVERVIEW_LEVEL=level, to select a particular overview level of a dataset.
4151
 * The level index starts at 0. The level number can be suffixed by "only" to
4152
 * specify that only this overview level must be visible, and not sub-levels.
4153
 * Open options are validated by default, and a warning is emitted in case the
4154
 * option is not recognized. In some scenarios, it might be not desirable (e.g.
4155
 * when not knowing which driver will open the file), so the special open option
4156
 * VALIDATE_OPEN_OPTIONS can be set to NO to avoid such warnings. Alternatively,
4157
 * that it may not cause a warning if the driver doesn't declare this option.
4158
 * OVERVIEW_LEVEL=NONE is supported to indicate that
4159
 * no overviews should be exposed.
4160
 *
4161
 * @return A GDALDataset unique pointer or NULL on failure.
4162
 *
4163
 * @since 3.13
4164
 */
4165
4166
std::unique_ptr<GDALDataset>
4167
GDALDataset::Open(GDALOpenInfo *poOpenInfo,
4168
                  const char *const *papszAllowedDrivers,
4169
                  const char *const *papszOpenOptions)
4170
0
{
4171
    // Hack for the ZARR driver. We translate the CACHE_KERCHUNK_JSON
4172
    // into VSIKERCHUNK_USE_CACHE config option
4173
0
    std::unique_ptr<CPLConfigOptionSetter> poVSIKERCHUNK_USE_CACHESetter;
4174
0
    if (CPLFetchBool(papszOpenOptions, "CACHE_KERCHUNK_JSON", false))
4175
0
    {
4176
0
        poVSIKERCHUNK_USE_CACHESetter = std::make_unique<CPLConfigOptionSetter>(
4177
0
            "VSIKERCHUNK_USE_CACHE", "YES", false);
4178
0
    }
4179
4180
0
    GDALDriverManager *poDM = GetGDALDriverManager();
4181
4182
0
    CPLAssert(nullptr != poDM);
4183
4184
0
    GDALOpenInfo &oOpenInfo = *poOpenInfo;
4185
0
    const char *pszFilename = poOpenInfo->pszFilename;
4186
0
    const int nOpenFlags = poOpenInfo->nOpenFlags;
4187
0
    oOpenInfo.papszAllowedDrivers = papszAllowedDrivers;
4188
4189
0
    GDALAntiRecursionStruct &sAntiRecursion = GetAntiRecursionOpen();
4190
0
    if (sAntiRecursion.nRecLevel == 100)
4191
0
    {
4192
0
        CPLError(CE_Failure, CPLE_AppDefined,
4193
0
                 "GDALOpen() called with too many recursion levels");
4194
0
        return nullptr;
4195
0
    }
4196
4197
0
    std::string osAllowedDrivers;
4198
0
    for (const char *pszDriverName : cpl::Iterate(papszAllowedDrivers))
4199
0
        osAllowedDrivers += pszDriverName;
4200
0
    auto dsCtxt = GDALAntiRecursionStruct::DatasetContext(
4201
0
        std::string(pszFilename), nOpenFlags, osAllowedDrivers);
4202
0
    if (cpl::contains(sAntiRecursion.aosDatasetNamesWithFlags, dsCtxt))
4203
0
    {
4204
0
        CPLError(CE_Failure, CPLE_AppDefined,
4205
0
                 "GDALOpen() called on %s recursively", pszFilename);
4206
0
        return nullptr;
4207
0
    }
4208
4209
    // Remove leading @ if present.
4210
0
    char **papszOpenOptionsCleaned =
4211
0
        CSLDuplicate(const_cast<char **>(papszOpenOptions));
4212
0
    for (char **papszIter = papszOpenOptionsCleaned; papszIter && *papszIter;
4213
0
         ++papszIter)
4214
0
    {
4215
0
        char *pszOption = *papszIter;
4216
0
        if (pszOption[0] == '@')
4217
0
            memmove(pszOption, pszOption + 1, strlen(pszOption + 1) + 1);
4218
0
    }
4219
4220
0
    oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4221
0
    oOpenInfo.nOpenFlags |= GDAL_OF_FROM_GDALOPEN;
4222
4223
0
#ifdef OGRAPISPY_ENABLED
4224
0
    const bool bUpdate = (nOpenFlags & GDAL_OF_UPDATE) != 0;
4225
0
    const int iSnapshot =
4226
0
        (nOpenFlags & GDAL_OF_VECTOR) != 0 && (nOpenFlags & GDAL_OF_RASTER) == 0
4227
0
            ? OGRAPISpyOpenTakeSnapshot(pszFilename, bUpdate)
4228
0
            : INT_MIN;
4229
0
#endif
4230
4231
0
    const int nDriverCount = poDM->GetDriverCount(/*bIncludeHidden=*/true);
4232
0
    GDALDriver *poMissingPluginDriver = nullptr;
4233
0
    std::vector<GDALDriver *> apoSecondPassDrivers;
4234
4235
    // Lookup of matching driver for dataset can involve up to 2 passes:
4236
    // - in the first pass, all drivers that are compabile of the request mode
4237
    //   (raster/vector/etc.) are probed using their Identify() method if it
4238
    //   exists. If the Identify() method returns FALSE, the driver is skipped.
4239
    //   If the Identify() methods returns GDAL_IDENTIFY_UNKNOWN and that the
4240
    //   driver is a deferred-loading plugin, it is added to the
4241
    //   apoSecondPassDrivers list for potential later probing, and execution
4242
    //   continues to the next driver in the list.
4243
    //   Otherwise if Identify() returns non-FALSE, the Open() method is used.
4244
    //   If Open() returns a non-NULL dataset, the loop stops and it is
4245
    //   returned. Otherwise looping over remaining drivers continues.
4246
    // - the second pass is optional, only if at least one driver was added
4247
    //   into apoSecondPassDrivers during the first pass. It is similar
4248
    //   to the first pass except it runs only on apoSecondPassDrivers drivers.
4249
    //   And the Open() method of such drivers is used, causing them to be
4250
    //   loaded for real.
4251
0
    int iPass = 1;
4252
0
retry:
4253
0
    for (int iDriver = 0;
4254
0
         iDriver < (iPass == 1 ? nDriverCount
4255
0
                               : static_cast<int>(apoSecondPassDrivers.size()));
4256
0
         ++iDriver)
4257
0
    {
4258
0
        GDALDriver *poDriver =
4259
0
            iPass == 1 ? poDM->GetDriver(iDriver, /*bIncludeHidden=*/true)
4260
0
                       : apoSecondPassDrivers[iDriver];
4261
0
        const char *pszDriverName = GDALGetDriverShortName(poDriver);
4262
0
        if (pszDriverName && papszAllowedDrivers)
4263
0
        {
4264
0
            bool bDriverMatchedPositively = false;
4265
0
            bool bDriverMatchedNegatively = false;
4266
0
            bool bOnlyExcludedDrivers = true;
4267
0
            for (const char *pszAllowedDriver :
4268
0
                 cpl::Iterate(papszAllowedDrivers))
4269
0
            {
4270
0
                if (pszAllowedDriver[0] != '-')
4271
0
                    bOnlyExcludedDrivers = false;
4272
0
                if (EQUAL(pszAllowedDriver, pszDriverName))
4273
0
                {
4274
0
                    bDriverMatchedPositively = true;
4275
0
                }
4276
0
                else if (pszAllowedDriver[0] == '-' &&
4277
0
                         EQUAL(pszAllowedDriver + 1, pszDriverName))
4278
0
                {
4279
0
                    bDriverMatchedNegatively = true;
4280
0
                    break;
4281
0
                }
4282
0
            }
4283
0
            if ((!bDriverMatchedPositively && !bOnlyExcludedDrivers) ||
4284
0
                bDriverMatchedNegatively)
4285
0
            {
4286
0
                continue;
4287
0
            }
4288
0
        }
4289
4290
0
        if (poDriver->GetMetadataItem(GDAL_DCAP_OPEN) == nullptr)
4291
0
            continue;
4292
4293
0
        if ((nOpenFlags & GDAL_OF_RASTER) != 0 &&
4294
0
            (nOpenFlags & GDAL_OF_VECTOR) == 0 &&
4295
0
            poDriver->GetMetadataItem(GDAL_DCAP_RASTER) == nullptr)
4296
0
            continue;
4297
0
        if ((nOpenFlags & GDAL_OF_VECTOR) != 0 &&
4298
0
            (nOpenFlags & GDAL_OF_RASTER) == 0 &&
4299
0
            poDriver->GetMetadataItem(GDAL_DCAP_VECTOR) == nullptr)
4300
0
            continue;
4301
0
        if ((nOpenFlags & GDAL_OF_MULTIDIM_RASTER) != 0 &&
4302
0
            (nOpenFlags & GDAL_OF_RASTER) == 0 &&
4303
0
            poDriver->GetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER) == nullptr)
4304
0
            continue;
4305
4306
        // Remove general OVERVIEW_LEVEL open options from list before passing
4307
        // it to the driver, if it isn't a driver specific option already.
4308
0
        char **papszTmpOpenOptions = nullptr;
4309
0
        char **papszTmpOpenOptionsToValidate = nullptr;
4310
0
        char **papszOptionsToValidate = const_cast<char **>(papszOpenOptions);
4311
0
        if (CSLFetchNameValue(papszOpenOptionsCleaned, "OVERVIEW_LEVEL") !=
4312
0
                nullptr &&
4313
0
            !poDriver->HasOpenOption("OVERVIEW_LEVEL"))
4314
0
        {
4315
0
            papszTmpOpenOptions = CSLDuplicate(papszOpenOptionsCleaned);
4316
0
            papszTmpOpenOptions =
4317
0
                CSLSetNameValue(papszTmpOpenOptions, "OVERVIEW_LEVEL", nullptr);
4318
0
            oOpenInfo.papszOpenOptions = papszTmpOpenOptions;
4319
4320
0
            papszOptionsToValidate = CSLDuplicate(papszOptionsToValidate);
4321
0
            papszOptionsToValidate = CSLSetNameValue(papszOptionsToValidate,
4322
0
                                                     "OVERVIEW_LEVEL", nullptr);
4323
0
            papszTmpOpenOptionsToValidate = papszOptionsToValidate;
4324
0
        }
4325
4326
0
        const int nIdentifyRes =
4327
0
            poDriver->pfnIdentifyEx
4328
0
                ? poDriver->pfnIdentifyEx(poDriver, &oOpenInfo)
4329
0
            : poDriver->pfnIdentify ? poDriver->pfnIdentify(&oOpenInfo)
4330
0
                                    : GDAL_IDENTIFY_UNKNOWN;
4331
0
        if (nIdentifyRes == FALSE)
4332
0
        {
4333
0
            CSLDestroy(papszTmpOpenOptions);
4334
0
            CSLDestroy(papszTmpOpenOptionsToValidate);
4335
0
            oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4336
0
            continue;
4337
0
        }
4338
0
        else if (iPass == 1 && nIdentifyRes < 0 &&
4339
0
                 poDriver->pfnOpen == nullptr &&
4340
0
                 poDriver->GetMetadataItem("IS_NON_LOADED_PLUGIN"))
4341
0
        {
4342
            // Not loaded plugin
4343
0
            apoSecondPassDrivers.push_back(poDriver);
4344
0
            CSLDestroy(papszTmpOpenOptions);
4345
0
            CSLDestroy(papszTmpOpenOptionsToValidate);
4346
0
            oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4347
0
            continue;
4348
0
        }
4349
4350
0
        const bool bIdentifyRes = nIdentifyRes == GDAL_IDENTIFY_TRUE;
4351
0
        if (bIdentifyRes)
4352
0
        {
4353
0
            GDALValidateOpenOptions(poDriver, papszOptionsToValidate);
4354
0
        }
4355
4356
0
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
4357
0
        const bool bFpAvailableBefore = oOpenInfo.fpL != nullptr;
4358
0
        CPLErrorReset();
4359
0
#endif
4360
4361
0
        sAntiRecursion.nRecLevel++;
4362
0
        sAntiRecursion.aosDatasetNamesWithFlags.insert(dsCtxt);
4363
4364
0
        GDALDataset *poDS = poDriver->Open(&oOpenInfo, false);
4365
4366
0
        sAntiRecursion.nRecLevel--;
4367
0
        sAntiRecursion.aosDatasetNamesWithFlags.erase(dsCtxt);
4368
4369
0
        if (poDriver->pfnOpen != nullptr)
4370
0
        {
4371
            // If we couldn't determine for sure with Identify() (it returned
4372
            // -1), but Open() managed to open the file, post validate options.
4373
0
            if (poDS != nullptr &&
4374
0
                (poDriver->pfnIdentify || poDriver->pfnIdentifyEx) &&
4375
0
                !bIdentifyRes)
4376
0
            {
4377
0
                GDALValidateOpenOptions(poDriver, papszOptionsToValidate);
4378
0
            }
4379
0
        }
4380
0
        else if (poDriver->pfnOpenWithDriverArg != nullptr)
4381
0
        {
4382
            // do nothing
4383
0
        }
4384
0
        else if (bIdentifyRes &&
4385
0
                 poDriver->GetMetadataItem("MISSING_PLUGIN_FILENAME"))
4386
0
        {
4387
0
            if (!poMissingPluginDriver)
4388
0
            {
4389
0
                poMissingPluginDriver = poDriver;
4390
0
            }
4391
0
        }
4392
0
        else
4393
0
        {
4394
            // should not happen given the GDAL_DCAP_OPEN check
4395
0
            CSLDestroy(papszTmpOpenOptions);
4396
0
            CSLDestroy(papszTmpOpenOptionsToValidate);
4397
0
            oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4398
0
            continue;
4399
0
        }
4400
4401
0
        CSLDestroy(papszTmpOpenOptions);
4402
0
        CSLDestroy(papszTmpOpenOptionsToValidate);
4403
0
        oOpenInfo.papszOpenOptions = papszOpenOptionsCleaned;
4404
4405
0
        if (poDS != nullptr)
4406
0
        {
4407
0
            if (poDS->papszOpenOptions == nullptr)
4408
0
            {
4409
0
                poDS->papszOpenOptions = papszOpenOptionsCleaned;
4410
0
                papszOpenOptionsCleaned = nullptr;
4411
0
            }
4412
4413
            // Deal with generic OVERVIEW_LEVEL open option, unless it is
4414
            // driver specific.
4415
0
            if (CSLFetchNameValue(papszOpenOptions, "OVERVIEW_LEVEL") !=
4416
0
                    nullptr &&
4417
0
                !poDriver->HasOpenOption("OVERVIEW_LEVEL"))
4418
0
            {
4419
0
                CPLString osVal(
4420
0
                    CSLFetchNameValue(papszOpenOptions, "OVERVIEW_LEVEL"));
4421
0
                const int nOvrLevel = EQUAL(osVal, "NONE") ? -1 : atoi(osVal);
4422
0
                const bool bThisLevelOnly =
4423
0
                    nOvrLevel == -1 || osVal.ifind("only") != std::string::npos;
4424
0
                GDALDataset *poOvrDS =
4425
0
                    GDALCreateOverviewDataset(poDS, nOvrLevel, bThisLevelOnly);
4426
0
                if (poOvrDS && (nOpenFlags & GDAL_OF_SHARED) != 0)
4427
0
                {
4428
0
                    if (strcmp(pszFilename, poDS->GetDescription()) != 0)
4429
0
                    {
4430
0
                        CPLError(
4431
0
                            CE_Warning, CPLE_NotSupported,
4432
0
                            "A dataset opened by GDALOpenShared should have "
4433
0
                            "the same filename (%s) "
4434
0
                            "and description (%s)",
4435
0
                            pszFilename, poDS->GetDescription());
4436
0
                    }
4437
0
                    else
4438
0
                    {
4439
0
                        CSLDestroy(poDS->papszOpenOptions);
4440
0
                        poDS->papszOpenOptions = CSLDuplicate(papszOpenOptions);
4441
0
                        poDS->papszOpenOptions = CSLSetNameValue(
4442
0
                            poDS->papszOpenOptions, "OVERVIEW_LEVEL", nullptr);
4443
0
                    }
4444
0
                }
4445
0
                poDS->ReleaseRef();
4446
0
                poDS = poOvrDS;
4447
0
                if (poDS == nullptr)
4448
0
                {
4449
0
                    if (nOpenFlags & GDAL_OF_VERBOSE_ERROR)
4450
0
                    {
4451
0
                        CPLError(CE_Failure, CPLE_OpenFailed,
4452
0
                                 "Cannot open overview level %d of %s",
4453
0
                                 nOvrLevel, pszFilename);
4454
0
                    }
4455
0
                }
4456
0
                else
4457
0
                {
4458
                    // For thread-safe opening, currently poDS is what will be
4459
                    // the "master" dataset owned by the thread-safe dataset
4460
                    // returned to the user, hence we do not register it as a
4461
                    // visible one in the open dataset list, or mark it as shared.
4462
0
                    if (!(nOpenFlags & GDAL_OF_INTERNAL) &&
4463
0
                        !(nOpenFlags & GDAL_OF_THREAD_SAFE))
4464
0
                    {
4465
0
                        poDS->AddToDatasetOpenList();
4466
0
                    }
4467
0
                    if (nOpenFlags & GDAL_OF_SHARED)
4468
0
                    {
4469
0
                        CSLDestroy(poDS->papszOpenOptions);
4470
0
                        poDS->papszOpenOptions = CSLDuplicate(papszOpenOptions);
4471
0
                        poDS->nOpenFlags = nOpenFlags;
4472
0
                        if (!(nOpenFlags & GDAL_OF_THREAD_SAFE))
4473
0
                            poDS->MarkAsShared();
4474
0
                    }
4475
0
                }
4476
0
            }
4477
0
            else if (nOpenFlags & GDAL_OF_SHARED)
4478
0
            {
4479
0
                if (strcmp(pszFilename, poDS->GetDescription()) != 0)
4480
0
                {
4481
0
                    CPLError(CE_Warning, CPLE_NotSupported,
4482
0
                             "A dataset opened by GDALOpenShared should have "
4483
0
                             "the same filename (%s) "
4484
0
                             "and description (%s)",
4485
0
                             pszFilename, poDS->GetDescription());
4486
0
                }
4487
0
                else if (!(nOpenFlags & GDAL_OF_THREAD_SAFE))
4488
0
                {
4489
                    // For thread-safe opening, currently poDS is what will be
4490
                    // the "master" dataset owned by the thread-safe dataset
4491
                    // returned to the user, hence we do not or mark it as shared.
4492
0
                    poDS->MarkAsShared();
4493
0
                }
4494
0
            }
4495
4496
0
            VSIErrorReset();
4497
4498
0
            CSLDestroy(papszOpenOptionsCleaned);
4499
4500
0
#ifdef OGRAPISPY_ENABLED
4501
0
            if (iSnapshot != INT_MIN)
4502
0
            {
4503
0
                GDALDatasetH hDS = GDALDataset::ToHandle(poDS);
4504
0
                OGRAPISpyOpen(pszFilename, bUpdate, iSnapshot, &hDS);
4505
0
                poDS = GDALDataset::FromHandle(hDS);
4506
0
            }
4507
0
#endif
4508
4509
0
            if (poDS)
4510
0
            {
4511
0
                poDS->m_bCanBeReopened = true;
4512
4513
0
                if ((nOpenFlags & GDAL_OF_THREAD_SAFE) != 0)
4514
0
                {
4515
0
                    poDS =
4516
0
                        GDALGetThreadSafeDataset(
4517
0
                            std::unique_ptr<GDALDataset>(poDS), GDAL_OF_RASTER)
4518
0
                            .release();
4519
0
                    if (poDS)
4520
0
                    {
4521
0
                        poDS->m_bCanBeReopened = true;
4522
0
                        poDS->poDriver = poDriver;
4523
0
                        poDS->nOpenFlags = nOpenFlags;
4524
0
                        if (!(nOpenFlags & GDAL_OF_INTERNAL))
4525
0
                            poDS->AddToDatasetOpenList();
4526
0
                        if (nOpenFlags & GDAL_OF_SHARED)
4527
0
                            poDS->MarkAsShared();
4528
0
                    }
4529
0
                }
4530
0
            }
4531
4532
0
            return std::unique_ptr<GDALDataset>(poDS);
4533
0
        }
4534
4535
0
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
4536
0
        if (bFpAvailableBefore && oOpenInfo.fpL == nullptr)
4537
0
        {
4538
            // In case the file descriptor was "consumed" by a driver
4539
            // that ultimately failed, re-open it for next drivers.
4540
0
            oOpenInfo.fpL = VSIFOpenL(
4541
0
                pszFilename, (oOpenInfo.eAccess == GA_Update) ? "r+b" : "rb");
4542
0
        }
4543
#else
4544
        if (CPLGetLastErrorNo() != 0 && CPLGetLastErrorType() > CE_Warning)
4545
        {
4546
            CSLDestroy(papszOpenOptionsCleaned);
4547
4548
#ifdef OGRAPISPY_ENABLED
4549
            if (iSnapshot != INT_MIN)
4550
            {
4551
                GDALDatasetH hDS = nullptr;
4552
                OGRAPISpyOpen(pszFilename, bUpdate, iSnapshot, &hDS);
4553
            }
4554
#endif
4555
            return nullptr;
4556
        }
4557
#endif
4558
0
    }
4559
4560
    // cppcheck-suppress knownConditionTrueFalse
4561
0
    if (iPass == 1 && !apoSecondPassDrivers.empty())
4562
0
    {
4563
0
        CPLDebugOnly("GDAL", "GDALOpen(): Second pass");
4564
0
        iPass = 2;
4565
0
        goto retry;
4566
0
    }
4567
4568
0
    CSLDestroy(papszOpenOptionsCleaned);
4569
4570
0
#ifdef OGRAPISPY_ENABLED
4571
0
    if (iSnapshot != INT_MIN)
4572
0
    {
4573
0
        GDALDatasetH hDS = nullptr;
4574
0
        OGRAPISpyOpen(pszFilename, bUpdate, iSnapshot, &hDS);
4575
0
    }
4576
0
#endif
4577
4578
0
    if (nOpenFlags & GDAL_OF_VERBOSE_ERROR)
4579
0
    {
4580
0
        if (nDriverCount == 0)
4581
0
        {
4582
0
            CPLError(CE_Failure, CPLE_OpenFailed, "No driver registered.");
4583
0
        }
4584
0
        else if (poMissingPluginDriver)
4585
0
        {
4586
0
            std::string osMsg("`");
4587
0
            osMsg += pszFilename;
4588
0
            osMsg += "' not recognized as being in a supported file format. "
4589
0
                     "It could have been recognized by driver ";
4590
0
            osMsg += poMissingPluginDriver->GetDescription();
4591
0
            osMsg += ", but plugin ";
4592
0
            osMsg +=
4593
0
                GDALGetMessageAboutMissingPluginDriver(poMissingPluginDriver);
4594
4595
0
            CPLError(CE_Failure, CPLE_OpenFailed, "%s", osMsg.c_str());
4596
0
        }
4597
        // Check to see if there was a filesystem error, and report it if so.
4598
        // If not, return a more generic error.
4599
0
        else if (!VSIToCPLError(CE_Failure, CPLE_OpenFailed))
4600
0
        {
4601
0
            if (oOpenInfo.bStatOK)
4602
0
            {
4603
0
                CPLError(CE_Failure, CPLE_OpenFailed,
4604
0
                         "`%s' not recognized as being in a supported file "
4605
0
                         "format.",
4606
0
                         pszFilename);
4607
0
            }
4608
0
            else
4609
0
            {
4610
                // If Stat failed and no VSI error was set, assume it is because
4611
                // the file did not exist on the filesystem.
4612
0
                CPLError(CE_Failure, CPLE_OpenFailed,
4613
0
                         "`%s' does not exist in the file system, "
4614
0
                         "and is not recognized as a supported dataset name.",
4615
0
                         pszFilename);
4616
0
            }
4617
0
        }
4618
0
    }
4619
4620
0
    return nullptr;
4621
0
}
4622
4623
/************************************************************************/
4624
/*                           GDALOpenShared()                           */
4625
/************************************************************************/
4626
4627
/**
4628
 * \brief Open a raster file as a GDALDataset.
4629
 *
4630
 * This function works the same as GDALOpen(), but allows the sharing of
4631
 * GDALDataset handles for a dataset with other callers to GDALOpenShared().
4632
 *
4633
 * In particular, GDALOpenShared() will first consult its list of currently
4634
 * open and shared GDALDataset's, and if the GetDescription() name for one
4635
 * exactly matches the pszFilename passed to GDALOpenShared() it will be
4636
 * referenced and returned.
4637
 *
4638
 * If GDALOpenShared() is called on the same
4639
 * pszFilename from two different threads, a different GDALDataset object will
4640
 * be returned as it is not safe to use the same dataset from different threads,
4641
 * unless the user does explicitly use mutexes in its code.
4642
 *
4643
 * For drivers supporting the VSI virtual file API, it is possible to open a
4644
 * file in a .zip archive (see VSIInstallZipFileHandler()), in a
4645
 * .tar/.tar.gz/.tgz archive (see VSIInstallTarFileHandler()) or on a HTTP / FTP
4646
 * server (see VSIInstallCurlFileHandler())
4647
 *
4648
 * \sa GDALOpen()
4649
 * \sa GDALOpenEx()
4650
 *
4651
 * @param pszFilename the name of the file to access.  In the case of
4652
 * exotic drivers this may not refer to a physical file, but instead contain
4653
 * information for the driver on how to access a dataset.  It should be in
4654
 * UTF-8 encoding.
4655
 *
4656
 * @param eAccess the desired access, either GA_Update or GA_ReadOnly.  Many
4657
 * drivers support only read only access.
4658
 *
4659
 * @return A GDALDatasetH handle or NULL on failure.  For C++ applications
4660
 * this handle can be cast to a GDALDataset *.
4661
 */
4662
4663
GDALDatasetH CPL_STDCALL GDALOpenShared(const char *pszFilename,
4664
                                        GDALAccess eAccess)
4665
0
{
4666
0
    VALIDATE_POINTER1(pszFilename, "GDALOpenShared", nullptr);
4667
0
    return GDALOpenEx(pszFilename,
4668
0
                      GDAL_OF_RASTER |
4669
0
                          (eAccess == GA_Update ? GDAL_OF_UPDATE : 0) |
4670
0
                          GDAL_OF_SHARED | GDAL_OF_VERBOSE_ERROR,
4671
0
                      nullptr, nullptr, nullptr);
4672
0
}
4673
4674
/************************************************************************/
4675
/*                             GDALClose()                              */
4676
/************************************************************************/
4677
4678
/**
4679
 * \brief Close GDAL dataset.
4680
 *
4681
 * For non-shared datasets (opened with GDALOpen()) the dataset is closed
4682
 * using the C++ "delete" operator, recovering all dataset related resources.
4683
 * For shared datasets (opened with GDALOpenShared()) the dataset is
4684
 * dereferenced, and closed only if the referenced count has dropped below 1.
4685
 *
4686
 * @param hDS The dataset to close, or nullptr.
4687
 * @return CE_None in case of success (return value since GDAL 3.7). On a
4688
 * shared dataset whose reference count is not dropped below 1, CE_None will
4689
 * be returned.
4690
 *
4691
 * @see GDALCloseEx()
4692
 */
4693
4694
CPLErr CPL_STDCALL GDALClose(GDALDatasetH hDS)
4695
4696
0
{
4697
0
    return GDALCloseEx(hDS, nullptr, nullptr);
4698
0
}
4699
4700
/************************************************************************/
4701
/*                            GDALCloseEx()                             */
4702
/************************************************************************/
4703
4704
/**
4705
 * \brief Close GDAL dataset.
4706
 *
4707
 * For non-shared datasets (opened with GDALOpen()) the dataset is closed
4708
 * using the C++ "delete" operator, recovering all dataset related resources.
4709
 * For shared datasets (opened with GDALOpenShared()) the dataset is
4710
 * dereferenced, and closed only if the referenced count has dropped below 1.
4711
 *
4712
 * This function may report progress if a progress
4713
 * callback if provided in the pfnProgress argument and if the dataset returns
4714
 * true for GDALDataset::GetCloseReportsProgress()
4715
4716
 * @param hDS The dataset to close, or nullptr
4717
 * @param pfnProgress Progress callback, or nullptr
4718
 * @param pProgressData User data of progress callback, or nullptr
4719
 *
4720
 * @return CE_None in case of success. On a
4721
 * shared dataset whose reference count is not dropped below 1, CE_None will
4722
 * be returned.
4723
 *
4724
 * @since GDAL 3.13
4725
 * @see GDALClose()
4726
 */
4727
4728
CPLErr GDALCloseEx(GDALDatasetH hDS, GDALProgressFunc pfnProgress,
4729
                   void *pProgressData)
4730
0
{
4731
0
    if (!hDS)
4732
0
        return CE_None;
4733
4734
0
#ifdef OGRAPISPY_ENABLED
4735
0
    if (bOGRAPISpyEnabled)
4736
0
        OGRAPISpyPreClose(hDS);
4737
0
#endif
4738
4739
0
    GDALDataset *poDS = GDALDataset::FromHandle(hDS);
4740
4741
0
    if (poDS->GetShared())
4742
0
    {
4743
        /* --------------------------------------------------------------------
4744
         */
4745
        /*      If this file is in the shared dataset list then dereference */
4746
        /*      it, and only delete/remote it if the reference count has */
4747
        /*      dropped to zero. */
4748
        /* --------------------------------------------------------------------
4749
         */
4750
0
        if (poDS->Dereference() > 0)
4751
0
            return CE_None;
4752
0
    }
4753
4754
0
    CPLErr eErr = poDS->Close(pfnProgress, pProgressData);
4755
0
    delete poDS;
4756
4757
0
#ifdef OGRAPISPY_ENABLED
4758
0
    if (bOGRAPISpyEnabled)
4759
0
        OGRAPISpyPostClose();
4760
0
#endif
4761
0
    return eErr;
4762
0
}
4763
4764
/************************************************************************/
4765
/*                        GDALDumpOpenDataset()                         */
4766
/************************************************************************/
4767
4768
static int GDALDumpOpenSharedDatasetsForeach(void *elt, void *user_data)
4769
0
{
4770
0
    SharedDatasetCtxt *psStruct = static_cast<SharedDatasetCtxt *>(elt);
4771
0
    FILE *fp = static_cast<FILE *>(user_data);
4772
0
    GDALDataset *poDS = psStruct->poDS;
4773
4774
0
    const char *pszDriverName = poDS->GetDriver() == nullptr
4775
0
                                    ? "DriverIsNULL"
4776
0
                                    : poDS->GetDriver()->GetDescription();
4777
4778
0
    poDS->Reference();
4779
0
    CPL_IGNORE_RET_VAL(
4780
0
        VSIFPrintf(fp, "  %d %c %-6s %7d %dx%dx%d %s\n", poDS->Dereference(),
4781
0
                   poDS->GetShared() ? 'S' : 'N', pszDriverName,
4782
0
                   static_cast<int>(psStruct->nPID), poDS->GetRasterXSize(),
4783
0
                   poDS->GetRasterYSize(), poDS->GetRasterCount(),
4784
0
                   poDS->GetDescription()));
4785
4786
0
    return TRUE;
4787
0
}
4788
4789
static int GDALDumpOpenDatasetsForeach(GDALDataset *poDS, FILE *fp)
4790
0
{
4791
4792
    // Don't list shared datasets. They have already been listed by
4793
    // GDALDumpOpenSharedDatasetsForeach.
4794
0
    if (poDS->GetShared())
4795
0
        return TRUE;
4796
4797
0
    const char *pszDriverName = poDS->GetDriver() == nullptr
4798
0
                                    ? "DriverIsNULL"
4799
0
                                    : poDS->GetDriver()->GetDescription();
4800
4801
0
    poDS->Reference();
4802
0
    CPL_IGNORE_RET_VAL(
4803
0
        VSIFPrintf(fp, "  %d %c %-6s %7d %dx%dx%d %s\n", poDS->Dereference(),
4804
0
                   poDS->GetShared() ? 'S' : 'N', pszDriverName, -1,
4805
0
                   poDS->GetRasterXSize(), poDS->GetRasterYSize(),
4806
0
                   poDS->GetRasterCount(), poDS->GetDescription()));
4807
4808
0
    return TRUE;
4809
0
}
4810
4811
/**
4812
 * \brief List open datasets.
4813
 *
4814
 * Dumps a list of all open datasets (shared or not) to the indicated
4815
 * text file (may be stdout or stderr).   This function is primarily intended
4816
 * to assist in debugging "dataset leaks" and reference counting issues.
4817
 * The information reported includes the dataset name, referenced count,
4818
 * shared status, driver name, size, and band count.
4819
 */
4820
4821
int CPL_STDCALL GDALDumpOpenDatasets(FILE *fp)
4822
4823
0
{
4824
0
    VALIDATE_POINTER1(fp, "GDALDumpOpenDatasets", 0);
4825
4826
0
    CPLMutexHolderD(&hDLMutex);
4827
4828
0
    if (poAllDatasetMap == nullptr)
4829
0
        return 0;
4830
4831
0
    CPL_IGNORE_RET_VAL(VSIFPrintf(fp, "Open GDAL Datasets:\n"));
4832
4833
0
    for (const auto &oIter : *poAllDatasetMap)
4834
0
    {
4835
0
        GDALDumpOpenDatasetsForeach(oIter.first, fp);
4836
0
    }
4837
4838
0
    if (phSharedDatasetSet != nullptr)
4839
0
    {
4840
0
        CPLHashSetForeach(phSharedDatasetSet, GDALDumpOpenSharedDatasetsForeach,
4841
0
                          fp);
4842
0
    }
4843
0
    return static_cast<int>(poAllDatasetMap->size());
4844
0
}
4845
4846
/************************************************************************/
4847
/*                          BeginAsyncReader()                          */
4848
/************************************************************************/
4849
4850
/**
4851
 * \brief Sets up an asynchronous data request
4852
 *
4853
 * This method establish an asynchronous raster read request for the
4854
 * indicated window on the dataset into the indicated buffer.  The parameters
4855
 * for windowing, buffer size, buffer type and buffer organization are similar
4856
 * to those for GDALDataset::RasterIO(); however, this call only launches
4857
 * the request and filling the buffer is accomplished via calls to
4858
 * GetNextUpdatedRegion() on the return GDALAsyncReader session object.
4859
 *
4860
 * Once all processing for the created session is complete, or if no further
4861
 * refinement of the request is required, the GDALAsyncReader object should
4862
 * be destroyed with the GDALDataset::EndAsyncReader() method.
4863
 *
4864
 * Note that the data buffer (pData) will potentially continue to be
4865
 * updated as long as the session lives, but it is not deallocated when
4866
 * the session (GDALAsyncReader) is destroyed with EndAsyncReader().  It
4867
 * should be deallocated by the application at that point.
4868
 *
4869
 * Additional information on asynchronous IO in GDAL may be found at:
4870
 *   https://gdal.org/development/rfc/rfc24_progressive_data_support.html
4871
 *
4872
 * This method is the same as the C GDALBeginAsyncReader() function.
4873
 *
4874
 * @param nXOff The pixel offset to the top left corner of the region
4875
 * of the band to be accessed.  This would be zero to start from the left side.
4876
 *
4877
 * @param nYOff The line offset to the top left corner of the region
4878
 * of the band to be accessed.  This would be zero to start from the top.
4879
 *
4880
 * @param nXSize The width of the region of the band to be accessed in pixels.
4881
 *
4882
 * @param nYSize The height of the region of the band to be accessed in lines.
4883
 *
4884
 * @param pBuf The buffer into which the data should be read. This buffer must
4885
 * contain at least nBufXSize * nBufYSize * nBandCount words of type eBufType.
4886
 * It is organized in left to right,top to bottom pixel order.  Spacing is
4887
 * controlled by the nPixelSpace, and nLineSpace parameters.
4888
 *
4889
 * @param nBufXSize the width of the buffer image into which the desired region
4890
 * is to be read, or from which it is to be written.
4891
 *
4892
 * @param nBufYSize the height of the buffer image into which the desired
4893
 * region is to be read, or from which it is to be written.
4894
 *
4895
 * @param eBufType the type of the pixel values in the pData data buffer.  The
4896
 * pixel values will automatically be translated to/from the GDALRasterBand
4897
 * data type as needed.
4898
 *
4899
 * @param nBandCount the number of bands being read or written.
4900
 *
4901
 * @param panBandMap the list of nBandCount band numbers being read/written.
4902
 * Note band numbers are 1 based.   This may be NULL to select the first
4903
 * nBandCount bands.
4904
 *
4905
 * @param nPixelSpace The byte offset from the start of one pixel value in
4906
 * pData to the start of the next pixel value within a scanline.  If defaulted
4907
 * (0) the size of the datatype eBufType is used.
4908
 *
4909
 * @param nLineSpace The byte offset from the start of one scanline in
4910
 * pData to the start of the next.  If defaulted the size of the datatype
4911
 * eBufType * nBufXSize is used.
4912
 *
4913
 * @param nBandSpace the byte offset from the start of one bands data to the
4914
 * start of the next.  If defaulted (zero) the value will be
4915
 * nLineSpace * nBufYSize implying band sequential organization
4916
 * of the data buffer.
4917
 *
4918
 * @param papszOptions Driver specific control options in a string list or NULL.
4919
 * Consult driver documentation for options supported.
4920
 *
4921
 * @return The GDALAsyncReader object representing the request.
4922
 */
4923
4924
GDALAsyncReader *GDALDataset::BeginAsyncReader(
4925
    int nXOff, int nYOff, int nXSize, int nYSize, void *pBuf, int nBufXSize,
4926
    int nBufYSize, GDALDataType eBufType, int nBandCount, int *panBandMap,
4927
    int nPixelSpace, int nLineSpace, int nBandSpace, CSLConstList papszOptions)
4928
0
{
4929
    // See gdaldefaultasync.cpp
4930
4931
0
    return GDALGetDefaultAsyncReader(this, nXOff, nYOff, nXSize, nYSize, pBuf,
4932
0
                                     nBufXSize, nBufYSize, eBufType, nBandCount,
4933
0
                                     panBandMap, nPixelSpace, nLineSpace,
4934
0
                                     nBandSpace, papszOptions);
4935
0
}
4936
4937
/************************************************************************/
4938
/*                        GDALBeginAsyncReader()                        */
4939
/************************************************************************/
4940
4941
/**
4942
 * \brief Sets up an asynchronous data request
4943
 *
4944
 * This method establish an asynchronous raster read request for the
4945
 * indicated window on the dataset into the indicated buffer.  The parameters
4946
 * for windowing, buffer size, buffer type and buffer organization are similar
4947
 * to those for GDALDataset::RasterIO(); however, this call only launches
4948
 * the request and filling the buffer is accomplished via calls to
4949
 * GetNextUpdatedRegion() on the return GDALAsyncReader session object.
4950
 *
4951
 * Once all processing for the created session is complete, or if no further
4952
 * refinement of the request is required, the GDALAsyncReader object should
4953
 * be destroyed with the GDALDataset::EndAsyncReader() method.
4954
 *
4955
 * Note that the data buffer (pData) will potentially continue to be
4956
 * updated as long as the session lives, but it is not deallocated when
4957
 * the session (GDALAsyncReader) is destroyed with EndAsyncReader().  It
4958
 * should be deallocated by the application at that point.
4959
 *
4960
 * Additional information on asynchronous IO in GDAL may be found at:
4961
 *   https://gdal.org/development/rfc/rfc24_progressive_data_support.html
4962
 *
4963
 * This method is the same as the C++ GDALDataset::BeginAsyncReader() method.
4964
 *
4965
 * @param hDS handle to the dataset object.
4966
 *
4967
 * @param nXOff The pixel offset to the top left corner of the region
4968
 * of the band to be accessed.  This would be zero to start from the left side.
4969
 *
4970
 * @param nYOff The line offset to the top left corner of the region
4971
 * of the band to be accessed.  This would be zero to start from the top.
4972
 *
4973
 * @param nXSize The width of the region of the band to be accessed in pixels.
4974
 *
4975
 * @param nYSize The height of the region of the band to be accessed in lines.
4976
 *
4977
 * @param pBuf The buffer into which the data should be read. This buffer must
4978
 * contain at least nBufXSize * nBufYSize * nBandCount words of type eBufType.
4979
 * It is organized in left to right,top to bottom pixel order.  Spacing is
4980
 * controlled by the nPixelSpace, and nLineSpace parameters.
4981
 *
4982
 * @param nBufXSize the width of the buffer image into which the desired region
4983
 * is to be read, or from which it is to be written.
4984
 *
4985
 * @param nBufYSize the height of the buffer image into which the desired
4986
 * region is to be read, or from which it is to be written.
4987
 *
4988
 * @param eBufType the type of the pixel values in the pData data buffer.  The
4989
 * pixel values will automatically be translated to/from the GDALRasterBand
4990
 * data type as needed.
4991
 *
4992
 * @param nBandCount the number of bands being read or written.
4993
 *
4994
 * @param panBandMap the list of nBandCount band numbers being read/written.
4995
 * Note band numbers are 1 based.   This may be NULL to select the first
4996
 * nBandCount bands.
4997
 *
4998
 * @param nPixelSpace The byte offset from the start of one pixel value in
4999
 * pData to the start of the next pixel value within a scanline.  If defaulted
5000
 * (0) the size of the datatype eBufType is used.
5001
 *
5002
 * @param nLineSpace The byte offset from the start of one scanline in
5003
 * pData to the start of the next.  If defaulted the size of the datatype
5004
 * eBufType * nBufXSize is used.
5005
 *
5006
 * @param nBandSpace the byte offset from the start of one bands data to the
5007
 * start of the next.  If defaulted (zero) the value will be
5008
 * nLineSpace * nBufYSize implying band sequential organization
5009
 * of the data buffer.
5010
 *
5011
 * @param papszOptions Driver specific control options in a string list or NULL.
5012
 * Consult driver documentation for options supported.
5013
 *
5014
 * @return handle representing the request.
5015
 */
5016
5017
GDALAsyncReaderH CPL_STDCALL GDALBeginAsyncReader(
5018
    GDALDatasetH hDS, int nXOff, int nYOff, int nXSize, int nYSize, void *pBuf,
5019
    int nBufXSize, int nBufYSize, GDALDataType eBufType, int nBandCount,
5020
    int *panBandMap, int nPixelSpace, int nLineSpace, int nBandSpace,
5021
    CSLConstList papszOptions)
5022
5023
0
{
5024
0
    VALIDATE_POINTER1(hDS, "GDALDataset", nullptr);
5025
0
    return static_cast<GDALAsyncReaderH>(
5026
0
        GDALDataset::FromHandle(hDS)->BeginAsyncReader(
5027
0
            nXOff, nYOff, nXSize, nYSize, pBuf, nBufXSize, nBufYSize, eBufType,
5028
0
            nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace,
5029
0
            const_cast<char **>(papszOptions)));
5030
0
}
5031
5032
/************************************************************************/
5033
/*                           EndAsyncReader()                           */
5034
/************************************************************************/
5035
5036
/**
5037
 * End asynchronous request.
5038
 *
5039
 * This method destroys an asynchronous io request and recovers all
5040
 * resources associated with it.
5041
 *
5042
 * This method is the same as the C function GDALEndAsyncReader().
5043
 *
5044
 * @param poARIO pointer to a GDALAsyncReader
5045
 */
5046
5047
void GDALDataset::EndAsyncReader(GDALAsyncReader *poARIO)
5048
0
{
5049
0
    delete poARIO;
5050
0
}
5051
5052
/************************************************************************/
5053
/*                         GDALEndAsyncReader()                         */
5054
/************************************************************************/
5055
5056
/**
5057
 * End asynchronous request.
5058
 *
5059
 * This method destroys an asynchronous io request and recovers all
5060
 * resources associated with it.
5061
 *
5062
 * This method is the same as the C++ method GDALDataset::EndAsyncReader().
5063
 *
5064
 * @param hDS handle to the dataset object.
5065
 * @param hAsyncReaderH handle returned by GDALBeginAsyncReader()
5066
 */
5067
5068
void CPL_STDCALL GDALEndAsyncReader(GDALDatasetH hDS,
5069
                                    GDALAsyncReaderH hAsyncReaderH)
5070
0
{
5071
0
    VALIDATE_POINTER0(hDS, "GDALDataset");
5072
0
    VALIDATE_POINTER0(hAsyncReaderH, "GDALAsyncReader");
5073
0
    GDALDataset::FromHandle(hDS)->EndAsyncReader(
5074
0
        static_cast<GDALAsyncReader *>(hAsyncReaderH));
5075
0
}
5076
5077
/************************************************************************/
5078
/*                       CloseDependentDatasets()                       */
5079
/************************************************************************/
5080
5081
/**
5082
 * Drop references to any other datasets referenced by this dataset.
5083
 *
5084
 * This method should release any reference to other datasets (e.g. a VRT
5085
 * dataset to its sources), but not close the current dataset itself.
5086
 *
5087
 * If at least, one reference to a dependent dataset has been dropped,
5088
 * this method should return TRUE. Otherwise it *should* return FALSE.
5089
 * (Failure to return the proper value might result in infinite loop)
5090
 *
5091
 * This method can be called several times on a given dataset. After
5092
 * the first time, it should not do anything and return FALSE.
5093
 *
5094
 * The driver implementation may choose to destroy its raster bands,
5095
 * so be careful not to call any method on the raster bands afterwards.
5096
 *
5097
 * Basically the only safe action you can do after calling
5098
 * CloseDependentDatasets() is to call the destructor.
5099
 *
5100
 * Note: the only legitimate caller of CloseDependentDatasets() is
5101
 * GDALDriverManager::~GDALDriverManager()
5102
 *
5103
 * @return TRUE if at least one reference to another dataset has been dropped.
5104
 */
5105
int GDALDataset::CloseDependentDatasets()
5106
0
{
5107
0
    return oOvManager.CloseDependentDatasets();
5108
0
}
5109
5110
/************************************************************************/
5111
/*                            ReportError()                             */
5112
/************************************************************************/
5113
5114
#ifndef DOXYGEN_XML
5115
/**
5116
 * \brief Emits an error related to a dataset.
5117
 *
5118
 * This function is a wrapper for regular CPLError(). The only difference
5119
 * with CPLError() is that it prepends the error message with the dataset
5120
 * name.
5121
 *
5122
 * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
5123
 * @param err_no the error number (CPLE_*) from cpl_error.h.
5124
 * @param fmt a printf() style format string.  Any additional arguments
5125
 * will be treated as arguments to fill in this format in a manner
5126
 * similar to printf().
5127
 *
5128
 */
5129
5130
void GDALDataset::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
5131
                              const char *fmt, ...) const
5132
0
{
5133
0
    va_list args;
5134
0
    va_start(args, fmt);
5135
0
    ReportErrorV(GetDescription(), eErrClass, err_no, fmt, args);
5136
0
    va_end(args);
5137
0
}
5138
5139
/**
5140
 * \brief Emits an error related to a dataset (static method)
5141
 *
5142
 * This function is a wrapper for regular CPLError(). The only difference
5143
 * with CPLError() is that it prepends the error message with the dataset
5144
 * name.
5145
 *
5146
 * @param pszDSName dataset name.
5147
 * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
5148
 * @param err_no the error number (CPLE_*) from cpl_error.h.
5149
 * @param fmt a printf() style format string.  Any additional arguments
5150
 * will be treated as arguments to fill in this format in a manner
5151
 * similar to printf().
5152
 *
5153
 * @since GDAL 3.2.0
5154
 */
5155
5156
void GDALDataset::ReportError(const char *pszDSName, CPLErr eErrClass,
5157
                              CPLErrorNum err_no, const char *fmt, ...)
5158
0
{
5159
0
    va_list args;
5160
0
    va_start(args, fmt);
5161
0
    ReportErrorV(pszDSName, eErrClass, err_no, fmt, args);
5162
0
    va_end(args);
5163
0
}
5164
5165
void GDALDataset::ReportErrorV(const char *pszDSName, CPLErr eErrClass,
5166
                               CPLErrorNum err_no, const char *fmt,
5167
                               va_list args)
5168
0
{
5169
0
    pszDSName = CPLGetFilename(pszDSName);
5170
0
    if (pszDSName[0] != '\0')
5171
0
    {
5172
0
        CPLError(eErrClass, err_no, "%s",
5173
0
                 std::string(pszDSName)
5174
0
                     .append(": ")
5175
0
                     .append(CPLString().vPrintf(fmt, args))
5176
0
                     .c_str());
5177
0
    }
5178
0
    else
5179
0
    {
5180
0
        CPLErrorV(eErrClass, err_no, fmt, args);
5181
0
    }
5182
0
}
5183
#endif
5184
5185
/************************************************************************/
5186
/*                            GetMetadata()                             */
5187
/************************************************************************/
5188
CSLConstList GDALDataset::GetMetadata(const char *pszDomain)
5189
0
{
5190
#ifndef WITHOUT_DERIVED
5191
    if (pszDomain != nullptr && EQUAL(pszDomain, "DERIVED_SUBDATASETS"))
5192
    {
5193
        oDerivedMetadataList.Clear();
5194
5195
        // First condition: at least one raster band.
5196
        if (GetRasterCount() > 0)
5197
        {
5198
            // Check if there is at least one complex band.
5199
            bool hasAComplexBand = false;
5200
5201
            for (int rasterId = 1; rasterId <= GetRasterCount(); ++rasterId)
5202
            {
5203
                if (GDALDataTypeIsComplex(
5204
                        GetRasterBand(rasterId)->GetRasterDataType()))
5205
                {
5206
                    hasAComplexBand = true;
5207
                    break;
5208
                }
5209
            }
5210
5211
            unsigned int nbSupportedDerivedDS = 0;
5212
            const DerivedDatasetDescription *poDDSDesc =
5213
                GDALGetDerivedDatasetDescriptions(&nbSupportedDerivedDS);
5214
5215
            int nNumDataset = 1;
5216
            for (unsigned int derivedId = 0; derivedId < nbSupportedDerivedDS;
5217
                 ++derivedId)
5218
            {
5219
                if (hasAComplexBand ||
5220
                    CPLString(poDDSDesc[derivedId].pszInputPixelType) !=
5221
                        "complex")
5222
                {
5223
                    oDerivedMetadataList.SetNameValue(
5224
                        CPLSPrintf("DERIVED_SUBDATASET_%d_NAME", nNumDataset),
5225
                        CPLSPrintf("DERIVED_SUBDATASET:%s:%s",
5226
                                   poDDSDesc[derivedId].pszDatasetName,
5227
                                   GetDescription()));
5228
5229
                    CPLString osDesc(
5230
                        CPLSPrintf("%s from %s",
5231
                                   poDDSDesc[derivedId].pszDatasetDescription,
5232
                                   GetDescription()));
5233
                    oDerivedMetadataList.SetNameValue(
5234
                        CPLSPrintf("DERIVED_SUBDATASET_%d_DESC", nNumDataset),
5235
                        osDesc.c_str());
5236
5237
                    nNumDataset++;
5238
                }
5239
            }
5240
        }
5241
        return oDerivedMetadataList.List();
5242
    }
5243
#endif
5244
5245
0
    return GDALMajorObject::GetMetadata(pszDomain);
5246
0
}
5247
5248
// clang-format off
5249
5250
/**
5251
 * \fn GDALDataset::SetMetadata( char ** papszMetadata, const char * pszDomain)
5252
 * \brief Set metadata.
5253
 *
5254
 * CAUTION: depending on the format, older values of the updated information
5255
 * might still be found in the file in a "ghost" state, even if no longer
5256
 * accessible through the GDAL API. This is for example the case of the GTiff
5257
 * format (this is not a exhaustive list)
5258
 *
5259
 * The C function GDALSetMetadata() does the same thing as this method.
5260
 *
5261
 * @param papszMetadata the metadata in name=value string list format to
5262
 * apply.
5263
 * @param pszDomain the domain of interest.  Use "" or NULL for the default
5264
 * domain.
5265
 * @return CE_None on success, CE_Failure on failure and CE_Warning if the
5266
 * metadata has been accepted, but is likely not maintained persistently
5267
 * by the underlying object between sessions.
5268
 */
5269
5270
/**
5271
 * \fn GDALDataset::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
5272
 * \brief Set single metadata item.
5273
 *
5274
 * CAUTION: depending on the format, older values of the updated information
5275
 * might still be found in the file in a "ghost" state, even if no longer
5276
 * accessible through the GDAL API. This is for example the case of the GTiff
5277
 * format (this is not a exhaustive list)
5278
 *
5279
 * The C function GDALSetMetadataItem() does the same thing as this method.
5280
 *
5281
 * @param pszName the key for the metadata item to fetch.
5282
 * @param pszValue the value to assign to the key.
5283
 * @param pszDomain the domain to set within, use NULL for the default domain.
5284
 *
5285
 * @return CE_None on success, or an error code on failure.
5286
 */
5287
5288
// clang-format on
5289
5290
/************************************************************************/
5291
/*                       GetMetadataDomainList()                        */
5292
/************************************************************************/
5293
5294
char **GDALDataset::GetMetadataDomainList()
5295
0
{
5296
0
    char **currentDomainList = CSLDuplicate(oMDMD.GetDomainList());
5297
5298
    // Ensure that we do not duplicate DERIVED domain.
5299
0
    if (GetRasterCount() > 0 &&
5300
0
        CSLFindString(currentDomainList, "DERIVED_SUBDATASETS") == -1)
5301
0
    {
5302
0
        currentDomainList =
5303
0
            CSLAddString(currentDomainList, "DERIVED_SUBDATASETS");
5304
0
    }
5305
0
    return currentDomainList;
5306
0
}
5307
5308
/************************************************************************/
5309
/*                           GetDriverName()                            */
5310
/************************************************************************/
5311
5312
/** Return driver name.
5313
 * @return driver name.
5314
 */
5315
const char *GDALDataset::GetDriverName() const
5316
0
{
5317
0
    if (poDriver)
5318
0
        return poDriver->GetDescription();
5319
0
    return "";
5320
0
}
5321
5322
/************************************************************************/
5323
/*                    GDALDatasetReleaseResultSet()                     */
5324
/************************************************************************/
5325
5326
/**
5327
 \brief Release results of ExecuteSQL().
5328
5329
 This function should only be used to deallocate OGRLayers resulting from
5330
 an ExecuteSQL() call on the same GDALDataset.  Failure to deallocate a
5331
 results set before destroying the GDALDataset may cause errors.
5332
5333
 This function is the same as the C++ method GDALDataset::ReleaseResultSet()
5334
5335
5336
 @param hDS the dataset handle.
5337
 @param hLayer the result of a previous ExecuteSQL() call.
5338
5339
*/
5340
void GDALDatasetReleaseResultSet(GDALDatasetH hDS, OGRLayerH hLayer)
5341
5342
0
{
5343
0
    VALIDATE_POINTER0(hDS, "GDALDatasetReleaseResultSet");
5344
5345
0
#ifdef OGRAPISPY_ENABLED
5346
0
    if (bOGRAPISpyEnabled)
5347
0
        OGRAPISpy_DS_ReleaseResultSet(hDS, hLayer);
5348
0
#endif
5349
5350
0
    GDALDataset::FromHandle(hDS)->ReleaseResultSet(
5351
0
        OGRLayer::FromHandle(hLayer));
5352
0
}
5353
5354
/************************************************************************/
5355
/*                      GDALDatasetGetLayerCount()                      */
5356
/************************************************************************/
5357
5358
/**
5359
 \brief Get the number of layers in this dataset.
5360
5361
 This function is the same as the C++ method GDALDataset::GetLayerCount()
5362
5363
5364
 @param hDS the dataset handle.
5365
 @return layer count.
5366
*/
5367
5368
int GDALDatasetGetLayerCount(GDALDatasetH hDS)
5369
5370
0
{
5371
0
    VALIDATE_POINTER1(hDS, "GDALDatasetH", 0);
5372
5373
0
#ifdef OGRAPISPY_ENABLED
5374
0
    if (bOGRAPISpyEnabled)
5375
0
        OGRAPISpy_DS_GetLayerCount(reinterpret_cast<GDALDatasetH>(hDS));
5376
0
#endif
5377
5378
0
    return GDALDataset::FromHandle(hDS)->GetLayerCount();
5379
0
}
5380
5381
/************************************************************************/
5382
/*                        GDALDatasetGetLayer()                         */
5383
/************************************************************************/
5384
5385
/**
5386
 \brief Fetch a layer by index.
5387
5388
 The returned layer remains owned by the
5389
 GDALDataset and should not be deleted by the application.
5390
5391
 This function is the same as the C++ method GDALDataset::GetLayer()
5392
5393
5394
 @param hDS the dataset handle.
5395
 @param iLayer a layer number between 0 and GetLayerCount()-1.
5396
5397
 @return the layer, or NULL if iLayer is out of range or an error occurs.
5398
*/
5399
5400
OGRLayerH GDALDatasetGetLayer(GDALDatasetH hDS, int iLayer)
5401
5402
0
{
5403
0
    VALIDATE_POINTER1(hDS, "GDALDatasetGetLayer", nullptr);
5404
5405
0
    OGRLayerH hLayer =
5406
0
        OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->GetLayer(iLayer));
5407
5408
0
#ifdef OGRAPISPY_ENABLED
5409
0
    if (bOGRAPISpyEnabled)
5410
0
        OGRAPISpy_DS_GetLayer(hDS, iLayer, hLayer);
5411
0
#endif
5412
5413
0
    return hLayer;
5414
0
}
5415
5416
/************************************************************************/
5417
/*                     GDALDatasetGetLayerByName()                      */
5418
/************************************************************************/
5419
5420
/**
5421
 \brief Fetch a layer by name.
5422
5423
 The returned layer remains owned by the
5424
 GDALDataset and should not be deleted by the application.
5425
5426
 This function is the same as the C++ method GDALDataset::GetLayerByName()
5427
5428
5429
 @param hDS the dataset handle.
5430
 @param pszName the layer name of the layer to fetch.
5431
5432
 @return the layer, or NULL if Layer is not found or an error occurs.
5433
*/
5434
5435
OGRLayerH GDALDatasetGetLayerByName(GDALDatasetH hDS, const char *pszName)
5436
5437
0
{
5438
0
    VALIDATE_POINTER1(hDS, "GDALDatasetGetLayerByName", nullptr);
5439
5440
0
    OGRLayerH hLayer = OGRLayer::ToHandle(
5441
0
        GDALDataset::FromHandle(hDS)->GetLayerByName(pszName));
5442
5443
0
#ifdef OGRAPISPY_ENABLED
5444
0
    if (bOGRAPISpyEnabled)
5445
0
        OGRAPISpy_DS_GetLayerByName(hDS, pszName, hLayer);
5446
0
#endif
5447
5448
0
    return hLayer;
5449
0
}
5450
5451
/************************************************************************/
5452
/*                     GDALDatasetIsLayerPrivate()                      */
5453
/************************************************************************/
5454
5455
/**
5456
 \brief Returns true if the layer at the specified index is deemed a private or
5457
 system table, or an internal detail only.
5458
5459
 This function is the same as the C++ method GDALDataset::IsLayerPrivate()
5460
5461
 @since GDAL 3.4
5462
5463
 @param hDS the dataset handle.
5464
 @param iLayer a layer number between 0 and GetLayerCount()-1.
5465
5466
 @return true if the layer is a private or system table.
5467
*/
5468
5469
int GDALDatasetIsLayerPrivate(GDALDatasetH hDS, int iLayer)
5470
5471
0
{
5472
0
    VALIDATE_POINTER1(hDS, "GDALDatasetIsLayerPrivate", false);
5473
5474
0
    const bool res = GDALDataset::FromHandle(hDS)->IsLayerPrivate(iLayer);
5475
5476
0
    return res ? 1 : 0;
5477
0
}
5478
5479
/************************************************************************/
5480
/*                           GetLayerIndex()                            */
5481
/************************************************************************/
5482
5483
/**
5484
 \brief Returns the index of the layer specified by name.
5485
5486
 @since GDAL 3.12
5487
5488
 @param pszName layer name (not NULL)
5489
5490
 @return an index >= 0, or -1 if not found.
5491
*/
5492
5493
int GDALDataset::GetLayerIndex(const char *pszName) const
5494
0
{
5495
0
    const int nLayerCount = GetLayerCount();
5496
0
    int iMatch = -1;
5497
0
    for (int i = 0; i < nLayerCount; ++i)
5498
0
    {
5499
0
        if (const auto poLayer = GetLayer(i))
5500
0
        {
5501
0
            const char *pszLayerName = poLayer->GetDescription();
5502
0
            if (strcmp(pszName, pszLayerName) == 0)
5503
0
            {
5504
0
                iMatch = i;
5505
0
                break;
5506
0
            }
5507
0
            else if (EQUAL(pszName, pszLayerName))
5508
0
            {
5509
0
                iMatch = i;
5510
0
            }
5511
0
        }
5512
0
    }
5513
0
    return iMatch;
5514
0
}
5515
5516
/************************************************************************/
5517
/*                       GDALDatasetDeleteLayer()                       */
5518
/************************************************************************/
5519
5520
/**
5521
 \brief Delete the indicated layer from the datasource.
5522
5523
 If this function is supported
5524
 the ODsCDeleteLayer capability will test TRUE on the GDALDataset.
5525
5526
 This method is the same as the C++ method GDALDataset::DeleteLayer().
5527
5528
5529
 @param hDS the dataset handle.
5530
 @param iLayer the index of the layer to delete.
5531
5532
 @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if deleting
5533
 layers is not supported for this datasource.
5534
5535
*/
5536
OGRErr GDALDatasetDeleteLayer(GDALDatasetH hDS, int iLayer)
5537
5538
0
{
5539
0
    VALIDATE_POINTER1(hDS, "GDALDatasetH", OGRERR_INVALID_HANDLE);
5540
5541
0
#ifdef OGRAPISPY_ENABLED
5542
0
    if (bOGRAPISpyEnabled)
5543
0
        OGRAPISpy_DS_DeleteLayer(hDS, iLayer);
5544
0
#endif
5545
5546
0
    return GDALDataset::FromHandle(hDS)->DeleteLayer(iLayer);
5547
0
}
5548
5549
/************************************************************************/
5550
/*                            CreateLayer()                             */
5551
/************************************************************************/
5552
5553
/**
5554
\brief This method attempts to create a new layer on the dataset with the
5555
indicated name, coordinate system, geometry type.
5556
5557
The papszOptions argument
5558
can be used to control driver specific creation options.  These options are
5559
normally documented in the format specific documentation.
5560
That function will try to validate the creation option list passed to the
5561
driver with the GDALValidateCreationOptions() method. This check can be
5562
disabled by defining the configuration option GDAL_VALIDATE_CREATION_OPTIONS set
5563
to NO.
5564
5565
Drivers should extend the ICreateLayer() method and not
5566
CreateLayer(). CreateLayer() adds validation of layer creation options, before
5567
delegating the actual work to ICreateLayer().
5568
5569
This method is the same as the C function GDALDatasetCreateLayer() and the
5570
deprecated OGR_DS_CreateLayer().
5571
5572
Example:
5573
5574
\code{.cpp}
5575
#include "gdal.h"
5576
#include "cpl_string.h"
5577
5578
...
5579
5580
        OGRLayer *poLayer;
5581
        char     **papszOptions;
5582
5583
        if( !poDS->TestCapability( ODsCCreateLayer ) )
5584
        {
5585
        ...
5586
        }
5587
5588
        papszOptions = CSLSetNameValue( papszOptions, "DIM", "2" );
5589
        poLayer = poDS->CreateLayer( "NewLayer", nullptr, wkbUnknown,
5590
                                     papszOptions );
5591
        CSLDestroy( papszOptions );
5592
5593
        if( poLayer == NULL )
5594
        {
5595
            ...
5596
        }
5597
\endcode
5598
5599
@param pszName the name for the new layer.  This should ideally not
5600
match any existing layer on the datasource.
5601
@param poSpatialRef the coordinate system to use for the new layer, or NULL if
5602
no coordinate system is available.
5603
@param eGType the geometry type for the layer.  Use wkbUnknown if there
5604
are no constraints on the types geometry to be written.
5605
@param papszOptions a StringList of name=value options.  Options are driver
5606
specific.
5607
5608
@return NULL is returned on failure, or a new OGRLayer handle on success.
5609
5610
*/
5611
5612
OGRLayer *GDALDataset::CreateLayer(const char *pszName,
5613
                                   const OGRSpatialReference *poSpatialRef,
5614
                                   OGRwkbGeometryType eGType,
5615
                                   CSLConstList papszOptions)
5616
5617
0
{
5618
0
    if (eGType == wkbNone)
5619
0
    {
5620
0
        return CreateLayer(pszName, nullptr, papszOptions);
5621
0
    }
5622
0
    else
5623
0
    {
5624
0
        OGRGeomFieldDefn oGeomFieldDefn("", eGType);
5625
0
        oGeomFieldDefn.SetSpatialRef(poSpatialRef);
5626
0
        return CreateLayer(pszName, &oGeomFieldDefn, papszOptions);
5627
0
    }
5628
0
}
5629
5630
/**
5631
\brief This method attempts to create a new layer on the dataset with the
5632
indicated name and geometry field definition.
5633
5634
When poGeomFieldDefn is not null, most drivers should honor
5635
poGeomFieldDefn->GetType() and poGeomFieldDefn->GetSpatialRef().
5636
Drivers that honor poGeomFieldDefn->GetCoordinatePrecision() will declare the
5637
GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability. Drivers may honor
5638
poGeomFieldDefn->GetNameRef() and poGeomFieldDefn->IsNullable(), but there are
5639
very few currently.
5640
5641
Note that even if a geometry coordinate precision is set and a driver honors the
5642
GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability, geometries passed to
5643
OGRLayer::CreateFeature() and OGRLayer::SetFeature() are assumed to be compatible
5644
with the coordinate precision. That is they are assumed to be valid once their
5645
coordinates are rounded to it. If it might not be the case, the user may set
5646
the OGR_APPLY_GEOM_SET_PRECISION configuration option before calling CreateFeature()
5647
or SetFeature() to force the OGRGeometry::SetPrecision() method to be called on
5648
the passed geometries.
5649
5650
The papszOptions argument
5651
can be used to control driver specific creation options. These options are
5652
normally documented in the format specific documentation.
5653
This function will try to validate the creation option list passed to the
5654
driver with the GDALValidateCreationOptions() method. This check can be
5655
disabled by defining the configuration option GDAL_VALIDATE_CREATION_OPTIONS set
5656
to NO.
5657
5658
Drivers should extend the ICreateLayer() method and not
5659
CreateLayer(). CreateLayer() adds validation of layer creation options, before
5660
delegating the actual work to ICreateLayer().
5661
5662
This method is the same as the C function GDALDatasetCreateLayerFromGeomFieldDefn().
5663
5664
@param pszName the name for the new layer.  This should ideally not
5665
match any existing layer on the datasource.
5666
@param poGeomFieldDefn the geometry field definition to use for the new layer,
5667
or NULL if there is no geometry field.
5668
@param papszOptions a StringList of name=value options.  Options are driver
5669
specific.
5670
5671
@return NULL is returned on failure, or a new OGRLayer handle on success.
5672
@since 3.9
5673
5674
*/
5675
5676
OGRLayer *GDALDataset::CreateLayer(const char *pszName,
5677
                                   const OGRGeomFieldDefn *poGeomFieldDefn,
5678
                                   CSLConstList papszOptions)
5679
5680
0
{
5681
0
    if (CPLTestBool(
5682
0
            CPLGetConfigOption("GDAL_VALIDATE_CREATION_OPTIONS", "YES")))
5683
0
    {
5684
0
        ValidateLayerCreationOptions(papszOptions);
5685
0
    }
5686
5687
0
    OGRLayer *poLayer;
5688
0
    if (poGeomFieldDefn)
5689
0
    {
5690
0
        OGRGeomFieldDefn oGeomFieldDefn(poGeomFieldDefn);
5691
0
        if (OGR_GT_IsNonLinear(poGeomFieldDefn->GetType()) &&
5692
0
            !TestCapability(ODsCCurveGeometries))
5693
0
        {
5694
0
            oGeomFieldDefn.SetType(
5695
0
                OGR_GT_GetLinear(poGeomFieldDefn->GetType()));
5696
0
        }
5697
5698
0
        poLayer = ICreateLayer(pszName, &oGeomFieldDefn, papszOptions);
5699
0
    }
5700
0
    else
5701
0
    {
5702
0
        poLayer = ICreateLayer(pszName, nullptr, papszOptions);
5703
0
    }
5704
0
#ifdef DEBUG
5705
0
    if (poLayer != nullptr && OGR_GT_IsNonLinear(poLayer->GetGeomType()) &&
5706
0
        !poLayer->TestCapability(OLCCurveGeometries))
5707
0
    {
5708
0
        CPLError(CE_Warning, CPLE_AppDefined,
5709
0
                 "Inconsistent driver: Layer geometry type is non-linear, but "
5710
0
                 "TestCapability(OLCCurveGeometries) returns FALSE.");
5711
0
    }
5712
0
#endif
5713
5714
0
    return poLayer;
5715
0
}
5716
5717
//! @cond Doxygen_Suppress
5718
5719
// Technical override to avoid ambiguous choice between the old and new
5720
// new CreateLayer() signatures.
5721
OGRLayer *GDALDataset::CreateLayer(const char *pszName)
5722
0
{
5723
0
    OGRGeomFieldDefn oGeomFieldDefn("", wkbUnknown);
5724
0
    return CreateLayer(pszName, &oGeomFieldDefn, nullptr);
5725
0
}
5726
5727
// Technical override to avoid ambiguous choice between the old and new
5728
// new CreateLayer() signatures.
5729
OGRLayer *GDALDataset::CreateLayer(const char *pszName, std::nullptr_t)
5730
0
{
5731
0
    OGRGeomFieldDefn oGeomFieldDefn("", wkbUnknown);
5732
0
    return CreateLayer(pszName, &oGeomFieldDefn, nullptr);
5733
0
}
5734
5735
//!@endcond
5736
5737
/************************************************************************/
5738
/*                       GDALDatasetCreateLayer()                       */
5739
/************************************************************************/
5740
5741
/**
5742
\brief This function attempts to create a new layer on the dataset with the
5743
indicated name, coordinate system, geometry type.
5744
5745
The papszOptions argument can be used to control driver specific creation
5746
options.  These options are normally documented in the format specific
5747
documentation.
5748
5749
This method is the same as the C++ method GDALDataset::CreateLayer().
5750
5751
Example:
5752
5753
\code{.c}
5754
#include "gdal.h"
5755
#include "cpl_string.h"
5756
5757
...
5758
5759
        OGRLayerH  hLayer;
5760
        char     **papszOptions;
5761
5762
        if( !GDALDatasetTestCapability( hDS, ODsCCreateLayer ) )
5763
        {
5764
        ...
5765
        }
5766
5767
        papszOptions = CSLSetNameValue( papszOptions, "DIM", "2" );
5768
        hLayer = GDALDatasetCreateLayer( hDS, "NewLayer", NULL, wkbUnknown,
5769
                                         papszOptions );
5770
        CSLDestroy( papszOptions );
5771
5772
        if( hLayer == NULL )
5773
        {
5774
            ...
5775
        }
5776
\endcode
5777
5778
5779
@param hDS the dataset handle
5780
@param pszName the name for the new layer.  This should ideally not
5781
match any existing layer on the datasource.
5782
@param hSpatialRef the coordinate system to use for the new layer, or NULL if
5783
no coordinate system is available.
5784
@param eGType the geometry type for the layer.  Use wkbUnknown if there
5785
are no constraints on the types geometry to be written.
5786
@param papszOptions a StringList of name=value options.  Options are driver
5787
specific.
5788
5789
@return NULL is returned on failure, or a new OGRLayer handle on success.
5790
5791
*/
5792
5793
OGRLayerH GDALDatasetCreateLayer(GDALDatasetH hDS, const char *pszName,
5794
                                 OGRSpatialReferenceH hSpatialRef,
5795
                                 OGRwkbGeometryType eGType,
5796
                                 CSLConstList papszOptions)
5797
5798
0
{
5799
0
    VALIDATE_POINTER1(hDS, "GDALDatasetCreateLayer", nullptr);
5800
5801
0
    if (pszName == nullptr)
5802
0
    {
5803
0
        CPLError(CE_Failure, CPLE_ObjectNull,
5804
0
                 "Name was NULL in GDALDatasetCreateLayer");
5805
0
        return nullptr;
5806
0
    }
5807
5808
0
    OGRLayerH hLayer =
5809
0
        OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->CreateLayer(
5810
0
            pszName, OGRSpatialReference::FromHandle(hSpatialRef), eGType,
5811
0
            const_cast<char **>(papszOptions)));
5812
5813
0
#ifdef OGRAPISPY_ENABLED
5814
0
    if (bOGRAPISpyEnabled)
5815
0
        OGRAPISpy_DS_CreateLayer(hDS, pszName, hSpatialRef, eGType,
5816
0
                                 const_cast<char **>(papszOptions), hLayer);
5817
0
#endif
5818
5819
0
    return hLayer;
5820
0
}
5821
5822
/************************************************************************/
5823
/*              GDALDatasetCreateLayerFromGeomFieldDefn()               */
5824
/************************************************************************/
5825
5826
/**
5827
\brief This function attempts to create a new layer on the dataset with the
5828
indicated name and geometry field.
5829
5830
When poGeomFieldDefn is not null, most drivers should honor
5831
poGeomFieldDefn->GetType() and poGeomFieldDefn->GetSpatialRef().
5832
Drivers that honor poGeomFieldDefn->GetCoordinatePrecision() will declare the
5833
GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability. Drivers may honor
5834
poGeomFieldDefn->GetNameRef() and poGeomFieldDefn->IsNullable(), but there are
5835
very few currently.
5836
5837
Note that even if a geometry coordinate precision is set and a driver honors the
5838
GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION capability, geometries passed to
5839
OGRLayer::CreateFeature() and OGRLayer::SetFeature() are assumed to be compatible
5840
with the coordinate precision. That is they are assumed to be valid once their
5841
coordinates are rounded to it. If it might not be the case, the user may set
5842
the OGR_APPLY_GEOM_SET_PRECISION configuration option before calling CreateFeature()
5843
or SetFeature() to force the OGRGeometry::SetPrecision() method to be called on
5844
the passed geometries.
5845
5846
The papszOptions argument can be used to control driver specific creation
5847
options.  These options are normally documented in the format specific
5848
documentation.
5849
5850
This method is the same as the C++ method GDALDataset::CreateLayer().
5851
5852
@param hDS the dataset handle
5853
@param pszName the name for the new layer.  This should ideally not
5854
match any existing layer on the datasource.
5855
@param hGeomFieldDefn the geometry field definition. May be NULL to indicate
5856
a non-spatial file (or if adding geometry fields later with OGR_L_CreateGeomField()
5857
for drivers supporting that interface).
5858
@param papszOptions a StringList of name=value options.  Options are driver
5859
specific.
5860
5861
@return NULL is returned on failure, or a new OGRLayer handle on success.
5862
5863
@since GDAL 3.9
5864
5865
*/
5866
5867
OGRLayerH
5868
GDALDatasetCreateLayerFromGeomFieldDefn(GDALDatasetH hDS, const char *pszName,
5869
                                        OGRGeomFieldDefnH hGeomFieldDefn,
5870
                                        CSLConstList papszOptions)
5871
5872
0
{
5873
0
    VALIDATE_POINTER1(hDS, "GDALDatasetCreateLayerFromGeomFieldDefn", nullptr);
5874
5875
0
    if (!pszName)
5876
0
    {
5877
0
        CPLError(CE_Failure, CPLE_ObjectNull,
5878
0
                 "Name was NULL in GDALDatasetCreateLayerFromGeomFieldDefn");
5879
0
        return nullptr;
5880
0
    }
5881
5882
0
    OGRLayerH hLayer =
5883
0
        OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->CreateLayer(
5884
0
            pszName, OGRGeomFieldDefn::FromHandle(hGeomFieldDefn),
5885
0
            papszOptions));
5886
0
    return hLayer;
5887
0
}
5888
5889
/************************************************************************/
5890
/*                        GDALDatasetCopyLayer()                        */
5891
/************************************************************************/
5892
5893
/**
5894
 \brief Duplicate an existing layer.
5895
5896
 This function creates a new layer, duplicate the field definitions of the
5897
 source layer and then duplicate each features of the source layer.
5898
 The papszOptions argument
5899
 can be used to control driver specific creation options.  These options are
5900
 normally documented in the format specific documentation.
5901
 The source layer may come from another dataset.
5902
5903
 This method is the same as the C++ method GDALDataset::CopyLayer()
5904
5905
5906
 @param hDS the dataset handle.
5907
 @param hSrcLayer source layer.
5908
 @param pszNewName the name of the layer to create.
5909
 @param papszOptions a StringList of name=value options.  Options are driver
5910
                     specific.
5911
5912
 @return a handle to the layer, or NULL if an error occurs.
5913
*/
5914
OGRLayerH GDALDatasetCopyLayer(GDALDatasetH hDS, OGRLayerH hSrcLayer,
5915
                               const char *pszNewName,
5916
                               CSLConstList papszOptions)
5917
5918
0
{
5919
0
    VALIDATE_POINTER1(hDS, "OGR_DS_CopyGDALDatasetCopyLayerLayer", nullptr);
5920
0
    VALIDATE_POINTER1(hSrcLayer, "GDALDatasetCopyLayer", nullptr);
5921
0
    VALIDATE_POINTER1(pszNewName, "GDALDatasetCopyLayer", nullptr);
5922
5923
0
    return OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->CopyLayer(
5924
0
        OGRLayer::FromHandle(hSrcLayer), pszNewName, papszOptions));
5925
0
}
5926
5927
/************************************************************************/
5928
/*                       GDALDatasetExecuteSQL()                        */
5929
/************************************************************************/
5930
5931
/**
5932
 \brief Execute an SQL statement against the data store.
5933
5934
 The result of an SQL query is either NULL for statements that are in error,
5935
 or that have no results set, or an OGRLayer pointer representing a results
5936
 set from the query.  Note that this OGRLayer is in addition to the layers
5937
 in the data store and must be destroyed with
5938
 ReleaseResultSet() before the dataset is closed
5939
 (destroyed).
5940
5941
 This method is the same as the C++ method GDALDataset::ExecuteSQL()
5942
5943
 For more information on the SQL dialect supported internally by OGR
5944
 review the <a href="https://gdal.org/user/ogr_sql_dialect.html">OGR SQL</a>
5945
 document.  Some drivers (i.e. Oracle and PostGIS) pass the SQL directly through
5946
 to the underlying RDBMS.
5947
5948
 Starting with OGR 1.10, the <a
5949
 href="https://gdal.org/user/sql_sqlite_dialect.html">SQLITE dialect</a> can
5950
 also be used.
5951
5952
5953
 @param hDS the dataset handle.
5954
 @param pszStatement the SQL statement to execute.
5955
 @param hSpatialFilter geometry which represents a spatial filter. Can be NULL.
5956
5957
 @param pszDialect allows control of the statement dialect. If set to NULL, the
5958
 OGR SQL engine will be used, except for RDBMS drivers that will use their
5959
 dedicated SQL engine, unless OGRSQL is explicitly passed as the
5960
 dialect. Starting with OGR 1.10, the SQLITE dialect can also be used.
5961
5962
 @return an OGRLayer containing the results of the query.  Deallocate with
5963
 GDALDatasetReleaseResultSet().
5964
5965
*/
5966
5967
OGRLayerH GDALDatasetExecuteSQL(GDALDatasetH hDS, const char *pszStatement,
5968
                                OGRGeometryH hSpatialFilter,
5969
                                const char *pszDialect)
5970
5971
0
{
5972
0
    VALIDATE_POINTER1(hDS, "GDALDatasetExecuteSQL", nullptr);
5973
5974
0
    OGRLayerH hLayer =
5975
0
        OGRLayer::ToHandle(GDALDataset::FromHandle(hDS)->ExecuteSQL(
5976
0
            pszStatement, OGRGeometry::FromHandle(hSpatialFilter), pszDialect));
5977
5978
0
#ifdef OGRAPISPY_ENABLED
5979
0
    if (bOGRAPISpyEnabled)
5980
0
        OGRAPISpy_DS_ExecuteSQL(hDS, pszStatement, hSpatialFilter, pszDialect,
5981
0
                                hLayer);
5982
0
#endif
5983
5984
0
    return hLayer;
5985
0
}
5986
5987
/************************************************************************/
5988
/*                        GDALDatasetAbortSQL()                         */
5989
/************************************************************************/
5990
5991
/**
5992
 \brief Abort any SQL statement running in the data store.
5993
5994
 This function can be safely called from any thread (pending that the dataset
5995
 object is still alive). Driver implementations will make sure that it can be
5996
 called in a thread-safe way.
5997
5998
 This might not be implemented by all drivers. At time of writing, only SQLite,
5999
 GPKG and PG drivers implement it
6000
6001
 This method is the same as the C++ method GDALDataset::AbortSQL()
6002
6003
 @since GDAL 3.2.0
6004
6005
 @param hDS the dataset handle.
6006
6007
 @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if AbortSQL
6008
 is not supported for this datasource. .
6009
6010
*/
6011
6012
OGRErr GDALDatasetAbortSQL(GDALDatasetH hDS)
6013
6014
0
{
6015
0
    VALIDATE_POINTER1(hDS, "GDALDatasetAbortSQL", OGRERR_FAILURE);
6016
0
    return GDALDataset::FromHandle(hDS)->AbortSQL();
6017
0
}
6018
6019
/************************************************************************/
6020
/*                      GDALDatasetGetStyleTable()                      */
6021
/************************************************************************/
6022
6023
/**
6024
 \brief Returns dataset style table.
6025
6026
 This function is the same as the C++ method GDALDataset::GetStyleTable()
6027
6028
6029
 @param hDS the dataset handle
6030
 @return handle to a style table which should not be modified or freed by the
6031
 caller.
6032
*/
6033
6034
OGRStyleTableH GDALDatasetGetStyleTable(GDALDatasetH hDS)
6035
6036
0
{
6037
0
    VALIDATE_POINTER1(hDS, "OGR_DS_GetStyleTable", nullptr);
6038
6039
0
    return reinterpret_cast<OGRStyleTableH>(
6040
0
        GDALDataset::FromHandle(hDS)->GetStyleTable());
6041
0
}
6042
6043
/************************************************************************/
6044
/*                  GDALDatasetSetStyleTableDirectly()                  */
6045
/************************************************************************/
6046
6047
/**
6048
 \brief Set dataset style table.
6049
6050
 This function operate exactly as GDALDatasetSetStyleTable() except that it
6051
 assumes ownership of the passed table.
6052
6053
 This function is the same as the C++ method
6054
 GDALDataset::SetStyleTableDirectly()
6055
6056
6057
 @param hDS the dataset handle
6058
 @param hStyleTable style table handle to set
6059
6060
*/
6061
6062
void GDALDatasetSetStyleTableDirectly(GDALDatasetH hDS,
6063
                                      OGRStyleTableH hStyleTable)
6064
6065
0
{
6066
0
    VALIDATE_POINTER0(hDS, "OGR_DS_SetStyleTableDirectly");
6067
6068
0
    GDALDataset::FromHandle(hDS)->SetStyleTableDirectly(
6069
0
        reinterpret_cast<OGRStyleTable *>(hStyleTable));
6070
0
}
6071
6072
/************************************************************************/
6073
/*                      GDALDatasetSetStyleTable()                      */
6074
/************************************************************************/
6075
6076
/**
6077
 \brief Set dataset style table.
6078
6079
 This function operate exactly as GDALDatasetSetStyleTableDirectly() except that
6080
 it assumes ownership of the passed table.
6081
6082
 This function is the same as the C++ method GDALDataset::SetStyleTable()
6083
6084
6085
 @param hDS the dataset handle
6086
 @param hStyleTable style table handle to set
6087
6088
*/
6089
6090
void GDALDatasetSetStyleTable(GDALDatasetH hDS, OGRStyleTableH hStyleTable)
6091
6092
0
{
6093
0
    VALIDATE_POINTER0(hDS, "OGR_DS_SetStyleTable");
6094
0
    VALIDATE_POINTER0(hStyleTable, "OGR_DS_SetStyleTable");
6095
6096
0
    GDALDataset::FromHandle(hDS)->SetStyleTable(
6097
0
        reinterpret_cast<OGRStyleTable *>(hStyleTable));
6098
0
}
6099
6100
/************************************************************************/
6101
/*                    ValidateLayerCreationOptions()                    */
6102
/************************************************************************/
6103
6104
//! @cond Doxygen_Suppress
6105
int GDALDataset::ValidateLayerCreationOptions(const char *const *papszLCO)
6106
0
{
6107
0
    const char *pszOptionList =
6108
0
        GetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST);
6109
0
    if (pszOptionList == nullptr && poDriver != nullptr)
6110
0
    {
6111
0
        pszOptionList =
6112
0
            poDriver->GetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST);
6113
0
    }
6114
0
    CPLString osDataset;
6115
0
    osDataset.Printf("dataset %s", GetDescription());
6116
0
    return GDALValidateOptions(pszOptionList, papszLCO, "layer creation option",
6117
0
                               osDataset);
6118
0
}
6119
6120
//! @endcond
6121
6122
/************************************************************************/
6123
/*                              Release()                               */
6124
/************************************************************************/
6125
6126
/**
6127
\brief Drop a reference to this dataset, and if the reference count drops to one
6128
close (destroy) the dataset.
6129
6130
This method is the same as the C function OGRReleaseDataSource().
6131
6132
@deprecated. Use GDALClose() instead
6133
6134
@return OGRERR_NONE on success or an error code.
6135
*/
6136
6137
OGRErr GDALDataset::Release()
6138
6139
0
{
6140
0
    ReleaseRef();
6141
0
    return OGRERR_NONE;
6142
0
}
6143
6144
/************************************************************************/
6145
/*                            GetRefCount()                             */
6146
/************************************************************************/
6147
6148
/**
6149
\brief Fetch reference count.
6150
6151
This method is the same as the C function OGR_DS_GetRefCount().
6152
6153
@return the current reference count for the datasource object itself.
6154
*/
6155
6156
int GDALDataset::GetRefCount() const
6157
0
{
6158
0
    return nRefCount;
6159
0
}
6160
6161
/************************************************************************/
6162
/*                         GetSummaryRefCount()                         */
6163
/************************************************************************/
6164
6165
/**
6166
\brief Fetch reference count of datasource and all owned layers.
6167
6168
This method is the same as the C function  OGR_DS_GetSummaryRefCount().
6169
6170
@deprecated
6171
6172
@return the current summary reference count for the datasource and its layers.
6173
*/
6174
6175
int GDALDataset::GetSummaryRefCount() const
6176
6177
0
{
6178
0
    CPLMutexHolderD(m_poPrivate ? &(m_poPrivate->hMutex) : nullptr);
6179
0
    int nSummaryCount = nRefCount;
6180
0
    GDALDataset *poUseThis = const_cast<GDALDataset *>(this);
6181
6182
0
    for (int iLayer = 0; iLayer < poUseThis->GetLayerCount(); ++iLayer)
6183
0
        nSummaryCount += poUseThis->GetLayer(iLayer)->GetRefCount();
6184
6185
0
    return nSummaryCount;
6186
0
}
6187
6188
/************************************************************************/
6189
/*                            ICreateLayer()                            */
6190
/************************************************************************/
6191
6192
/**
6193
 \brief This method attempts to create a new layer on the dataset with the
6194
 indicated name, coordinate system, geometry type.
6195
6196
 This method is reserved to implementation by drivers.
6197
6198
 The papszOptions argument can be used to control driver specific creation
6199
 options.  These options are normally documented in the format specific
6200
 documentation.
6201
6202
 @param pszName the name for the new layer.  This should ideally not
6203
 match any existing layer on the datasource.
6204
 @param poGeomFieldDefn the geometry field definition to use for the new layer,
6205
 or NULL if there is no geometry field.
6206
 @param papszOptions a StringList of name=value options.  Options are driver
6207
 specific.
6208
6209
 @return NULL is returned on failure, or a new OGRLayer handle on success.
6210
6211
*/
6212
6213
OGRLayer *
6214
GDALDataset::ICreateLayer(CPL_UNUSED const char *pszName,
6215
                          CPL_UNUSED const OGRGeomFieldDefn *poGeomFieldDefn,
6216
                          CPL_UNUSED CSLConstList papszOptions)
6217
6218
0
{
6219
0
    CPLError(CE_Failure, CPLE_NotSupported,
6220
0
             "CreateLayer() not supported by this dataset.");
6221
6222
0
    return nullptr;
6223
0
}
6224
6225
/************************************************************************/
6226
/*                             CopyLayer()                              */
6227
/************************************************************************/
6228
6229
/**
6230
 \brief Duplicate an existing layer.
6231
6232
 This method creates a new layer, duplicate the field definitions of the
6233
 source layer and then duplicate each features of the source layer.
6234
 The papszOptions argument
6235
 can be used to control driver specific creation options.  These options are
6236
 normally documented in the format specific documentation.
6237
 The source layer may come from another dataset.
6238
6239
 This method is the same as the C function GDALDatasetCopyLayer() and the
6240
 deprecated OGR_DS_CopyLayer().
6241
6242
 @param poSrcLayer source layer.
6243
 @param pszNewName the name of the layer to create.
6244
 @param papszOptions a StringList of name=value options.  Options are driver
6245
                     specific. There is a common option to set output layer
6246
                     spatial reference: DST_SRSWKT. The option should be in
6247
                     WKT format. Starting with GDAL 3.7, the common option
6248
                     COPY_MD can be set to NO to prevent the default copying
6249
                     of the metadata from the source layer to the target layer.
6250
6251
 @return a handle to the layer, or NULL if an error occurs.
6252
*/
6253
6254
OGRLayer *GDALDataset::CopyLayer(OGRLayer *poSrcLayer, const char *pszNewName,
6255
                                 CSLConstList papszOptions)
6256
6257
0
{
6258
    /* -------------------------------------------------------------------- */
6259
    /*      Create the layer.                                               */
6260
    /* -------------------------------------------------------------------- */
6261
0
    if (!TestCapability(ODsCCreateLayer))
6262
0
    {
6263
0
        CPLError(CE_Failure, CPLE_NotSupported,
6264
0
                 "This datasource does not support creation of layers.");
6265
0
        return nullptr;
6266
0
    }
6267
6268
0
    const char *pszSRSWKT = CSLFetchNameValue(papszOptions, "DST_SRSWKT");
6269
0
    OGRSpatialReference oDstSpaRef(pszSRSWKT);
6270
0
    oDstSpaRef.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
6271
0
    OGRFeatureDefn *poSrcDefn = poSrcLayer->GetLayerDefn();
6272
0
    OGRLayer *poDstLayer = nullptr;
6273
6274
0
    CPLStringList aosCleanedUpOptions(CSLDuplicate(papszOptions));
6275
0
    aosCleanedUpOptions.SetNameValue("DST_SRSWKT", nullptr);
6276
0
    aosCleanedUpOptions.SetNameValue("COPY_MD", nullptr);
6277
6278
0
    CPLErrorReset();
6279
0
    const int nSrcGeomFieldCount = poSrcDefn->GetGeomFieldCount();
6280
0
    if (nSrcGeomFieldCount == 1)
6281
0
    {
6282
0
        OGRGeomFieldDefn oGeomFieldDefn(poSrcDefn->GetGeomFieldDefn(0));
6283
0
        if (pszSRSWKT)
6284
0
            oGeomFieldDefn.SetSpatialRef(&oDstSpaRef);
6285
0
        poDstLayer = ICreateLayer(pszNewName, &oGeomFieldDefn,
6286
0
                                  aosCleanedUpOptions.List());
6287
0
    }
6288
0
    else
6289
0
    {
6290
0
        poDstLayer =
6291
0
            ICreateLayer(pszNewName, nullptr, aosCleanedUpOptions.List());
6292
0
    }
6293
6294
0
    if (poDstLayer == nullptr)
6295
0
        return nullptr;
6296
6297
0
    if (CPLTestBool(CSLFetchNameValueDef(papszOptions, "COPY_MD", "YES")))
6298
0
    {
6299
0
        CSLConstList papszMD = poSrcLayer->GetMetadata();
6300
0
        if (papszMD)
6301
0
            poDstLayer->SetMetadata(papszMD);
6302
0
    }
6303
6304
    /* -------------------------------------------------------------------- */
6305
    /*      Add fields.  Default to copy all fields, and make sure to       */
6306
    /*      establish a mapping between indices, rather than names, in      */
6307
    /*      case the target datasource has altered it (e.g. Shapefile       */
6308
    /*      limited to 10 char field names).                                */
6309
    /* -------------------------------------------------------------------- */
6310
0
    const int nSrcFieldCount = poSrcDefn->GetFieldCount();
6311
6312
    // Initialize the index-to-index map to -1's.
6313
0
    std::vector<int> anMap(nSrcFieldCount, -1);
6314
6315
    // Caution: At the time of writing, the MapInfo driver
6316
    // returns NULL until a field has been added.
6317
0
    OGRFeatureDefn *poDstFDefn = poDstLayer->GetLayerDefn();
6318
0
    int nDstFieldCount = poDstFDefn ? poDstFDefn->GetFieldCount() : 0;
6319
0
    for (int iField = 0; iField < nSrcFieldCount; ++iField)
6320
0
    {
6321
0
        OGRFieldDefn *poSrcFieldDefn = poSrcDefn->GetFieldDefn(iField);
6322
0
        OGRFieldDefn oFieldDefn(poSrcFieldDefn);
6323
6324
        // The field may have been already created at layer creation.
6325
0
        int iDstField = -1;
6326
0
        if (poDstFDefn)
6327
0
            iDstField = poDstFDefn->GetFieldIndex(oFieldDefn.GetNameRef());
6328
0
        if (iDstField >= 0)
6329
0
        {
6330
0
            anMap[iField] = iDstField;
6331
0
        }
6332
0
        else if (poDstLayer->CreateField(&oFieldDefn) == OGRERR_NONE)
6333
0
        {
6334
            // Now that we've created a field, GetLayerDefn() won't return NULL.
6335
0
            if (poDstFDefn == nullptr)
6336
0
                poDstFDefn = poDstLayer->GetLayerDefn();
6337
6338
            // Sanity check: if it fails, the driver is buggy.
6339
0
            if (poDstFDefn != nullptr &&
6340
0
                poDstFDefn->GetFieldCount() != nDstFieldCount + 1)
6341
0
            {
6342
0
                CPLError(CE_Warning, CPLE_AppDefined,
6343
0
                         "The output driver has claimed to have added the %s "
6344
0
                         "field, but it did not!",
6345
0
                         oFieldDefn.GetNameRef());
6346
0
            }
6347
0
            else
6348
0
            {
6349
0
                anMap[iField] = nDstFieldCount;
6350
0
                ++nDstFieldCount;
6351
0
            }
6352
0
        }
6353
0
    }
6354
6355
    /* -------------------------------------------------------------------- */
6356
0
    std::unique_ptr<OGRCoordinateTransformation> poCT;
6357
0
    const OGRSpatialReference *sourceSRS = poSrcLayer->GetSpatialRef();
6358
0
    if (sourceSRS != nullptr && pszSRSWKT != nullptr && !oDstSpaRef.IsEmpty() &&
6359
0
        sourceSRS->IsSame(&oDstSpaRef) == FALSE)
6360
0
    {
6361
0
        poCT.reset(OGRCreateCoordinateTransformation(sourceSRS, &oDstSpaRef));
6362
0
        if (nullptr == poCT)
6363
0
        {
6364
0
            CPLError(CE_Failure, CPLE_NotSupported,
6365
0
                     "This input/output spatial reference is not supported.");
6366
0
            return nullptr;
6367
0
        }
6368
0
    }
6369
    /* -------------------------------------------------------------------- */
6370
    /*      Create geometry fields.                                         */
6371
    /* -------------------------------------------------------------------- */
6372
0
    if (nSrcGeomFieldCount > 1 &&
6373
0
        TestCapability(ODsCCreateGeomFieldAfterCreateLayer))
6374
0
    {
6375
6376
0
        for (int iField = 0; iField < nSrcGeomFieldCount; ++iField)
6377
0
        {
6378
0
            if (nullptr == pszSRSWKT)
6379
0
            {
6380
0
                poDstLayer->CreateGeomField(
6381
0
                    poSrcDefn->GetGeomFieldDefn(iField));
6382
0
            }
6383
0
            else
6384
0
            {
6385
0
                OGRGeomFieldDefn *pDstGeomFieldDefn =
6386
0
                    poSrcDefn->GetGeomFieldDefn(iField);
6387
0
                pDstGeomFieldDefn->SetSpatialRef(&oDstSpaRef);
6388
0
                poDstLayer->CreateGeomField(pDstGeomFieldDefn);
6389
0
            }
6390
0
        }
6391
0
    }
6392
6393
    /* -------------------------------------------------------------------- */
6394
    /*      Check if the destination layer supports transactions and set a  */
6395
    /*      default number of features in a single transaction.             */
6396
    /* -------------------------------------------------------------------- */
6397
0
    const int nGroupTransactions =
6398
0
        poDstLayer->TestCapability(OLCTransactions) ? 128 : 0;
6399
6400
    /* -------------------------------------------------------------------- */
6401
    /*      Transfer features.                                              */
6402
    /* -------------------------------------------------------------------- */
6403
0
    poSrcLayer->ResetReading();
6404
6405
0
    if (nGroupTransactions <= 0)
6406
0
    {
6407
0
        while (true)
6408
0
        {
6409
0
            auto poFeature =
6410
0
                std::unique_ptr<OGRFeature>(poSrcLayer->GetNextFeature());
6411
6412
0
            if (poFeature == nullptr)
6413
0
                break;
6414
6415
0
            CPLErrorReset();
6416
0
            auto poDstFeature =
6417
0
                std::make_unique<OGRFeature>(poDstLayer->GetLayerDefn());
6418
6419
0
            if (poDstFeature->SetFrom(poFeature.get(), anMap.data(), TRUE) !=
6420
0
                OGRERR_NONE)
6421
0
            {
6422
0
                CPLError(CE_Failure, CPLE_AppDefined,
6423
0
                         "Unable to translate feature " CPL_FRMT_GIB
6424
0
                         " from layer %s.",
6425
0
                         poFeature->GetFID(), poSrcDefn->GetName());
6426
0
                return poDstLayer;
6427
0
            }
6428
6429
0
            if (nullptr != poCT)
6430
0
            {
6431
0
                for (int iField = 0; iField < nSrcGeomFieldCount; ++iField)
6432
0
                {
6433
0
                    OGRGeometry *pGeom = poDstFeature->GetGeomFieldRef(iField);
6434
0
                    if (nullptr == pGeom)
6435
0
                        continue;
6436
6437
0
                    const OGRErr eErr = pGeom->transform(poCT.get());
6438
0
                    if (eErr == OGRERR_NONE)
6439
0
                        continue;
6440
6441
0
                    CPLError(CE_Failure, CPLE_AppDefined,
6442
0
                             "Unable to transform geometry " CPL_FRMT_GIB
6443
0
                             " from layer %s.",
6444
0
                             poFeature->GetFID(), poSrcDefn->GetName());
6445
0
                    return poDstLayer;
6446
0
                }
6447
0
            }
6448
6449
0
            poDstFeature->SetFID(poFeature->GetFID());
6450
6451
0
            CPLErrorReset();
6452
0
            if (poDstLayer->CreateFeature(poDstFeature.get()) != OGRERR_NONE)
6453
0
            {
6454
0
                return poDstLayer;
6455
0
            }
6456
0
        }
6457
0
    }
6458
0
    else
6459
0
    {
6460
0
        std::vector<std::unique_ptr<OGRFeature>> apoDstFeatures;
6461
0
        try
6462
0
        {
6463
0
            apoDstFeatures.resize(nGroupTransactions);
6464
0
        }
6465
0
        catch (const std::exception &e)
6466
0
        {
6467
0
            CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
6468
0
            return poDstLayer;
6469
0
        }
6470
0
        bool bStopTransfer = false;
6471
0
        while (!bStopTransfer)
6472
0
        {
6473
            /* --------------------------------------------------------------------
6474
             */
6475
            /*      Fill the array with features. */
6476
            /* --------------------------------------------------------------------
6477
             */
6478
            // Number of features in the temporary array.
6479
0
            int nFeatCount = 0;  // Used after for.
6480
0
            for (nFeatCount = 0; nFeatCount < nGroupTransactions; ++nFeatCount)
6481
0
            {
6482
0
                auto poFeature =
6483
0
                    std::unique_ptr<OGRFeature>(poSrcLayer->GetNextFeature());
6484
6485
0
                if (poFeature == nullptr)
6486
0
                {
6487
0
                    bStopTransfer = true;
6488
0
                    break;
6489
0
                }
6490
6491
0
                CPLErrorReset();
6492
0
                apoDstFeatures[nFeatCount] =
6493
0
                    std::make_unique<OGRFeature>(poDstLayer->GetLayerDefn());
6494
6495
0
                if (apoDstFeatures[nFeatCount]->SetFrom(
6496
0
                        poFeature.get(), anMap.data(), TRUE) != OGRERR_NONE)
6497
0
                {
6498
0
                    CPLError(CE_Failure, CPLE_AppDefined,
6499
0
                             "Unable to translate feature " CPL_FRMT_GIB
6500
0
                             " from layer %s.",
6501
0
                             poFeature->GetFID(), poSrcDefn->GetName());
6502
0
                    bStopTransfer = true;
6503
0
                    poFeature.reset();
6504
0
                    break;
6505
0
                }
6506
6507
0
                if (nullptr != poCT)
6508
0
                {
6509
0
                    for (int iField = 0; iField < nSrcGeomFieldCount; ++iField)
6510
0
                    {
6511
0
                        OGRGeometry *pGeom =
6512
0
                            apoDstFeatures[nFeatCount]->GetGeomFieldRef(iField);
6513
0
                        if (nullptr == pGeom)
6514
0
                            continue;
6515
6516
0
                        const OGRErr eErr = pGeom->transform(poCT.get());
6517
0
                        if (eErr == OGRERR_NONE)
6518
0
                            continue;
6519
6520
0
                        CPLError(CE_Failure, CPLE_AppDefined,
6521
0
                                 "Unable to transform geometry " CPL_FRMT_GIB
6522
0
                                 " from layer %s.",
6523
0
                                 poFeature->GetFID(), poSrcDefn->GetName());
6524
0
                        bStopTransfer = true;
6525
0
                        poFeature.reset();
6526
0
                        break;
6527
0
                    }
6528
0
                }
6529
6530
0
                if (poFeature)
6531
0
                {
6532
0
                    apoDstFeatures[nFeatCount]->SetFID(poFeature->GetFID());
6533
0
                }
6534
0
            }
6535
6536
0
            CPLErrorReset();
6537
0
            bool bStopTransaction = false;
6538
0
            while (!bStopTransaction)
6539
0
            {
6540
0
                bStopTransaction = true;
6541
0
                if (poDstLayer->StartTransaction() != OGRERR_NONE)
6542
0
                    break;
6543
0
                for (int i = 0; i < nFeatCount; ++i)
6544
0
                {
6545
0
                    if (poDstLayer->CreateFeature(apoDstFeatures[i].get()) !=
6546
0
                        OGRERR_NONE)
6547
0
                    {
6548
0
                        bStopTransfer = true;
6549
0
                        bStopTransaction = false;
6550
0
                        break;
6551
0
                    }
6552
0
                    apoDstFeatures[i].reset();
6553
0
                }
6554
0
                if (bStopTransaction)
6555
0
                {
6556
0
                    if (poDstLayer->CommitTransaction() != OGRERR_NONE)
6557
0
                        break;
6558
0
                }
6559
0
                else
6560
0
                {
6561
0
                    poDstLayer->RollbackTransaction();
6562
0
                }
6563
0
            }
6564
0
        }
6565
0
    }
6566
6567
0
    return poDstLayer;
6568
0
}
6569
6570
/************************************************************************/
6571
/*                            DeleteLayer()                             */
6572
/************************************************************************/
6573
6574
/**
6575
 \fn GDALDataset::DeleteLayer(int)
6576
 \brief Delete the indicated layer from the datasource.
6577
6578
 If this method is supported
6579
 the ODsCDeleteLayer capability will test TRUE on the GDALDataset.
6580
6581
 This method is the same as the C function GDALDatasetDeleteLayer() and the
6582
 deprecated OGR_DS_DeleteLayer().
6583
6584
 @param iLayer the index of the layer to delete.
6585
6586
 @return OGRERR_NONE on success, or OGRERR_UNSUPPORTED_OPERATION if deleting
6587
 layers is not supported for this datasource.
6588
6589
*/
6590
6591
OGRErr GDALDataset::DeleteLayer(CPL_UNUSED int iLayer)
6592
6593
0
{
6594
0
    CPLError(CE_Failure, CPLE_NotSupported,
6595
0
             "DeleteLayer() not supported by this dataset.");
6596
6597
0
    return OGRERR_UNSUPPORTED_OPERATION;
6598
0
}
6599
6600
/************************************************************************/
6601
/*                           GetLayerByName()                           */
6602
/************************************************************************/
6603
6604
/**
6605
 \brief Fetch a layer by name.
6606
6607
 The returned layer remains owned by the
6608
 GDALDataset and should not be deleted by the application.
6609
6610
 This method is the same as the C function GDALDatasetGetLayerByName() and the
6611
 deprecated OGR_DS_GetLayerByName().
6612
6613
 @param pszName the layer name of the layer to fetch.
6614
6615
 @return the layer, or NULL if Layer is not found or an error occurs.
6616
*/
6617
6618
OGRLayer *GDALDataset::GetLayerByName(const char *pszName)
6619
6620
0
{
6621
0
    CPLMutexHolderD(m_poPrivate ? &(m_poPrivate->hMutex) : nullptr);
6622
6623
0
    if (!pszName)
6624
0
        return nullptr;
6625
6626
    // First a case sensitive check.
6627
0
    for (int i = 0; i < GetLayerCount(); ++i)
6628
0
    {
6629
0
        OGRLayer *poLayer = GetLayer(i);
6630
6631
0
        if (strcmp(pszName, poLayer->GetName()) == 0)
6632
0
            return poLayer;
6633
0
    }
6634
6635
    // Then case insensitive.
6636
0
    for (int i = 0; i < GetLayerCount(); ++i)
6637
0
    {
6638
0
        OGRLayer *poLayer = GetLayer(i);
6639
6640
0
        if (EQUAL(pszName, poLayer->GetName()))
6641
0
            return poLayer;
6642
0
    }
6643
6644
0
    return nullptr;
6645
0
}
6646
6647
//! @cond Doxygen_Suppress
6648
/************************************************************************/
6649
/*                       ProcessSQLCreateIndex()                        */
6650
/*                                                                      */
6651
/*      The correct syntax for creating an index in our dialect of      */
6652
/*      SQL is:                                                         */
6653
/*                                                                      */
6654
/*        CREATE INDEX ON <layername> USING <columnname>                */
6655
/************************************************************************/
6656
6657
OGRErr GDALDataset::ProcessSQLCreateIndex(const char *pszSQLCommand)
6658
6659
0
{
6660
0
    char **papszTokens = CSLTokenizeString(pszSQLCommand);
6661
6662
    /* -------------------------------------------------------------------- */
6663
    /*      Do some general syntax checking.                                */
6664
    /* -------------------------------------------------------------------- */
6665
0
    if (CSLCount(papszTokens) != 6 || !EQUAL(papszTokens[0], "CREATE") ||
6666
0
        !EQUAL(papszTokens[1], "INDEX") || !EQUAL(papszTokens[2], "ON") ||
6667
0
        !EQUAL(papszTokens[4], "USING"))
6668
0
    {
6669
0
        CSLDestroy(papszTokens);
6670
0
        CPLError(CE_Failure, CPLE_AppDefined,
6671
0
                 "Syntax error in CREATE INDEX command.\n"
6672
0
                 "Was '%s'\n"
6673
0
                 "Should be of form 'CREATE INDEX ON <table> USING <field>'",
6674
0
                 pszSQLCommand);
6675
0
        return OGRERR_FAILURE;
6676
0
    }
6677
6678
    /* -------------------------------------------------------------------- */
6679
    /*      Find the named layer.                                           */
6680
    /* -------------------------------------------------------------------- */
6681
0
    OGRLayer *poLayer = GetLayerByName(papszTokens[3]);
6682
0
    if (poLayer == nullptr)
6683
0
    {
6684
0
        CPLError(CE_Failure, CPLE_AppDefined,
6685
0
                 "CREATE INDEX ON failed, no such layer as `%s'.",
6686
0
                 papszTokens[3]);
6687
0
        CSLDestroy(papszTokens);
6688
0
        return OGRERR_FAILURE;
6689
0
    }
6690
6691
    /* -------------------------------------------------------------------- */
6692
    /*      Does this layer even support attribute indexes?                 */
6693
    /* -------------------------------------------------------------------- */
6694
0
    if (poLayer->GetIndex() == nullptr)
6695
0
    {
6696
0
        CPLError(CE_Failure, CPLE_AppDefined,
6697
0
                 "CREATE INDEX ON not supported by this driver.");
6698
0
        CSLDestroy(papszTokens);
6699
0
        return OGRERR_FAILURE;
6700
0
    }
6701
6702
    /* -------------------------------------------------------------------- */
6703
    /*      Find the named field.                                           */
6704
    /* -------------------------------------------------------------------- */
6705
0
    int i = poLayer->GetLayerDefn()->GetFieldIndex(papszTokens[5]);
6706
6707
0
    CSLDestroy(papszTokens);
6708
6709
0
    if (i >= poLayer->GetLayerDefn()->GetFieldCount())
6710
0
    {
6711
0
        CPLError(CE_Failure, CPLE_AppDefined, "`%s' failed, field not found.",
6712
0
                 pszSQLCommand);
6713
0
        return OGRERR_FAILURE;
6714
0
    }
6715
6716
    /* -------------------------------------------------------------------- */
6717
    /*      Attempt to create the index.                                    */
6718
    /* -------------------------------------------------------------------- */
6719
0
    OGRErr eErr = poLayer->GetIndex()->CreateIndex(i);
6720
0
    if (eErr == OGRERR_NONE)
6721
0
    {
6722
0
        eErr = poLayer->GetIndex()->IndexAllFeatures(i);
6723
0
    }
6724
0
    else
6725
0
    {
6726
0
        if (strlen(CPLGetLastErrorMsg()) == 0)
6727
0
            CPLError(CE_Failure, CPLE_AppDefined, "Cannot '%s'", pszSQLCommand);
6728
0
    }
6729
6730
0
    return eErr;
6731
0
}
6732
6733
/************************************************************************/
6734
/*                        ProcessSQLDropIndex()                         */
6735
/*                                                                      */
6736
/*      The correct syntax for dropping one or more indexes in          */
6737
/*      the OGR SQL dialect is:                                         */
6738
/*                                                                      */
6739
/*          DROP INDEX ON <layername> [USING <columnname>]              */
6740
/************************************************************************/
6741
6742
OGRErr GDALDataset::ProcessSQLDropIndex(const char *pszSQLCommand)
6743
6744
0
{
6745
0
    char **papszTokens = CSLTokenizeString(pszSQLCommand);
6746
6747
    /* -------------------------------------------------------------------- */
6748
    /*      Do some general syntax checking.                                */
6749
    /* -------------------------------------------------------------------- */
6750
0
    if ((CSLCount(papszTokens) != 4 && CSLCount(papszTokens) != 6) ||
6751
0
        !EQUAL(papszTokens[0], "DROP") || !EQUAL(papszTokens[1], "INDEX") ||
6752
0
        !EQUAL(papszTokens[2], "ON") ||
6753
0
        (CSLCount(papszTokens) == 6 && !EQUAL(papszTokens[4], "USING")))
6754
0
    {
6755
0
        CSLDestroy(papszTokens);
6756
0
        CPLError(CE_Failure, CPLE_AppDefined,
6757
0
                 "Syntax error in DROP INDEX command.\n"
6758
0
                 "Was '%s'\n"
6759
0
                 "Should be of form 'DROP INDEX ON <table> [USING <field>]'",
6760
0
                 pszSQLCommand);
6761
0
        return OGRERR_FAILURE;
6762
0
    }
6763
6764
    /* -------------------------------------------------------------------- */
6765
    /*      Find the named layer.                                           */
6766
    /* -------------------------------------------------------------------- */
6767
0
    OGRLayer *poLayer = GetLayerByName(papszTokens[3]);
6768
0
    if (poLayer == nullptr)
6769
0
    {
6770
0
        CPLError(CE_Failure, CPLE_AppDefined,
6771
0
                 "DROP INDEX ON failed, no such layer as `%s'.",
6772
0
                 papszTokens[3]);
6773
0
        CSLDestroy(papszTokens);
6774
0
        return OGRERR_FAILURE;
6775
0
    }
6776
6777
    /* -------------------------------------------------------------------- */
6778
    /*      Does this layer even support attribute indexes?                 */
6779
    /* -------------------------------------------------------------------- */
6780
0
    if (poLayer->GetIndex() == nullptr)
6781
0
    {
6782
0
        CPLError(CE_Failure, CPLE_AppDefined,
6783
0
                 "Indexes not supported by this driver.");
6784
0
        CSLDestroy(papszTokens);
6785
0
        return OGRERR_FAILURE;
6786
0
    }
6787
6788
    /* -------------------------------------------------------------------- */
6789
    /*      If we were not given a field name, drop all indexes.            */
6790
    /* -------------------------------------------------------------------- */
6791
0
    if (CSLCount(papszTokens) == 4)
6792
0
    {
6793
0
        for (int i = 0; i < poLayer->GetLayerDefn()->GetFieldCount(); ++i)
6794
0
        {
6795
0
            OGRAttrIndex *poAttrIndex;
6796
6797
0
            poAttrIndex = poLayer->GetIndex()->GetFieldIndex(i);
6798
0
            if (poAttrIndex != nullptr)
6799
0
            {
6800
0
                const OGRErr eErr = poLayer->GetIndex()->DropIndex(i);
6801
0
                if (eErr != OGRERR_NONE)
6802
0
                {
6803
0
                    CSLDestroy(papszTokens);
6804
0
                    return eErr;
6805
0
                }
6806
0
            }
6807
0
        }
6808
6809
0
        CSLDestroy(papszTokens);
6810
0
        return OGRERR_NONE;
6811
0
    }
6812
6813
    /* -------------------------------------------------------------------- */
6814
    /*      Find the named field.                                           */
6815
    /* -------------------------------------------------------------------- */
6816
0
    int i = poLayer->GetLayerDefn()->GetFieldIndex(papszTokens[5]);
6817
0
    CSLDestroy(papszTokens);
6818
6819
0
    if (i >= poLayer->GetLayerDefn()->GetFieldCount())
6820
0
    {
6821
0
        CPLError(CE_Failure, CPLE_AppDefined, "`%s' failed, field not found.",
6822
0
                 pszSQLCommand);
6823
0
        return OGRERR_FAILURE;
6824
0
    }
6825
6826
    /* -------------------------------------------------------------------- */
6827
    /*      Attempt to drop the index.                                      */
6828
    /* -------------------------------------------------------------------- */
6829
0
    const OGRErr eErr = poLayer->GetIndex()->DropIndex(i);
6830
6831
0
    return eErr;
6832
0
}
6833
6834
/************************************************************************/
6835
/*                        ProcessSQLDropTable()                         */
6836
/*                                                                      */
6837
/*      The correct syntax for dropping a table (layer) in the OGR SQL  */
6838
/*      dialect is:                                                     */
6839
/*                                                                      */
6840
/*          DROP TABLE <layername>                                      */
6841
/************************************************************************/
6842
6843
OGRErr GDALDataset::ProcessSQLDropTable(const char *pszSQLCommand)
6844
6845
0
{
6846
0
    char **papszTokens = CSLTokenizeString(pszSQLCommand);
6847
6848
    /* -------------------------------------------------------------------- */
6849
    /*      Do some general syntax checking.                                */
6850
    /* -------------------------------------------------------------------- */
6851
0
    if (CSLCount(papszTokens) != 3 || !EQUAL(papszTokens[0], "DROP") ||
6852
0
        !EQUAL(papszTokens[1], "TABLE"))
6853
0
    {
6854
0
        CSLDestroy(papszTokens);
6855
0
        CPLError(CE_Failure, CPLE_AppDefined,
6856
0
                 "Syntax error in DROP TABLE command.\n"
6857
0
                 "Was '%s'\n"
6858
0
                 "Should be of form 'DROP TABLE <table>'",
6859
0
                 pszSQLCommand);
6860
0
        return OGRERR_FAILURE;
6861
0
    }
6862
6863
    /* -------------------------------------------------------------------- */
6864
    /*      Find the named layer.                                           */
6865
    /* -------------------------------------------------------------------- */
6866
0
    OGRLayer *poLayer = nullptr;
6867
6868
0
    int i = 0;  // Used after for.
6869
0
    for (; i < GetLayerCount(); ++i)
6870
0
    {
6871
0
        poLayer = GetLayer(i);
6872
6873
0
        if (poLayer != nullptr && EQUAL(poLayer->GetName(), papszTokens[2]))
6874
0
            break;
6875
0
        poLayer = nullptr;
6876
0
    }
6877
6878
0
    if (poLayer == nullptr)
6879
0
    {
6880
0
        CPLError(CE_Failure, CPLE_AppDefined,
6881
0
                 "DROP TABLE failed, no such layer as `%s'.", papszTokens[2]);
6882
0
        CSLDestroy(papszTokens);
6883
0
        return OGRERR_FAILURE;
6884
0
    }
6885
6886
0
    CSLDestroy(papszTokens);
6887
6888
    /* -------------------------------------------------------------------- */
6889
    /*      Delete it.                                                      */
6890
    /* -------------------------------------------------------------------- */
6891
6892
0
    return DeleteLayer(i);
6893
0
}
6894
6895
//! @endcond
6896
6897
/************************************************************************/
6898
/*                      GDALDatasetParseSQLType()                       */
6899
/************************************************************************/
6900
6901
/* All arguments will be altered */
6902
static OGRFieldType GDALDatasetParseSQLType(char *pszType, int &nWidth,
6903
                                            int &nPrecision)
6904
0
{
6905
0
    char *pszParenthesis = strchr(pszType, '(');
6906
0
    if (pszParenthesis)
6907
0
    {
6908
0
        nWidth = atoi(pszParenthesis + 1);
6909
0
        *pszParenthesis = '\0';
6910
0
        char *pszComma = strchr(pszParenthesis + 1, ',');
6911
0
        if (pszComma)
6912
0
            nPrecision = atoi(pszComma + 1);
6913
0
    }
6914
6915
0
    OGRFieldType eType = OFTString;
6916
0
    if (EQUAL(pszType, "INTEGER"))
6917
0
        eType = OFTInteger;
6918
0
    else if (EQUAL(pszType, "INTEGER[]"))
6919
0
        eType = OFTIntegerList;
6920
0
    else if (EQUAL(pszType, "FLOAT") || EQUAL(pszType, "NUMERIC") ||
6921
0
             EQUAL(pszType, "DOUBLE") /* unofficial alias */ ||
6922
0
             EQUAL(pszType, "REAL") /* unofficial alias */)
6923
0
        eType = OFTReal;
6924
0
    else if (EQUAL(pszType, "FLOAT[]") || EQUAL(pszType, "NUMERIC[]") ||
6925
0
             EQUAL(pszType, "DOUBLE[]") /* unofficial alias */ ||
6926
0
             EQUAL(pszType, "REAL[]") /* unofficial alias */)
6927
0
        eType = OFTRealList;
6928
0
    else if (EQUAL(pszType, "CHARACTER") ||
6929
0
             EQUAL(pszType, "TEXT") /* unofficial alias */ ||
6930
0
             EQUAL(pszType, "STRING") /* unofficial alias */ ||
6931
0
             EQUAL(pszType, "VARCHAR") /* unofficial alias */)
6932
0
        eType = OFTString;
6933
0
    else if (EQUAL(pszType, "TEXT[]") ||
6934
0
             EQUAL(pszType, "STRING[]") /* unofficial alias */ ||
6935
0
             EQUAL(pszType, "VARCHAR[]") /* unofficial alias */)
6936
0
        eType = OFTStringList;
6937
0
    else if (EQUAL(pszType, "DATE"))
6938
0
        eType = OFTDate;
6939
0
    else if (EQUAL(pszType, "TIME"))
6940
0
        eType = OFTTime;
6941
0
    else if (EQUAL(pszType, "TIMESTAMP") ||
6942
0
             EQUAL(pszType, "DATETIME") /* unofficial alias */)
6943
0
        eType = OFTDateTime;
6944
0
    else
6945
0
        CPLError(CE_Warning, CPLE_NotSupported,
6946
0
                 "Unsupported column type '%s'. Defaulting to VARCHAR",
6947
0
                 pszType);
6948
6949
0
    return eType;
6950
0
}
6951
6952
/************************************************************************/
6953
/*                    ProcessSQLAlterTableAddColumn()                   */
6954
/*                                                                      */
6955
/*      The correct syntax for adding a column in the OGR SQL           */
6956
/*      dialect is:                                                     */
6957
/*                                                                      */
6958
/*       ALTER TABLE <layername> ADD [COLUMN] <columnname> <columntype> */
6959
/************************************************************************/
6960
6961
//! @cond Doxygen_Suppress
6962
OGRErr GDALDataset::ProcessSQLAlterTableAddColumn(const char *pszSQLCommand)
6963
6964
0
{
6965
0
    char **papszTokens = CSLTokenizeString(pszSQLCommand);
6966
6967
    /* -------------------------------------------------------------------- */
6968
    /*      Do some general syntax checking.                                */
6969
    /* -------------------------------------------------------------------- */
6970
0
    const char *pszLayerName = nullptr;
6971
0
    const char *pszColumnName = nullptr;
6972
0
    int iTypeIndex = 0;
6973
0
    const int nTokens = CSLCount(papszTokens);
6974
6975
0
    if (nTokens >= 7 && EQUAL(papszTokens[0], "ALTER") &&
6976
0
        EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ADD") &&
6977
0
        EQUAL(papszTokens[4], "COLUMN"))
6978
0
    {
6979
0
        pszLayerName = papszTokens[2];
6980
0
        pszColumnName = papszTokens[5];
6981
0
        iTypeIndex = 6;
6982
0
    }
6983
0
    else if (nTokens >= 6 && EQUAL(papszTokens[0], "ALTER") &&
6984
0
             EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ADD"))
6985
0
    {
6986
0
        pszLayerName = papszTokens[2];
6987
0
        pszColumnName = papszTokens[4];
6988
0
        iTypeIndex = 5;
6989
0
    }
6990
0
    else
6991
0
    {
6992
0
        CSLDestroy(papszTokens);
6993
0
        CPLError(CE_Failure, CPLE_AppDefined,
6994
0
                 "Syntax error in ALTER TABLE ADD COLUMN command.\n"
6995
0
                 "Was '%s'\n"
6996
0
                 "Should be of form 'ALTER TABLE <layername> ADD [COLUMN] "
6997
0
                 "<columnname> <columntype>'",
6998
0
                 pszSQLCommand);
6999
0
        return OGRERR_FAILURE;
7000
0
    }
7001
7002
    /* -------------------------------------------------------------------- */
7003
    /*      Merge type components into a single string if there were split  */
7004
    /*      with spaces                                                     */
7005
    /* -------------------------------------------------------------------- */
7006
0
    CPLString osType;
7007
0
    for (int i = iTypeIndex; i < nTokens; ++i)
7008
0
    {
7009
0
        osType += papszTokens[i];
7010
0
        CPLFree(papszTokens[i]);
7011
0
    }
7012
0
    char *pszType = papszTokens[iTypeIndex] = CPLStrdup(osType);
7013
0
    papszTokens[iTypeIndex + 1] = nullptr;
7014
7015
    /* -------------------------------------------------------------------- */
7016
    /*      Find the named layer.                                           */
7017
    /* -------------------------------------------------------------------- */
7018
0
    OGRLayer *poLayer = GetLayerByName(pszLayerName);
7019
0
    if (poLayer == nullptr)
7020
0
    {
7021
0
        CPLError(CE_Failure, CPLE_AppDefined,
7022
0
                 "%s failed, no such layer as `%s'.", pszSQLCommand,
7023
0
                 pszLayerName);
7024
0
        CSLDestroy(papszTokens);
7025
0
        return OGRERR_FAILURE;
7026
0
    }
7027
7028
    /* -------------------------------------------------------------------- */
7029
    /*      Add column.                                                     */
7030
    /* -------------------------------------------------------------------- */
7031
7032
0
    int nWidth = 0;
7033
0
    int nPrecision = 0;
7034
0
    OGRFieldType eType = GDALDatasetParseSQLType(pszType, nWidth, nPrecision);
7035
0
    OGRFieldDefn oFieldDefn(pszColumnName, eType);
7036
0
    oFieldDefn.SetWidth(nWidth);
7037
0
    oFieldDefn.SetPrecision(nPrecision);
7038
7039
0
    CSLDestroy(papszTokens);
7040
7041
0
    return poLayer->CreateField(&oFieldDefn);
7042
0
}
7043
7044
/************************************************************************/
7045
/*                    ProcessSQLAlterTableDropColumn()                  */
7046
/*                                                                      */
7047
/*      The correct syntax for dropping a column in the OGR SQL         */
7048
/*      dialect is:                                                     */
7049
/*                                                                      */
7050
/*          ALTER TABLE <layername> DROP [COLUMN] <columnname>          */
7051
/************************************************************************/
7052
7053
OGRErr GDALDataset::ProcessSQLAlterTableDropColumn(const char *pszSQLCommand)
7054
7055
0
{
7056
0
    char **papszTokens = CSLTokenizeString(pszSQLCommand);
7057
7058
    /* -------------------------------------------------------------------- */
7059
    /*      Do some general syntax checking.                                */
7060
    /* -------------------------------------------------------------------- */
7061
0
    const char *pszLayerName = nullptr;
7062
0
    const char *pszColumnName = nullptr;
7063
0
    if (CSLCount(papszTokens) == 6 && EQUAL(papszTokens[0], "ALTER") &&
7064
0
        EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "DROP") &&
7065
0
        EQUAL(papszTokens[4], "COLUMN"))
7066
0
    {
7067
0
        pszLayerName = papszTokens[2];
7068
0
        pszColumnName = papszTokens[5];
7069
0
    }
7070
0
    else if (CSLCount(papszTokens) == 5 && EQUAL(papszTokens[0], "ALTER") &&
7071
0
             EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "DROP"))
7072
0
    {
7073
0
        pszLayerName = papszTokens[2];
7074
0
        pszColumnName = papszTokens[4];
7075
0
    }
7076
0
    else
7077
0
    {
7078
0
        CSLDestroy(papszTokens);
7079
0
        CPLError(CE_Failure, CPLE_AppDefined,
7080
0
                 "Syntax error in ALTER TABLE DROP COLUMN command.\n"
7081
0
                 "Was '%s'\n"
7082
0
                 "Should be of form 'ALTER TABLE <layername> DROP [COLUMN] "
7083
0
                 "<columnname>'",
7084
0
                 pszSQLCommand);
7085
0
        return OGRERR_FAILURE;
7086
0
    }
7087
7088
    /* -------------------------------------------------------------------- */
7089
    /*      Find the named layer.                                           */
7090
    /* -------------------------------------------------------------------- */
7091
0
    OGRLayer *poLayer = GetLayerByName(pszLayerName);
7092
0
    if (poLayer == nullptr)
7093
0
    {
7094
0
        CPLError(CE_Failure, CPLE_AppDefined,
7095
0
                 "%s failed, no such layer as `%s'.", pszSQLCommand,
7096
0
                 pszLayerName);
7097
0
        CSLDestroy(papszTokens);
7098
0
        return OGRERR_FAILURE;
7099
0
    }
7100
7101
    /* -------------------------------------------------------------------- */
7102
    /*      Find the field.                                                 */
7103
    /* -------------------------------------------------------------------- */
7104
7105
0
    int nFieldIndex = poLayer->GetLayerDefn()->GetFieldIndex(pszColumnName);
7106
0
    if (nFieldIndex < 0)
7107
0
    {
7108
0
        CPLError(CE_Failure, CPLE_AppDefined,
7109
0
                 "%s failed, no such field as `%s'.", pszSQLCommand,
7110
0
                 pszColumnName);
7111
0
        CSLDestroy(papszTokens);
7112
0
        return OGRERR_FAILURE;
7113
0
    }
7114
7115
    /* -------------------------------------------------------------------- */
7116
    /*      Remove it.                                                      */
7117
    /* -------------------------------------------------------------------- */
7118
7119
0
    CSLDestroy(papszTokens);
7120
7121
0
    return poLayer->DeleteField(nFieldIndex);
7122
0
}
7123
7124
/************************************************************************/
7125
/*                 ProcessSQLAlterTableRenameColumn()                   */
7126
/*                                                                      */
7127
/*      The correct syntax for renaming a column in the OGR SQL         */
7128
/*      dialect is:                                                     */
7129
/*                                                                      */
7130
/*       ALTER TABLE <layername> RENAME [COLUMN] <oldname> TO <newname> */
7131
/************************************************************************/
7132
7133
OGRErr GDALDataset::ProcessSQLAlterTableRenameColumn(const char *pszSQLCommand)
7134
7135
0
{
7136
0
    char **papszTokens = CSLTokenizeString(pszSQLCommand);
7137
7138
    /* -------------------------------------------------------------------- */
7139
    /*      Do some general syntax checking.                                */
7140
    /* -------------------------------------------------------------------- */
7141
0
    const char *pszLayerName = nullptr;
7142
0
    const char *pszOldColName = nullptr;
7143
0
    const char *pszNewColName = nullptr;
7144
0
    if (CSLCount(papszTokens) == 8 && EQUAL(papszTokens[0], "ALTER") &&
7145
0
        EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "RENAME") &&
7146
0
        EQUAL(papszTokens[4], "COLUMN") && EQUAL(papszTokens[6], "TO"))
7147
0
    {
7148
0
        pszLayerName = papszTokens[2];
7149
0
        pszOldColName = papszTokens[5];
7150
0
        pszNewColName = papszTokens[7];
7151
0
    }
7152
0
    else if (CSLCount(papszTokens) == 7 && EQUAL(papszTokens[0], "ALTER") &&
7153
0
             EQUAL(papszTokens[1], "TABLE") &&
7154
0
             EQUAL(papszTokens[3], "RENAME") && EQUAL(papszTokens[5], "TO"))
7155
0
    {
7156
0
        pszLayerName = papszTokens[2];
7157
0
        pszOldColName = papszTokens[4];
7158
0
        pszNewColName = papszTokens[6];
7159
0
    }
7160
0
    else
7161
0
    {
7162
0
        CSLDestroy(papszTokens);
7163
0
        CPLError(CE_Failure, CPLE_AppDefined,
7164
0
                 "Syntax error in ALTER TABLE RENAME COLUMN command.\n"
7165
0
                 "Was '%s'\n"
7166
0
                 "Should be of form 'ALTER TABLE <layername> RENAME [COLUMN] "
7167
0
                 "<columnname> TO <newname>'",
7168
0
                 pszSQLCommand);
7169
0
        return OGRERR_FAILURE;
7170
0
    }
7171
7172
    /* -------------------------------------------------------------------- */
7173
    /*      Find the named layer.                                           */
7174
    /* -------------------------------------------------------------------- */
7175
0
    OGRLayer *poLayer = GetLayerByName(pszLayerName);
7176
0
    if (poLayer == nullptr)
7177
0
    {
7178
0
        CPLError(CE_Failure, CPLE_AppDefined,
7179
0
                 "%s failed, no such layer as `%s'.", pszSQLCommand,
7180
0
                 pszLayerName);
7181
0
        CSLDestroy(papszTokens);
7182
0
        return OGRERR_FAILURE;
7183
0
    }
7184
7185
    /* -------------------------------------------------------------------- */
7186
    /*      Find the field.                                                 */
7187
    /* -------------------------------------------------------------------- */
7188
7189
0
    const int nFieldIndex =
7190
0
        poLayer->GetLayerDefn()->GetFieldIndex(pszOldColName);
7191
0
    if (nFieldIndex < 0)
7192
0
    {
7193
0
        CPLError(CE_Failure, CPLE_AppDefined,
7194
0
                 "%s failed, no such field as `%s'.", pszSQLCommand,
7195
0
                 pszOldColName);
7196
0
        CSLDestroy(papszTokens);
7197
0
        return OGRERR_FAILURE;
7198
0
    }
7199
7200
    /* -------------------------------------------------------------------- */
7201
    /*      Rename column.                                                  */
7202
    /* -------------------------------------------------------------------- */
7203
0
    OGRFieldDefn *poOldFieldDefn =
7204
0
        poLayer->GetLayerDefn()->GetFieldDefn(nFieldIndex);
7205
0
    OGRFieldDefn oNewFieldDefn(poOldFieldDefn);
7206
0
    oNewFieldDefn.SetName(pszNewColName);
7207
7208
0
    CSLDestroy(papszTokens);
7209
7210
0
    return poLayer->AlterFieldDefn(nFieldIndex, &oNewFieldDefn,
7211
0
                                   ALTER_NAME_FLAG);
7212
0
}
7213
7214
/************************************************************************/
7215
/*                 ProcessSQLAlterTableAlterColumn()                    */
7216
/*                                                                      */
7217
/*      The correct syntax for altering the type of a column in the     */
7218
/*      OGR SQL dialect is:                                             */
7219
/*                                                                      */
7220
/*   ALTER TABLE <layername> ALTER [COLUMN] <columnname> TYPE <newtype> */
7221
/************************************************************************/
7222
7223
OGRErr GDALDataset::ProcessSQLAlterTableAlterColumn(const char *pszSQLCommand)
7224
7225
0
{
7226
0
    char **papszTokens = CSLTokenizeString(pszSQLCommand);
7227
7228
    /* -------------------------------------------------------------------- */
7229
    /*      Do some general syntax checking.                                */
7230
    /* -------------------------------------------------------------------- */
7231
0
    const char *pszLayerName = nullptr;
7232
0
    const char *pszColumnName = nullptr;
7233
0
    int iTypeIndex = 0;
7234
0
    const int nTokens = CSLCount(papszTokens);
7235
7236
0
    if (nTokens >= 8 && EQUAL(papszTokens[0], "ALTER") &&
7237
0
        EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ALTER") &&
7238
0
        EQUAL(papszTokens[4], "COLUMN") && EQUAL(papszTokens[6], "TYPE"))
7239
0
    {
7240
0
        pszLayerName = papszTokens[2];
7241
0
        pszColumnName = papszTokens[5];
7242
0
        iTypeIndex = 7;
7243
0
    }
7244
0
    else if (nTokens >= 7 && EQUAL(papszTokens[0], "ALTER") &&
7245
0
             EQUAL(papszTokens[1], "TABLE") && EQUAL(papszTokens[3], "ALTER") &&
7246
0
             EQUAL(papszTokens[5], "TYPE"))
7247
0
    {
7248
0
        pszLayerName = papszTokens[2];
7249
0
        pszColumnName = papszTokens[4];
7250
0
        iTypeIndex = 6;
7251
0
    }
7252
0
    else
7253
0
    {
7254
0
        CSLDestroy(papszTokens);
7255
0
        CPLError(CE_Failure, CPLE_AppDefined,
7256
0
                 "Syntax error in ALTER TABLE ALTER COLUMN command.\n"
7257
0
                 "Was '%s'\n"
7258
0
                 "Should be of form 'ALTER TABLE <layername> ALTER [COLUMN] "
7259
0
                 "<columnname> TYPE <columntype>'",
7260
0
                 pszSQLCommand);
7261
0
        return OGRERR_FAILURE;
7262
0
    }
7263
7264
    /* -------------------------------------------------------------------- */
7265
    /*      Merge type components into a single string if there were split  */
7266
    /*      with spaces                                                     */
7267
    /* -------------------------------------------------------------------- */
7268
0
    CPLString osType;
7269
0
    for (int i = iTypeIndex; i < nTokens; ++i)
7270
0
    {
7271
0
        osType += papszTokens[i];
7272
0
        CPLFree(papszTokens[i]);
7273
0
    }
7274
0
    char *pszType = papszTokens[iTypeIndex] = CPLStrdup(osType);
7275
0
    papszTokens[iTypeIndex + 1] = nullptr;
7276
7277
    /* -------------------------------------------------------------------- */
7278
    /*      Find the named layer.                                           */
7279
    /* -------------------------------------------------------------------- */
7280
0
    OGRLayer *poLayer = GetLayerByName(pszLayerName);
7281
0
    if (poLayer == nullptr)
7282
0
    {
7283
0
        CPLError(CE_Failure, CPLE_AppDefined,
7284
0
                 "%s failed, no such layer as `%s'.", pszSQLCommand,
7285
0
                 pszLayerName);
7286
0
        CSLDestroy(papszTokens);
7287
0
        return OGRERR_FAILURE;
7288
0
    }
7289
7290
    /* -------------------------------------------------------------------- */
7291
    /*      Find the field.                                                 */
7292
    /* -------------------------------------------------------------------- */
7293
7294
0
    const int nFieldIndex =
7295
0
        poLayer->GetLayerDefn()->GetFieldIndex(pszColumnName);
7296
0
    if (nFieldIndex < 0)
7297
0
    {
7298
0
        CPLError(CE_Failure, CPLE_AppDefined,
7299
0
                 "%s failed, no such field as `%s'.", pszSQLCommand,
7300
0
                 pszColumnName);
7301
0
        CSLDestroy(papszTokens);
7302
0
        return OGRERR_FAILURE;
7303
0
    }
7304
7305
    /* -------------------------------------------------------------------- */
7306
    /*      Alter column.                                                   */
7307
    /* -------------------------------------------------------------------- */
7308
7309
0
    OGRFieldDefn *poOldFieldDefn =
7310
0
        poLayer->GetLayerDefn()->GetFieldDefn(nFieldIndex);
7311
0
    OGRFieldDefn oNewFieldDefn(poOldFieldDefn);
7312
7313
0
    int nWidth = 0;
7314
0
    int nPrecision = 0;
7315
0
    OGRFieldType eType = GDALDatasetParseSQLType(pszType, nWidth, nPrecision);
7316
0
    oNewFieldDefn.SetType(eType);
7317
0
    oNewFieldDefn.SetWidth(nWidth);
7318
0
    oNewFieldDefn.SetPrecision(nPrecision);
7319
7320
0
    int l_nFlags = 0;
7321
0
    if (poOldFieldDefn->GetType() != oNewFieldDefn.GetType())
7322
0
        l_nFlags |= ALTER_TYPE_FLAG;
7323
0
    if (poOldFieldDefn->GetWidth() != oNewFieldDefn.GetWidth() ||
7324
0
        poOldFieldDefn->GetPrecision() != oNewFieldDefn.GetPrecision())
7325
0
        l_nFlags |= ALTER_WIDTH_PRECISION_FLAG;
7326
7327
0
    CSLDestroy(papszTokens);
7328
7329
0
    if (l_nFlags == 0)
7330
0
        return OGRERR_NONE;
7331
7332
0
    return poLayer->AlterFieldDefn(nFieldIndex, &oNewFieldDefn, l_nFlags);
7333
0
}
7334
7335
//! @endcond
7336
7337
/************************************************************************/
7338
/*                             ExecuteSQL()                             */
7339
/************************************************************************/
7340
7341
/**
7342
 \brief Execute an SQL statement against the data store.
7343
7344
 The result of an SQL query is either NULL for statements that are in error,
7345
 or that have no results set, or an OGRLayer pointer representing a results
7346
 set from the query.  Note that this OGRLayer is in addition to the layers
7347
 in the data store and must be destroyed with
7348
 ReleaseResultSet() before the dataset is closed
7349
 (destroyed).
7350
7351
 This method is the same as the C function GDALDatasetExecuteSQL() and the
7352
 deprecated OGR_DS_ExecuteSQL().
7353
7354
 For more information on the SQL dialect supported internally by OGR
7355
 review the <a href="https://gdal.org/user/ogr_sql_dialect.html">OGR SQL</a>
7356
 document.  Some drivers (i.e. Oracle and PostGIS) pass the SQL directly through
7357
 to the underlying RDBMS.
7358
7359
 Starting with OGR 1.10, the <a
7360
 href="https://gdal.org/user/sql_sqlite_dialect.html">SQLITE dialect</a> can
7361
 also be used.
7362
7363
 @param pszStatement the SQL statement to execute.
7364
 @param poSpatialFilter geometry which represents a spatial filter. Can be NULL.
7365
 @param pszDialect allows control of the statement dialect. If set to NULL, the
7366
 OGR SQL engine will be used, except for RDBMS drivers that will use their
7367
 dedicated SQL engine, unless OGRSQL is explicitly passed as the
7368
 dialect. Starting with OGR 1.10, the SQLITE dialect can also be used.
7369
7370
 @return an OGRLayer containing the results of the query.  Deallocate with
7371
 ReleaseResultSet().
7372
7373
*/
7374
7375
OGRLayer *GDALDataset::ExecuteSQL(const char *pszStatement,
7376
                                  OGRGeometry *poSpatialFilter,
7377
                                  const char *pszDialect)
7378
7379
0
{
7380
0
    return ExecuteSQL(pszStatement, poSpatialFilter, pszDialect, nullptr);
7381
0
}
7382
7383
//! @cond Doxygen_Suppress
7384
OGRLayer *
7385
GDALDataset::ExecuteSQL(const char *pszStatement, OGRGeometry *poSpatialFilter,
7386
                        const char *pszDialect,
7387
                        swq_select_parse_options *poSelectParseOptions)
7388
7389
0
{
7390
0
    if (pszDialect != nullptr && EQUAL(pszDialect, "SQLite"))
7391
0
    {
7392
#ifdef SQLITE_ENABLED
7393
        return OGRSQLiteExecuteSQL(this, pszStatement, poSpatialFilter,
7394
                                   pszDialect);
7395
#else
7396
0
        CPLError(CE_Failure, CPLE_NotSupported,
7397
0
                 "The SQLite driver needs to be compiled to support the "
7398
0
                 "SQLite SQL dialect");
7399
0
        return nullptr;
7400
0
#endif
7401
0
    }
7402
7403
0
    if (pszDialect != nullptr && !EQUAL(pszDialect, "") &&
7404
0
        !EQUAL(pszDialect, "OGRSQL"))
7405
0
    {
7406
0
        std::string osDialectList = "'OGRSQL'";
7407
#ifdef SQLITE_ENABLED
7408
        osDialectList += ", 'SQLITE'";
7409
#endif
7410
0
        const char *pszDialects =
7411
0
            GetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS);
7412
0
        if (pszDialects)
7413
0
        {
7414
0
            const CPLStringList aosTokens(
7415
0
                CSLTokenizeString2(pszDialects, " ", 0));
7416
0
            for (int i = 0; i < aosTokens.size(); ++i)
7417
0
            {
7418
0
                if (!EQUAL(aosTokens[i], "OGRSQL") &&
7419
0
                    !EQUAL(aosTokens[i], "SQLITE"))
7420
0
                {
7421
0
                    osDialectList += ", '";
7422
0
                    osDialectList += aosTokens[i];
7423
0
                    osDialectList += "'";
7424
0
                }
7425
0
            }
7426
0
        }
7427
0
        CPLError(CE_Warning, CPLE_NotSupported,
7428
0
                 "Dialect '%s' is unsupported. Only supported dialects are %s. "
7429
0
                 "Defaulting to OGRSQL",
7430
0
                 pszDialect, osDialectList.c_str());
7431
0
    }
7432
7433
    /* -------------------------------------------------------------------- */
7434
    /*      Handle CREATE INDEX statements specially.                       */
7435
    /* -------------------------------------------------------------------- */
7436
0
    if (STARTS_WITH_CI(pszStatement, "CREATE INDEX"))
7437
0
    {
7438
0
        ProcessSQLCreateIndex(pszStatement);
7439
0
        return nullptr;
7440
0
    }
7441
7442
    /* -------------------------------------------------------------------- */
7443
    /*      Handle DROP INDEX statements specially.                         */
7444
    /* -------------------------------------------------------------------- */
7445
0
    if (STARTS_WITH_CI(pszStatement, "DROP INDEX"))
7446
0
    {
7447
0
        ProcessSQLDropIndex(pszStatement);
7448
0
        return nullptr;
7449
0
    }
7450
7451
    /* -------------------------------------------------------------------- */
7452
    /*      Handle DROP TABLE statements specially.                         */
7453
    /* -------------------------------------------------------------------- */
7454
0
    if (STARTS_WITH_CI(pszStatement, "DROP TABLE"))
7455
0
    {
7456
0
        ProcessSQLDropTable(pszStatement);
7457
0
        return nullptr;
7458
0
    }
7459
7460
    /* -------------------------------------------------------------------- */
7461
    /*      Handle ALTER TABLE statements specially.                        */
7462
    /* -------------------------------------------------------------------- */
7463
0
    if (STARTS_WITH_CI(pszStatement, "ALTER TABLE"))
7464
0
    {
7465
0
        char **papszTokens = CSLTokenizeString(pszStatement);
7466
0
        const int nTokens = CSLCount(papszTokens);
7467
0
        if (nTokens >= 4 && EQUAL(papszTokens[3], "ADD"))
7468
0
        {
7469
0
            ProcessSQLAlterTableAddColumn(pszStatement);
7470
0
            CSLDestroy(papszTokens);
7471
0
            return nullptr;
7472
0
        }
7473
0
        else if (nTokens >= 4 && EQUAL(papszTokens[3], "DROP"))
7474
0
        {
7475
0
            ProcessSQLAlterTableDropColumn(pszStatement);
7476
0
            CSLDestroy(papszTokens);
7477
0
            return nullptr;
7478
0
        }
7479
0
        else if (nTokens == 6 && EQUAL(papszTokens[3], "RENAME") &&
7480
0
                 EQUAL(papszTokens[4], "TO"))
7481
0
        {
7482
0
            const char *pszSrcTableName = papszTokens[2];
7483
0
            const char *pszDstTableName = papszTokens[5];
7484
0
            auto poSrcLayer = GetLayerByName(pszSrcTableName);
7485
0
            if (poSrcLayer)
7486
0
            {
7487
0
                CPL_IGNORE_RET_VAL(poSrcLayer->Rename(pszDstTableName));
7488
0
            }
7489
0
            else
7490
0
            {
7491
0
                CPLError(CE_Failure, CPLE_AppDefined, "Invalid layer name");
7492
0
            }
7493
0
            CSLDestroy(papszTokens);
7494
0
            return nullptr;
7495
0
        }
7496
0
        else if (nTokens >= 4 && EQUAL(papszTokens[3], "RENAME"))
7497
0
        {
7498
0
            ProcessSQLAlterTableRenameColumn(pszStatement);
7499
0
            CSLDestroy(papszTokens);
7500
0
            return nullptr;
7501
0
        }
7502
0
        else if (nTokens >= 4 && EQUAL(papszTokens[3], "ALTER"))
7503
0
        {
7504
0
            ProcessSQLAlterTableAlterColumn(pszStatement);
7505
0
            CSLDestroy(papszTokens);
7506
0
            return nullptr;
7507
0
        }
7508
0
        else
7509
0
        {
7510
0
            CPLError(CE_Failure, CPLE_AppDefined,
7511
0
                     "Unsupported ALTER TABLE command : %s", pszStatement);
7512
0
            CSLDestroy(papszTokens);
7513
0
            return nullptr;
7514
0
        }
7515
0
    }
7516
7517
    /* -------------------------------------------------------------------- */
7518
    /*      Preparse the SQL statement.                                     */
7519
    /* -------------------------------------------------------------------- */
7520
0
    swq_select *psSelectInfo = new swq_select();
7521
0
    swq_custom_func_registrar *poCustomFuncRegistrar = nullptr;
7522
0
    if (poSelectParseOptions != nullptr)
7523
0
        poCustomFuncRegistrar = poSelectParseOptions->poCustomFuncRegistrar;
7524
0
    if (psSelectInfo->preparse(pszStatement,
7525
0
                               poCustomFuncRegistrar != nullptr) != CE_None)
7526
0
    {
7527
0
        delete psSelectInfo;
7528
0
        return nullptr;
7529
0
    }
7530
7531
    /* -------------------------------------------------------------------- */
7532
    /*      If there is no UNION ALL, build result layer.                   */
7533
    /* -------------------------------------------------------------------- */
7534
0
    if (psSelectInfo->poOtherSelect == nullptr)
7535
0
    {
7536
0
        return BuildLayerFromSelectInfo(psSelectInfo, poSpatialFilter,
7537
0
                                        pszDialect, poSelectParseOptions);
7538
0
    }
7539
7540
    /* -------------------------------------------------------------------- */
7541
    /*      Build result union layer.                                       */
7542
    /* -------------------------------------------------------------------- */
7543
0
    int nSrcLayers = 0;
7544
0
    OGRLayer **papoSrcLayers = nullptr;
7545
7546
0
    do
7547
0
    {
7548
0
        swq_select *psNextSelectInfo = psSelectInfo->poOtherSelect;
7549
0
        psSelectInfo->poOtherSelect = nullptr;
7550
7551
0
        OGRLayer *poLayer = BuildLayerFromSelectInfo(
7552
0
            psSelectInfo, poSpatialFilter, pszDialect, poSelectParseOptions);
7553
0
        if (poLayer == nullptr)
7554
0
        {
7555
            // Each source layer owns an independent select info.
7556
0
            for (int i = 0; i < nSrcLayers; ++i)
7557
0
                delete papoSrcLayers[i];
7558
0
            CPLFree(papoSrcLayers);
7559
7560
            // So we just have to destroy the remaining select info.
7561
0
            delete psNextSelectInfo;
7562
7563
0
            return nullptr;
7564
0
        }
7565
0
        else
7566
0
        {
7567
0
            papoSrcLayers = static_cast<OGRLayer **>(CPLRealloc(
7568
0
                papoSrcLayers, sizeof(OGRLayer *) * (nSrcLayers + 1)));
7569
0
            papoSrcLayers[nSrcLayers] = poLayer;
7570
0
            ++nSrcLayers;
7571
7572
0
            psSelectInfo = psNextSelectInfo;
7573
0
        }
7574
0
    } while (psSelectInfo != nullptr);
7575
7576
0
    return new OGRUnionLayer("SELECT", nSrcLayers, papoSrcLayers, TRUE);
7577
0
}
7578
7579
//! @endcond
7580
7581
/************************************************************************/
7582
/*                              AbortSQL()                              */
7583
/************************************************************************/
7584
7585
/**
7586
 \brief Abort any SQL statement running in the data store.
7587
7588
 This function can be safely called from any thread (pending that the dataset
7589
 object is still alive). Driver implementations will make sure that it can be
7590
 called in a thread-safe way.
7591
7592
 This might not be implemented by all drivers. At time of writing, only SQLite,
7593
 GPKG and PG drivers implement it
7594
7595
 This method is the same as the C method GDALDatasetAbortSQL()
7596
7597
 @since GDAL 3.2.0
7598
7599
7600
*/
7601
7602
OGRErr GDALDataset::AbortSQL()
7603
0
{
7604
0
    CPLError(CE_Failure, CPLE_NotSupported,
7605
0
             "AbortSQL is not supported for this driver.");
7606
0
    return OGRERR_UNSUPPORTED_OPERATION;
7607
0
}
7608
7609
/************************************************************************/
7610
/*                      BuildLayerFromSelectInfo()                      */
7611
/************************************************************************/
7612
7613
struct GDALSQLParseInfo
7614
{
7615
    swq_field_list sFieldList;
7616
    int nExtraDSCount;
7617
    GDALDataset **papoExtraDS;
7618
    char *pszWHERE;
7619
};
7620
7621
OGRLayer *GDALDataset::BuildLayerFromSelectInfo(
7622
    swq_select *psSelectInfo, OGRGeometry *poSpatialFilter,
7623
    const char *pszDialect, swq_select_parse_options *poSelectParseOptions)
7624
0
{
7625
0
    std::unique_ptr<swq_select> psSelectInfoUnique(psSelectInfo);
7626
7627
0
    std::unique_ptr<OGRGenSQLResultsLayer> poResults;
7628
0
    GDALSQLParseInfo *psParseInfo =
7629
0
        BuildParseInfo(psSelectInfoUnique.get(), poSelectParseOptions);
7630
7631
0
    if (psParseInfo)
7632
0
    {
7633
0
        const auto nErrorCounter = CPLGetErrorCounter();
7634
0
        poResults = std::make_unique<OGRGenSQLResultsLayer>(
7635
0
            this, std::move(psSelectInfoUnique), poSpatialFilter,
7636
0
            psParseInfo->pszWHERE, pszDialect);
7637
0
        if (CPLGetErrorCounter() > nErrorCounter &&
7638
0
            CPLGetLastErrorType() != CE_None)
7639
0
            poResults.reset();
7640
0
    }
7641
7642
0
    DestroyParseInfo(psParseInfo);
7643
7644
0
    return poResults.release();
7645
0
}
7646
7647
/************************************************************************/
7648
/*                          DestroyParseInfo()                          */
7649
/************************************************************************/
7650
7651
//! @cond Doxygen_Suppress
7652
void GDALDataset::DestroyParseInfo(GDALSQLParseInfo *psParseInfo)
7653
0
{
7654
0
    if (psParseInfo == nullptr)
7655
0
        return;
7656
7657
0
    CPLFree(psParseInfo->sFieldList.names);
7658
0
    CPLFree(psParseInfo->sFieldList.types);
7659
0
    CPLFree(psParseInfo->sFieldList.table_ids);
7660
0
    CPLFree(psParseInfo->sFieldList.ids);
7661
7662
    // Release the datasets we have opened with OGROpenShared()
7663
    // It is safe to do that as the 'new OGRGenSQLResultsLayer' itself
7664
    // has taken a reference on them, which it will release in its
7665
    // destructor.
7666
0
    for (int iEDS = 0; iEDS < psParseInfo->nExtraDSCount; ++iEDS)
7667
0
        GDALClose(psParseInfo->papoExtraDS[iEDS]);
7668
7669
0
    CPLFree(psParseInfo->papoExtraDS);
7670
0
    CPLFree(psParseInfo->pszWHERE);
7671
0
    CPLFree(psParseInfo);
7672
0
}
7673
7674
/************************************************************************/
7675
/*                           BuildParseInfo()                           */
7676
/************************************************************************/
7677
7678
GDALSQLParseInfo *
7679
GDALDataset::BuildParseInfo(swq_select *psSelectInfo,
7680
                            swq_select_parse_options *poSelectParseOptions)
7681
0
{
7682
0
    int nFirstLayerFirstSpecialFieldIndex = 0;
7683
7684
0
    GDALSQLParseInfo *psParseInfo =
7685
0
        static_cast<GDALSQLParseInfo *>(CPLCalloc(1, sizeof(GDALSQLParseInfo)));
7686
7687
    /* -------------------------------------------------------------------- */
7688
    /*      Validate that all the source tables are recognized, count       */
7689
    /*      fields.                                                         */
7690
    /* -------------------------------------------------------------------- */
7691
0
    int nFieldCount = 0;
7692
7693
0
    for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
7694
0
    {
7695
0
        swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
7696
0
        GDALDataset *poTableDS = this;
7697
7698
0
        if (psTableDef->data_source != nullptr)
7699
0
        {
7700
0
            poTableDS = GDALDataset::FromHandle(
7701
0
                OGROpenShared(psTableDef->data_source, FALSE, nullptr));
7702
0
            if (poTableDS == nullptr)
7703
0
            {
7704
0
                if (strlen(CPLGetLastErrorMsg()) == 0)
7705
0
                    CPLError(CE_Failure, CPLE_AppDefined,
7706
0
                             "Unable to open secondary datasource "
7707
0
                             "`%s' required by JOIN.",
7708
0
                             psTableDef->data_source);
7709
7710
0
                DestroyParseInfo(psParseInfo);
7711
0
                return nullptr;
7712
0
            }
7713
7714
            // Keep in an array to release at the end of this function.
7715
0
            psParseInfo->papoExtraDS = static_cast<GDALDataset **>(CPLRealloc(
7716
0
                psParseInfo->papoExtraDS,
7717
0
                sizeof(GDALDataset *) * (psParseInfo->nExtraDSCount + 1)));
7718
0
            psParseInfo->papoExtraDS[psParseInfo->nExtraDSCount++] = poTableDS;
7719
0
        }
7720
7721
0
        OGRLayer *poSrcLayer =
7722
0
            poTableDS->GetLayerByName(psTableDef->table_name);
7723
7724
0
        if (poSrcLayer == nullptr)
7725
0
        {
7726
0
            CPLError(CE_Failure, CPLE_AppDefined,
7727
0
                     "SELECT from table %s failed, no such table/featureclass.",
7728
0
                     psTableDef->table_name);
7729
7730
0
            DestroyParseInfo(psParseInfo);
7731
0
            return nullptr;
7732
0
        }
7733
7734
0
        nFieldCount += poSrcLayer->GetLayerDefn()->GetFieldCount();
7735
0
        if (iTable == 0 ||
7736
0
            (poSelectParseOptions &&
7737
0
             poSelectParseOptions->bAddSecondaryTablesGeometryFields))
7738
0
            nFieldCount += poSrcLayer->GetLayerDefn()->GetGeomFieldCount();
7739
7740
0
        const char *pszFID = poSrcLayer->GetFIDColumn();
7741
0
        if (pszFID && !EQUAL(pszFID, "") && !EQUAL(pszFID, "FID") &&
7742
0
            poSrcLayer->GetLayerDefn()->GetFieldIndex(pszFID) < 0)
7743
0
            nFieldCount++;
7744
0
    }
7745
7746
    /* -------------------------------------------------------------------- */
7747
    /*      Build the field list for all indicated tables.                  */
7748
    /* -------------------------------------------------------------------- */
7749
7750
0
    psParseInfo->sFieldList.table_count = psSelectInfo->table_count;
7751
0
    psParseInfo->sFieldList.table_defs = psSelectInfo->table_defs;
7752
7753
0
    psParseInfo->sFieldList.count = 0;
7754
0
    psParseInfo->sFieldList.names = static_cast<char **>(
7755
0
        CPLMalloc(sizeof(char *) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7756
0
    psParseInfo->sFieldList.types = static_cast<swq_field_type *>(CPLMalloc(
7757
0
        sizeof(swq_field_type) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7758
0
    psParseInfo->sFieldList.table_ids = static_cast<int *>(
7759
0
        CPLMalloc(sizeof(int) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7760
0
    psParseInfo->sFieldList.ids = static_cast<int *>(
7761
0
        CPLMalloc(sizeof(int) * (nFieldCount + SPECIAL_FIELD_COUNT)));
7762
7763
0
    bool bIsFID64 = false;
7764
0
    for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
7765
0
    {
7766
0
        swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
7767
0
        GDALDataset *poTableDS = this;
7768
7769
0
        if (psTableDef->data_source != nullptr)
7770
0
        {
7771
0
            poTableDS = GDALDataset::FromHandle(
7772
0
                OGROpenShared(psTableDef->data_source, FALSE, nullptr));
7773
0
            CPLAssert(poTableDS != nullptr);
7774
0
            poTableDS->Dereference();
7775
0
        }
7776
7777
0
        OGRLayer *poSrcLayer =
7778
0
            poTableDS->GetLayerByName(psTableDef->table_name);
7779
7780
0
        for (int iField = 0;
7781
0
             iField < poSrcLayer->GetLayerDefn()->GetFieldCount(); iField++)
7782
0
        {
7783
0
            OGRFieldDefn *poFDefn =
7784
0
                poSrcLayer->GetLayerDefn()->GetFieldDefn(iField);
7785
0
            const int iOutField = psParseInfo->sFieldList.count++;
7786
0
            psParseInfo->sFieldList.names[iOutField] =
7787
0
                const_cast<char *>(poFDefn->GetNameRef());
7788
0
            if (poFDefn->GetType() == OFTInteger)
7789
0
            {
7790
0
                if (poFDefn->GetSubType() == OFSTBoolean)
7791
0
                    psParseInfo->sFieldList.types[iOutField] = SWQ_BOOLEAN;
7792
0
                else
7793
0
                    psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER;
7794
0
            }
7795
0
            else if (poFDefn->GetType() == OFTInteger64)
7796
0
            {
7797
0
                if (poFDefn->GetSubType() == OFSTBoolean)
7798
0
                    psParseInfo->sFieldList.types[iOutField] = SWQ_BOOLEAN;
7799
0
                else
7800
0
                    psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER64;
7801
0
            }
7802
0
            else if (poFDefn->GetType() == OFTReal)
7803
0
                psParseInfo->sFieldList.types[iOutField] = SWQ_FLOAT;
7804
0
            else if (poFDefn->GetType() == OFTString)
7805
0
                psParseInfo->sFieldList.types[iOutField] = SWQ_STRING;
7806
0
            else if (poFDefn->GetType() == OFTTime)
7807
0
                psParseInfo->sFieldList.types[iOutField] = SWQ_TIME;
7808
0
            else if (poFDefn->GetType() == OFTDate)
7809
0
                psParseInfo->sFieldList.types[iOutField] = SWQ_DATE;
7810
0
            else if (poFDefn->GetType() == OFTDateTime)
7811
0
                psParseInfo->sFieldList.types[iOutField] = SWQ_TIMESTAMP;
7812
0
            else
7813
0
                psParseInfo->sFieldList.types[iOutField] = SWQ_OTHER;
7814
7815
0
            psParseInfo->sFieldList.table_ids[iOutField] = iTable;
7816
0
            psParseInfo->sFieldList.ids[iOutField] = iField;
7817
0
        }
7818
7819
0
        if (iTable == 0)
7820
0
        {
7821
0
            nFirstLayerFirstSpecialFieldIndex = psParseInfo->sFieldList.count;
7822
0
        }
7823
7824
0
        if (iTable == 0 ||
7825
0
            (poSelectParseOptions &&
7826
0
             poSelectParseOptions->bAddSecondaryTablesGeometryFields))
7827
0
        {
7828
7829
0
            for (int iField = 0;
7830
0
                 iField < poSrcLayer->GetLayerDefn()->GetGeomFieldCount();
7831
0
                 iField++)
7832
0
            {
7833
0
                OGRGeomFieldDefn *poFDefn =
7834
0
                    poSrcLayer->GetLayerDefn()->GetGeomFieldDefn(iField);
7835
0
                const int iOutField = psParseInfo->sFieldList.count++;
7836
0
                psParseInfo->sFieldList.names[iOutField] =
7837
0
                    const_cast<char *>(poFDefn->GetNameRef());
7838
0
                if (*psParseInfo->sFieldList.names[iOutField] == '\0')
7839
0
                    psParseInfo->sFieldList.names[iOutField] =
7840
0
                        const_cast<char *>(OGR_GEOMETRY_DEFAULT_NON_EMPTY_NAME);
7841
0
                psParseInfo->sFieldList.types[iOutField] = SWQ_GEOMETRY;
7842
7843
0
                psParseInfo->sFieldList.table_ids[iOutField] = iTable;
7844
0
                psParseInfo->sFieldList.ids[iOutField] =
7845
0
                    GEOM_FIELD_INDEX_TO_ALL_FIELD_INDEX(
7846
0
                        poSrcLayer->GetLayerDefn(), iField);
7847
0
            }
7848
0
        }
7849
7850
0
        if (iTable == 0 && poSrcLayer->GetMetadataItem(OLMD_FID64) != nullptr &&
7851
0
            EQUAL(poSrcLayer->GetMetadataItem(OLMD_FID64), "YES"))
7852
0
        {
7853
0
            bIsFID64 = true;
7854
0
        }
7855
0
    }
7856
7857
    /* -------------------------------------------------------------------- */
7858
    /*      Expand '*' in 'SELECT *' now before we add the pseudo fields    */
7859
    /* -------------------------------------------------------------------- */
7860
0
    const bool bAlwaysPrefixWithTableName =
7861
0
        poSelectParseOptions &&
7862
0
        poSelectParseOptions->bAlwaysPrefixWithTableName;
7863
0
    if (psSelectInfo->expand_wildcard(&psParseInfo->sFieldList,
7864
0
                                      bAlwaysPrefixWithTableName) != CE_None)
7865
0
    {
7866
0
        DestroyParseInfo(psParseInfo);
7867
0
        return nullptr;
7868
0
    }
7869
7870
0
    for (int iField = 0; iField < SPECIAL_FIELD_COUNT; iField++)
7871
0
    {
7872
0
        psParseInfo->sFieldList.names[psParseInfo->sFieldList.count] =
7873
0
            const_cast<char *>(SpecialFieldNames[iField]);
7874
0
        psParseInfo->sFieldList.types[psParseInfo->sFieldList.count] =
7875
0
            (iField == SPF_FID && bIsFID64) ? SWQ_INTEGER64
7876
0
                                            : SpecialFieldTypes[iField];
7877
0
        psParseInfo->sFieldList.table_ids[psParseInfo->sFieldList.count] = 0;
7878
0
        psParseInfo->sFieldList.ids[psParseInfo->sFieldList.count] =
7879
0
            nFirstLayerFirstSpecialFieldIndex + iField;
7880
0
        psParseInfo->sFieldList.count++;
7881
0
    }
7882
7883
    /* In the case a layer has an explicit FID column name, then add it */
7884
    /* so it can be selected */
7885
0
    for (int iTable = 0; iTable < psSelectInfo->table_count; iTable++)
7886
0
    {
7887
0
        swq_table_def *psTableDef = psSelectInfo->table_defs + iTable;
7888
0
        GDALDataset *poTableDS = this;
7889
7890
0
        if (psTableDef->data_source != nullptr)
7891
0
        {
7892
0
            poTableDS = GDALDataset::FromHandle(
7893
0
                OGROpenShared(psTableDef->data_source, FALSE, nullptr));
7894
0
            CPLAssert(poTableDS != nullptr);
7895
0
            poTableDS->Dereference();
7896
0
        }
7897
7898
0
        OGRLayer *poSrcLayer =
7899
0
            poTableDS->GetLayerByName(psTableDef->table_name);
7900
7901
0
        const char *pszFID = poSrcLayer->GetFIDColumn();
7902
0
        if (pszFID && !EQUAL(pszFID, "") && !EQUAL(pszFID, "FID") &&
7903
0
            poSrcLayer->GetLayerDefn()->GetFieldIndex(pszFID) < 0)
7904
0
        {
7905
0
            const int iOutField = psParseInfo->sFieldList.count++;
7906
0
            psParseInfo->sFieldList.names[iOutField] =
7907
0
                const_cast<char *>(pszFID);
7908
0
            if (poSrcLayer->GetMetadataItem(OLMD_FID64) != nullptr &&
7909
0
                EQUAL(poSrcLayer->GetMetadataItem(OLMD_FID64), "YES"))
7910
0
            {
7911
0
                psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER64;
7912
0
            }
7913
0
            else
7914
0
            {
7915
0
                psParseInfo->sFieldList.types[iOutField] = SWQ_INTEGER;
7916
0
            }
7917
0
            psParseInfo->sFieldList.table_ids[iOutField] = iTable;
7918
0
            psParseInfo->sFieldList.ids[iOutField] =
7919
0
                poSrcLayer->GetLayerDefn()->GetFieldCount() + SPF_FID;
7920
0
        }
7921
0
    }
7922
7923
    /* -------------------------------------------------------------------- */
7924
    /*      Finish the parse operation.                                     */
7925
    /* -------------------------------------------------------------------- */
7926
0
    if (psSelectInfo->parse(&psParseInfo->sFieldList, poSelectParseOptions) !=
7927
0
        CE_None)
7928
0
    {
7929
0
        DestroyParseInfo(psParseInfo);
7930
0
        return nullptr;
7931
0
    }
7932
7933
    /* -------------------------------------------------------------------- */
7934
    /*      Extract the WHERE expression to use separately.                 */
7935
    /* -------------------------------------------------------------------- */
7936
0
    if (psSelectInfo->where_expr != nullptr)
7937
0
    {
7938
0
        psParseInfo->pszWHERE =
7939
0
            psSelectInfo->where_expr->Unparse(&psParseInfo->sFieldList, '"');
7940
        // CPLDebug( "OGR", "Unparse() -> %s", pszWHERE );
7941
0
    }
7942
7943
0
    return psParseInfo;
7944
0
}
7945
7946
//! @endcond
7947
7948
/************************************************************************/
7949
/*                          ReleaseResultSet()                          */
7950
/************************************************************************/
7951
7952
/**
7953
 \brief Release results of ExecuteSQL().
7954
7955
 This method should only be used to deallocate OGRLayers resulting from
7956
 an ExecuteSQL() call on the same GDALDataset.  Failure to deallocate a
7957
 results set before destroying the GDALDataset may cause errors.
7958
7959
 This method is the same as the C function GDALDatasetReleaseResultSet() and the
7960
 deprecated OGR_DS_ReleaseResultSet().
7961
7962
 @param poResultsSet the result of a previous ExecuteSQL() call.
7963
*/
7964
7965
void GDALDataset::ReleaseResultSet(OGRLayer *poResultsSet)
7966
7967
0
{
7968
0
    delete poResultsSet;
7969
0
}
7970
7971
/************************************************************************/
7972
/*                           GetStyleTable()                            */
7973
/************************************************************************/
7974
7975
/**
7976
 \brief Returns dataset style table.
7977
7978
 This method is the same as the C function GDALDatasetGetStyleTable() and the
7979
 deprecated OGR_DS_GetStyleTable().
7980
7981
 @return pointer to a style table which should not be modified or freed by the
7982
 caller.
7983
*/
7984
7985
OGRStyleTable *GDALDataset::GetStyleTable()
7986
0
{
7987
0
    return m_poStyleTable;
7988
0
}
7989
7990
/************************************************************************/
7991
/*                       SetStyleTableDirectly()                        */
7992
/************************************************************************/
7993
7994
/**
7995
 \brief Set dataset style table.
7996
7997
 This method operate exactly as SetStyleTable() except that it
7998
 assumes ownership of the passed table.
7999
8000
 This method is the same as the C function GDALDatasetSetStyleTableDirectly()
8001
 and the deprecated OGR_DS_SetStyleTableDirectly().
8002
8003
 @param poStyleTable pointer to style table to set
8004
8005
*/
8006
void GDALDataset::SetStyleTableDirectly(OGRStyleTable *poStyleTable)
8007
0
{
8008
0
    if (m_poStyleTable)
8009
0
        delete m_poStyleTable;
8010
0
    m_poStyleTable = poStyleTable;
8011
0
}
8012
8013
/************************************************************************/
8014
/*                           SetStyleTable()                            */
8015
/************************************************************************/
8016
8017
/**
8018
 \brief Set dataset style table.
8019
8020
 This method operate exactly as SetStyleTableDirectly() except
8021
 that it does not assume ownership of the passed table.
8022
8023
 This method is the same as the C function GDALDatasetSetStyleTable() and the
8024
 deprecated OGR_DS_SetStyleTable().
8025
8026
 @param poStyleTable pointer to style table to set
8027
8028
*/
8029
8030
void GDALDataset::SetStyleTable(OGRStyleTable *poStyleTable)
8031
0
{
8032
0
    if (m_poStyleTable)
8033
0
        delete m_poStyleTable;
8034
0
    if (poStyleTable)
8035
0
        m_poStyleTable = poStyleTable->Clone();
8036
0
}
8037
8038
/************************************************************************/
8039
/*                        IsGenericSQLDialect()                         */
8040
/************************************************************************/
8041
8042
//! @cond Doxygen_Suppress
8043
int GDALDataset::IsGenericSQLDialect(const char *pszDialect)
8044
0
{
8045
0
    return pszDialect != nullptr &&
8046
0
           (EQUAL(pszDialect, "OGRSQL") || EQUAL(pszDialect, "SQLITE"));
8047
0
}
8048
8049
//! @endcond
8050
8051
/************************************************************************/
8052
/*                           GetLayerCount()                            */
8053
/************************************************************************/
8054
8055
/**
8056
 \brief Get the number of layers in this dataset.
8057
8058
 This method is the same as the C function GDALDatasetGetLayerCount(),
8059
 and the deprecated OGR_DS_GetLayerCount().
8060
8061
 Note that even if this method is const, there is no guarantee it can be
8062
 safely called by concurrent threads on the same GDALDataset object.
8063
8064
 @return layer count.
8065
*/
8066
8067
int GDALDataset::GetLayerCount() const
8068
0
{
8069
0
    return 0;
8070
0
}
8071
8072
/************************************************************************/
8073
/*                              GetLayer()                              */
8074
/************************************************************************/
8075
8076
/**
8077
 \fn const GDALDataset::GetLayer(int) const
8078
 \brief Fetch a layer by index.
8079
8080
 The returned layer remains owned by the
8081
 GDALDataset and should not be deleted by the application.
8082
8083
 Note that even if this method is const, there is no guarantee it can be
8084
 safely called by concurrent threads on the same GDALDataset object.
8085
8086
 See GetLayers() for a C++ iterator version of this method.
8087
8088
 This method is the same as the C function GDALDatasetGetLayer() and the
8089
 deprecated OGR_DS_GetLayer().
8090
8091
 @param iLayer a layer number between 0 and GetLayerCount()-1.
8092
8093
 @return the layer, or NULL if iLayer is out of range or an error occurs.
8094
8095
 @see GetLayers()
8096
8097
 @since GDAL 3.12
8098
*/
8099
8100
const OGRLayer *GDALDataset::GetLayer(CPL_UNUSED int iLayer) const
8101
0
{
8102
0
    return nullptr;
8103
0
}
8104
8105
/**
8106
 \fn GDALDataset::GetLayer(int)
8107
 \brief Fetch a layer by index.
8108
8109
 The returned layer remains owned by the
8110
 GDALDataset and should not be deleted by the application.
8111
8112
 See GetLayers() for a C++ iterator version of this method.
8113
8114
 This method is the same as the C function GDALDatasetGetLayer() and the
8115
 deprecated OGR_DS_GetLayer().
8116
8117
 @param iLayer a layer number between 0 and GetLayerCount()-1.
8118
8119
 @return the layer, or NULL if iLayer is out of range or an error occurs.
8120
8121
 @see GetLayers()
8122
*/
8123
8124
/************************************************************************/
8125
/*                           IsLayerPrivate()                           */
8126
/************************************************************************/
8127
8128
/**
8129
 \fn GDALDataset::IsLayerPrivate(int)
8130
 \brief Returns true if the layer at the specified index is deemed a private or
8131
 system table, or an internal detail only.
8132
8133
 This method is the same as the C function GDALDatasetIsLayerPrivate().
8134
8135
 @param iLayer a layer number between 0 and GetLayerCount()-1.
8136
8137
 @return true if the layer is a private or system table.
8138
8139
 @since GDAL 3.4
8140
*/
8141
8142
bool GDALDataset::IsLayerPrivate(CPL_UNUSED int iLayer) const
8143
0
{
8144
0
    return false;
8145
0
}
8146
8147
/************************************************************************/
8148
/*                            ResetReading()                            */
8149
/************************************************************************/
8150
8151
/**
8152
 \brief Reset feature reading to start on the first feature.
8153
8154
 This affects GetNextFeature().
8155
8156
 Depending on drivers, this may also have the side effect of calling
8157
 OGRLayer::ResetReading() on the layers of this dataset.
8158
8159
 This method is the same as the C function GDALDatasetResetReading().
8160
8161
*/
8162
void GDALDataset::ResetReading()
8163
0
{
8164
0
    if (!m_poPrivate)
8165
0
        return;
8166
0
    m_poPrivate->nCurrentLayerIdx = 0;
8167
0
    m_poPrivate->nLayerCount = -1;
8168
0
    m_poPrivate->poCurrentLayer = nullptr;
8169
0
    m_poPrivate->nFeatureReadInLayer = 0;
8170
0
    m_poPrivate->nFeatureReadInDataset = 0;
8171
0
    m_poPrivate->nTotalFeaturesInLayer = TOTAL_FEATURES_NOT_INIT;
8172
0
    m_poPrivate->nTotalFeatures = TOTAL_FEATURES_NOT_INIT;
8173
0
}
8174
8175
/************************************************************************/
8176
/*                      GDALDatasetResetReading()                       */
8177
/************************************************************************/
8178
8179
/**
8180
 \brief Reset feature reading to start on the first feature.
8181
8182
 This affects GDALDatasetGetNextFeature().
8183
8184
 Depending on drivers, this may also have the side effect of calling
8185
 OGR_L_ResetReading() on the layers of this dataset.
8186
8187
 This method is the same as the C++ method GDALDataset::ResetReading()
8188
8189
 @param hDS dataset handle
8190
*/
8191
void CPL_DLL GDALDatasetResetReading(GDALDatasetH hDS)
8192
0
{
8193
0
    VALIDATE_POINTER0(hDS, "GDALDatasetResetReading");
8194
8195
0
    return GDALDataset::FromHandle(hDS)->ResetReading();
8196
0
}
8197
8198
/************************************************************************/
8199
/*                           GetNextFeature()                           */
8200
/************************************************************************/
8201
8202
/**
8203
 \brief Fetch the next available feature from this dataset.
8204
8205
 This method is intended for the few drivers where OGRLayer::GetNextFeature()
8206
 is not efficient, but in general OGRLayer::GetNextFeature() is a more
8207
 natural API.
8208
8209
 See GetFeatures() for a C++ iterator version of this method.
8210
8211
 The returned feature becomes the responsibility of the caller to
8212
 delete with OGRFeature::DestroyFeature().
8213
8214
 Depending on the driver, this method may return features from layers in a
8215
 non sequential way. This is what may happen when the
8216
 ODsCRandomLayerRead capability is declared (for example for the
8217
 OSM and GMLAS drivers). When datasets declare this capability, it is strongly
8218
 advised to use GDALDataset::GetNextFeature() instead of
8219
 OGRLayer::GetNextFeature(), as the later might have a slow, incomplete or stub
8220
 implementation.
8221
8222
 The default implementation, used by most drivers, will
8223
 however iterate over each layer, and then over each feature within this
8224
 layer.
8225
8226
 This method takes into account spatial and attribute filters set on layers that
8227
 will be iterated upon.
8228
8229
 The ResetReading() method can be used to start at the beginning again.
8230
8231
 Depending on drivers, this may also have the side effect of calling
8232
 OGRLayer::GetNextFeature() on the layers of this dataset.
8233
8234
 This method is the same as the C function GDALDatasetGetNextFeature().
8235
8236
 @param ppoBelongingLayer a pointer to a OGRLayer* variable to receive the
8237
                          layer to which the object belongs to, or NULL.
8238
                          It is possible that the output of *ppoBelongingLayer
8239
                          to be NULL despite the feature not being NULL.
8240
 @param pdfProgressPct    a pointer to a double variable to receive the
8241
                          percentage progress (in [0,1] range), or NULL.
8242
                          On return, the pointed value might be negative if
8243
                          determining the progress is not possible.
8244
 @param pfnProgress       a progress callback to report progress (for
8245
                          GetNextFeature() calls that might have a long
8246
                          duration) and offer cancellation possibility, or NULL.
8247
 @param pProgressData     user data provided to pfnProgress, or NULL
8248
 @return a feature, or NULL if no more features are available.
8249
 @see GetFeatures()
8250
*/
8251
8252
OGRFeature *GDALDataset::GetNextFeature(OGRLayer **ppoBelongingLayer,
8253
                                        double *pdfProgressPct,
8254
                                        GDALProgressFunc pfnProgress,
8255
                                        void *pProgressData)
8256
0
{
8257
0
    if (!m_poPrivate || m_poPrivate->nCurrentLayerIdx < 0)
8258
0
    {
8259
0
        if (ppoBelongingLayer != nullptr)
8260
0
            *ppoBelongingLayer = nullptr;
8261
0
        if (pdfProgressPct != nullptr)
8262
0
            *pdfProgressPct = 1.0;
8263
0
        if (pfnProgress != nullptr)
8264
0
            pfnProgress(1.0, "", pProgressData);
8265
0
        return nullptr;
8266
0
    }
8267
8268
0
    if (m_poPrivate->poCurrentLayer == nullptr &&
8269
0
        (pdfProgressPct != nullptr || pfnProgress != nullptr))
8270
0
    {
8271
0
        if (m_poPrivate->nLayerCount < 0)
8272
0
        {
8273
0
            m_poPrivate->nLayerCount = GetLayerCount();
8274
0
        }
8275
8276
0
        if (m_poPrivate->nTotalFeatures == TOTAL_FEATURES_NOT_INIT)
8277
0
        {
8278
0
            m_poPrivate->nTotalFeatures = 0;
8279
0
            for (int i = 0; i < m_poPrivate->nLayerCount; i++)
8280
0
            {
8281
0
                OGRLayer *poLayer = GetLayer(i);
8282
0
                if (poLayer == nullptr ||
8283
0
                    !poLayer->TestCapability(OLCFastFeatureCount))
8284
0
                {
8285
0
                    m_poPrivate->nTotalFeatures = TOTAL_FEATURES_UNKNOWN;
8286
0
                    break;
8287
0
                }
8288
0
                GIntBig nCount = poLayer->GetFeatureCount(FALSE);
8289
0
                if (nCount < 0)
8290
0
                {
8291
0
                    m_poPrivate->nTotalFeatures = TOTAL_FEATURES_UNKNOWN;
8292
0
                    break;
8293
0
                }
8294
0
                m_poPrivate->nTotalFeatures += nCount;
8295
0
            }
8296
0
        }
8297
0
    }
8298
8299
0
    while (true)
8300
0
    {
8301
0
        if (m_poPrivate->poCurrentLayer == nullptr)
8302
0
        {
8303
0
            m_poPrivate->poCurrentLayer =
8304
0
                GetLayer(m_poPrivate->nCurrentLayerIdx);
8305
0
            if (m_poPrivate->poCurrentLayer == nullptr)
8306
0
            {
8307
0
                m_poPrivate->nCurrentLayerIdx = -1;
8308
0
                if (ppoBelongingLayer != nullptr)
8309
0
                    *ppoBelongingLayer = nullptr;
8310
0
                if (pdfProgressPct != nullptr)
8311
0
                    *pdfProgressPct = 1.0;
8312
0
                return nullptr;
8313
0
            }
8314
0
            m_poPrivate->poCurrentLayer->ResetReading();
8315
0
            m_poPrivate->nFeatureReadInLayer = 0;
8316
0
            if (m_poPrivate->nTotalFeatures < 0 && pdfProgressPct != nullptr)
8317
0
            {
8318
0
                if (m_poPrivate->poCurrentLayer->TestCapability(
8319
0
                        OLCFastFeatureCount))
8320
0
                    m_poPrivate->nTotalFeaturesInLayer =
8321
0
                        m_poPrivate->poCurrentLayer->GetFeatureCount(FALSE);
8322
0
                else
8323
0
                    m_poPrivate->nTotalFeaturesInLayer = 0;
8324
0
            }
8325
0
        }
8326
0
        OGRFeature *poFeature = m_poPrivate->poCurrentLayer->GetNextFeature();
8327
0
        if (poFeature == nullptr)
8328
0
        {
8329
0
            m_poPrivate->nCurrentLayerIdx++;
8330
0
            m_poPrivate->poCurrentLayer = nullptr;
8331
0
            continue;
8332
0
        }
8333
8334
0
        m_poPrivate->nFeatureReadInLayer++;
8335
0
        m_poPrivate->nFeatureReadInDataset++;
8336
0
        if (pdfProgressPct != nullptr || pfnProgress != nullptr)
8337
0
        {
8338
0
            double dfPct = 0.0;
8339
0
            if (m_poPrivate->nTotalFeatures > 0)
8340
0
            {
8341
0
                dfPct = 1.0 * m_poPrivate->nFeatureReadInDataset /
8342
0
                        m_poPrivate->nTotalFeatures;
8343
0
            }
8344
0
            else
8345
0
            {
8346
0
                dfPct = 1.0 * m_poPrivate->nCurrentLayerIdx /
8347
0
                        m_poPrivate->nLayerCount;
8348
0
                if (m_poPrivate->nTotalFeaturesInLayer > 0)
8349
0
                {
8350
0
                    dfPct += 1.0 * m_poPrivate->nFeatureReadInLayer /
8351
0
                             m_poPrivate->nTotalFeaturesInLayer /
8352
0
                             m_poPrivate->nLayerCount;
8353
0
                }
8354
0
            }
8355
0
            if (pdfProgressPct)
8356
0
                *pdfProgressPct = dfPct;
8357
0
            if (pfnProgress)
8358
0
                pfnProgress(dfPct, "", nullptr);
8359
0
        }
8360
8361
0
        if (ppoBelongingLayer != nullptr)
8362
0
            *ppoBelongingLayer = m_poPrivate->poCurrentLayer;
8363
0
        return poFeature;
8364
0
    }
8365
0
}
8366
8367
/************************************************************************/
8368
/*                     GDALDatasetGetNextFeature()                      */
8369
/************************************************************************/
8370
/**
8371
 \brief Fetch the next available feature from this dataset.
8372
8373
 This method is intended for the few drivers where OGR_L_GetNextFeature()
8374
 is not efficient, but in general OGR_L_GetNextFeature() is a more
8375
 natural API.
8376
8377
 The returned feature becomes the responsibility of the caller to
8378
 delete with OGRFeature::DestroyFeature().
8379
8380
 Depending on the driver, this method may return features from layers in a
8381
 non sequential way. This is what may happen when the
8382
 ODsCRandomLayerRead capability is declared (for example for the
8383
 OSM and GMLAS drivers). When datasets declare this capability, it is strongly
8384
 advised to use GDALDataset::GetNextFeature() instead of
8385
 OGRLayer::GetNextFeature(), as the later might have a slow, incomplete or stub
8386
 implementation.
8387
8388
 The default implementation, used by most drivers, will
8389
 however iterate over each layer, and then over each feature within this
8390
 layer.
8391
8392
 This method takes into account spatial and attribute filters set on layers that
8393
 will be iterated upon.
8394
8395
 The ResetReading() method can be used to start at the beginning again.
8396
8397
 Depending on drivers, this may also have the side effect of calling
8398
 OGRLayer::GetNextFeature() on the layers of this dataset.
8399
8400
 This method is the same as the C++ method GDALDataset::GetNextFeature()
8401
8402
 @param hDS               dataset handle.
8403
 @param phBelongingLayer  a pointer to a OGRLayer* variable to receive the
8404
                          layer to which the object belongs to, or NULL.
8405
                          It is possible that the output of *ppoBelongingLayer
8406
                          to be NULL despite the feature not being NULL.
8407
 @param pdfProgressPct    a pointer to a double variable to receive the
8408
                          percentage progress (in [0,1] range), or NULL.
8409
                          On return, the pointed value might be negative if
8410
                          determining the progress is not possible.
8411
 @param pfnProgress       a progress callback to report progress (for
8412
                          GetNextFeature() calls that might have a long
8413
                          duration) and offer cancellation possibility, or NULL
8414
 @param pProgressData     user data provided to pfnProgress, or NULL
8415
 @return a feature, or NULL if no more features are available.
8416
*/
8417
OGRFeatureH CPL_DLL GDALDatasetGetNextFeature(GDALDatasetH hDS,
8418
                                              OGRLayerH *phBelongingLayer,
8419
                                              double *pdfProgressPct,
8420
                                              GDALProgressFunc pfnProgress,
8421
                                              void *pProgressData)
8422
0
{
8423
0
    VALIDATE_POINTER1(hDS, "GDALDatasetGetNextFeature", nullptr);
8424
8425
0
    return OGRFeature::ToHandle(GDALDataset::FromHandle(hDS)->GetNextFeature(
8426
0
        reinterpret_cast<OGRLayer **>(phBelongingLayer), pdfProgressPct,
8427
0
        pfnProgress, pProgressData));
8428
0
}
8429
8430
/************************************************************************/
8431
/*                           TestCapability()                           */
8432
/************************************************************************/
8433
8434
/**
8435
 \fn GDALDataset::TestCapability( const char * pszCap )
8436
 \brief Test if capability is available.
8437
8438
 One of the following dataset capability names can be passed into this
8439
 method, and a TRUE or FALSE value will be returned indicating whether or not
8440
 the capability is available for this object.
8441
8442
 <ul>
8443
  <li> <b>ODsCCreateLayer</b>: True if this datasource can create new layers.<p>
8444
  <li> <b>ODsCDeleteLayer</b>: True if this datasource can delete existing
8445
          layers.<p>
8446
  <li> <b>ODsCCreateGeomFieldAfterCreateLayer</b>: True if the layers of this
8447
          datasource support CreateGeomField() just after layer creation.<p>
8448
  <li> <b>ODsCCurveGeometries</b>: True if this datasource supports curve
8449
          geometries.<p>
8450
  <li> <b>ODsCTransactions</b>: True if this datasource supports (efficient)
8451
          transactions.<p>
8452
  <li> <b>ODsCEmulatedTransactions</b>: True if this datasource supports
8453
          transactions through emulation.<p>
8454
  <li> <b>ODsCRandomLayerRead</b>: True if this datasource has a dedicated
8455
          GetNextFeature() implementation, potentially returning features from
8456
          layers in a non sequential way.<p>
8457
  <li> <b>ODsCRandomLayerWrite</b>: True if this datasource supports calling
8458
         CreateFeature() on layers in a non sequential way.<p>
8459
  <li> <b>GDsCAddRelationship</b>: True if AddRelationship() is supported</li>
8460
  <li> <b>GDsCDeleteRelationship</b>: True if DeleteRelationship() is supported</li>
8461
  <li> <b>GDsCUpdateRelationship</b>: True if UpdateRelationship() is supported</li>
8462
  <li> <b>GDsCFastGetExtent</b>: True if GetExtent() is fast</li>
8463
  <li> <b>GDsCFastGetExtentWGS84LongLat</b>: True if GetExtentWGS84LongLat() is fast</li>
8464
 </ul>
8465
8466
 The \#define macro forms of the capability names should be used in preference
8467
 to the strings themselves to avoid misspelling.
8468
8469
 This method is the same as the C function GDALDatasetTestCapability() and the
8470
 deprecated OGR_DS_TestCapability().
8471
8472
 @param pszCap the capability to test.
8473
8474
 @return TRUE if capability available otherwise FALSE.
8475
*/
8476
8477
int GDALDataset::TestCapability(const char *pszCap) const
8478
0
{
8479
0
    if (EQUAL(pszCap, GDsCFastGetExtent) ||
8480
0
        EQUAL(pszCap, GDsCFastGetExtentWGS84LongLat))
8481
0
    {
8482
0
        for (auto &&poLayer : GetLayers())
8483
0
        {
8484
0
            if (!poLayer->TestCapability(OLCFastGetExtent))
8485
0
                return FALSE;
8486
0
        }
8487
0
        return TRUE;
8488
0
    }
8489
0
    return FALSE;
8490
0
}
8491
8492
/************************************************************************/
8493
/*                     GDALDatasetTestCapability()                      */
8494
/************************************************************************/
8495
8496
/**
8497
 \brief Test if capability is available.
8498
8499
 One of the following dataset capability names can be passed into this
8500
 function, and a TRUE or FALSE value will be returned indicating whether or not
8501
 the capability is available for this object.
8502
8503
 <ul>
8504
  <li> <b>ODsCCreateLayer</b>: True if this datasource can create new layers.<p>
8505
  <li> <b>ODsCDeleteLayer</b>: True if this datasource can delete existing
8506
          layers.<p>
8507
  <li> <b>ODsCCreateGeomFieldAfterCreateLayer</b>: True if the layers of this
8508
          datasource support CreateGeomField() just after layer creation.<p>
8509
  <li> <b>ODsCCurveGeometries</b>: True if this datasource supports curve
8510
          geometries.<p>
8511
  <li> <b>ODsCTransactions</b>: True if this datasource supports (efficient)
8512
          transactions.<p>
8513
  <li> <b>ODsCEmulatedTransactions</b>: True if this datasource supports
8514
          transactions through emulation.<p>
8515
  <li> <b>ODsCRandomLayerRead</b>: True if this datasource has a dedicated
8516
          GetNextFeature() implementation, potentially returning features from
8517
          layers in a non sequential way.<p>
8518
  <li> <b>ODsCRandomLayerWrite</b>: True if this datasource supports calling
8519
          CreateFeature() on layers in a non sequential way.<p>
8520
  <li> <b>GDsCAddRelationship</b>: True if AddRelationship() is supported</li>
8521
  <li> <b>GDsCDeleteRelationship</b>: True if DeleteRelationship() is supported</li>
8522
  <li> <b>GDsCUpdateRelationship</b>: True if UpdateRelationship() is supported</li>
8523
  <li> <b>GDsCFastGetExtent</b>: True if GetExtent() is fast</li>
8524
  <li> <b>GDsCFastGetExtentWGS84LongLat</b>: True if GetExtentWGS84LongLat() is fast</li>
8525
 </ul>
8526
8527
 The \#define macro forms of the capability names should be used in preference
8528
 to the strings themselves to avoid misspelling.
8529
8530
 This function is the same as the C++ method GDALDataset::TestCapability()
8531
8532
8533
 @param hDS the dataset handle.
8534
 @param pszCap the capability to test.
8535
8536
 @return TRUE if capability available otherwise FALSE.
8537
*/
8538
int GDALDatasetTestCapability(GDALDatasetH hDS, const char *pszCap)
8539
8540
0
{
8541
0
    VALIDATE_POINTER1(hDS, "GDALDatasetTestCapability", 0);
8542
0
    VALIDATE_POINTER1(pszCap, "GDALDatasetTestCapability", 0);
8543
8544
0
    return GDALDataset::FromHandle(hDS)->TestCapability(pszCap);
8545
0
}
8546
8547
/************************************************************************/
8548
/*                          StartTransaction()                          */
8549
/************************************************************************/
8550
8551
/**
8552
 \fn GDALDataset::StartTransaction(int)
8553
 \brief For datasources which support transactions, StartTransaction creates a
8554
`transaction.
8555
8556
 If starting the transaction fails, will return
8557
 OGRERR_FAILURE. Datasources which do not support transactions will
8558
 always return OGRERR_UNSUPPORTED_OPERATION.
8559
8560
 Nested transactions are not supported.
8561
8562
 All changes done after the start of the transaction are definitely applied in
8563
 the datasource if CommitTransaction() is called. They may be canceled by
8564
 calling RollbackTransaction() instead.
8565
8566
 At the time of writing, transactions only apply on vector layers.
8567
8568
 Datasets that support transactions will advertise the ODsCTransactions
8569
 capability.  Use of transactions at dataset level is generally preferred to
8570
 transactions at layer level, whose scope is rarely limited to the layer from
8571
 which it was started.
8572
8573
 In case StartTransaction() fails, neither CommitTransaction() or
8574
 RollbackTransaction() should be called.
8575
8576
 If an error occurs after a successful StartTransaction(), the whole transaction
8577
 may or may not be implicitly canceled, depending on drivers. (e.g.  the PG
8578
 driver will cancel it, SQLite/GPKG not). In any case, in the event of an error,
8579
 an explicit call to RollbackTransaction() should be done to keep things
8580
 balanced.
8581
8582
 By default, when bForce is set to FALSE, only "efficient" transactions will be
8583
 attempted. Some drivers may offer an emulation of transactions, but sometimes
8584
 with significant overhead, in which case the user must explicitly allow for
8585
 such an emulation by setting bForce to TRUE. Drivers that offer emulated
8586
 transactions should advertise the ODsCEmulatedTransactions capability (and not
8587
 ODsCTransactions).
8588
8589
 This function is the same as the C function GDALDatasetStartTransaction().
8590
8591
 @param bForce can be set to TRUE if an emulation, possibly slow, of a
8592
 transaction
8593
               mechanism is acceptable.
8594
8595
 @return OGRERR_NONE on success.
8596
*/
8597
8598
OGRErr GDALDataset::StartTransaction(CPL_UNUSED int bForce)
8599
0
{
8600
0
    return OGRERR_UNSUPPORTED_OPERATION;
8601
0
}
8602
8603
/************************************************************************/
8604
/*                    GDALDatasetStartTransaction()                     */
8605
/************************************************************************/
8606
8607
/**
8608
 \brief For datasources which support transactions, StartTransaction creates a
8609
 transaction.
8610
8611
 If starting the transaction fails, will return
8612
 OGRERR_FAILURE. Datasources which do not support transactions will
8613
 always return OGRERR_UNSUPPORTED_OPERATION.
8614
8615
 Nested transactions are not supported.
8616
8617
 All changes done after the start of the transaction are definitely applied in
8618
 the datasource if CommitTransaction() is called. They may be canceled by
8619
 calling RollbackTransaction() instead.
8620
8621
 At the time of writing, transactions only apply on vector layers.
8622
8623
 Datasets that support transactions will advertise the ODsCTransactions
8624
 capability.
8625
 Use of transactions at dataset level is generally preferred to transactions at
8626
 layer level, whose scope is rarely limited to the layer from which it was
8627
 started.
8628
8629
 In case StartTransaction() fails, neither CommitTransaction() or
8630
 RollbackTransaction() should be called.
8631
8632
 If an error occurs after a successful StartTransaction(), the whole
8633
 transaction may or may not be implicitly canceled, depending on drivers. (e.g.
8634
 the PG driver will cancel it, SQLite/GPKG not). In any case, in the event of an
8635
 error, an explicit call to RollbackTransaction() should be done to keep things
8636
 balanced.
8637
8638
 By default, when bForce is set to FALSE, only "efficient" transactions will be
8639
 attempted. Some drivers may offer an emulation of transactions, but sometimes
8640
 with significant overhead, in which case the user must explicitly allow for
8641
 such an emulation by setting bForce to TRUE. Drivers that offer emulated
8642
 transactions should advertise the ODsCEmulatedTransactions capability (and not
8643
 ODsCTransactions).
8644
8645
 This function is the same as the C++ method GDALDataset::StartTransaction()
8646
8647
 @param hDS the dataset handle.
8648
 @param bForce can be set to TRUE if an emulation, possibly slow, of a
8649
 transaction
8650
               mechanism is acceptable.
8651
8652
 @return OGRERR_NONE on success.
8653
*/
8654
OGRErr GDALDatasetStartTransaction(GDALDatasetH hDS, int bForce)
8655
0
{
8656
0
    VALIDATE_POINTER1(hDS, "GDALDatasetStartTransaction",
8657
0
                      OGRERR_INVALID_HANDLE);
8658
8659
0
#ifdef OGRAPISPY_ENABLED
8660
0
    if (bOGRAPISpyEnabled)
8661
0
        OGRAPISpy_Dataset_StartTransaction(hDS, bForce);
8662
0
#endif
8663
8664
0
    return GDALDataset::FromHandle(hDS)->StartTransaction(bForce);
8665
0
}
8666
8667
/************************************************************************/
8668
/*                         CommitTransaction()                          */
8669
/************************************************************************/
8670
8671
/**
8672
 \brief For datasources which support transactions, CommitTransaction commits a
8673
 transaction.
8674
8675
 If no transaction is active, or the commit fails, will return
8676
 OGRERR_FAILURE. Datasources which do not support transactions will
8677
 always return OGRERR_UNSUPPORTED_OPERATION.
8678
8679
 Depending on drivers, this may or may not abort layer sequential readings that
8680
 are active.
8681
8682
 This function is the same as the C function GDALDatasetCommitTransaction().
8683
8684
 @return OGRERR_NONE on success.
8685
*/
8686
OGRErr GDALDataset::CommitTransaction()
8687
0
{
8688
0
    return OGRERR_UNSUPPORTED_OPERATION;
8689
0
}
8690
8691
/************************************************************************/
8692
/*                    GDALDatasetCommitTransaction()                    */
8693
/************************************************************************/
8694
8695
/**
8696
 \brief For datasources which support transactions, CommitTransaction commits a
8697
 transaction.
8698
8699
 If no transaction is active, or the commit fails, will return
8700
 OGRERR_FAILURE. Datasources which do not support transactions will
8701
 always return OGRERR_UNSUPPORTED_OPERATION.
8702
8703
 Depending on drivers, this may or may not abort layer sequential readings that
8704
 are active.
8705
8706
 This function is the same as the C++ method GDALDataset::CommitTransaction()
8707
8708
 @return OGRERR_NONE on success.
8709
*/
8710
OGRErr GDALDatasetCommitTransaction(GDALDatasetH hDS)
8711
0
{
8712
0
    VALIDATE_POINTER1(hDS, "GDALDatasetCommitTransaction",
8713
0
                      OGRERR_INVALID_HANDLE);
8714
8715
0
#ifdef OGRAPISPY_ENABLED
8716
0
    if (bOGRAPISpyEnabled)
8717
0
        OGRAPISpy_Dataset_CommitTransaction(hDS);
8718
0
#endif
8719
8720
0
    return GDALDataset::FromHandle(hDS)->CommitTransaction();
8721
0
}
8722
8723
/************************************************************************/
8724
/*                        RollbackTransaction()                         */
8725
/************************************************************************/
8726
8727
/**
8728
 \brief For datasources which support transactions, RollbackTransaction will
8729
 roll back a datasource to its state before the start of the current
8730
 transaction.
8731
 If no transaction is active, or the rollback fails, will return
8732
 OGRERR_FAILURE. Datasources which do not support transactions will
8733
 always return OGRERR_UNSUPPORTED_OPERATION.
8734
8735
 This function is the same as the C function GDALDatasetRollbackTransaction().
8736
8737
 @return OGRERR_NONE on success.
8738
*/
8739
OGRErr GDALDataset::RollbackTransaction()
8740
0
{
8741
0
    return OGRERR_UNSUPPORTED_OPERATION;
8742
0
}
8743
8744
/************************************************************************/
8745
/*                   GDALDatasetRollbackTransaction()                   */
8746
/************************************************************************/
8747
8748
/**
8749
 \brief For datasources which support transactions, RollbackTransaction will
8750
 roll back a datasource to its state before the start of the current
8751
 transaction.
8752
 If no transaction is active, or the rollback fails, will return
8753
 OGRERR_FAILURE. Datasources which do not support transactions will
8754
 always return OGRERR_UNSUPPORTED_OPERATION.
8755
8756
 This function is the same as the C++ method GDALDataset::RollbackTransaction().
8757
8758
 @return OGRERR_NONE on success.
8759
*/
8760
OGRErr GDALDatasetRollbackTransaction(GDALDatasetH hDS)
8761
0
{
8762
0
    VALIDATE_POINTER1(hDS, "GDALDatasetRollbackTransaction",
8763
0
                      OGRERR_INVALID_HANDLE);
8764
8765
0
#ifdef OGRAPISPY_ENABLED
8766
0
    if (bOGRAPISpyEnabled)
8767
0
        OGRAPISpy_Dataset_RollbackTransaction(hDS);
8768
0
#endif
8769
8770
0
    return GDALDataset::FromHandle(hDS)->RollbackTransaction();
8771
0
}
8772
8773
//! @cond Doxygen_Suppress
8774
8775
/************************************************************************/
8776
/*                     ShareLockWithParentDataset()                     */
8777
/************************************************************************/
8778
8779
/* To be used typically by the GTiff driver to link overview datasets */
8780
/* with their main dataset, so that they share the same lock */
8781
/* Cf https://github.com/OSGeo/gdal/issues/1488 */
8782
/* The parent dataset should remain alive while the this dataset is alive */
8783
8784
void GDALDataset::ShareLockWithParentDataset(GDALDataset *poParentDataset)
8785
0
{
8786
0
    if (m_poPrivate != nullptr)
8787
0
    {
8788
0
        m_poPrivate->poParentDataset = poParentDataset;
8789
0
    }
8790
0
}
8791
8792
/************************************************************************/
8793
/*                         SetQueryLoggerFunc()                         */
8794
/************************************************************************/
8795
8796
bool GDALDataset::SetQueryLoggerFunc(CPL_UNUSED GDALQueryLoggerFunc callback,
8797
                                     CPL_UNUSED void *context)
8798
0
{
8799
0
    return false;
8800
0
}
8801
8802
/************************************************************************/
8803
/*                           EnterReadWrite()                           */
8804
/************************************************************************/
8805
8806
int GDALDataset::EnterReadWrite(GDALRWFlag eRWFlag)
8807
0
{
8808
0
    if (m_poPrivate == nullptr ||
8809
0
        IsThreadSafe(GDAL_OF_RASTER | (nOpenFlags & GDAL_OF_UPDATE)))
8810
0
        return FALSE;
8811
8812
0
    if (m_poPrivate->poParentDataset)
8813
0
        return m_poPrivate->poParentDataset->EnterReadWrite(eRWFlag);
8814
8815
0
    if (eAccess == GA_Update)
8816
0
    {
8817
0
        if (m_poPrivate->eStateReadWriteMutex ==
8818
0
            GDALAllowReadWriteMutexState::RW_MUTEX_STATE_UNKNOWN)
8819
0
        {
8820
            // In case dead-lock would occur, which is not impossible,
8821
            // this can be used to prevent it, but at the risk of other
8822
            // issues.
8823
0
            if (CPLTestBool(
8824
0
                    CPLGetConfigOption("GDAL_ENABLE_READ_WRITE_MUTEX", "YES")))
8825
0
            {
8826
0
                m_poPrivate->eStateReadWriteMutex =
8827
0
                    GDALAllowReadWriteMutexState::RW_MUTEX_STATE_ALLOWED;
8828
0
            }
8829
0
            else
8830
0
            {
8831
0
                m_poPrivate->eStateReadWriteMutex =
8832
0
                    GDALAllowReadWriteMutexState::RW_MUTEX_STATE_DISABLED;
8833
0
            }
8834
0
        }
8835
0
        if (m_poPrivate->eStateReadWriteMutex ==
8836
0
            GDALAllowReadWriteMutexState::RW_MUTEX_STATE_ALLOWED)
8837
0
        {
8838
            // There should be no race related to creating this mutex since
8839
            // it should be first created through IWriteBlock() / IRasterIO()
8840
            // and then GDALRasterBlock might call it from another thread.
8841
#ifdef DEBUG_VERBOSE
8842
            CPLDebug("GDAL",
8843
                     "[Thread " CPL_FRMT_GIB "] Acquiring RW mutex for %s",
8844
                     CPLGetPID(), GetDescription());
8845
#endif
8846
0
            CPLCreateOrAcquireMutex(&(m_poPrivate->hMutex), 1000.0);
8847
8848
0
            const int nCountMutex =
8849
0
                m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()]++;
8850
0
            if (nCountMutex == 0 && eRWFlag == GF_Read)
8851
0
            {
8852
0
                CPLReleaseMutex(m_poPrivate->hMutex);
8853
0
                for (int i = 0; i < nBands; i++)
8854
0
                {
8855
0
                    auto blockCache = papoBands[i]->poBandBlockCache;
8856
0
                    if (blockCache)
8857
0
                        blockCache->WaitCompletionPendingTasks();
8858
0
                }
8859
0
                CPLCreateOrAcquireMutex(&(m_poPrivate->hMutex), 1000.0);
8860
0
            }
8861
8862
0
            return TRUE;
8863
0
        }
8864
0
    }
8865
0
    return FALSE;
8866
0
}
8867
8868
/************************************************************************/
8869
/*                           LeaveReadWrite()                           */
8870
/************************************************************************/
8871
8872
void GDALDataset::LeaveReadWrite()
8873
0
{
8874
0
    if (m_poPrivate)
8875
0
    {
8876
0
        if (m_poPrivate->poParentDataset)
8877
0
        {
8878
0
            m_poPrivate->poParentDataset->LeaveReadWrite();
8879
0
            return;
8880
0
        }
8881
8882
0
        m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()]--;
8883
0
        CPLReleaseMutex(m_poPrivate->hMutex);
8884
#ifdef DEBUG_VERBOSE
8885
        CPLDebug("GDAL", "[Thread " CPL_FRMT_GIB "] Releasing RW mutex for %s",
8886
                 CPLGetPID(), GetDescription());
8887
#endif
8888
0
    }
8889
0
}
8890
8891
/************************************************************************/
8892
/*                             InitRWLock()                             */
8893
/************************************************************************/
8894
8895
void GDALDataset::InitRWLock()
8896
0
{
8897
0
    if (m_poPrivate)
8898
0
    {
8899
0
        if (m_poPrivate->poParentDataset)
8900
0
        {
8901
0
            m_poPrivate->poParentDataset->InitRWLock();
8902
0
            return;
8903
0
        }
8904
8905
0
        if (m_poPrivate->eStateReadWriteMutex ==
8906
0
            GDALAllowReadWriteMutexState::RW_MUTEX_STATE_UNKNOWN)
8907
0
        {
8908
0
            if (EnterReadWrite(GF_Write))
8909
0
                LeaveReadWrite();
8910
0
        }
8911
0
    }
8912
0
}
8913
8914
/************************************************************************/
8915
/*                       DisableReadWriteMutex()                        */
8916
/************************************************************************/
8917
8918
// The mutex logic is broken in multi-threaded situations, for example
8919
// with 2 WarpedVRT datasets being read at the same time. In that
8920
// particular case, the mutex is not needed, so allow the VRTWarpedDataset code
8921
// to disable it.
8922
void GDALDataset::DisableReadWriteMutex()
8923
0
{
8924
0
    if (m_poPrivate)
8925
0
    {
8926
0
        if (m_poPrivate->poParentDataset)
8927
0
        {
8928
0
            m_poPrivate->poParentDataset->DisableReadWriteMutex();
8929
0
            return;
8930
0
        }
8931
8932
0
        m_poPrivate->eStateReadWriteMutex =
8933
0
            GDALAllowReadWriteMutexState::RW_MUTEX_STATE_DISABLED;
8934
0
    }
8935
0
}
8936
8937
/************************************************************************/
8938
/*                    TemporarilyDropReadWriteLock()                    */
8939
/************************************************************************/
8940
8941
void GDALDataset::TemporarilyDropReadWriteLock()
8942
0
{
8943
0
    if (m_poPrivate == nullptr)
8944
0
        return;
8945
8946
0
    if (m_poPrivate->poParentDataset)
8947
0
    {
8948
0
        m_poPrivate->poParentDataset->TemporarilyDropReadWriteLock();
8949
0
        return;
8950
0
    }
8951
8952
0
#ifndef __COVERITY__
8953
0
    if (m_poPrivate->hMutex)
8954
0
    {
8955
#ifdef DEBUG_VERBOSE
8956
        CPLDebug("GDAL",
8957
                 "[Thread " CPL_FRMT_GIB "] "
8958
                 "Temporarily drop RW mutex for %s",
8959
                 CPLGetPID(), GetDescription());
8960
#endif
8961
0
        CPLAcquireMutex(m_poPrivate->hMutex, 1000.0);
8962
0
        const int nCount =
8963
0
            m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()];
8964
#ifdef DEBUG_EXTRA
8965
        m_poPrivate->oMapThreadToMutexTakenCountSaved[CPLGetPID()] = nCount;
8966
#endif
8967
0
        for (int i = 0; i < nCount + 1; i++)
8968
0
        {
8969
            // The mutex is recursive
8970
0
            CPLReleaseMutex(m_poPrivate->hMutex);
8971
0
        }
8972
0
    }
8973
0
#endif
8974
0
}
8975
8976
/************************************************************************/
8977
/*                       ReacquireReadWriteLock()                       */
8978
/************************************************************************/
8979
8980
void GDALDataset::ReacquireReadWriteLock()
8981
0
{
8982
0
    if (m_poPrivate == nullptr)
8983
0
        return;
8984
8985
0
    if (m_poPrivate->poParentDataset)
8986
0
    {
8987
0
        m_poPrivate->poParentDataset->ReacquireReadWriteLock();
8988
0
        return;
8989
0
    }
8990
8991
0
#ifndef __COVERITY__
8992
0
    if (m_poPrivate->hMutex)
8993
0
    {
8994
#ifdef DEBUG_VERBOSE
8995
        CPLDebug("GDAL",
8996
                 "[Thread " CPL_FRMT_GIB "] "
8997
                 "Reacquire temporarily dropped RW mutex for %s",
8998
                 CPLGetPID(), GetDescription());
8999
#endif
9000
0
        CPLAcquireMutex(m_poPrivate->hMutex, 1000.0);
9001
0
        const int nCount =
9002
0
            m_poPrivate->oMapThreadToMutexTakenCount[CPLGetPID()];
9003
#ifdef DEBUG_EXTRA
9004
        CPLAssert(nCount ==
9005
                  m_poPrivate->oMapThreadToMutexTakenCountSaved[CPLGetPID()]);
9006
#endif
9007
0
        if (nCount == 0)
9008
0
            CPLReleaseMutex(m_poPrivate->hMutex);
9009
0
        for (int i = 0; i < nCount - 1; i++)
9010
0
        {
9011
            // The mutex is recursive
9012
0
            CPLAcquireMutex(m_poPrivate->hMutex, 1000.0);
9013
0
        }
9014
0
    }
9015
0
#endif
9016
0
}
9017
9018
/************************************************************************/
9019
/*                            AcquireMutex()                            */
9020
/************************************************************************/
9021
9022
int GDALDataset::AcquireMutex()
9023
0
{
9024
0
    if (m_poPrivate == nullptr)
9025
0
        return 0;
9026
0
    if (m_poPrivate->poParentDataset)
9027
0
    {
9028
0
        return m_poPrivate->poParentDataset->AcquireMutex();
9029
0
    }
9030
9031
0
    return CPLCreateOrAcquireMutex(&(m_poPrivate->hMutex), 1000.0);
9032
0
}
9033
9034
/************************************************************************/
9035
/*                            ReleaseMutex()                            */
9036
/************************************************************************/
9037
9038
void GDALDataset::ReleaseMutex()
9039
0
{
9040
0
    if (m_poPrivate)
9041
0
    {
9042
0
        if (m_poPrivate->poParentDataset)
9043
0
        {
9044
0
            m_poPrivate->poParentDataset->ReleaseMutex();
9045
0
            return;
9046
0
        }
9047
9048
0
        CPLReleaseMutex(m_poPrivate->hMutex);
9049
0
    }
9050
0
}
9051
9052
//! @endcond
9053
9054
/************************************************************************/
9055
/*               GDALDataset::Features::Iterator::Private               */
9056
/************************************************************************/
9057
9058
struct GDALDataset::Features::Iterator::Private
9059
{
9060
    GDALDataset::FeatureLayerPair m_oPair{};
9061
    GDALDataset *m_poDS = nullptr;
9062
    bool m_bEOF = true;
9063
};
9064
9065
GDALDataset::Features::Iterator::Iterator(GDALDataset *poDS, bool bStart)
9066
0
    : m_poPrivate(new GDALDataset::Features::Iterator::Private())
9067
0
{
9068
0
    m_poPrivate->m_poDS = poDS;
9069
0
    if (bStart)
9070
0
    {
9071
0
        poDS->ResetReading();
9072
0
        m_poPrivate->m_oPair.feature.reset(poDS->GetNextFeature(
9073
0
            &m_poPrivate->m_oPair.layer, nullptr, nullptr, nullptr));
9074
0
        m_poPrivate->m_bEOF = m_poPrivate->m_oPair.feature == nullptr;
9075
0
    }
9076
0
}
9077
9078
0
GDALDataset::Features::Iterator::~Iterator() = default;
9079
9080
const GDALDataset::FeatureLayerPair &
9081
GDALDataset::Features::Iterator::operator*() const
9082
0
{
9083
0
    return m_poPrivate->m_oPair;
9084
0
}
9085
9086
GDALDataset::Features::Iterator &GDALDataset::Features::Iterator::operator++()
9087
0
{
9088
0
    m_poPrivate->m_oPair.feature.reset(m_poPrivate->m_poDS->GetNextFeature(
9089
0
        &m_poPrivate->m_oPair.layer, nullptr, nullptr, nullptr));
9090
0
    m_poPrivate->m_bEOF = m_poPrivate->m_oPair.feature == nullptr;
9091
0
    return *this;
9092
0
}
9093
9094
bool GDALDataset::Features::Iterator::operator!=(const Iterator &it) const
9095
0
{
9096
0
    return m_poPrivate->m_bEOF != it.m_poPrivate->m_bEOF;
9097
0
}
9098
9099
/************************************************************************/
9100
/*                            GetFeatures()                             */
9101
/************************************************************************/
9102
9103
/** Function that return an iterable object over features in the dataset
9104
 * layer.
9105
 *
9106
 * This is a C++ iterator friendly version of GetNextFeature().
9107
 *
9108
 * Using this iterator for standard range-based loops is safe, but
9109
 * due to implementation limitations, you shouldn't try to access
9110
 * (dereference) more than one iterator step at a time, since the
9111
 * FeatureLayerPair reference which is returned is reused.
9112
 *
9113
 * Typical use is:
9114
 * \code{.cpp}
9115
 * for( auto&& oFeatureLayerPair: poDS->GetFeatures() )
9116
 * {
9117
 *       std::cout << "Feature of layer " <<
9118
 *               oFeatureLayerPair.layer->GetName() << std::endl;
9119
 *       oFeatureLayerPair.feature->DumpReadable();
9120
 * }
9121
 * \endcode
9122
 *
9123
 * @see GetNextFeature()
9124
 *
9125
 */
9126
GDALDataset::Features GDALDataset::GetFeatures()
9127
0
{
9128
0
    return Features(this);
9129
0
}
9130
9131
/************************************************************************/
9132
/*                               begin()                                */
9133
/************************************************************************/
9134
9135
/**
9136
 \brief Return beginning of feature iterator.
9137
9138
*/
9139
9140
const GDALDataset::Features::Iterator GDALDataset::Features::begin() const
9141
0
{
9142
0
    return {m_poSelf, true};
9143
0
}
9144
9145
/************************************************************************/
9146
/*                                end()                                 */
9147
/************************************************************************/
9148
9149
/**
9150
 \brief Return end of feature iterator.
9151
9152
*/
9153
9154
const GDALDataset::Features::Iterator GDALDataset::Features::end() const
9155
0
{
9156
0
    return {m_poSelf, false};
9157
0
}
9158
9159
/************************************************************************/
9160
/*                GDALDataset::Layers::Iterator::Private                */
9161
/************************************************************************/
9162
9163
struct GDALDataset::Layers::Iterator::Private
9164
{
9165
    OGRLayer *m_poLayer = nullptr;
9166
    int m_iCurLayer = 0;
9167
    int m_nLayerCount = 0;
9168
    GDALDataset *m_poDS = nullptr;
9169
};
9170
9171
0
GDALDataset::Layers::Iterator::Iterator() : m_poPrivate(new Private())
9172
0
{
9173
0
}
9174
9175
// False positive of cppcheck 1.72
9176
// cppcheck-suppress uninitMemberVar
9177
GDALDataset::Layers::Iterator::Iterator(const Iterator &oOther)
9178
0
    : m_poPrivate(new Private(*(oOther.m_poPrivate)))
9179
0
{
9180
0
}
9181
9182
GDALDataset::Layers::Iterator::Iterator(Iterator &&oOther) noexcept
9183
0
    : m_poPrivate(std::move(oOther.m_poPrivate))
9184
0
{
9185
0
}
9186
9187
GDALDataset::Layers::Iterator::Iterator(GDALDataset *poDS, bool bStart)
9188
0
    : m_poPrivate(new Private())
9189
0
{
9190
0
    m_poPrivate->m_poDS = poDS;
9191
0
    m_poPrivate->m_nLayerCount = poDS->GetLayerCount();
9192
0
    if (bStart)
9193
0
    {
9194
0
        if (m_poPrivate->m_nLayerCount)
9195
0
            m_poPrivate->m_poLayer = poDS->GetLayer(0);
9196
0
    }
9197
0
    else
9198
0
    {
9199
0
        m_poPrivate->m_iCurLayer = m_poPrivate->m_nLayerCount;
9200
0
    }
9201
0
}
9202
9203
0
GDALDataset::Layers::Iterator::~Iterator() = default;
9204
9205
// False positive of cppcheck 1.72
9206
// cppcheck-suppress operatorEqVarError
9207
GDALDataset::Layers::Iterator &
9208
GDALDataset::Layers::Iterator::operator=(const Iterator &oOther)
9209
0
{
9210
0
    *m_poPrivate = *oOther.m_poPrivate;
9211
0
    return *this;
9212
0
}
9213
9214
GDALDataset::Layers::Iterator &GDALDataset::Layers::Iterator::operator=(
9215
    GDALDataset::Layers::Iterator &&oOther) noexcept
9216
0
{
9217
0
    m_poPrivate = std::move(oOther.m_poPrivate);
9218
0
    return *this;
9219
0
}
9220
9221
OGRLayer *GDALDataset::Layers::Iterator::operator*() const
9222
0
{
9223
0
    return m_poPrivate->m_poLayer;
9224
0
}
9225
9226
GDALDataset::Layers::Iterator &GDALDataset::Layers::Iterator::operator++()
9227
0
{
9228
0
    m_poPrivate->m_iCurLayer++;
9229
0
    if (m_poPrivate->m_iCurLayer < m_poPrivate->m_nLayerCount)
9230
0
    {
9231
0
        m_poPrivate->m_poLayer =
9232
0
            m_poPrivate->m_poDS->GetLayer(m_poPrivate->m_iCurLayer);
9233
0
    }
9234
0
    else
9235
0
    {
9236
0
        m_poPrivate->m_poLayer = nullptr;
9237
0
    }
9238
0
    return *this;
9239
0
}
9240
9241
GDALDataset::Layers::Iterator GDALDataset::Layers::Iterator::operator++(int)
9242
0
{
9243
0
    GDALDataset::Layers::Iterator temp = *this;
9244
0
    ++(*this);
9245
0
    return temp;
9246
0
}
9247
9248
bool GDALDataset::Layers::Iterator::operator!=(const Iterator &it) const
9249
0
{
9250
0
    return m_poPrivate->m_iCurLayer != it.m_poPrivate->m_iCurLayer;
9251
0
}
9252
9253
/************************************************************************/
9254
/*                             GetLayers()                              */
9255
/************************************************************************/
9256
9257
/** Function that returns an iterable object over layers in the dataset.
9258
 *
9259
 * This is a C++ iterator friendly version of GetLayer().
9260
 *
9261
 * Typical use is:
9262
 * \code{.cpp}
9263
 * for( auto&& poLayer: poDS->GetLayers() )
9264
 * {
9265
 *       std::cout << "Layer  << poLayer->GetName() << std::endl;
9266
 * }
9267
 * \endcode
9268
 *
9269
 * @see GetLayer()
9270
 *
9271
 */
9272
GDALDataset::Layers GDALDataset::GetLayers()
9273
0
{
9274
0
    return Layers(this);
9275
0
}
9276
9277
/************************************************************************/
9278
/*                               begin()                                */
9279
/************************************************************************/
9280
9281
/**
9282
 \brief Return beginning of layer iterator.
9283
9284
*/
9285
9286
GDALDataset::Layers::Iterator GDALDataset::Layers::begin() const
9287
0
{
9288
0
    return {m_poSelf, true};
9289
0
}
9290
9291
/************************************************************************/
9292
/*                                end()                                 */
9293
/************************************************************************/
9294
9295
/**
9296
 \brief Return end of layer iterator.
9297
9298
*/
9299
9300
GDALDataset::Layers::Iterator GDALDataset::Layers::end() const
9301
0
{
9302
0
    return {m_poSelf, false};
9303
0
}
9304
9305
/************************************************************************/
9306
/*                                size()                                */
9307
/************************************************************************/
9308
9309
/**
9310
 \brief Get the number of layers in this dataset.
9311
9312
 @return layer count.
9313
9314
*/
9315
9316
size_t GDALDataset::Layers::size() const
9317
0
{
9318
0
    return static_cast<size_t>(m_poSelf->GetLayerCount());
9319
0
}
9320
9321
/************************************************************************/
9322
/*                             operator[]()                             */
9323
/************************************************************************/
9324
/**
9325
 \brief Fetch a layer by index.
9326
9327
 The returned layer remains owned by the
9328
 GDALDataset and should not be deleted by the application.
9329
9330
 @param iLayer a layer number between 0 and size()-1.
9331
9332
 @return the layer, or nullptr if iLayer is out of range or an error occurs.
9333
9334
*/
9335
9336
OGRLayer *GDALDataset::Layers::operator[](int iLayer)
9337
0
{
9338
0
    return m_poSelf->GetLayer(iLayer);
9339
0
}
9340
9341
/************************************************************************/
9342
/*                             operator[]()                             */
9343
/************************************************************************/
9344
/**
9345
 \brief Fetch a layer by index.
9346
9347
 The returned layer remains owned by the
9348
 GDALDataset and should not be deleted by the application.
9349
9350
 @param iLayer a layer number between 0 and size()-1.
9351
9352
 @return the layer, or nullptr if iLayer is out of range or an error occurs.
9353
9354
*/
9355
9356
OGRLayer *GDALDataset::Layers::operator[](size_t iLayer)
9357
0
{
9358
0
    return m_poSelf->GetLayer(static_cast<int>(iLayer));
9359
0
}
9360
9361
/************************************************************************/
9362
/*                             operator[]()                             */
9363
/************************************************************************/
9364
/**
9365
 \brief Fetch a layer by name.
9366
9367
 The returned layer remains owned by the
9368
 GDALDataset and should not be deleted by the application.
9369
9370
 @param pszLayerName layer name
9371
9372
 @return the layer, or nullptr if pszLayerName does not match with a layer
9373
9374
*/
9375
9376
OGRLayer *GDALDataset::Layers::operator[](const char *pszLayerName)
9377
0
{
9378
0
    return m_poSelf->GetLayerByName(pszLayerName);
9379
0
}
9380
9381
/************************************************************************/
9382
/*             GDALDataset::ConstLayers::Iterator::Private              */
9383
/************************************************************************/
9384
9385
struct GDALDataset::ConstLayers::Iterator::Private
9386
{
9387
    const OGRLayer *m_poLayer = nullptr;
9388
    int m_iCurLayer = 0;
9389
    int m_nLayerCount = 0;
9390
    const GDALDataset *m_poDS = nullptr;
9391
};
9392
9393
0
GDALDataset::ConstLayers::Iterator::Iterator() : m_poPrivate(new Private())
9394
0
{
9395
0
}
9396
9397
// False positive of cppcheck 1.72
9398
// cppcheck-suppress uninitMemberVar
9399
GDALDataset::ConstLayers::Iterator::Iterator(const Iterator &oOther)
9400
0
    : m_poPrivate(new Private(*(oOther.m_poPrivate)))
9401
0
{
9402
0
}
9403
9404
GDALDataset::ConstLayers::Iterator::Iterator(Iterator &&oOther) noexcept
9405
0
    : m_poPrivate(std::move(oOther.m_poPrivate))
9406
0
{
9407
0
}
9408
9409
GDALDataset::ConstLayers::Iterator::Iterator(const GDALDataset *poDS,
9410
                                             bool bStart)
9411
0
    : m_poPrivate(new Private())
9412
0
{
9413
0
    m_poPrivate->m_poDS = poDS;
9414
0
    m_poPrivate->m_nLayerCount = poDS->GetLayerCount();
9415
0
    if (bStart)
9416
0
    {
9417
0
        if (m_poPrivate->m_nLayerCount)
9418
0
            m_poPrivate->m_poLayer = poDS->GetLayer(0);
9419
0
    }
9420
0
    else
9421
0
    {
9422
0
        m_poPrivate->m_iCurLayer = m_poPrivate->m_nLayerCount;
9423
0
    }
9424
0
}
9425
9426
0
GDALDataset::ConstLayers::Iterator::~Iterator() = default;
9427
9428
// False positive of cppcheck 1.72
9429
// cppcheck-suppress operatorEqVarError
9430
GDALDataset::ConstLayers::Iterator &
9431
GDALDataset::ConstLayers::Iterator::operator=(const Iterator &oOther)
9432
0
{
9433
0
    *m_poPrivate = *oOther.m_poPrivate;
9434
0
    return *this;
9435
0
}
9436
9437
GDALDataset::ConstLayers::Iterator &
9438
GDALDataset::ConstLayers::Iterator::operator=(
9439
    GDALDataset::ConstLayers::Iterator &&oOther) noexcept
9440
0
{
9441
0
    m_poPrivate = std::move(oOther.m_poPrivate);
9442
0
    return *this;
9443
0
}
9444
9445
const OGRLayer *GDALDataset::ConstLayers::Iterator::operator*() const
9446
0
{
9447
0
    return m_poPrivate->m_poLayer;
9448
0
}
9449
9450
GDALDataset::ConstLayers::Iterator &
9451
GDALDataset::ConstLayers::Iterator::operator++()
9452
0
{
9453
0
    m_poPrivate->m_iCurLayer++;
9454
0
    if (m_poPrivate->m_iCurLayer < m_poPrivate->m_nLayerCount)
9455
0
    {
9456
0
        m_poPrivate->m_poLayer =
9457
0
            m_poPrivate->m_poDS->GetLayer(m_poPrivate->m_iCurLayer);
9458
0
    }
9459
0
    else
9460
0
    {
9461
0
        m_poPrivate->m_poLayer = nullptr;
9462
0
    }
9463
0
    return *this;
9464
0
}
9465
9466
GDALDataset::ConstLayers::Iterator
9467
GDALDataset::ConstLayers::Iterator::operator++(int)
9468
0
{
9469
0
    GDALDataset::ConstLayers::Iterator temp = *this;
9470
0
    ++(*this);
9471
0
    return temp;
9472
0
}
9473
9474
bool GDALDataset::ConstLayers::Iterator::operator!=(const Iterator &it) const
9475
0
{
9476
0
    return m_poPrivate->m_iCurLayer != it.m_poPrivate->m_iCurLayer;
9477
0
}
9478
9479
/************************************************************************/
9480
/*                             GetLayers()                              */
9481
/************************************************************************/
9482
9483
/** Function that returns an iterable object over layers in the dataset.
9484
 *
9485
 * This is a C++ iterator friendly version of GetLayer().
9486
 *
9487
 * Typical use is:
9488
 * \code{.cpp}
9489
 * for( auto&& poLayer: poDS->GetLayers() )
9490
 * {
9491
 *       std::cout << "Layer  << poLayer->GetName() << std::endl;
9492
 * }
9493
 * \endcode
9494
 *
9495
 * @see GetLayer()
9496
 *
9497
 * @since GDAL 3.12
9498
 */
9499
GDALDataset::ConstLayers GDALDataset::GetLayers() const
9500
0
{
9501
0
    return ConstLayers(this);
9502
0
}
9503
9504
/************************************************************************/
9505
/*                               begin()                                */
9506
/************************************************************************/
9507
9508
/**
9509
 \brief Return beginning of layer iterator.
9510
9511
 @since GDAL 3.12
9512
*/
9513
9514
GDALDataset::ConstLayers::Iterator GDALDataset::ConstLayers::begin() const
9515
0
{
9516
0
    return {m_poSelf, true};
9517
0
}
9518
9519
/************************************************************************/
9520
/*                                end()                                 */
9521
/************************************************************************/
9522
9523
/**
9524
 \brief Return end of layer iterator.
9525
9526
 @since GDAL 3.12
9527
*/
9528
9529
GDALDataset::ConstLayers::Iterator GDALDataset::ConstLayers::end() const
9530
0
{
9531
0
    return {m_poSelf, false};
9532
0
}
9533
9534
/************************************************************************/
9535
/*                                size()                                */
9536
/************************************************************************/
9537
9538
/**
9539
 \brief Get the number of layers in this dataset.
9540
9541
 @return layer count.
9542
9543
 @since GDAL 3.12
9544
*/
9545
9546
size_t GDALDataset::ConstLayers::size() const
9547
0
{
9548
0
    return static_cast<size_t>(m_poSelf->GetLayerCount());
9549
0
}
9550
9551
/************************************************************************/
9552
/*                             operator[]()                             */
9553
/************************************************************************/
9554
/**
9555
 \brief Fetch a layer by index.
9556
9557
 The returned layer remains owned by the
9558
 GDALDataset and should not be deleted by the application.
9559
9560
 @param iLayer a layer number between 0 and size()-1.
9561
9562
 @return the layer, or nullptr if iLayer is out of range or an error occurs.
9563
9564
 @since GDAL 3.12
9565
*/
9566
9567
const OGRLayer *GDALDataset::ConstLayers::operator[](int iLayer)
9568
0
{
9569
0
    return m_poSelf->GetLayer(iLayer);
9570
0
}
9571
9572
/************************************************************************/
9573
/*                             operator[]()                             */
9574
/************************************************************************/
9575
/**
9576
 \brief Fetch a layer by index.
9577
9578
 The returned layer remains owned by the
9579
 GDALDataset and should not be deleted by the application.
9580
9581
 @param iLayer a layer number between 0 and size()-1.
9582
9583
 @return the layer, or nullptr if iLayer is out of range or an error occurs.
9584
9585
 @since GDAL 3.12
9586
*/
9587
9588
const OGRLayer *GDALDataset::ConstLayers::operator[](size_t iLayer)
9589
0
{
9590
0
    return m_poSelf->GetLayer(static_cast<int>(iLayer));
9591
0
}
9592
9593
/************************************************************************/
9594
/*                             operator[]()                             */
9595
/************************************************************************/
9596
/**
9597
 \brief Fetch a layer by name.
9598
9599
 The returned layer remains owned by the
9600
 GDALDataset and should not be deleted by the application.
9601
9602
 @param pszLayerName layer name
9603
9604
 @return the layer, or nullptr if pszLayerName does not match with a layer
9605
9606
 @since GDAL 3.12
9607
*/
9608
9609
const OGRLayer *GDALDataset::ConstLayers::operator[](const char *pszLayerName)
9610
0
{
9611
0
    return const_cast<GDALDataset *>(m_poSelf)->GetLayerByName(pszLayerName);
9612
0
}
9613
9614
/************************************************************************/
9615
/*                GDALDataset::Bands::Iterator::Private                 */
9616
/************************************************************************/
9617
9618
struct GDALDataset::Bands::Iterator::Private
9619
{
9620
    GDALRasterBand *m_poBand = nullptr;
9621
    int m_iCurBand = 0;
9622
    int m_nBandCount = 0;
9623
    GDALDataset *m_poDS = nullptr;
9624
};
9625
9626
GDALDataset::Bands::Iterator::Iterator(GDALDataset *poDS, bool bStart)
9627
0
    : m_poPrivate(new GDALDataset::Bands::Iterator::Private())
9628
0
{
9629
0
    m_poPrivate->m_poDS = poDS;
9630
0
    m_poPrivate->m_nBandCount = poDS->GetRasterCount();
9631
0
    if (bStart)
9632
0
    {
9633
0
        if (m_poPrivate->m_nBandCount)
9634
0
            m_poPrivate->m_poBand = poDS->GetRasterBand(1);
9635
0
    }
9636
0
    else
9637
0
    {
9638
0
        m_poPrivate->m_iCurBand = m_poPrivate->m_nBandCount;
9639
0
    }
9640
0
}
9641
9642
0
GDALDataset::Bands::Iterator::~Iterator() = default;
9643
9644
GDALRasterBand *GDALDataset::Bands::Iterator::operator*()
9645
0
{
9646
0
    return m_poPrivate->m_poBand;
9647
0
}
9648
9649
GDALDataset::Bands::Iterator &GDALDataset::Bands::Iterator::operator++()
9650
0
{
9651
0
    m_poPrivate->m_iCurBand++;
9652
0
    if (m_poPrivate->m_iCurBand < m_poPrivate->m_nBandCount)
9653
0
    {
9654
0
        m_poPrivate->m_poBand =
9655
0
            m_poPrivate->m_poDS->GetRasterBand(1 + m_poPrivate->m_iCurBand);
9656
0
    }
9657
0
    else
9658
0
    {
9659
0
        m_poPrivate->m_poBand = nullptr;
9660
0
    }
9661
0
    return *this;
9662
0
}
9663
9664
bool GDALDataset::Bands::Iterator::operator!=(const Iterator &it) const
9665
0
{
9666
0
    return m_poPrivate->m_iCurBand != it.m_poPrivate->m_iCurBand;
9667
0
}
9668
9669
/************************************************************************/
9670
/*                              GetBands()                              */
9671
/************************************************************************/
9672
9673
/** Function that returns an iterable object over GDALRasterBand in the dataset.
9674
 *
9675
 * This is a C++ iterator friendly version of GetRasterBand().
9676
 *
9677
 * Typical use is:
9678
 * \code{.cpp}
9679
 * for( auto&& poBand: poDS->GetBands() )
9680
 * {
9681
 *       std::cout << "Band  << poBand->GetDescription() << std::endl;
9682
 * }
9683
 * \endcode
9684
 *
9685
 * @see GetRasterBand()
9686
 *
9687
 */
9688
GDALDataset::Bands GDALDataset::GetBands()
9689
0
{
9690
0
    return Bands(this);
9691
0
}
9692
9693
/************************************************************************/
9694
/*                               begin()                                */
9695
/************************************************************************/
9696
9697
/**
9698
 \brief Return beginning of band iterator.
9699
9700
*/
9701
9702
const GDALDataset::Bands::Iterator GDALDataset::Bands::begin() const
9703
0
{
9704
0
    return {m_poSelf, true};
9705
0
}
9706
9707
/************************************************************************/
9708
/*                                end()                                 */
9709
/************************************************************************/
9710
9711
/**
9712
 \brief Return end of band iterator.
9713
9714
*/
9715
9716
const GDALDataset::Bands::Iterator GDALDataset::Bands::end() const
9717
0
{
9718
0
    return {m_poSelf, false};
9719
0
}
9720
9721
/************************************************************************/
9722
/*                                size()                                */
9723
/************************************************************************/
9724
9725
/**
9726
 \brief Get the number of raster bands in this dataset.
9727
9728
 @return raster band count.
9729
9730
*/
9731
9732
size_t GDALDataset::Bands::size() const
9733
0
{
9734
0
    return static_cast<size_t>(m_poSelf->GetRasterCount());
9735
0
}
9736
9737
/************************************************************************/
9738
/*                             operator[]()                             */
9739
/************************************************************************/
9740
/**
9741
 \brief Fetch a raster band by index.
9742
9743
 The returned band remains owned by the
9744
 GDALDataset and should not be deleted by the application.
9745
9746
 @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9747
 consistent with the conventions of C/C++, i.e. starting at 0.
9748
9749
 @param iBand a band index between 0 and size()-1.
9750
9751
 @return the band, or nullptr if iBand is out of range or an error occurs.
9752
9753
*/
9754
9755
GDALRasterBand *GDALDataset::Bands::operator[](int iBand)
9756
0
{
9757
0
    return m_poSelf->GetRasterBand(1 + iBand);
9758
0
}
9759
9760
/************************************************************************/
9761
/*                             operator[]()                             */
9762
/************************************************************************/
9763
9764
/**
9765
 \brief Fetch a raster band by index.
9766
9767
 The returned band remains owned by the
9768
 GDALDataset and should not be deleted by the application.
9769
9770
 @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9771
 consistent with the conventions of C/C++, i.e. starting at 0.
9772
9773
 @param iBand a band index between 0 and size()-1.
9774
9775
 @return the band, or nullptr if iBand is out of range or an error occurs.
9776
9777
*/
9778
9779
GDALRasterBand *GDALDataset::Bands::operator[](size_t iBand)
9780
0
{
9781
0
    return m_poSelf->GetRasterBand(1 + static_cast<int>(iBand));
9782
0
}
9783
9784
/************************************************************************/
9785
/*              GDALDataset::ConstBands::Iterator::Private              */
9786
/************************************************************************/
9787
9788
struct GDALDataset::ConstBands::Iterator::Private
9789
{
9790
    const GDALRasterBand *m_poBand = nullptr;
9791
    int m_iCurBand = 0;
9792
    int m_nBandCount = 0;
9793
    const GDALDataset *m_poDS = nullptr;
9794
};
9795
9796
GDALDataset::ConstBands::Iterator::Iterator(const GDALDataset *poDS,
9797
                                            bool bStart)
9798
0
    : m_poPrivate(new GDALDataset::ConstBands::Iterator::Private())
9799
0
{
9800
0
    m_poPrivate->m_poDS = poDS;
9801
0
    m_poPrivate->m_nBandCount = poDS->GetRasterCount();
9802
0
    if (bStart)
9803
0
    {
9804
0
        if (m_poPrivate->m_nBandCount)
9805
0
            m_poPrivate->m_poBand = poDS->GetRasterBand(1);
9806
0
    }
9807
0
    else
9808
0
    {
9809
0
        m_poPrivate->m_iCurBand = m_poPrivate->m_nBandCount;
9810
0
    }
9811
0
}
9812
9813
0
GDALDataset::ConstBands::Iterator::~Iterator() = default;
9814
9815
const GDALRasterBand *GDALDataset::ConstBands::Iterator::operator*() const
9816
0
{
9817
0
    return m_poPrivate->m_poBand;
9818
0
}
9819
9820
GDALDataset::ConstBands::Iterator &
9821
GDALDataset::ConstBands::Iterator::operator++()
9822
0
{
9823
0
    m_poPrivate->m_iCurBand++;
9824
0
    if (m_poPrivate->m_iCurBand < m_poPrivate->m_nBandCount)
9825
0
    {
9826
0
        m_poPrivate->m_poBand =
9827
0
            m_poPrivate->m_poDS->GetRasterBand(1 + m_poPrivate->m_iCurBand);
9828
0
    }
9829
0
    else
9830
0
    {
9831
0
        m_poPrivate->m_poBand = nullptr;
9832
0
    }
9833
0
    return *this;
9834
0
}
9835
9836
bool GDALDataset::ConstBands::Iterator::operator!=(const Iterator &it) const
9837
0
{
9838
0
    return m_poPrivate->m_iCurBand != it.m_poPrivate->m_iCurBand;
9839
0
}
9840
9841
/************************************************************************/
9842
/*                              GetBands()                              */
9843
/************************************************************************/
9844
9845
/** Function that returns an iterable object over GDALRasterBand in the dataset.
9846
 *
9847
 * This is a C++ iterator friendly version of GetRasterBand().
9848
 *
9849
 * Typical use is:
9850
 * \code{.cpp}
9851
 * for( const auto* poBand: poDS->GetConstBands() )
9852
 * {
9853
 *       std::cout << "Band  << poBand->GetDescription() << std::endl;
9854
 * }
9855
 * \endcode
9856
 *
9857
 * @see GetRasterBand()
9858
 *
9859
 * @since GDAL 3.12
9860
 */
9861
GDALDataset::ConstBands GDALDataset::GetBands() const
9862
0
{
9863
0
    return ConstBands(this);
9864
0
}
9865
9866
/************************************************************************/
9867
/*                               begin()                                */
9868
/************************************************************************/
9869
9870
/**
9871
 \brief Return beginning of band iterator.
9872
9873
 @since GDAL 3.12
9874
*/
9875
9876
const GDALDataset::ConstBands::Iterator GDALDataset::ConstBands::begin() const
9877
0
{
9878
0
    return {m_poSelf, true};
9879
0
}
9880
9881
/************************************************************************/
9882
/*                                end()                                 */
9883
/************************************************************************/
9884
9885
/**
9886
 \brief Return end of band iterator.
9887
9888
 @since GDAL 3.12
9889
*/
9890
9891
const GDALDataset::ConstBands::Iterator GDALDataset::ConstBands::end() const
9892
0
{
9893
0
    return {m_poSelf, false};
9894
0
}
9895
9896
/************************************************************************/
9897
/*                                size()                                */
9898
/************************************************************************/
9899
9900
/**
9901
 \brief Get the number of raster bands in this dataset.
9902
9903
 @return raster band count.
9904
9905
 @since GDAL 3.12
9906
*/
9907
9908
size_t GDALDataset::ConstBands::size() const
9909
0
{
9910
0
    return static_cast<size_t>(m_poSelf->GetRasterCount());
9911
0
}
9912
9913
/************************************************************************/
9914
/*                             operator[]()                             */
9915
/************************************************************************/
9916
/**
9917
 \brief Fetch a raster band by index.
9918
9919
 The returned band remains owned by the
9920
 GDALDataset and should not be deleted by the application.
9921
9922
 @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9923
 consistent with the conventions of C/C++, i.e. starting at 0.
9924
9925
 @param iBand a band index between 0 and size()-1.
9926
9927
 @return the band, or nullptr if iBand is out of range or an error occurs.
9928
9929
 @since GDAL 3.12
9930
*/
9931
9932
const GDALRasterBand *GDALDataset::ConstBands::operator[](int iBand) const
9933
0
{
9934
0
    return m_poSelf->GetRasterBand(1 + iBand);
9935
0
}
9936
9937
/************************************************************************/
9938
/*                             operator[]()                             */
9939
/************************************************************************/
9940
9941
/**
9942
 \brief Fetch a raster band by index.
9943
9944
 The returned band remains owned by the
9945
 GDALDataset and should not be deleted by the application.
9946
9947
 @warning Contrary to GDALDataset::GetRasterBand(), the indexing here is
9948
 consistent with the conventions of C/C++, i.e. starting at 0.
9949
9950
 @param iBand a band index between 0 and size()-1.
9951
9952
 @return the band, or nullptr if iBand is out of range or an error occurs.
9953
9954
 @since GDAL 3.12
9955
*/
9956
9957
const GDALRasterBand *GDALDataset::ConstBands::operator[](size_t iBand) const
9958
0
{
9959
0
    return m_poSelf->GetRasterBand(1 + static_cast<int>(iBand));
9960
0
}
9961
9962
/************************************************************************/
9963
/*                            GetRootGroup()                            */
9964
/************************************************************************/
9965
9966
/**
9967
 \brief Return the root GDALGroup of this dataset.
9968
9969
 Only valid for multidimensional datasets.
9970
9971
 This is the same as the C function GDALDatasetGetRootGroup().
9972
9973
 @since GDAL 3.1
9974
*/
9975
9976
std::shared_ptr<GDALGroup> GDALDataset::GetRootGroup() const
9977
0
{
9978
0
    return nullptr;
9979
0
}
9980
9981
/************************************************************************/
9982
/*                         GetRawBinaryLayout()                         */
9983
/************************************************************************/
9984
9985
//! @cond Doxygen_Suppress
9986
/**
9987
 \brief Return the layout of a dataset that can be considered as a raw binary
9988
 format.
9989
9990
 @param sLayout Structure that will be set if the dataset is a raw binary one.
9991
 @return true if the dataset is a raw binary one.
9992
 @since GDAL 3.1
9993
*/
9994
9995
bool GDALDataset::GetRawBinaryLayout(RawBinaryLayout &sLayout)
9996
0
{
9997
0
    CPL_IGNORE_RET_VAL(sLayout);
9998
0
    return false;
9999
0
}
10000
10001
//! @endcond
10002
10003
/************************************************************************/
10004
/*                          ClearStatistics()                           */
10005
/************************************************************************/
10006
10007
/**
10008
 \brief Clear statistics
10009
10010
 Only implemented for now in PAM supported datasets
10011
10012
 This is the same as the C function GDALDatasetClearStatistics().
10013
10014
 @since GDAL 3.2
10015
*/
10016
10017
void GDALDataset::ClearStatistics()
10018
0
{
10019
0
    auto poRootGroup = GetRootGroup();
10020
0
    if (poRootGroup)
10021
0
        poRootGroup->ClearStatistics();
10022
0
}
10023
10024
/************************************************************************/
10025
/*                     GDALDatasetClearStatistics()                     */
10026
/************************************************************************/
10027
10028
/**
10029
 \brief Clear statistics
10030
10031
 This is the same as the C++ method GDALDataset::ClearStatistics().
10032
10033
 @since GDAL 3.2
10034
*/
10035
10036
void GDALDatasetClearStatistics(GDALDatasetH hDS)
10037
0
{
10038
0
    VALIDATE_POINTER0(hDS, __func__);
10039
0
    GDALDataset::FromHandle(hDS)->ClearStatistics();
10040
0
}
10041
10042
/************************************************************************/
10043
/*                        GetFieldDomainNames()                         */
10044
/************************************************************************/
10045
10046
/** Returns a list of the names of all field domains stored in the dataset.
10047
 *
10048
 * @note The default implementation assumes that drivers fully populate
10049
 * m_oMapFieldDomains when opening a dataset. If this assumption is incorrect
10050
 * then a specialized implementation of GetFieldDomainNames() must be
10051
 * implemented.
10052
 *
10053
 * @param papszOptions Driver specific options determining how attributes
10054
 * should be retrieved. Pass nullptr for default behavior.
10055
 *
10056
 * @return list of field domain names
10057
 * @since GDAL 3.5
10058
 */
10059
std::vector<std::string>
10060
GDALDataset::GetFieldDomainNames(CPL_UNUSED CSLConstList papszOptions) const
10061
0
{
10062
10063
0
    std::vector<std::string> names;
10064
0
    names.reserve(m_oMapFieldDomains.size());
10065
0
    for (const auto &it : m_oMapFieldDomains)
10066
0
    {
10067
0
        names.emplace_back(it.first);
10068
0
    }
10069
0
    return names;
10070
0
}
10071
10072
/************************************************************************/
10073
/*                   GDALDatasetGetFieldDomainNames()                   */
10074
/************************************************************************/
10075
10076
/** Returns a list of the names of all field domains stored in the dataset.
10077
 *
10078
 * This is the same as the C++ method GDALDataset::GetFieldDomainNames().
10079
 *
10080
 * @param hDS Dataset handle.
10081
 * @param papszOptions Driver specific options determining how attributes
10082
 * should be retrieved. Pass nullptr for default behavior.
10083
 *
10084
 * @return list of field domain names, to be freed with CSLDestroy()
10085
 * @since GDAL 3.5
10086
 */
10087
char **GDALDatasetGetFieldDomainNames(GDALDatasetH hDS,
10088
                                      CSLConstList papszOptions)
10089
0
{
10090
0
    VALIDATE_POINTER1(hDS, __func__, nullptr);
10091
0
    auto names =
10092
0
        GDALDataset::FromHandle(hDS)->GetFieldDomainNames(papszOptions);
10093
0
    CPLStringList res;
10094
0
    for (const auto &name : names)
10095
0
    {
10096
0
        res.AddString(name.c_str());
10097
0
    }
10098
0
    return res.StealList();
10099
0
}
10100
10101
/************************************************************************/
10102
/*                           GetFieldDomain()                           */
10103
/************************************************************************/
10104
10105
/** Get a field domain from its name.
10106
 *
10107
 * @return the field domain, or nullptr if not found.
10108
 * @since GDAL 3.3
10109
 */
10110
const OGRFieldDomain *GDALDataset::GetFieldDomain(const std::string &name) const
10111
0
{
10112
0
    const auto iter = m_oMapFieldDomains.find(name);
10113
0
    if (iter == m_oMapFieldDomains.end())
10114
0
        return nullptr;
10115
0
    return iter->second.get();
10116
0
}
10117
10118
/************************************************************************/
10119
/*                     GDALDatasetGetFieldDomain()                      */
10120
/************************************************************************/
10121
10122
/** Get a field domain from its name.
10123
 *
10124
 * This is the same as the C++ method GDALDataset::GetFieldDomain().
10125
 *
10126
 * @param hDS Dataset handle.
10127
 * @param pszName Name of field domain.
10128
 * @return the field domain (ownership remains to the dataset), or nullptr if
10129
 * not found.
10130
 * @since GDAL 3.3
10131
 */
10132
OGRFieldDomainH GDALDatasetGetFieldDomain(GDALDatasetH hDS, const char *pszName)
10133
0
{
10134
0
    VALIDATE_POINTER1(hDS, __func__, nullptr);
10135
0
    VALIDATE_POINTER1(pszName, __func__, nullptr);
10136
0
    return OGRFieldDomain::ToHandle(const_cast<OGRFieldDomain *>(
10137
0
        GDALDataset::FromHandle(hDS)->GetFieldDomain(pszName)));
10138
0
}
10139
10140
/************************************************************************/
10141
/*                           AddFieldDomain()                           */
10142
/************************************************************************/
10143
10144
/** Add a field domain to the dataset.
10145
 *
10146
 * Only a few drivers will support this operation, and some of them might only
10147
 * support it only for some types of field domains.
10148
 * At the time of writing (GDAL 3.3), only the Memory and GeoPackage drivers
10149
 * support this operation. A dataset having at least some support for this
10150
 * operation should report the ODsCAddFieldDomain dataset capability.
10151
 *
10152
 * Anticipated failures will not be emitted through the CPLError()
10153
 * infrastructure, but will be reported in the failureReason output parameter.
10154
 *
10155
 * @note Drivers should make sure to update m_oMapFieldDomains in order for the
10156
 * default implementation of GetFieldDomainNames() to work correctly, or
10157
 * alternatively a specialized implementation of GetFieldDomainNames() should be
10158
 * implemented.
10159
 *
10160
 * @param domain The domain definition.
10161
 * @param failureReason      Output parameter. Will contain an error message if
10162
 *                           an error occurs.
10163
 * @return true in case of success.
10164
 * @since GDAL 3.3
10165
 */
10166
bool GDALDataset::AddFieldDomain(
10167
    CPL_UNUSED std::unique_ptr<OGRFieldDomain> &&domain,
10168
    std::string &failureReason)
10169
0
{
10170
0
    failureReason = "AddFieldDomain not supported by this driver";
10171
0
    return false;
10172
0
}
10173
10174
/************************************************************************/
10175
/*                     GDALDatasetAddFieldDomain()                      */
10176
/************************************************************************/
10177
10178
/** Add a field domain to the dataset.
10179
 *
10180
 * Only a few drivers will support this operation, and some of them might only
10181
 * support it only for some types of field domains.
10182
 * At the time of writing (GDAL 3.3), only the Memory and GeoPackage drivers
10183
 * support this operation. A dataset having at least some support for this
10184
 * operation should report the ODsCAddFieldDomain dataset capability.
10185
 *
10186
 * Anticipated failures will not be emitted through the CPLError()
10187
 * infrastructure, but will be reported in the ppszFailureReason output
10188
 * parameter.
10189
 *
10190
 * @param hDS                Dataset handle.
10191
 * @param hFieldDomain       The domain definition. Contrary to the C++ version,
10192
 *                           the passed object is copied.
10193
 * @param ppszFailureReason  Output parameter. Will contain an error message if
10194
 *                           an error occurs (*ppszFailureReason to be freed
10195
 *                           with CPLFree). May be NULL.
10196
 * @return true in case of success.
10197
 * @since GDAL 3.3
10198
 */
10199
bool GDALDatasetAddFieldDomain(GDALDatasetH hDS, OGRFieldDomainH hFieldDomain,
10200
                               char **ppszFailureReason)
10201
0
{
10202
0
    VALIDATE_POINTER1(hDS, __func__, false);
10203
0
    VALIDATE_POINTER1(hFieldDomain, __func__, false);
10204
0
    auto poDomain = std::unique_ptr<OGRFieldDomain>(
10205
0
        OGRFieldDomain::FromHandle(hFieldDomain)->Clone());
10206
0
    if (poDomain == nullptr)
10207
0
        return false;
10208
0
    std::string failureReason;
10209
0
    const bool bRet = GDALDataset::FromHandle(hDS)->AddFieldDomain(
10210
0
        std::move(poDomain), failureReason);
10211
0
    if (ppszFailureReason)
10212
0
    {
10213
0
        *ppszFailureReason =
10214
0
            failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10215
0
    }
10216
0
    return bRet;
10217
0
}
10218
10219
/************************************************************************/
10220
/*                         DeleteFieldDomain()                          */
10221
/************************************************************************/
10222
10223
/** Removes a field domain from the dataset.
10224
 *
10225
 * Only a few drivers will support this operation.
10226
 *
10227
 * At the time of writing (GDAL 3.5), only the Memory and GeoPackage drivers
10228
 * support this operation. A dataset having at least some support for this
10229
 * operation should report the ODsCDeleteFieldDomain dataset capability.
10230
 *
10231
 * Anticipated failures will not be emitted through the CPLError()
10232
 * infrastructure, but will be reported in the failureReason output parameter.
10233
 *
10234
 * @note Drivers should make sure to update m_oMapFieldDomains in order for the
10235
 * default implementation of GetFieldDomainNames() to work correctly, or
10236
 * alternatively a specialized implementation of GetFieldDomainNames() should be
10237
 * implemented.
10238
 *
10239
 * @param name The domain name.
10240
 * @param failureReason      Output parameter. Will contain an error message if
10241
 *                           an error occurs.
10242
 * @return true in case of success.
10243
 * @since GDAL 3.5
10244
 */
10245
bool GDALDataset::DeleteFieldDomain(CPL_UNUSED const std::string &name,
10246
                                    std::string &failureReason)
10247
0
{
10248
0
    failureReason = "DeleteFieldDomain not supported by this driver";
10249
0
    return false;
10250
0
}
10251
10252
/************************************************************************/
10253
/*                    GDALDatasetDeleteFieldDomain()                    */
10254
/************************************************************************/
10255
10256
/** Removes a field domain from the dataset.
10257
 *
10258
 * Only a few drivers will support this operation.
10259
 *
10260
 * At the time of writing (GDAL 3.5), only the Memory and GeoPackage drivers
10261
 * support this operation. A dataset having at least some support for this
10262
 * operation should report the ODsCDeleteFieldDomain dataset capability.
10263
 *
10264
 * Anticipated failures will not be emitted through the CPLError()
10265
 * infrastructure, but will be reported in the ppszFailureReason output
10266
 * parameter.
10267
 *
10268
 * @param hDS                Dataset handle.
10269
 * @param pszName            The domain name.
10270
 * @param ppszFailureReason  Output parameter. Will contain an error message if
10271
 *                           an error occurs (*ppszFailureReason to be freed
10272
 *                           with CPLFree). May be NULL.
10273
 * @return true in case of success.
10274
 * @since GDAL 3.3
10275
 */
10276
bool GDALDatasetDeleteFieldDomain(GDALDatasetH hDS, const char *pszName,
10277
                                  char **ppszFailureReason)
10278
0
{
10279
0
    VALIDATE_POINTER1(hDS, __func__, false);
10280
0
    VALIDATE_POINTER1(pszName, __func__, false);
10281
0
    std::string failureReason;
10282
0
    const bool bRet =
10283
0
        GDALDataset::FromHandle(hDS)->DeleteFieldDomain(pszName, failureReason);
10284
0
    if (ppszFailureReason)
10285
0
    {
10286
0
        *ppszFailureReason =
10287
0
            failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10288
0
    }
10289
0
    return bRet;
10290
0
}
10291
10292
/************************************************************************/
10293
/*                         UpdateFieldDomain()                          */
10294
/************************************************************************/
10295
10296
/** Updates an existing field domain by replacing its definition.
10297
 *
10298
 * The existing field domain with matching name will be replaced.
10299
 *
10300
 * Only a few drivers will support this operation, and some of them might only
10301
 * support it only for some types of field domains.
10302
 * At the time of writing (GDAL 3.5), only the Memory driver
10303
 * supports this operation. A dataset having at least some support for this
10304
 * operation should report the ODsCUpdateFieldDomain dataset capability.
10305
 *
10306
 * Anticipated failures will not be emitted through the CPLError()
10307
 * infrastructure, but will be reported in the failureReason output parameter.
10308
 *
10309
 * @param domain The domain definition.
10310
 * @param failureReason      Output parameter. Will contain an error message if
10311
 *                           an error occurs.
10312
 * @return true in case of success.
10313
 * @since GDAL 3.5
10314
 */
10315
bool GDALDataset::UpdateFieldDomain(
10316
    CPL_UNUSED std::unique_ptr<OGRFieldDomain> &&domain,
10317
    std::string &failureReason)
10318
0
{
10319
0
    failureReason = "UpdateFieldDomain not supported by this driver";
10320
0
    return false;
10321
0
}
10322
10323
/************************************************************************/
10324
/*                    GDALDatasetUpdateFieldDomain()                    */
10325
/************************************************************************/
10326
10327
/** Updates an existing field domain by replacing its definition.
10328
 *
10329
 * The existing field domain with matching name will be replaced.
10330
 *
10331
 * Only a few drivers will support this operation, and some of them might only
10332
 * support it only for some types of field domains.
10333
 * At the time of writing (GDAL 3.5), only the Memory driver
10334
 * supports this operation. A dataset having at least some support for this
10335
 * operation should report the ODsCUpdateFieldDomain dataset capability.
10336
 *
10337
 * Anticipated failures will not be emitted through the CPLError()
10338
 * infrastructure, but will be reported in the failureReason output parameter.
10339
 *
10340
 * @param hDS                Dataset handle.
10341
 * @param hFieldDomain       The domain definition. Contrary to the C++ version,
10342
 *                           the passed object is copied.
10343
 * @param ppszFailureReason  Output parameter. Will contain an error message if
10344
 *                           an error occurs (*ppszFailureReason to be freed
10345
 *                           with CPLFree). May be NULL.
10346
 * @return true in case of success.
10347
 * @since GDAL 3.5
10348
 */
10349
bool GDALDatasetUpdateFieldDomain(GDALDatasetH hDS,
10350
                                  OGRFieldDomainH hFieldDomain,
10351
                                  char **ppszFailureReason)
10352
0
{
10353
0
    VALIDATE_POINTER1(hDS, __func__, false);
10354
0
    VALIDATE_POINTER1(hFieldDomain, __func__, false);
10355
0
    auto poDomain = std::unique_ptr<OGRFieldDomain>(
10356
0
        OGRFieldDomain::FromHandle(hFieldDomain)->Clone());
10357
0
    if (poDomain == nullptr)
10358
0
        return false;
10359
0
    std::string failureReason;
10360
0
    const bool bRet = GDALDataset::FromHandle(hDS)->UpdateFieldDomain(
10361
0
        std::move(poDomain), failureReason);
10362
0
    if (ppszFailureReason)
10363
0
    {
10364
0
        *ppszFailureReason =
10365
0
            failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10366
0
    }
10367
0
    return bRet;
10368
0
}
10369
10370
/************************************************************************/
10371
/*                        GetRelationshipNames()                        */
10372
/************************************************************************/
10373
10374
/** Returns a list of the names of all relationships stored in the dataset.
10375
 *
10376
 * @param papszOptions Driver specific options determining how relationships
10377
 * should be retrieved. Pass nullptr for default behavior.
10378
 *
10379
 * @return list of relationship names
10380
 * @since GDAL 3.6
10381
 */
10382
std::vector<std::string>
10383
GDALDataset::GetRelationshipNames(CPL_UNUSED CSLConstList papszOptions) const
10384
0
{
10385
0
    return {};
10386
0
}
10387
10388
/************************************************************************/
10389
/*                  GDALDatasetGetRelationshipNames()                   */
10390
/************************************************************************/
10391
10392
/** Returns a list of the names of all relationships stored in the dataset.
10393
 *
10394
 * This is the same as the C++ method GDALDataset::GetRelationshipNames().
10395
 *
10396
 * @param hDS Dataset handle.
10397
 * @param papszOptions Driver specific options determining how relationships
10398
 * should be retrieved. Pass nullptr for default behavior.
10399
 *
10400
 * @return list of relationship names, to be freed with CSLDestroy()
10401
 * @since GDAL 3.6
10402
 */
10403
char **GDALDatasetGetRelationshipNames(GDALDatasetH hDS,
10404
                                       CSLConstList papszOptions)
10405
0
{
10406
0
    VALIDATE_POINTER1(hDS, __func__, nullptr);
10407
0
    auto names =
10408
0
        GDALDataset::FromHandle(hDS)->GetRelationshipNames(papszOptions);
10409
0
    CPLStringList res;
10410
0
    for (const auto &name : names)
10411
0
    {
10412
0
        res.AddString(name.c_str());
10413
0
    }
10414
0
    return res.StealList();
10415
0
}
10416
10417
/************************************************************************/
10418
/*                          GetRelationship()                           */
10419
/************************************************************************/
10420
10421
/** Get a relationship from its name.
10422
 *
10423
 * @return the relationship, or nullptr if not found.
10424
 * @since GDAL 3.6
10425
 */
10426
const GDALRelationship *
10427
GDALDataset::GetRelationship(CPL_UNUSED const std::string &name) const
10428
0
{
10429
0
    return nullptr;
10430
0
}
10431
10432
/************************************************************************/
10433
/*                     GDALDatasetGetRelationship()                     */
10434
/************************************************************************/
10435
10436
/** Get a relationship from its name.
10437
 *
10438
 * This is the same as the C++ method GDALDataset::GetRelationship().
10439
 *
10440
 * @param hDS Dataset handle.
10441
 * @param pszName Name of relationship.
10442
 * @return the relationship (ownership remains to the dataset), or nullptr if
10443
 * not found.
10444
 * @since GDAL 3.6
10445
 */
10446
GDALRelationshipH GDALDatasetGetRelationship(GDALDatasetH hDS,
10447
                                             const char *pszName)
10448
0
{
10449
0
    VALIDATE_POINTER1(hDS, __func__, nullptr);
10450
0
    VALIDATE_POINTER1(pszName, __func__, nullptr);
10451
0
    return GDALRelationship::ToHandle(const_cast<GDALRelationship *>(
10452
0
        GDALDataset::FromHandle(hDS)->GetRelationship(pszName)));
10453
0
}
10454
10455
/************************************************************************/
10456
/*                          AddRelationship()                           */
10457
/************************************************************************/
10458
10459
/** Add a relationship to the dataset.
10460
 *
10461
 * Only a few drivers will support this operation, and some of them might only
10462
 * support it only for some types of relationships.
10463
 *
10464
 * A dataset having at least some support for this
10465
 * operation should report the GDsCAddRelationship dataset capability.
10466
 *
10467
 * Anticipated failures will not be emitted through the CPLError()
10468
 * infrastructure, but will be reported in the failureReason output parameter.
10469
 *
10470
 * When adding a many-to-many relationship
10471
 * (GDALRelationshipCardinality::GRC_MANY_TO_MANY), it is possible to omit the
10472
 * mapping table name (see GDALRelationship::GetMappingTableName) to instruct
10473
 * the driver to create an appropriately named and structured mapping table.
10474
 * Some dataset formats require particular naming conventions and field
10475
 * structures for the mapping table, and delegating the construction of the
10476
 * mapping table to the driver will avoid these pitfalls.
10477
 *
10478
 * @param relationship The relationship definition.
10479
 * @param failureReason      Output parameter. Will contain an error message if
10480
 *                           an error occurs.
10481
 * @return true in case of success.
10482
 * @since GDAL 3.6
10483
 */
10484
bool GDALDataset::AddRelationship(
10485
    CPL_UNUSED std::unique_ptr<GDALRelationship> &&relationship,
10486
    std::string &failureReason)
10487
0
{
10488
0
    failureReason = "AddRelationship not supported by this driver";
10489
0
    return false;
10490
0
}
10491
10492
/************************************************************************/
10493
/*                     GDALDatasetAddRelationship()                     */
10494
/************************************************************************/
10495
10496
/** Add a relationship to the dataset.
10497
 *
10498
 * Only a few drivers will support this operation, and some of them might only
10499
 * support it only for some types of relationships.
10500
 *
10501
 * A dataset having at least some support for this
10502
 * operation should report the GDsCAddRelationship dataset capability.
10503
 *
10504
 * Anticipated failures will not be emitted through the CPLError()
10505
 * infrastructure, but will be reported in the failureReason output parameter.
10506
 *
10507
 * When adding a many-to-many relationship
10508
 * (GDALRelationshipCardinality::GRC_MANY_TO_MANY), it is possible to omit the
10509
 * mapping table name (see GDALRelationshipGetMappingTableName) to instruct the
10510
 * driver to create an appropriately named and structured mapping table. Some
10511
 * dataset formats require particular naming conventions and field structures
10512
 * for the mapping table, and delegating the construction of the mapping table
10513
 * to the driver will avoid these pitfalls.
10514
 *
10515
 * @param hDS                Dataset handle.
10516
 * @param hRelationship      The relationship definition. Contrary to the C++
10517
 * version, the passed object is copied.
10518
 * @param ppszFailureReason  Output parameter. Will contain an error message if
10519
 *                           an error occurs (*ppszFailureReason to be freed
10520
 *                           with CPLFree). May be NULL.
10521
 * @return true in case of success.
10522
 * @since GDAL 3.6
10523
 */
10524
bool GDALDatasetAddRelationship(GDALDatasetH hDS,
10525
                                GDALRelationshipH hRelationship,
10526
                                char **ppszFailureReason)
10527
0
{
10528
0
    VALIDATE_POINTER1(hDS, __func__, false);
10529
0
    VALIDATE_POINTER1(hRelationship, __func__, false);
10530
0
    std::unique_ptr<GDALRelationship> poRelationship(
10531
0
        new GDALRelationship(*GDALRelationship::FromHandle(hRelationship)));
10532
0
    std::string failureReason;
10533
0
    const bool bRet = GDALDataset::FromHandle(hDS)->AddRelationship(
10534
0
        std::move(poRelationship), failureReason);
10535
0
    if (ppszFailureReason)
10536
0
    {
10537
0
        *ppszFailureReason =
10538
0
            failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10539
0
    }
10540
0
    return bRet;
10541
0
}
10542
10543
/************************************************************************/
10544
/*                         DeleteRelationship()                         */
10545
/************************************************************************/
10546
10547
/** Removes a relationship from the dataset.
10548
 *
10549
 * Only a few drivers will support this operation.
10550
 *
10551
 * A dataset having at least some support for this
10552
 * operation should report the GDsCDeleteRelationship dataset capability.
10553
 *
10554
 * Anticipated failures will not be emitted through the CPLError()
10555
 * infrastructure, but will be reported in the failureReason output parameter.
10556
 *
10557
 * @param name The relationship name.
10558
 * @param failureReason      Output parameter. Will contain an error message if
10559
 *                           an error occurs.
10560
 * @return true in case of success.
10561
 * @since GDAL 3.6
10562
 */
10563
bool GDALDataset::DeleteRelationship(CPL_UNUSED const std::string &name,
10564
                                     std::string &failureReason)
10565
0
{
10566
0
    failureReason = "DeleteRelationship not supported by this driver";
10567
0
    return false;
10568
0
}
10569
10570
/************************************************************************/
10571
/*                   GDALDatasetDeleteRelationship()                    */
10572
/************************************************************************/
10573
10574
/** Removes a relationship from the dataset.
10575
 *
10576
 * Only a few drivers will support this operation.
10577
 *
10578
 * A dataset having at least some support for this
10579
 * operation should report the GDsCDeleteRelationship dataset capability.
10580
 *
10581
 * Anticipated failures will not be emitted through the CPLError()
10582
 * infrastructure, but will be reported in the ppszFailureReason output
10583
 * parameter.
10584
 *
10585
 * @param hDS                Dataset handle.
10586
 * @param pszName            The relationship name.
10587
 * @param ppszFailureReason  Output parameter. Will contain an error message if
10588
 *                           an error occurs (*ppszFailureReason to be freed
10589
 *                           with CPLFree). May be NULL.
10590
 * @return true in case of success.
10591
 * @since GDAL 3.6
10592
 */
10593
bool GDALDatasetDeleteRelationship(GDALDatasetH hDS, const char *pszName,
10594
                                   char **ppszFailureReason)
10595
0
{
10596
0
    VALIDATE_POINTER1(hDS, __func__, false);
10597
0
    VALIDATE_POINTER1(pszName, __func__, false);
10598
0
    std::string failureReason;
10599
0
    const bool bRet = GDALDataset::FromHandle(hDS)->DeleteRelationship(
10600
0
        pszName, failureReason);
10601
0
    if (ppszFailureReason)
10602
0
    {
10603
0
        *ppszFailureReason =
10604
0
            failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10605
0
    }
10606
0
    return bRet;
10607
0
}
10608
10609
/************************************************************************/
10610
/*                         UpdateRelationship()                         */
10611
/************************************************************************/
10612
10613
/** Updates an existing relationship by replacing its definition.
10614
 *
10615
 * The existing relationship with matching name will be replaced.
10616
 *
10617
 * Only a few drivers will support this operation, and some of them might only
10618
 * support it only for some types of relationships.
10619
 * A dataset having at least some support for this
10620
 * operation should report the GDsCUpdateRelationship dataset capability.
10621
 *
10622
 * Anticipated failures will not be emitted through the CPLError()
10623
 * infrastructure, but will be reported in the failureReason output parameter.
10624
 *
10625
 * @param relationship   The relationship definition.
10626
 * @param failureReason  Output parameter. Will contain an error message if
10627
 *                       an error occurs.
10628
 * @return true in case of success.
10629
 * @since GDAL 3.6
10630
 */
10631
bool GDALDataset::UpdateRelationship(
10632
    CPL_UNUSED std::unique_ptr<GDALRelationship> &&relationship,
10633
    std::string &failureReason)
10634
0
{
10635
0
    failureReason = "UpdateRelationship not supported by this driver";
10636
0
    return false;
10637
0
}
10638
10639
/************************************************************************/
10640
/*                   GDALDatasetUpdateRelationship()                    */
10641
/************************************************************************/
10642
10643
/** Updates an existing relationship by replacing its definition.
10644
 *
10645
 * The existing relationship with matching name will be replaced.
10646
 *
10647
 * Only a few drivers will support this operation, and some of them might only
10648
 * support it only for some types of relationships.
10649
 * A dataset having at least some support for this
10650
 * operation should report the GDsCUpdateRelationship dataset capability.
10651
 *
10652
 * Anticipated failures will not be emitted through the CPLError()
10653
 * infrastructure, but will be reported in the failureReason output parameter.
10654
 *
10655
 * @param hDS                Dataset handle.
10656
 * @param hRelationship      The relationship definition. Contrary to the C++
10657
 * version, the passed object is copied.
10658
 * @param ppszFailureReason  Output parameter. Will contain an error message if
10659
 *                           an error occurs (*ppszFailureReason to be freed
10660
 *                           with CPLFree). May be NULL.
10661
 * @return true in case of success.
10662
 * @since GDAL 3.5
10663
 */
10664
bool GDALDatasetUpdateRelationship(GDALDatasetH hDS,
10665
                                   GDALRelationshipH hRelationship,
10666
                                   char **ppszFailureReason)
10667
0
{
10668
0
    VALIDATE_POINTER1(hDS, __func__, false);
10669
0
    VALIDATE_POINTER1(hRelationship, __func__, false);
10670
0
    std::unique_ptr<GDALRelationship> poRelationship(
10671
0
        new GDALRelationship(*GDALRelationship::FromHandle(hRelationship)));
10672
0
    std::string failureReason;
10673
0
    const bool bRet = GDALDataset::FromHandle(hDS)->UpdateRelationship(
10674
0
        std::move(poRelationship), failureReason);
10675
0
    if (ppszFailureReason)
10676
0
    {
10677
0
        *ppszFailureReason =
10678
0
            failureReason.empty() ? nullptr : CPLStrdup(failureReason.c_str());
10679
0
    }
10680
0
    return bRet;
10681
0
}
10682
10683
/************************************************************************/
10684
/*                   GDALDatasetSetQueryLoggerFunc()                    */
10685
/************************************************************************/
10686
10687
/**
10688
 * Sets the SQL query logger callback.
10689
 *
10690
 * When supported by the driver, the callback will be called with
10691
 * the executed SQL text, the error message, the execution time in milliseconds,
10692
 * the number of records fetched/affected and the client status data.
10693
 *
10694
 * A value of -1 in the execution time or in the number of records indicates
10695
 * that the values are unknown.
10696
 *
10697
 * @param hDS                   Dataset handle.
10698
 * @param pfnQueryLoggerFunc    Callback function
10699
 * @param poQueryLoggerArg      Opaque client status data
10700
 * @return                      true in case of success.
10701
 * @since                       GDAL 3.7
10702
 */
10703
bool GDALDatasetSetQueryLoggerFunc(GDALDatasetH hDS,
10704
                                   GDALQueryLoggerFunc pfnQueryLoggerFunc,
10705
                                   void *poQueryLoggerArg)
10706
0
{
10707
0
    VALIDATE_POINTER1(hDS, __func__, false);
10708
0
    return GDALDataset::FromHandle(hDS)->SetQueryLoggerFunc(pfnQueryLoggerFunc,
10709
0
                                                            poQueryLoggerArg);
10710
0
}
10711
10712
//! @cond Doxygen_Suppress
10713
10714
/************************************************************************/
10715
/*                         SetEnableOverviews()                         */
10716
/************************************************************************/
10717
10718
void GDALDataset::SetEnableOverviews(bool bEnable)
10719
0
{
10720
0
    if (m_poPrivate)
10721
0
    {
10722
0
        m_poPrivate->m_bOverviewsEnabled = bEnable;
10723
0
    }
10724
0
}
10725
10726
/************************************************************************/
10727
/*                        AreOverviewsEnabled()                         */
10728
/************************************************************************/
10729
10730
bool GDALDataset::AreOverviewsEnabled() const
10731
0
{
10732
0
    return m_poPrivate ? m_poPrivate->m_bOverviewsEnabled : true;
10733
0
}
10734
10735
/************************************************************************/
10736
/*                             IsAllBands()                             */
10737
/************************************************************************/
10738
10739
bool GDALDataset::IsAllBands(int nBandCount, const int *panBandList) const
10740
0
{
10741
0
    if (nBands != nBandCount)
10742
0
        return false;
10743
0
    if (panBandList)
10744
0
    {
10745
0
        for (int i = 0; i < nBandCount; ++i)
10746
0
        {
10747
0
            if (panBandList[i] != i + 1)
10748
0
                return false;
10749
0
        }
10750
0
    }
10751
0
    return true;
10752
0
}
10753
10754
//! @endcond
10755
10756
/************************************************************************/
10757
/*                       GetCompressionFormats()                        */
10758
/************************************************************************/
10759
10760
/** Return the compression formats that can be natively obtained for the
10761
 * window of interest and requested bands.
10762
 *
10763
 * For example, a tiled dataset may be able to return data in a compressed
10764
 * format if the window of interest matches exactly a tile. For some formats,
10765
 * drivers may also be able to merge several tiles together (not currently
10766
 * implemented though).
10767
 *
10768
 * Each format string is a pseudo MIME type, whose first part can be passed
10769
 * as the pszFormat argument of ReadCompressedData(), with additional
10770
 * parameters specified as key=value with a semi-colon separator.
10771
 *
10772
 * The amount and types of optional parameters passed after the MIME type is
10773
 * format dependent, and driver dependent (some drivers might not be able to
10774
 * return those extra information without doing a rather costly processing).
10775
 *
10776
 * For example, a driver might return "JPEG;frame_type=SOF0_baseline;"
10777
 * "bit_depth=8;num_components=3;subsampling=4:2:0;colorspace=YCbCr", and
10778
 * consequently "JPEG" can be passed as the pszFormat argument of
10779
 * ReadCompressedData(). For JPEG, implementations can use the
10780
 * GDALGetCompressionFormatForJPEG() helper method to generate a string like
10781
 * above from a JPEG codestream.
10782
 *
10783
 * Several values might be returned. For example,
10784
 * the JPEGXL driver will return "JXL", but also potentially "JPEG"
10785
 * if the JPEGXL codestream includes a JPEG reconstruction box.
10786
 *
10787
 * In the general case this method will return an empty list.
10788
 *
10789
 * This is the same as C function GDALDatasetGetCompressionFormats().
10790
 *
10791
 * @param nXOff The pixel offset to the top left corner of the region
10792
 * of the band to be accessed.  This would be zero to start from the left side.
10793
 *
10794
 * @param nYOff The line offset to the top left corner of the region
10795
 * of the band to be accessed.  This would be zero to start from the top.
10796
 *
10797
 * @param nXSize The width of the region of the band to be accessed in pixels.
10798
 *
10799
 * @param nYSize The height of the region of the band to be accessed in lines.
10800
 *
10801
 * @param nBandCount the number of bands being requested.
10802
 *
10803
 * @param panBandList the list of nBandCount band numbers.
10804
 * Note band numbers are 1 based. This may be NULL to select the first
10805
 * nBandCount bands.
10806
 *
10807
 * @return a list of compatible formats (which may be empty)
10808
 *
10809
 * For example, to check if native compression format(s) are available on the
10810
 * whole image:
10811
 * \code{.cpp}
10812
 *   const CPLStringList aosFormats =
10813
 *      poDataset->GetCompressionFormats(0, 0,
10814
 *                                       poDataset->GetRasterXSize(),
10815
 *                                       poDataset->GetRasterYSize(),
10816
 *                                       poDataset->GetRasterCount(),
10817
 *                                       nullptr);
10818
 *   for( const char* pszFormat: aosFormats )
10819
 *   {
10820
 *      // Remove optional parameters and just print out the MIME type.
10821
 *      const CPLStringList aosTokens(CSLTokenizeString2(pszFormat, ";", 0));
10822
 *      printf("Found format %s\n, aosTokens[0]);
10823
 *   }
10824
 * \endcode
10825
 *
10826
 * @since GDAL 3.7
10827
 */
10828
CPLStringList
10829
GDALDataset::GetCompressionFormats(CPL_UNUSED int nXOff, CPL_UNUSED int nYOff,
10830
                                   CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
10831
                                   CPL_UNUSED int nBandCount,
10832
                                   CPL_UNUSED const int *panBandList)
10833
0
{
10834
0
    return CPLStringList();
10835
0
}
10836
10837
/************************************************************************/
10838
/*                  GDALDatasetGetCompressionFormats()                  */
10839
/************************************************************************/
10840
10841
/** Return the compression formats that can be natively obtained for the
10842
 * window of interest and requested bands.
10843
 *
10844
 * For example, a tiled dataset may be able to return data in a compressed
10845
 * format if the window of interest matches exactly a tile. For some formats,
10846
 * drivers may also be able to merge several tiles together (not currently
10847
 * implemented though).
10848
 *
10849
 * Each format string is a pseudo MIME type, whose first part can be passed
10850
 * as the pszFormat argument of ReadCompressedData(), with additional
10851
 * parameters specified as key=value with a semi-colon separator.
10852
 *
10853
 * The amount and types of optional parameters passed after the MIME type is
10854
 * format dependent, and driver dependent (some drivers might not be able to
10855
 * return those extra information without doing a rather costly processing).
10856
 *
10857
 * For example, a driver might return "JPEG;frame_type=SOF0_baseline;"
10858
 * "bit_depth=8;num_components=3;subsampling=4:2:0;colorspace=YCbCr", and
10859
 * consequently "JPEG" can be passed as the pszFormat argument of
10860
 * ReadCompressedData(). For JPEG, implementations can use the
10861
 * GDALGetCompressionFormatForJPEG() helper method to generate a string like
10862
 * above from a JPEG codestream.
10863
 *
10864
 * Several values might be returned. For example,
10865
 * the JPEGXL driver will return "JXL", but also potentially "JPEG"
10866
 * if the JPEGXL codestream includes a JPEG reconstruction box.
10867
 *
10868
 * In the general case this method will return an empty list.
10869
 *
10870
 * This is the same as C++ method GDALDataset::GetCompressionFormats().
10871
 *
10872
 * @param hDS Dataset handle.
10873
 *
10874
 * @param nXOff The pixel offset to the top left corner of the region
10875
 * of the band to be accessed.  This would be zero to start from the left side.
10876
 *
10877
 * @param nYOff The line offset to the top left corner of the region
10878
 * of the band to be accessed.  This would be zero to start from the top.
10879
 *
10880
 * @param nXSize The width of the region of the band to be accessed in pixels.
10881
 *
10882
 * @param nYSize The height of the region of the band to be accessed in lines.
10883
 *
10884
 * @param nBandCount the number of bands being requested.
10885
 *
10886
 * @param panBandList the list of nBandCount band numbers.
10887
 * Note band numbers are 1 based. This may be NULL to select the first
10888
 * nBandCount bands.
10889
 *
10890
 * @return a list of compatible formats (which may be empty) that should be
10891
 * freed with CSLDestroy(), or nullptr.
10892
 *
10893
 * @since GDAL 3.7
10894
 */
10895
char **GDALDatasetGetCompressionFormats(GDALDatasetH hDS, int nXOff, int nYOff,
10896
                                        int nXSize, int nYSize, int nBandCount,
10897
                                        const int *panBandList)
10898
0
{
10899
0
    VALIDATE_POINTER1(hDS, __func__, nullptr);
10900
0
    return GDALDataset::FromHandle(hDS)
10901
0
        ->GetCompressionFormats(nXOff, nYOff, nXSize, nYSize, nBandCount,
10902
0
                                panBandList)
10903
0
        .StealList();
10904
0
}
10905
10906
/************************************************************************/
10907
/*                         ReadCompressedData()                         */
10908
/************************************************************************/
10909
10910
/** Return the compressed content that can be natively obtained for the
10911
 * window of interest and requested bands.
10912
 *
10913
 * For example, a tiled dataset may be able to return data in compressed format
10914
 * if the window of interest matches exactly a tile. For some formats, drivers
10915
 * may also be example to merge several tiles together (not currently
10916
 * implemented though).
10917
 *
10918
 * The implementation should make sure that the content returned forms a valid
10919
 * standalone file. For example, for the GeoTIFF implementation of this method,
10920
 * when extracting a JPEG tile, the method will automatically add the content
10921
 * of the JPEG Huffman and/or quantization tables that might be stored in the
10922
 * TIFF JpegTables tag, and not in tile data itself.
10923
 *
10924
 * In the general case this method will return CE_Failure.
10925
 *
10926
 * This is the same as C function GDALDatasetReadCompressedData().
10927
 *
10928
 * @param pszFormat Requested compression format (e.g. "JPEG",
10929
 * "WEBP", "JXL"). This is the MIME type of one of the values
10930
 * returned by GetCompressionFormats(). The format string is designed to
10931
 * potentially include at a later point key=value optional parameters separated
10932
 * by a semi-colon character. At time of writing, none are implemented.
10933
 * ReadCompressedData() implementations should verify optional parameters and
10934
 * return CE_Failure if they cannot support one of them.
10935
 *
10936
 * @param nXOff The pixel offset to the top left corner of the region
10937
 * of the band to be accessed.  This would be zero to start from the left side.
10938
 *
10939
 * @param nYOff The line offset to the top left corner of the region
10940
 * of the band to be accessed.  This would be zero to start from the top.
10941
 *
10942
 * @param nXSize The width of the region of the band to be accessed in pixels.
10943
 *
10944
 * @param nYSize The height of the region of the band to be accessed in lines.
10945
 *
10946
 * @param nBandCount the number of bands being requested.
10947
 *
10948
 * @param panBandList the list of nBandCount band numbers.
10949
 * Note band numbers are 1 based. This may be NULL to select the first
10950
 * nBandCount bands.
10951
 *
10952
 * @param ppBuffer Pointer to a buffer to store the compressed data or nullptr.
10953
 * If ppBuffer is not nullptr, then pnBufferSize should also not be nullptr.
10954
 * If ppBuffer is not nullptr, and *ppBuffer is not nullptr, then the provided
10955
 * buffer will be filled with the compressed data, provided that pnBufferSize
10956
 * and *pnBufferSize are not nullptr, and *pnBufferSize, indicating the size
10957
 * of *ppBuffer, is sufficiently large to hold the data.
10958
 * If ppBuffer is not nullptr, but *ppBuffer is nullptr, then the method will
10959
 * allocate *ppBuffer using VSIMalloc(), and thus the caller is responsible to
10960
 * free it with VSIFree().
10961
 * If ppBuffer is nullptr, then the compressed data itself will not be returned,
10962
 * but *pnBufferSize will be updated with an upper bound of the size that would
10963
 * be necessary to hold it (if pnBufferSize != nullptr).
10964
 *
10965
 * @param pnBufferSize Output buffer size, or nullptr.
10966
 * If ppBuffer != nullptr && *ppBuffer != nullptr, then pnBufferSize should
10967
 * be != nullptr and *pnBufferSize contain the size of *ppBuffer. If the
10968
 * method is successful, *pnBufferSize will be updated with the actual size
10969
 * used.
10970
 *
10971
 * @param ppszDetailedFormat Pointer to an output string, or nullptr.
10972
 * If ppszDetailedFormat is not nullptr, then, on success, the method will
10973
 * allocate a new string in *ppszDetailedFormat (to be freed with VSIFree())
10974
 * *ppszDetailedFormat might contain strings like
10975
 * "JPEG;frame_type=SOF0_baseline;bit_depth=8;num_components=3;"
10976
 * "subsampling=4:2:0;colorspace=YCbCr" or simply the MIME type.
10977
 * The string will contain at least as much information as what
10978
 * GetCompressionFormats() returns, and potentially more when
10979
 * ppBuffer != nullptr.
10980
 *
10981
 * @return CE_None in case of success, CE_Failure otherwise.
10982
 *
10983
 * For example, to request JPEG content on the whole image and let GDAL deal
10984
 * with the buffer allocation.
10985
 * \code{.cpp}
10986
 *   void* pBuffer = nullptr;
10987
 *   size_t nBufferSize = 0;
10988
 *   CPLErr eErr =
10989
 *      poDataset->ReadCompressedData("JPEG",
10990
 *                                    0, 0,
10991
 *                                    poDataset->GetRasterXSize(),
10992
 *                                    poDataset->GetRasterYSize(),
10993
 *                                    poDataset->GetRasterCount(),
10994
 *                                    nullptr, // panBandList
10995
 *                                    &pBuffer,
10996
 *                                    &nBufferSize,
10997
 *                                    nullptr // ppszDetailedFormat
10998
 *                                   );
10999
 *   if (eErr == CE_None)
11000
 *   {
11001
 *       CPLAssert(pBuffer != nullptr);
11002
 *       CPLAssert(nBufferSize > 0);
11003
 *       VSILFILE* fp = VSIFOpenL("my.jpeg", "wb");
11004
 *       if (fp)
11005
 *       {
11006
 *           VSIFWriteL(pBuffer, nBufferSize, 1, fp);
11007
 *           VSIFCloseL(fp);
11008
 *       }
11009
 *       VSIFree(pBuffer);
11010
 *   }
11011
 * \endcode
11012
 *
11013
 * Or to manage the buffer allocation on your side:
11014
 * \code{.cpp}
11015
 *   size_t nUpperBoundBufferSize = 0;
11016
 *   CPLErr eErr =
11017
 *      poDataset->ReadCompressedData("JPEG",
11018
 *                                    0, 0,
11019
 *                                    poDataset->GetRasterXSize(),
11020
 *                                    poDataset->GetRasterYSize(),
11021
 *                                    poDataset->GetRasterCount(),
11022
 *                                    nullptr, // panBandList
11023
 *                                    nullptr, // ppBuffer,
11024
 *                                    &nUpperBoundBufferSize,
11025
 *                                    nullptr // ppszDetailedFormat
11026
 *                                   );
11027
 *   if (eErr == CE_None)
11028
 *   {
11029
 *       std::vector<uint8_t> myBuffer;
11030
 *       myBuffer.resize(nUpperBoundBufferSize);
11031
 *       void* pBuffer = myBuffer.data();
11032
 *       size_t nActualSize = nUpperBoundBufferSize;
11033
 *       char* pszDetailedFormat = nullptr;
11034
 *       // We also request detailed format, but we could have passed it to
11035
 *       // nullptr as well.
11036
 *       eErr =
11037
 *         poDataset->ReadCompressedData("JPEG",
11038
 *                                       0, 0,
11039
 *                                       poDataset->GetRasterXSize(),
11040
 *                                       poDataset->GetRasterYSize(),
11041
 *                                       poDataset->GetRasterCount(),
11042
 *                                       nullptr, // panBandList
11043
 *                                       &pBuffer,
11044
 *                                       &nActualSize,
11045
 *                                       &pszDetailedFormat);
11046
 *       if (eErr == CE_None)
11047
 *       {
11048
 *          CPLAssert(pBuffer == myBuffer.data()); // pointed value not modified
11049
 *          CPLAssert(nActualSize <= nUpperBoundBufferSize);
11050
 *          myBuffer.resize(nActualSize);
11051
 *          // do something useful
11052
 *          VSIFree(pszDetailedFormat);
11053
 *       }
11054
 *   }
11055
 * \endcode
11056
 *
11057
 * @since GDAL 3.7
11058
 */
11059
CPLErr GDALDataset::ReadCompressedData(
11060
    CPL_UNUSED const char *pszFormat, CPL_UNUSED int nXOff,
11061
    CPL_UNUSED int nYOff, CPL_UNUSED int nXSize, CPL_UNUSED int nYSize,
11062
    CPL_UNUSED int nBandCount, CPL_UNUSED const int *panBandList,
11063
    CPL_UNUSED void **ppBuffer, CPL_UNUSED size_t *pnBufferSize,
11064
    CPL_UNUSED char **ppszDetailedFormat)
11065
0
{
11066
0
    return CE_Failure;
11067
0
}
11068
11069
/************************************************************************/
11070
/*                   GDALDatasetReadCompressedData()                    */
11071
/************************************************************************/
11072
11073
/** Return the compressed content that can be natively obtained for the
11074
 * window of interest and requested bands.
11075
 *
11076
 * For example, a tiled dataset may be able to return data in compressed format
11077
 * if the window of interest matches exactly a tile. For some formats, drivers
11078
 * may also be example to merge several tiles together (not currently
11079
 * implemented though).
11080
 *
11081
 * The implementation should make sure that the content returned forms a valid
11082
 * standalone file. For example, for the GeoTIFF implementation of this method,
11083
 * when extracting a JPEG tile, the method will automatically adds the content
11084
 * of the JPEG Huffman and/or quantization tables that might be stored in the
11085
 * TIFF JpegTables tag, and not in tile data itself.
11086
 *
11087
 * In the general case this method will return CE_Failure.
11088
 *
11089
 * This is the same as C++ method GDALDataset:ReadCompressedData().
11090
 *
11091
 * @param hDS Dataset handle.
11092
 *
11093
 * @param pszFormat Requested compression format (e.g. "JPEG",
11094
 * "WEBP", "JXL"). This is the MIME type of one of the values
11095
 * returned by GetCompressionFormats(). The format string is designed to
11096
 * potentially include at a later point key=value optional parameters separated
11097
 * by a semi-colon character. At time of writing, none are implemented.
11098
 * ReadCompressedData() implementations should verify optional parameters and
11099
 * return CE_Failure if they cannot support one of them.
11100
 *
11101
 * @param nXOff The pixel offset to the top left corner of the region
11102
 * of the band to be accessed.  This would be zero to start from the left side.
11103
 *
11104
 * @param nYOff The line offset to the top left corner of the region
11105
 * of the band to be accessed.  This would be zero to start from the top.
11106
 *
11107
 * @param nXSize The width of the region of the band to be accessed in pixels.
11108
 *
11109
 * @param nYSize The height of the region of the band to be accessed in lines.
11110
 *
11111
 * @param nBandCount the number of bands being requested.
11112
 *
11113
 * @param panBandList the list of nBandCount band numbers.
11114
 * Note band numbers are 1 based. This may be NULL to select the first
11115
 * nBandCount bands.
11116
 *
11117
 * @param ppBuffer Pointer to a buffer to store the compressed data or nullptr.
11118
 * If ppBuffer is not nullptr, then pnBufferSize should also not be nullptr.
11119
 * If ppBuffer is not nullptr, and *ppBuffer is not nullptr, then the provided
11120
 * buffer will be filled with the compressed data, provided that pnBufferSize
11121
 * and *pnBufferSize are not nullptr, and *pnBufferSize, indicating the size
11122
 * of *ppBuffer, is sufficiently large to hold the data.
11123
 * If ppBuffer is not nullptr, but *ppBuffer is nullptr, then the method will
11124
 * allocate *ppBuffer using VSIMalloc(), and thus the caller is responsible to
11125
 * free it with VSIFree().
11126
 * If ppBuffer is nullptr, then the compressed data itself will not be returned,
11127
 * but *pnBufferSize will be updated with an upper bound of the size that would
11128
 * be necessary to hold it (if pnBufferSize != nullptr).
11129
 *
11130
 * @param pnBufferSize Output buffer size, or nullptr.
11131
 * If ppBuffer != nullptr && *ppBuffer != nullptr, then pnBufferSize should
11132
 * be != nullptr and *pnBufferSize contain the size of *ppBuffer. If the
11133
 * method is successful, *pnBufferSize will be updated with the actual size
11134
 * used.
11135
 *
11136
 * @param ppszDetailedFormat Pointer to an output string, or nullptr.
11137
 * If ppszDetailedFormat is not nullptr, then, on success, the method will
11138
 * allocate a new string in *ppszDetailedFormat (to be freed with VSIFree())
11139
 * *ppszDetailedFormat might contain strings like
11140
 * "JPEG;frame_type=SOF0_baseline;bit_depth=8;num_components=3;"
11141
 * "subsampling=4:2:0;colorspace=YCbCr" or simply the MIME type.
11142
 * The string will contain at least as much information as what
11143
 * GetCompressionFormats() returns, and potentially more when
11144
 * ppBuffer != nullptr.
11145
 *
11146
 * @return CE_None in case of success, CE_Failure otherwise.
11147
 *
11148
 * @since GDAL 3.7
11149
 */
11150
CPLErr GDALDatasetReadCompressedData(GDALDatasetH hDS, const char *pszFormat,
11151
                                     int nXOff, int nYOff, int nXSize,
11152
                                     int nYSize, int nBandCount,
11153
                                     const int *panBandList, void **ppBuffer,
11154
                                     size_t *pnBufferSize,
11155
                                     char **ppszDetailedFormat)
11156
0
{
11157
0
    VALIDATE_POINTER1(hDS, __func__, CE_Failure);
11158
0
    return GDALDataset::FromHandle(hDS)->ReadCompressedData(
11159
0
        pszFormat, nXOff, nYOff, nXSize, nYSize, nBandCount, panBandList,
11160
0
        ppBuffer, pnBufferSize, ppszDetailedFormat);
11161
0
}
11162
11163
/************************************************************************/
11164
/*                            CanBeCloned()                             */
11165
/************************************************************************/
11166
11167
//! @cond Doxygen_Suppress
11168
11169
/** This method is called by GDALThreadSafeDataset::Create() to determine if
11170
 * it is possible to create a thread-safe wrapper for a dataset, which involves
11171
 * the ability to Clone() it.
11172
 *
11173
 * Implementations of this method must be thread-safe.
11174
 *
11175
 * @param nScopeFlags Combination of GDAL_OF_RASTER, GDAL_OF_VECTOR, etc. flags,
11176
 *                    expressing the intended use for thread-safety.
11177
 *                    Currently, the only valid scope is in the base
11178
 *                    implementation is GDAL_OF_RASTER.
11179
 * @param bCanShareState Determines if cloned datasets are allowed to share
11180
 *                       state with the dataset they have been cloned from.
11181
 *                       If set to true, the dataset from which they have been
11182
 *                       cloned from must remain opened during the lifetime of
11183
 *                       its clones.
11184
 * @return true if the Clone() method is expected to succeed with the same values
11185
 *         of nScopeFlags and bCanShareState.
11186
 */
11187
bool GDALDataset::CanBeCloned(int nScopeFlags,
11188
                              [[maybe_unused]] bool bCanShareState) const
11189
0
{
11190
0
    return m_bCanBeReopened && nScopeFlags == GDAL_OF_RASTER;
11191
0
}
11192
11193
//! @endcond
11194
11195
/************************************************************************/
11196
/*                               Clone()                                */
11197
/************************************************************************/
11198
11199
//! @cond Doxygen_Suppress
11200
11201
/** This method "clones" the current dataset, that is it returns a new instance
11202
 * that is opened on the same underlying "file".
11203
 *
11204
 * The base implementation uses GDALDataset::Open() to re-open the dataset.
11205
 * The MEM driver has a specialized implementation that returns a new instance,
11206
 * but which shares the same memory buffer as this.
11207
 *
11208
 * Implementations of this method must be thread-safe.
11209
 *
11210
 * @param nScopeFlags Combination of GDAL_OF_RASTER, GDAL_OF_VECTOR, etc. flags,
11211
 *                    expressing the intended use for thread-safety.
11212
 *                    Currently, the only valid scope is in the base
11213
 *                    implementation is GDAL_OF_RASTER.
11214
 * @param bCanShareState Determines if cloned datasets are allowed to share
11215
 *                       state with the dataset they have been cloned from.
11216
 *                       If set to true, the dataset from which they have been
11217
 *                       cloned from must remain opened during the lifetime of
11218
 *                       its clones.
11219
 * @return a new instance, or nullptr in case of error.
11220
 */
11221
std::unique_ptr<GDALDataset>
11222
GDALDataset::Clone(int nScopeFlags, [[maybe_unused]] bool bCanShareState) const
11223
0
{
11224
0
    CPLStringList aosAllowedDrivers;
11225
0
    if (poDriver)
11226
0
        aosAllowedDrivers.AddString(poDriver->GetDescription());
11227
0
    return std::unique_ptr<GDALDataset>(GDALDataset::Open(
11228
0
        GetDescription(),
11229
0
        nScopeFlags | GDAL_OF_INTERNAL | GDAL_OF_VERBOSE_ERROR,
11230
0
        aosAllowedDrivers.List(), papszOpenOptions));
11231
0
}
11232
11233
//! @endcond
11234
11235
/************************************************************************/
11236
/*                       GeolocationToPixelLine()                       */
11237
/************************************************************************/
11238
11239
/** Transform georeferenced coordinates to pixel/line coordinates.
11240
 *
11241
 * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
11242
 * must be in the "natural" SRS of the dataset, that is the one returned by
11243
 * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
11244
 * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
11245
 * array (generally WGS 84) if there is a geolocation array.
11246
 * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
11247
 * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
11248
 * be a easting, and dfGeolocY a northing.
11249
 *
11250
 * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
11251
 * expressed in that CRS, and that tuple must be conformant with the
11252
 * data-axis-to-crs-axis setting of poSRS, that is the one returned by
11253
 * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
11254
 * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
11255
 * before calling this method, and in that case, dfGeolocX must be a longitude
11256
 * or an easting value, and dfGeolocX a latitude or a northing value.
11257
 *
11258
 * This method uses GDALCreateGenImgProjTransformer2() underneath.
11259
 *
11260
 * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
11261
 * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11262
 * where interpolation should be done.
11263
 * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
11264
 * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11265
 * where interpolation should be done.
11266
 * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
11267
 * @param[out] pdfPixel Pointer to the variable where to the store the pixel/column coordinate.
11268
 * @param[out] pdfLine Pointer to the variable where to the store the line coordinate.
11269
 * @param papszTransformerOptions Options accepted by GDALCreateGenImgProjTransformer2(), or nullptr.
11270
 *
11271
 * @return CE_None on success, or an error code on failure.
11272
 * @since GDAL 3.11
11273
 */
11274
11275
CPLErr
11276
GDALDataset::GeolocationToPixelLine(double dfGeolocX, double dfGeolocY,
11277
                                    const OGRSpatialReference *poSRS,
11278
                                    double *pdfPixel, double *pdfLine,
11279
                                    CSLConstList papszTransformerOptions) const
11280
0
{
11281
0
    CPLStringList aosTO(papszTransformerOptions);
11282
11283
0
    if (poSRS)
11284
0
    {
11285
0
        const char *const apszOptions[] = {"FORMAT=WKT2", nullptr};
11286
0
        const std::string osWKT = poSRS->exportToWkt(apszOptions);
11287
0
        aosTO.SetNameValue("DST_SRS", osWKT.c_str());
11288
0
        const auto eAxisMappingStrategy = poSRS->GetAxisMappingStrategy();
11289
0
        if (eAxisMappingStrategy == OAMS_TRADITIONAL_GIS_ORDER)
11290
0
            aosTO.SetNameValue("DST_SRS_AXIS_MAPPING_STRATEGY",
11291
0
                               "TRADITIONAL_GIS_ORDER");
11292
0
        else if (eAxisMappingStrategy == OAMS_AUTHORITY_COMPLIANT)
11293
0
            aosTO.SetNameValue("DST_SRS_AXIS_MAPPING_STRATEGY",
11294
0
                               "AUTHORITY_COMPLIANT");
11295
0
        else
11296
0
        {
11297
0
            const auto &anValues = poSRS->GetDataAxisToSRSAxisMapping();
11298
0
            std::string osVal;
11299
0
            for (int v : anValues)
11300
0
            {
11301
0
                if (!osVal.empty())
11302
0
                    osVal += ',';
11303
0
                osVal += std::to_string(v);
11304
0
            }
11305
0
            aosTO.SetNameValue("DST_SRS_DATA_AXIS_TO_SRS_AXIS_MAPPING",
11306
0
                               osVal.c_str());
11307
0
        }
11308
0
    }
11309
11310
0
    auto hTransformer = GDALCreateGenImgProjTransformer2(
11311
0
        GDALDataset::ToHandle(const_cast<GDALDataset *>(this)), nullptr,
11312
0
        aosTO.List());
11313
0
    if (hTransformer == nullptr)
11314
0
    {
11315
0
        return CE_Failure;
11316
0
    }
11317
11318
0
    double z = 0;
11319
0
    int bSuccess = 0;
11320
0
    GDALGenImgProjTransform(hTransformer, TRUE, 1, &dfGeolocX, &dfGeolocY, &z,
11321
0
                            &bSuccess);
11322
0
    GDALDestroyTransformer(hTransformer);
11323
0
    if (bSuccess)
11324
0
    {
11325
0
        if (pdfPixel)
11326
0
            *pdfPixel = dfGeolocX;
11327
0
        if (pdfLine)
11328
0
            *pdfLine = dfGeolocY;
11329
0
        return CE_None;
11330
0
    }
11331
0
    else
11332
0
    {
11333
0
        return CE_Failure;
11334
0
    }
11335
0
}
11336
11337
/************************************************************************/
11338
/*                 GDALDatasetGeolocationToPixelLine()                  */
11339
/************************************************************************/
11340
11341
/** Transform georeferenced coordinates to pixel/line coordinates.
11342
 *
11343
 * @see GDALDataset::GeolocationToPixelLine()
11344
 * @since GDAL 3.11
11345
 */
11346
11347
CPLErr GDALDatasetGeolocationToPixelLine(GDALDatasetH hDS, double dfGeolocX,
11348
                                         double dfGeolocY,
11349
                                         OGRSpatialReferenceH hSRS,
11350
                                         double *pdfPixel, double *pdfLine,
11351
                                         CSLConstList papszTransformerOptions)
11352
0
{
11353
0
    VALIDATE_POINTER1(hDS, "GDALDatasetGeolocationToPixelLine", CE_Failure);
11354
11355
0
    GDALDataset *poDS = GDALDataset::FromHandle(hDS);
11356
0
    return poDS->GeolocationToPixelLine(
11357
0
        dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS), pdfPixel,
11358
0
        pdfLine, papszTransformerOptions);
11359
0
}
11360
11361
/************************************************************************/
11362
/*                             GetExtent()                              */
11363
/************************************************************************/
11364
11365
/** Return extent of dataset in specified CRS.
11366
 *
11367
 * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11368
 *
11369
 * For rasters, the base implementation of this method only succeeds if
11370
 * GetGeoTransform() and GetSpatialRef() succeed.
11371
 * For vectors, the base implementation of this method iterates over layers
11372
 * and call their OGRLayer::GetExtent() method.
11373
 *
11374
 * TestCapability(GDsCFastGetExtent) can be used to test if the execution
11375
 * time of this method is fast.
11376
 *
11377
 * This is the same as C function GDALGetExtent()
11378
 *
11379
 * @param[out] psExtent Pointer to output extent. Must NOT be null.
11380
 * @param poCRS CRS in which to express the extent. If not specified, this will
11381
 * be the raster CRS or the CRS of the first layer for a vector dataset.
11382
 * @return CE_None in case of success, CE_Failure otherwise
11383
 * @since GDAL 3.12
11384
 */
11385
11386
CPLErr GDALDataset::GetExtent(OGREnvelope *psExtent,
11387
                              const OGRSpatialReference *poCRS) const
11388
0
{
11389
0
    const OGRSpatialReference *poThisCRS = GetSpatialRefRasterOnly();
11390
0
    int nLayerCount = 0;
11391
0
    if (!poThisCRS)
11392
0
    {
11393
0
        nLayerCount = GetLayerCount();
11394
0
        if (nLayerCount >= 1)
11395
0
        {
11396
0
            if (auto poLayer = GetLayer(0))
11397
0
                poThisCRS = poLayer->GetSpatialRef();
11398
0
        }
11399
0
    }
11400
0
    if (!poCRS)
11401
0
        poCRS = poThisCRS;
11402
0
    else if (!poThisCRS)
11403
0
        return CE_Failure;
11404
11405
0
    *psExtent = OGREnvelope();
11406
11407
0
    GDALGeoTransform gt;
11408
0
    auto poThisDS = const_cast<GDALDataset *>(this);
11409
0
    const bool bHasGT = poThisDS->GetGeoTransform(gt) == CE_None;
11410
0
    if (bHasGT)
11411
0
    {
11412
0
        std::unique_ptr<OGRCoordinateTransformation> poCT;
11413
0
        if (poCRS)
11414
0
        {
11415
0
            poCT.reset(OGRCreateCoordinateTransformation(poThisCRS, poCRS));
11416
0
        }
11417
11418
0
        constexpr int DENSIFY_POINT_COUNT = 21;
11419
0
        double dfULX = gt.xorig;
11420
0
        double dfULY = gt.yorig;
11421
0
        double dfURX = 0, dfURY = 0;
11422
0
        gt.Apply(nRasterXSize, 0, &dfURX, &dfURY);
11423
0
        double dfLLX = 0, dfLLY = 0;
11424
0
        gt.Apply(0, nRasterYSize, &dfLLX, &dfLLY);
11425
0
        double dfLRX = 0, dfLRY = 0;
11426
0
        gt.Apply(nRasterXSize, nRasterYSize, &dfLRX, &dfLRY);
11427
0
        const double xmin = std::min({dfULX, dfURX, dfLLX, dfLRX});
11428
0
        const double ymin = std::min({dfULY, dfURY, dfLLY, dfLRY});
11429
0
        const double xmax = std::max({dfULX, dfURX, dfLLX, dfLRX});
11430
0
        const double ymax = std::max({dfULY, dfURY, dfLLY, dfLRY});
11431
0
        if (poCT)
11432
0
        {
11433
0
            OGREnvelope sEnvTmp;
11434
0
            if (!poCT->TransformBounds(xmin, ymin, xmax, ymax, &(sEnvTmp.MinX),
11435
0
                                       &(sEnvTmp.MinY), &(sEnvTmp.MaxX),
11436
0
                                       &(sEnvTmp.MaxY), DENSIFY_POINT_COUNT))
11437
0
            {
11438
0
                return CE_Failure;
11439
0
            }
11440
0
            *psExtent = sEnvTmp;
11441
0
        }
11442
0
        else
11443
0
        {
11444
0
            psExtent->MinX = xmin;
11445
0
            psExtent->MinY = ymin;
11446
0
            psExtent->MaxX = xmax;
11447
0
            psExtent->MaxY = ymax;
11448
0
        }
11449
0
    }
11450
11451
0
    if (nLayerCount > 0)
11452
0
    {
11453
0
        for (auto &&poLayer : poThisDS->GetLayers())
11454
0
        {
11455
0
            auto poLayerCRS = poLayer->GetSpatialRef();
11456
0
            if (poLayerCRS)
11457
0
            {
11458
0
                OGREnvelope sLayerExtent;
11459
0
                if (poLayer->GetExtent(&sLayerExtent) == OGRERR_NONE)
11460
0
                {
11461
0
                    auto poCT = std::unique_ptr<OGRCoordinateTransformation>(
11462
0
                        OGRCreateCoordinateTransformation(poLayerCRS, poCRS));
11463
0
                    if (poCT)
11464
0
                    {
11465
0
                        constexpr int DENSIFY_POINT_COUNT = 21;
11466
0
                        OGREnvelope sEnvTmp;
11467
0
                        if (poCT->TransformBounds(
11468
0
                                sLayerExtent.MinX, sLayerExtent.MinY,
11469
0
                                sLayerExtent.MaxX, sLayerExtent.MaxY,
11470
0
                                &(sEnvTmp.MinX), &(sEnvTmp.MinY),
11471
0
                                &(sEnvTmp.MaxX), &(sEnvTmp.MaxY),
11472
0
                                DENSIFY_POINT_COUNT))
11473
0
                        {
11474
0
                            psExtent->Merge(sEnvTmp);
11475
0
                        }
11476
0
                    }
11477
0
                }
11478
0
            }
11479
0
        }
11480
0
    }
11481
11482
0
    return psExtent->IsInit() ? CE_None : CE_Failure;
11483
0
}
11484
11485
/************************************************************************/
11486
/*                           GDALGetExtent()                            */
11487
/************************************************************************/
11488
11489
/** Return extent of dataset in specified CRS.
11490
 *
11491
 * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11492
 *
11493
 * For rasters, the base implementation of this method only succeeds if
11494
 * GetGeoTransform() and GetSpatialRef() succeed.
11495
 * For vectors, the base implementation of this method iterates over layers
11496
 * and call their OGRLayer::GetExtent() method.
11497
 *
11498
 * TestCapability(GDsCFastGetExtent) can be used to test if the execution
11499
 * time of this method is fast.
11500
 *
11501
 * This is the same as C++ method GDALDataset::GetExtent()
11502
 *
11503
 * @param hDS Dataset handle. Must NOT be null.
11504
 * @param[out] psExtent Pointer to output extent. Must NOT be null.
11505
 * @param hCRS CRS in which to express the extent. If not specified, this will
11506
 * be the raster CRS or the CRS of the first layer for a vector dataset.
11507
 * @return extent in poCRS (valid only if IsInit() method returns true)
11508
 * @since GDAL 3.12
11509
 */
11510
11511
CPLErr GDALGetExtent(GDALDatasetH hDS, OGREnvelope *psExtent,
11512
                     OGRSpatialReferenceH hCRS)
11513
0
{
11514
0
    VALIDATE_POINTER1(hDS, __func__, CE_Failure);
11515
0
    VALIDATE_POINTER1(psExtent, __func__, CE_Failure);
11516
0
    return GDALDataset::FromHandle(hDS)->GetExtent(
11517
0
        psExtent, OGRSpatialReference::FromHandle(hCRS));
11518
0
}
11519
11520
/************************************************************************/
11521
/*                       GetExtentWGS84LongLat()                        */
11522
/************************************************************************/
11523
11524
/** Return extent of dataset in WGS84 longitude/latitude
11525
 *
11526
 * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11527
 *
11528
 * TestCapability(GDsCFastGetExtentWGS84LongLat) can be used to test if the execution
11529
 * time of this method is fast.
11530
 *
11531
 * This is the same as C function GDALGetExtentWGS84LongLat()
11532
 *
11533
 * @return extent (valid only if IsInit() method returns true)
11534
 * @since GDAL 3.12
11535
 */
11536
11537
CPLErr GDALDataset::GetExtentWGS84LongLat(OGREnvelope *psExtent) const
11538
0
{
11539
0
    OGRSpatialReference oSRS_WGS84;
11540
0
    oSRS_WGS84.SetFromUserInput("WGS84");
11541
0
    oSRS_WGS84.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
11542
0
    return GetExtent(psExtent, &oSRS_WGS84);
11543
0
}
11544
11545
/************************************************************************/
11546
/*                     GDALGetExtentWGS84LongLat()                      */
11547
/************************************************************************/
11548
11549
/** Return extent of dataset in WGS84 longitude/latitude
11550
 *
11551
 * OGREnvelope.MinX/MaxX represents longitudes, and MinY/MaxY latitudes.
11552
 *
11553
 * TestCapability(GDsCFastGetExtentWGS84LongLat) can be used to test if the execution
11554
 * time of this method is fast.
11555
 *
11556
 * This is the same as C++ method GDALDataset::GetExtentWGS84LongLat()
11557
 *
11558
 * @param hDS Dataset handle. Must NOT be null.
11559
 * @param[out] psExtent Pointer to output extent. Must NOT be null.
11560
 * @return extent (valid only if IsInit() method returns true)
11561
 * @since GDAL 3.12
11562
 */
11563
11564
CPLErr GDALGetExtentWGS84LongLat(GDALDatasetH hDS, OGREnvelope *psExtent)
11565
0
{
11566
0
    VALIDATE_POINTER1(hDS, __func__, CE_Failure);
11567
0
    VALIDATE_POINTER1(psExtent, __func__, CE_Failure);
11568
0
    return GDALDataset::FromHandle(hDS)->GetExtentWGS84LongLat(psExtent);
11569
0
}
11570
11571
/************************************************************************/
11572
/*                  ReportUpdateNotSupportedByDriver()                  */
11573
/************************************************************************/
11574
11575
//! @cond Doxygen_Suppress
11576
11577
/* static */
11578
void GDALDataset::ReportUpdateNotSupportedByDriver(const char *pszDriverName)
11579
0
{
11580
0
    CPLError(CE_Failure, CPLE_NotSupported,
11581
0
             "The %s driver does not support update access to existing "
11582
0
             "datasets.",
11583
0
             pszDriverName);
11584
0
}
11585
11586
//! @endcond
11587
11588
/************************************************************************/
11589
/*                           BuildFilename()                            */
11590
/************************************************************************/
11591
11592
/** Generates a filename, potentially relative to another one.
11593
 *
11594
 * Given the path to a reference directory, and a path to a file
11595
 * referenced from it, build a path to the file that the current application
11596
 * can use. If the file path is already absolute, rather than relative, or if
11597
 * bRelativeToReferencePath is false, then the filename of interest will be
11598
 * returned unaltered.
11599
 *
11600
 * This is enhanced version of CPLProjectRelativeFilenameSafe() that takes
11601
 * into account the subdataset syntax.
11602
 *
11603
 * Examples:
11604
 * \code{.cpp}
11605
 * BuildFilename("tmp/abc.gif", "abc/def", true) == "abc/def/tmp/abc.gif"
11606
 * BuildFilename("../abc.gif", "/abc/def") == "/abc/abc.gif"
11607
 * BuildFilename("abc.gif", "C:\WIN", true) == "C:\WIN\abc.gif"
11608
 * BuildFilename("abc.gif", "C:\WIN", false) == "abc.gif"
11609
 * BuildFilename("/home/even/foo.tif", "/home/even/workdir", true) == "/home/even/foo.tif"
11610
 * \endcode
11611
 *
11612
 * @param pszFilename Filename of interest.
11613
 * @param pszReferencePath Path to a reference directory.
11614
 * @param bRelativeToReferencePath Whether pszFilename, if a relative path, is
11615
 *                                 relative to pszReferencePath
11616
 * @since 3.11
11617
 */
11618
11619
/* static */
11620
std::string GDALDataset::BuildFilename(const char *pszFilename,
11621
                                       const char *pszReferencePath,
11622
                                       bool bRelativeToReferencePath)
11623
0
{
11624
0
    std::string osSrcDSName;
11625
0
    if (pszReferencePath != nullptr && bRelativeToReferencePath)
11626
0
    {
11627
        // Try subdatasetinfo API first
11628
        // Note: this will become the only branch when subdatasetinfo will become
11629
        //       available for NITF_IM, RASTERLITE and TILEDB
11630
0
        const auto oSubDSInfo{GDALGetSubdatasetInfo(pszFilename)};
11631
0
        if (oSubDSInfo && !oSubDSInfo->GetPathComponent().empty())
11632
0
        {
11633
0
            auto path{oSubDSInfo->GetPathComponent()};
11634
0
            osSrcDSName = oSubDSInfo->ModifyPathComponent(
11635
0
                CPLProjectRelativeFilenameSafe(pszReferencePath, path.c_str())
11636
0
                    .c_str());
11637
0
            GDALDestroySubdatasetInfo(oSubDSInfo);
11638
0
        }
11639
0
        else
11640
0
        {
11641
0
            bool bDone = false;
11642
0
            for (const char *pszSyntax : apszSpecialSubDatasetSyntax)
11643
0
            {
11644
0
                CPLString osPrefix(pszSyntax);
11645
0
                osPrefix.resize(strchr(pszSyntax, ':') - pszSyntax + 1);
11646
0
                if (pszSyntax[osPrefix.size()] == '"')
11647
0
                    osPrefix += '"';
11648
0
                if (EQUALN(pszFilename, osPrefix, osPrefix.size()))
11649
0
                {
11650
0
                    if (STARTS_WITH_CI(pszSyntax + osPrefix.size(), "{ANY}"))
11651
0
                    {
11652
0
                        const char *pszLastPart = strrchr(pszFilename, ':') + 1;
11653
                        // CSV:z:/foo.xyz
11654
0
                        if ((pszLastPart[0] == '/' || pszLastPart[0] == '\\') &&
11655
0
                            pszLastPart - pszFilename >= 3 &&
11656
0
                            pszLastPart[-3] == ':')
11657
0
                        {
11658
0
                            pszLastPart -= 2;
11659
0
                        }
11660
0
                        CPLString osPrefixFilename = pszFilename;
11661
0
                        osPrefixFilename.resize(pszLastPart - pszFilename);
11662
0
                        osSrcDSName = osPrefixFilename +
11663
0
                                      CPLProjectRelativeFilenameSafe(
11664
0
                                          pszReferencePath, pszLastPart);
11665
0
                        bDone = true;
11666
0
                    }
11667
0
                    else if (STARTS_WITH_CI(pszSyntax + osPrefix.size(),
11668
0
                                            "{FILENAME}"))
11669
0
                    {
11670
0
                        CPLString osFilename(pszFilename + osPrefix.size());
11671
0
                        size_t nPos = 0;
11672
0
                        if (osFilename.size() >= 3 && osFilename[1] == ':' &&
11673
0
                            (osFilename[2] == '\\' || osFilename[2] == '/'))
11674
0
                            nPos = 2;
11675
0
                        nPos = osFilename.find(
11676
0
                            pszSyntax[osPrefix.size() + strlen("{FILENAME}")],
11677
0
                            nPos);
11678
0
                        if (nPos != std::string::npos)
11679
0
                        {
11680
0
                            const CPLString osSuffix = osFilename.substr(nPos);
11681
0
                            osFilename.resize(nPos);
11682
0
                            osSrcDSName = osPrefix +
11683
0
                                          CPLProjectRelativeFilenameSafe(
11684
0
                                              pszReferencePath, osFilename) +
11685
0
                                          osSuffix;
11686
0
                            bDone = true;
11687
0
                        }
11688
0
                    }
11689
0
                    break;
11690
0
                }
11691
0
            }
11692
0
            if (!bDone)
11693
0
            {
11694
0
                std::string osReferencePath = pszReferencePath;
11695
0
                if (!CPLIsFilenameRelative(pszReferencePath))
11696
0
                {
11697
                    // Simplify path by replacing "foo/a/../b" with "foo/b"
11698
0
                    while (STARTS_WITH(pszFilename, "../"))
11699
0
                    {
11700
0
                        osReferencePath =
11701
0
                            CPLGetPathSafe(osReferencePath.c_str());
11702
0
                        pszFilename += strlen("../");
11703
0
                    }
11704
0
                }
11705
11706
0
                osSrcDSName = CPLProjectRelativeFilenameSafe(
11707
0
                    osReferencePath.c_str(), pszFilename);
11708
0
            }
11709
0
        }
11710
0
    }
11711
0
    else
11712
0
    {
11713
0
        osSrcDSName = pszFilename;
11714
0
    }
11715
0
    return osSrcDSName;
11716
0
}
11717
11718
/************************************************************************/
11719
/*                        GDALMDArrayFromDataset                        */
11720
/************************************************************************/
11721
11722
class GDALMDArrayFromDataset final : public GDALMDArray
11723
{
11724
    CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromDataset)
11725
11726
    GDALDataset *const m_poDS;
11727
    const GDALExtendedDataType m_dt;
11728
    std::vector<std::shared_ptr<GDALDimension>> m_dims{};
11729
    std::string m_osUnit{};
11730
    std::vector<GByte> m_abyNoData{};
11731
    std::shared_ptr<GDALMDArray> m_varX{};
11732
    std::shared_ptr<GDALMDArray> m_varY{};
11733
    std::shared_ptr<GDALMDArray> m_varBand{};
11734
    const std::string m_osFilename;
11735
    const CPLStringList m_aosOptions;
11736
    int m_iBandDim = 0;
11737
    int m_iYDim = 1;
11738
    int m_iXDim = 2;
11739
    mutable std::vector<std::shared_ptr<GDALMDArray>> m_apoOverviews{};
11740
11741
    bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
11742
                   const size_t *count, const GInt64 *arrayStep,
11743
                   const GPtrDiff_t *bufferStride,
11744
                   const GDALExtendedDataType &bufferDataType,
11745
                   void *pBuffer) const;
11746
11747
  protected:
11748
    GDALMDArrayFromDataset(GDALDataset *poDS, CSLConstList papszOptions)
11749
0
        : GDALAbstractMDArray(std::string(),
11750
0
                              std::string(poDS->GetDescription())),
11751
0
          GDALMDArray(std::string(), std::string(poDS->GetDescription())),
11752
0
          m_poDS(poDS), m_dt(GDALExtendedDataType::Create(
11753
0
                            poDS->GetRasterBand(1)->GetRasterDataType())),
11754
0
          m_osFilename(poDS->GetDescription()), m_aosOptions(papszOptions)
11755
0
    {
11756
0
        m_poDS->Reference();
11757
11758
0
        const int nBandCount = poDS->GetRasterCount();
11759
0
        for (int i = 1; i <= nBandCount; ++i)
11760
0
        {
11761
0
            const auto poBand = poDS->GetRasterBand(i);
11762
0
            if (i == 1)
11763
0
                m_osUnit = poBand->GetUnitType();
11764
0
            else if (m_osUnit != poBand->GetUnitType())
11765
0
                m_osUnit.clear();
11766
11767
0
            std::vector<GByte> abyNoData;
11768
0
            int bHasNoData = false;
11769
0
            switch (poBand->GetRasterDataType())
11770
0
            {
11771
0
                case GDT_Int64:
11772
0
                {
11773
0
                    const auto nNoData =
11774
0
                        poBand->GetNoDataValueAsInt64(&bHasNoData);
11775
0
                    if (bHasNoData)
11776
0
                    {
11777
0
                        abyNoData.resize(m_dt.GetSize());
11778
0
                        GDALCopyWords64(&nNoData, GDT_Int64, 0, &abyNoData[0],
11779
0
                                        m_dt.GetNumericDataType(), 0, 1);
11780
0
                    }
11781
0
                    break;
11782
0
                }
11783
11784
0
                case GDT_UInt64:
11785
0
                {
11786
0
                    const auto nNoData =
11787
0
                        poBand->GetNoDataValueAsUInt64(&bHasNoData);
11788
0
                    if (bHasNoData)
11789
0
                    {
11790
0
                        abyNoData.resize(m_dt.GetSize());
11791
0
                        GDALCopyWords64(&nNoData, GDT_UInt64, 0, &abyNoData[0],
11792
0
                                        m_dt.GetNumericDataType(), 0, 1);
11793
0
                    }
11794
0
                    break;
11795
0
                }
11796
11797
0
                default:
11798
0
                {
11799
0
                    const auto dfNoData = poBand->GetNoDataValue(&bHasNoData);
11800
0
                    if (bHasNoData)
11801
0
                    {
11802
0
                        abyNoData.resize(m_dt.GetSize());
11803
0
                        GDALCopyWords64(&dfNoData, GDT_Float64, 0,
11804
0
                                        &abyNoData[0],
11805
0
                                        m_dt.GetNumericDataType(), 0, 1);
11806
0
                    }
11807
0
                    break;
11808
0
                }
11809
0
            }
11810
11811
0
            if (i == 1)
11812
0
                m_abyNoData = std::move(abyNoData);
11813
0
            else if (m_abyNoData != abyNoData)
11814
0
                m_abyNoData.clear();
11815
0
        }
11816
11817
0
        const int nXSize = poDS->GetRasterXSize();
11818
0
        const int nYSize = poDS->GetRasterYSize();
11819
11820
0
        auto poSRS = poDS->GetSpatialRef();
11821
0
        std::string osTypeY;
11822
0
        std::string osTypeX;
11823
0
        std::string osDirectionY;
11824
0
        std::string osDirectionX;
11825
0
        if (poSRS && poSRS->GetAxesCount() == 2)
11826
0
        {
11827
0
            const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
11828
0
            OGRAxisOrientation eOrientation1 = OAO_Other;
11829
0
            poSRS->GetAxis(nullptr, 0, &eOrientation1);
11830
0
            OGRAxisOrientation eOrientation2 = OAO_Other;
11831
0
            poSRS->GetAxis(nullptr, 1, &eOrientation2);
11832
0
            if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
11833
0
            {
11834
0
                if (mapping == std::vector<int>{1, 2})
11835
0
                {
11836
0
                    osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
11837
0
                    osDirectionY = "NORTH";
11838
0
                    osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
11839
0
                    osDirectionX = "EAST";
11840
0
                }
11841
0
            }
11842
0
            else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
11843
0
            {
11844
0
                if (mapping == std::vector<int>{2, 1})
11845
0
                {
11846
0
                    osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
11847
0
                    osDirectionY = "NORTH";
11848
0
                    osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
11849
0
                    osDirectionX = "EAST";
11850
0
                }
11851
0
            }
11852
0
        }
11853
11854
0
        const bool bBandYX = [papszOptions, poDS, nBandCount]()
11855
0
        {
11856
0
            const char *pszDimOrder =
11857
0
                CSLFetchNameValueDef(papszOptions, "DIM_ORDER", "AUTO");
11858
0
            if (EQUAL(pszDimOrder, "AUTO"))
11859
0
            {
11860
0
                const char *pszInterleave =
11861
0
                    poDS->GetMetadataItem("INTERLEAVE", "IMAGE_STRUCTURE");
11862
0
                return nBandCount == 1 || !pszInterleave ||
11863
0
                       !EQUAL(pszInterleave, "PIXEL");
11864
0
            }
11865
0
            else
11866
0
            {
11867
0
                return EQUAL(pszDimOrder, "BAND,Y,X");
11868
0
            }
11869
0
        }();
11870
0
        const char *const pszBandDimName =
11871
0
            CSLFetchNameValueDef(papszOptions, "BAND_DIM_NAME", "Band");
11872
0
        auto poBandDim = std::make_shared<GDALDimensionWeakIndexingVar>(
11873
0
            "/", pszBandDimName, std::string(), std::string(), nBandCount);
11874
0
        const char *const pszYDimName =
11875
0
            CSLFetchNameValueDef(papszOptions, "Y_DIM_NAME", "Y");
11876
0
        auto poYDim = std::make_shared<GDALDimensionWeakIndexingVar>(
11877
0
            "/", pszYDimName, osTypeY, osDirectionY, nYSize);
11878
0
        const char *const pszXDimName =
11879
0
            CSLFetchNameValueDef(papszOptions, "X_DIM_NAME", "X");
11880
0
        auto poXDim = std::make_shared<GDALDimensionWeakIndexingVar>(
11881
0
            "/", pszXDimName, osTypeX, osDirectionX, nXSize);
11882
11883
0
        const char *const pszBandIndexingVarItem = CSLFetchNameValueDef(
11884
0
            papszOptions, "BAND_INDEXING_VAR_ITEM", "{Description}");
11885
0
        if (EQUAL(pszBandIndexingVarItem, "{Description}"))
11886
0
        {
11887
0
            const auto oIndexingVarType =
11888
0
                GDALExtendedDataType::CreateString(strlen("Band 65535"));
11889
0
            auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
11890
0
                                                {poBandDim}, oIndexingVarType);
11891
0
            CPL_IGNORE_RET_VAL(poBandVar->Init());
11892
0
            for (int i = 0; i < nBandCount; ++i)
11893
0
            {
11894
0
                const char *pszDesc =
11895
0
                    poDS->GetRasterBand(i + 1)->GetDescription();
11896
0
                const std::string osBandName =
11897
0
                    pszDesc[0] ? pszDesc : CPLSPrintf("Band %d", i + 1);
11898
0
                const char *pszBandName = osBandName.c_str();
11899
0
                const char *const apszBandVal[] = {pszBandName};
11900
0
                const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
11901
0
                const size_t anCount[] = {1};
11902
0
                const GInt64 arrayStep[] = {1};
11903
0
                const GPtrDiff_t anBufferStride[] = {1};
11904
0
                poBandVar->Write(anStartIdx, anCount, arrayStep, anBufferStride,
11905
0
                                 oIndexingVarType, apszBandVal);
11906
0
            }
11907
0
            m_varBand = std::move(poBandVar);
11908
0
            poBandDim->SetIndexingVariable(m_varBand);
11909
0
        }
11910
0
        else if (EQUAL(pszBandIndexingVarItem, "{Index}"))
11911
0
        {
11912
0
            const auto oIndexingVarType =
11913
0
                GDALExtendedDataType::Create(GDT_Int32);
11914
0
            auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
11915
0
                                                {poBandDim}, oIndexingVarType);
11916
0
            CPL_IGNORE_RET_VAL(poBandVar->Init());
11917
0
            for (int i = 0; i < nBandCount; ++i)
11918
0
            {
11919
0
                const int anBandIdx[] = {i + 1};
11920
0
                const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
11921
0
                const size_t anCount[] = {1};
11922
0
                const GInt64 arrayStep[] = {1};
11923
0
                const GPtrDiff_t anBufferStride[] = {1};
11924
0
                poBandVar->Write(anStartIdx, anCount, arrayStep, anBufferStride,
11925
0
                                 oIndexingVarType, anBandIdx);
11926
0
            }
11927
0
            m_varBand = std::move(poBandVar);
11928
0
            poBandDim->SetIndexingVariable(m_varBand);
11929
0
        }
11930
0
        else if (EQUAL(pszBandIndexingVarItem, "{ColorInterpretation}"))
11931
0
        {
11932
0
            size_t nMaxLen = 0;
11933
0
            for (int i = 0; i < nBandCount; ++i)
11934
0
            {
11935
0
                const char *pszDesc = GDALGetColorInterpretationName(
11936
0
                    poDS->GetRasterBand(i + 1)->GetColorInterpretation());
11937
0
                nMaxLen = std::max(nMaxLen, strlen(pszDesc));
11938
0
            }
11939
0
            const auto oIndexingVarType =
11940
0
                GDALExtendedDataType::CreateString(nMaxLen);
11941
0
            auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
11942
0
                                                {poBandDim}, oIndexingVarType);
11943
0
            CPL_IGNORE_RET_VAL(poBandVar->Init());
11944
0
            for (int i = 0; i < nBandCount; ++i)
11945
0
            {
11946
0
                const char *pszDesc = GDALGetColorInterpretationName(
11947
0
                    poDS->GetRasterBand(i + 1)->GetColorInterpretation());
11948
0
                const char *const apszBandVal[] = {pszDesc};
11949
0
                const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
11950
0
                const size_t anCount[] = {1};
11951
0
                const GInt64 arrayStep[] = {1};
11952
0
                const GPtrDiff_t anBufferStride[] = {1};
11953
0
                poBandVar->Write(anStartIdx, anCount, arrayStep, anBufferStride,
11954
0
                                 oIndexingVarType, apszBandVal);
11955
0
            }
11956
0
            m_varBand = std::move(poBandVar);
11957
0
            poBandDim->SetIndexingVariable(m_varBand);
11958
0
        }
11959
0
        else if (!EQUAL(pszBandIndexingVarItem, "{None}"))
11960
0
        {
11961
0
            const char *const pszBandIndexingVarType = CSLFetchNameValueDef(
11962
0
                papszOptions, "BAND_INDEXING_VAR_TYPE", "String");
11963
0
            size_t nMaxLen = 0;
11964
0
            if (EQUAL(pszBandIndexingVarType, "String"))
11965
0
            {
11966
0
                for (int i = 0; i < nBandCount; ++i)
11967
0
                {
11968
0
                    const char *pszVal =
11969
0
                        poDS->GetRasterBand(i + 1)->GetMetadataItem(
11970
0
                            pszBandIndexingVarItem);
11971
0
                    if (pszVal)
11972
0
                        nMaxLen = std::max(nMaxLen, strlen(pszVal));
11973
0
                }
11974
0
            }
11975
0
            const auto oIndexingVarType =
11976
0
                EQUAL(pszBandIndexingVarType, "String")
11977
0
                    ? GDALExtendedDataType::CreateString(nMaxLen)
11978
0
                : EQUAL(pszBandIndexingVarType, "Integer")
11979
0
                    ? GDALExtendedDataType::Create(GDT_Int32)
11980
0
                    : GDALExtendedDataType::Create(GDT_Float64);
11981
0
            auto poBandVar = MEMMDArray::Create("/", poBandDim->GetName(),
11982
0
                                                {poBandDim}, oIndexingVarType);
11983
0
            CPL_IGNORE_RET_VAL(poBandVar->Init());
11984
0
            for (int i = 0; i < nBandCount; ++i)
11985
0
            {
11986
0
                const GUInt64 anStartIdx[] = {static_cast<GUInt64>(i)};
11987
0
                const size_t anCount[] = {1};
11988
0
                const GInt64 arrayStep[] = {1};
11989
0
                const GPtrDiff_t anBufferStride[] = {1};
11990
0
                const char *pszVal =
11991
0
                    poDS->GetRasterBand(i + 1)->GetMetadataItem(
11992
0
                        pszBandIndexingVarItem);
11993
0
                if (oIndexingVarType.GetClass() == GEDTC_STRING)
11994
0
                {
11995
0
                    const char *const apszBandVal[] = {pszVal ? pszVal : ""};
11996
0
                    poBandVar->Write(anStartIdx, anCount, arrayStep,
11997
0
                                     anBufferStride, oIndexingVarType,
11998
0
                                     apszBandVal);
11999
0
                }
12000
0
                else if (oIndexingVarType.GetNumericDataType() == GDT_Int32)
12001
0
                {
12002
0
                    const int anVal[] = {pszVal ? atoi(pszVal) : 0};
12003
0
                    poBandVar->Write(anStartIdx, anCount, arrayStep,
12004
0
                                     anBufferStride, oIndexingVarType, anVal);
12005
0
                }
12006
0
                else
12007
0
                {
12008
0
                    const double adfVal[] = {pszVal ? CPLAtof(pszVal) : 0.0};
12009
0
                    poBandVar->Write(anStartIdx, anCount, arrayStep,
12010
0
                                     anBufferStride, oIndexingVarType, adfVal);
12011
0
                }
12012
0
            }
12013
0
            m_varBand = std::move(poBandVar);
12014
0
            poBandDim->SetIndexingVariable(m_varBand);
12015
0
        }
12016
12017
0
        GDALGeoTransform gt;
12018
0
        if (m_poDS->GetGeoTransform(gt) == CE_None && gt.IsAxisAligned())
12019
0
        {
12020
0
            m_varX = GDALMDArrayRegularlySpaced::Create(
12021
0
                "/", poBandDim->GetName(), poXDim, gt.xorig, gt.xscale, 0.5);
12022
0
            poXDim->SetIndexingVariable(m_varX);
12023
12024
0
            m_varY = GDALMDArrayRegularlySpaced::Create(
12025
0
                "/", poYDim->GetName(), poYDim, gt.yorig, gt.yscale, 0.5);
12026
0
            poYDim->SetIndexingVariable(m_varY);
12027
0
        }
12028
0
        if (bBandYX)
12029
0
        {
12030
0
            m_dims = {std::move(poBandDim), std::move(poYDim),
12031
0
                      std::move(poXDim)};
12032
0
        }
12033
0
        else
12034
0
        {
12035
0
            m_iYDim = 0;
12036
0
            m_iXDim = 1;
12037
0
            m_iBandDim = 2;
12038
0
            m_dims = {std::move(poYDim), std::move(poXDim),
12039
0
                      std::move(poBandDim)};
12040
0
        }
12041
0
    }
12042
12043
    bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
12044
               const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
12045
               const GDALExtendedDataType &bufferDataType,
12046
               void *pDstBuffer) const override;
12047
12048
    bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
12049
                const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
12050
                const GDALExtendedDataType &bufferDataType,
12051
                const void *pSrcBuffer) override
12052
0
    {
12053
0
        return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
12054
0
                         bufferStride, bufferDataType,
12055
0
                         const_cast<void *>(pSrcBuffer));
12056
0
    }
12057
12058
  public:
12059
    ~GDALMDArrayFromDataset() override
12060
0
    {
12061
0
        m_poDS->ReleaseRef();
12062
0
    }
12063
12064
    static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
12065
                                               CSLConstList papszOptions)
12066
0
    {
12067
0
        auto array(std::shared_ptr<GDALMDArrayFromDataset>(
12068
0
            new GDALMDArrayFromDataset(poDS, papszOptions)));
12069
0
        array->SetSelf(array);
12070
0
        return array;
12071
0
    }
12072
12073
    bool IsWritable() const override
12074
0
    {
12075
0
        return m_poDS->GetAccess() == GA_Update;
12076
0
    }
12077
12078
    const std::string &GetFilename() const override
12079
0
    {
12080
0
        return m_osFilename;
12081
0
    }
12082
12083
    const std::vector<std::shared_ptr<GDALDimension>> &
12084
    GetDimensions() const override
12085
0
    {
12086
0
        return m_dims;
12087
0
    }
12088
12089
    const GDALExtendedDataType &GetDataType() const override
12090
0
    {
12091
0
        return m_dt;
12092
0
    }
12093
12094
    const std::string &GetUnit() const override
12095
0
    {
12096
0
        return m_osUnit;
12097
0
    }
12098
12099
    const void *GetRawNoDataValue() const override
12100
0
    {
12101
0
        return m_abyNoData.empty() ? nullptr : m_abyNoData.data();
12102
0
    }
12103
12104
    double GetOffset(bool *pbHasOffset,
12105
                     GDALDataType *peStorageType) const override
12106
0
    {
12107
0
        double dfRes = 0;
12108
0
        int bHasOffset = false;
12109
0
        auto poFirstBand = m_poDS->GetRasterBand(1);
12110
0
        if (poFirstBand)  // to avoid -Wnull-dereference
12111
0
        {
12112
0
            dfRes = poFirstBand->GetOffset(&bHasOffset);
12113
0
            for (int i = 2; bHasOffset && i <= m_poDS->GetRasterCount(); ++i)
12114
0
            {
12115
0
                const double dfOtherRes =
12116
0
                    m_poDS->GetRasterBand(i)->GetOffset(&bHasOffset);
12117
0
                bHasOffset = bHasOffset && (dfOtherRes == dfRes);
12118
0
            }
12119
0
        }
12120
0
        if (pbHasOffset)
12121
0
            *pbHasOffset = CPL_TO_BOOL(bHasOffset);
12122
0
        if (peStorageType)
12123
0
            *peStorageType = GDT_Unknown;
12124
0
        return dfRes;
12125
0
    }
12126
12127
    double GetScale(bool *pbHasScale,
12128
                    GDALDataType *peStorageType) const override
12129
0
    {
12130
0
        double dfRes = 0;
12131
0
        int bHasScale = false;
12132
0
        auto poFirstBand = m_poDS->GetRasterBand(1);
12133
0
        if (poFirstBand)  // to avoid -Wnull-dereference
12134
0
        {
12135
0
            dfRes = poFirstBand->GetScale(&bHasScale);
12136
0
            for (int i = 2; bHasScale && i <= m_poDS->GetRasterCount(); ++i)
12137
0
            {
12138
0
                const double dfOtherRes =
12139
0
                    m_poDS->GetRasterBand(i)->GetScale(&bHasScale);
12140
0
                bHasScale = bHasScale && (dfOtherRes == dfRes);
12141
0
            }
12142
0
        }
12143
0
        if (pbHasScale)
12144
0
            *pbHasScale = CPL_TO_BOOL(bHasScale);
12145
0
        if (peStorageType)
12146
0
            *peStorageType = GDT_Unknown;
12147
0
        return dfRes;
12148
0
    }
12149
12150
    std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
12151
0
    {
12152
0
        auto poSrcSRS = m_poDS->GetSpatialRef();
12153
0
        if (!poSrcSRS)
12154
0
            return nullptr;
12155
0
        auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
12156
12157
0
        auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
12158
0
        for (auto &m : axisMapping)
12159
0
        {
12160
0
            if (m == 1)
12161
0
                m = m_iXDim + 1;
12162
0
            else if (m == 2)
12163
0
                m = m_iYDim + 1;
12164
0
            else
12165
0
                m = 0;
12166
0
        }
12167
0
        poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
12168
0
        return poSRS;
12169
0
    }
12170
12171
    std::vector<GUInt64> GetBlockSize() const override
12172
0
    {
12173
0
        int nBlockXSize = 0;
12174
0
        int nBlockYSize = 0;
12175
0
        m_poDS->GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize);
12176
0
        if (m_iBandDim == 0)
12177
0
        {
12178
0
            return std::vector<GUInt64>{1, static_cast<GUInt64>(nBlockYSize),
12179
0
                                        static_cast<GUInt64>(nBlockXSize)};
12180
0
        }
12181
0
        else
12182
0
        {
12183
0
            return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
12184
0
                                        static_cast<GUInt64>(nBlockXSize), 1};
12185
0
        }
12186
0
    }
12187
12188
    std::vector<std::shared_ptr<GDALAttribute>>
12189
    GetAttributes(CSLConstList) const override
12190
0
    {
12191
0
        std::vector<std::shared_ptr<GDALAttribute>> res;
12192
0
        auto papszMD = m_poDS->GetMetadata();
12193
0
        for (auto iter = papszMD; iter && iter[0]; ++iter)
12194
0
        {
12195
0
            char *pszKey = nullptr;
12196
0
            const char *pszValue = CPLParseNameValue(*iter, &pszKey);
12197
0
            if (pszKey && pszValue)
12198
0
            {
12199
0
                res.emplace_back(
12200
0
                    std::make_shared<GDALMDIAsAttribute>(pszKey, pszValue));
12201
0
            }
12202
0
            CPLFree(pszKey);
12203
0
        }
12204
0
        return res;
12205
0
    }
12206
12207
    int GetOverviewCount() const override
12208
0
    {
12209
0
        int nOvrCount = 0;
12210
0
        GDALDataset *poOvrDS = nullptr;
12211
0
        bool bOK = true;
12212
0
        for (int i = 1; bOK && i <= m_poDS->GetRasterCount(); ++i)
12213
0
        {
12214
0
            auto poBand = m_poDS->GetRasterBand(i);
12215
0
            const int nThisOvrCount = poBand->GetOverviewCount();
12216
0
            bOK = (nThisOvrCount > 0 && (i == 1 || nThisOvrCount == nOvrCount));
12217
0
            if (bOK)
12218
0
            {
12219
0
                nOvrCount = nThisOvrCount;
12220
0
                auto poFirstOvrBand = poBand->GetOverview(0);
12221
0
                bOK = poFirstOvrBand != nullptr;
12222
0
                if (bOK)
12223
0
                {
12224
0
                    auto poThisOvrDS = poFirstOvrBand->GetDataset();
12225
0
                    bOK = poThisOvrDS != nullptr &&
12226
0
                          poThisOvrDS->GetRasterBand(i) == poFirstOvrBand &&
12227
0
                          (i == 1 || poThisOvrDS == poOvrDS);
12228
0
                    if (bOK)
12229
0
                        poOvrDS = poThisOvrDS;
12230
0
                }
12231
0
            }
12232
0
        }
12233
0
        return bOK ? nOvrCount : 0;
12234
0
    }
12235
12236
    std::shared_ptr<GDALMDArray> GetOverview(int idx) const override
12237
0
    {
12238
0
        const int nOverviews = GetOverviewCount();
12239
0
        if (idx < 0 || idx >= nOverviews)
12240
0
            return nullptr;
12241
0
        m_apoOverviews.resize(nOverviews);
12242
0
        if (!m_apoOverviews[idx])
12243
0
        {
12244
0
            if (auto poBand = m_poDS->GetRasterBand(1))
12245
0
            {
12246
0
                if (auto poOvrBand = poBand->GetOverview(idx))
12247
0
                {
12248
0
                    if (auto poOvrDS = poOvrBand->GetDataset())
12249
0
                    {
12250
0
                        m_apoOverviews[idx] =
12251
0
                            Create(poOvrDS, m_aosOptions.List());
12252
0
                    }
12253
0
                }
12254
0
            }
12255
0
        }
12256
0
        return m_apoOverviews[idx];
12257
0
    }
12258
};
12259
12260
bool GDALMDArrayFromDataset::IRead(const GUInt64 *arrayStartIdx,
12261
                                   const size_t *count, const GInt64 *arrayStep,
12262
                                   const GPtrDiff_t *bufferStride,
12263
                                   const GDALExtendedDataType &bufferDataType,
12264
                                   void *pDstBuffer) const
12265
0
{
12266
0
    return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
12267
0
                     bufferDataType, pDstBuffer);
12268
0
}
12269
12270
/************************************************************************/
12271
/*                             ReadWrite()                              */
12272
/************************************************************************/
12273
12274
bool GDALMDArrayFromDataset::ReadWrite(
12275
    GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
12276
    const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
12277
    const GDALExtendedDataType &bufferDataType, void *pBuffer) const
12278
0
{
12279
0
    const auto eDT(bufferDataType.GetNumericDataType());
12280
0
    const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
12281
0
    const int nX =
12282
0
        arrayStep[m_iXDim] > 0
12283
0
            ? static_cast<int>(arrayStartIdx[m_iXDim])
12284
0
            : static_cast<int>(arrayStartIdx[m_iXDim] -
12285
0
                               (count[m_iXDim] - 1) * -arrayStep[m_iXDim]);
12286
0
    const int nY =
12287
0
        arrayStep[m_iYDim] > 0
12288
0
            ? static_cast<int>(arrayStartIdx[m_iYDim])
12289
0
            : static_cast<int>(arrayStartIdx[m_iYDim] -
12290
0
                               (count[m_iYDim] - 1) * -arrayStep[m_iYDim]);
12291
0
    const int nSizeX =
12292
0
        static_cast<int>(count[m_iXDim] * ABS(arrayStep[m_iXDim]));
12293
0
    const int nSizeY =
12294
0
        static_cast<int>(count[m_iYDim] * ABS(arrayStep[m_iYDim]));
12295
0
    GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
12296
0
    int nStrideXSign = 1;
12297
0
    if (arrayStep[m_iXDim] < 0)
12298
0
    {
12299
0
        pabyBuffer += (count[m_iXDim] - 1) * bufferStride[m_iXDim] * nDTSize;
12300
0
        nStrideXSign = -1;
12301
0
    }
12302
0
    int nStrideYSign = 1;
12303
0
    if (arrayStep[m_iYDim] < 0)
12304
0
    {
12305
0
        pabyBuffer += (count[m_iYDim] - 1) * bufferStride[m_iYDim] * nDTSize;
12306
0
        nStrideYSign = -1;
12307
0
    }
12308
0
    const GSpacing nPixelSpace =
12309
0
        static_cast<GSpacing>(nStrideXSign * bufferStride[m_iXDim] * nDTSize);
12310
0
    const GSpacing nLineSpace =
12311
0
        static_cast<GSpacing>(nStrideYSign * bufferStride[m_iYDim] * nDTSize);
12312
0
    const GSpacing nBandSpace =
12313
0
        static_cast<GSpacing>(bufferStride[m_iBandDim] * nDTSize);
12314
0
    std::vector<int> anBandList;
12315
0
    for (int i = 0; i < static_cast<int>(count[m_iBandDim]); ++i)
12316
0
        anBandList.push_back(1 + static_cast<int>(arrayStartIdx[m_iBandDim]) +
12317
0
                             i * static_cast<int>(arrayStep[m_iBandDim]));
12318
12319
0
    return m_poDS->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
12320
0
                            static_cast<int>(count[m_iXDim]),
12321
0
                            static_cast<int>(count[m_iYDim]), eDT,
12322
0
                            static_cast<int>(count[m_iBandDim]),
12323
0
                            anBandList.data(), nPixelSpace, nLineSpace,
12324
0
                            nBandSpace, nullptr) == CE_None;
12325
0
}
12326
12327
/************************************************************************/
12328
/*                             AsMDArray()                              */
12329
/************************************************************************/
12330
12331
/** Return a view of this dataset as a 3D multidimensional GDALMDArray.
12332
 *
12333
 * If this dataset is not already marked as shared, it will be, so that the
12334
 * returned array holds a reference to it.
12335
 *
12336
 * If the dataset has a geotransform attached, the X and Y dimensions of the
12337
 * returned array will have an associated indexing variable.
12338
 *
12339
 * The currently supported list of options is:
12340
 * <ul>
12341
 * <li>DIM_ORDER=&lt;order&gt; where order can be "AUTO", "Band,Y,X" or "Y,X,Band".
12342
 * "Band,Y,X" means that the first (slowest changing) dimension is Band
12343
 * and the last (fastest changing direction) is X
12344
 * "Y,X,Band" means that the first (slowest changing) dimension is Y
12345
 * and the last (fastest changing direction) is Band.
12346
 * "AUTO" (the default) selects "Band,Y,X" for single band datasets, or takes
12347
 * into account the INTERLEAVE metadata item in the IMAGE_STRUCTURE domain.
12348
 * If it equals BAND, then "Band,Y,X" is used. Otherwise (if it equals PIXEL),
12349
 * "Y,X,Band" is use.
12350
 * </li>
12351
 * <li>BAND_INDEXING_VAR_ITEM={Description}|{None}|{Index}|{ColorInterpretation}|&lt;BandMetadataItem&gt;:
12352
 * item from which to build the band indexing variable.
12353
 * <ul>
12354
 * <li>"{Description}", the default, means to use the band description (or "Band index" if empty).</li>
12355
 * <li>"{None}" means that no band indexing variable must be created.</li>
12356
 * <li>"{Index}" means that the band index (starting at one) is used.</li>
12357
 * <li>"{ColorInterpretation}" means that the band color interpretation is used (i.e. "Red", "Green", "Blue").</li>
12358
 * <li>&lt;BandMetadataItem&gt; is the name of a band metadata item to use.</li>
12359
 * </ul>
12360
 * </li>
12361
 * <li>BAND_INDEXING_VAR_TYPE=String|Real|Integer: the data type of the band
12362
 * indexing variable, when BAND_INDEXING_VAR_ITEM corresponds to a band metadata item.
12363
 * Defaults to String.
12364
 * </li>
12365
 * <li>BAND_DIM_NAME=&lt;string&gt;: Name of the band dimension.
12366
 * Defaults to "Band".
12367
 * </li>
12368
 * <li>X_DIM_NAME=&lt;string&gt;: Name of the X dimension. Defaults to "X".
12369
 * </li>
12370
 * <li>Y_DIM_NAME=&lt;string&gt;: Name of the Y dimension. Defaults to "Y".
12371
 * </li>
12372
 * </ul>
12373
 *
12374
 * This is the same as the C function GDALDatasetAsMDArray().
12375
 *
12376
 * The "reverse" method is GDALMDArray::AsClassicDataset().
12377
 *
12378
 * @param papszOptions Null-terminated list of strings, or nullptr.
12379
 * @return a new array, or nullptr.
12380
 *
12381
 * @since GDAL 3.12
12382
 */
12383
std::shared_ptr<GDALMDArray> GDALDataset::AsMDArray(CSLConstList papszOptions)
12384
0
{
12385
0
    if (!GetShared())
12386
0
    {
12387
0
        MarkAsShared();
12388
0
    }
12389
0
    if (nBands == 0 || nRasterXSize == 0 || nRasterYSize == 0)
12390
0
    {
12391
0
        ReportError(
12392
0
            CE_Failure, CPLE_AppDefined,
12393
0
            "Degenerated array (band, Y and/or X dimension of size zero)");
12394
0
        return nullptr;
12395
0
    }
12396
0
    const GDALDataType eDT = papoBands[0]->GetRasterDataType();
12397
0
    for (int i = 1; i < nBands; ++i)
12398
0
    {
12399
0
        if (eDT != papoBands[i]->GetRasterDataType())
12400
0
        {
12401
0
            ReportError(CE_Failure, CPLE_AppDefined,
12402
0
                        "Non-uniform data type amongst bands");
12403
0
            return nullptr;
12404
0
        }
12405
0
    }
12406
0
    const char *pszDimOrder =
12407
0
        CSLFetchNameValueDef(papszOptions, "DIM_ORDER", "AUTO");
12408
0
    if (!EQUAL(pszDimOrder, "AUTO") && !EQUAL(pszDimOrder, "Band,Y,X") &&
12409
0
        !EQUAL(pszDimOrder, "Y,X,Band"))
12410
0
    {
12411
0
        ReportError(CE_Failure, CPLE_IllegalArg,
12412
0
                    "Illegal value for DIM_ORDER option");
12413
0
        return nullptr;
12414
0
    }
12415
0
    return GDALMDArrayFromDataset::Create(this, papszOptions);
12416
0
}
12417
12418
/************************************************************************/
12419
/*             GDALDataset::GetInterBandCovarianceMatrix()              */
12420
/************************************************************************/
12421
12422
/**
12423
 \brief Fetch or compute the covariance matrix between bands of this dataset.
12424
12425
 The covariance indicates the level to which two bands vary together.
12426
12427
 If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12428
 and \f$ mean_i \f$ the mean value of all pixels of band i, then
12429
12430
 \f[
12431
    \mathrm{cov}[i,j] =
12432
    \frac{
12433
        \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12434
        \left( v_j[y,x] - \mathrm{mean}_j \right)
12435
    }{
12436
        \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12437
    }
12438
 \f]
12439
12440
 When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12441
 We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12442
 is symmetric.
12443
12444
 A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12445
 if the pixels in bands are considered to be a sample of the whole population.
12446
 This is consistent with the default of
12447
 https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12448
 matrix is consistent with what can be obtained with
12449
12450
 \verbatim embed:rst
12451
 .. code-block:: python
12452
12453
     numpy.cov(
12454
        [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12455
     )
12456
 \endverbatim
12457
12458
 Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12459
 to be the whole population.
12460
12461
 If STATISTICS_COVARIANCES metadata items are available in band metadata,
12462
 this method uses them.
12463
 Otherwise, if bForce is true, ComputeInterBandCovarianceMatrix() is called.
12464
 Otherwise, if bForce is false, an empty vector is returned
12465
12466
 @param nBandCount Zero for all bands, or number of values in panBandList.
12467
                   Defaults to 0.
12468
 @param panBandList nullptr for all bands if nBandCount == 0, or array of
12469
                    nBandCount values such as panBandList[i] is the index
12470
                    between 1 and GetRasterCount() of a band that must be used
12471
                    in the covariance computation. Defaults to nullptr.
12472
 @param bApproxOK Whether it is acceptable to use a subsample of values in
12473
                  ComputeInterBandCovarianceMatrix().
12474
                  Defaults to false.
12475
 @param bForce Whether ComputeInterBandCovarianceMatrix() should be called
12476
               when the STATISTICS_COVARIANCES metadata items are missing.
12477
               Defaults to false.
12478
 @param bWriteIntoMetadata Whether ComputeInterBandCovarianceMatrix() must
12479
                           write STATISTICS_COVARIANCES band metadata items.
12480
                           Defaults to true.
12481
 @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12482
                              averaging phase of the covariance computation.
12483
                              Defaults to 1.
12484
 @param pfnProgress a function to call to report progress, or NULL.
12485
 @param pProgressData application data to pass to the progress function.
12486
12487
 @return a vector of nBandCount * nBandCount values if successful,
12488
         in row-major order, or an empty vector in case of failure
12489
12490
 @since 3.13
12491
12492
 @see ComputeInterBandCovarianceMatrix()
12493
 */
12494
12495
std::vector<double> GDALDataset::GetInterBandCovarianceMatrix(
12496
    int nBandCount, const int *panBandList, bool bApproxOK, bool bForce,
12497
    bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
12498
    GDALProgressFunc pfnProgress, void *pProgressData)
12499
0
{
12500
0
    std::vector<double> res;
12501
0
    const int nBandCountToUse = nBandCount == 0 ? nBands : nBandCount;
12502
0
    if (nBandCountToUse == 0)
12503
0
        return res;
12504
    if constexpr (sizeof(size_t) < sizeof(uint64_t))
12505
    {
12506
        // Check that nBandCountToUse * nBandCountToUse will not overflow size_t
12507
        if (static_cast<uint32_t>(nBandCountToUse) >
12508
            std::numeric_limits<uint16_t>::max())
12509
        {
12510
            CPLError(CE_Failure, CPLE_OutOfMemory,
12511
                     "Not enough memory to store result");
12512
            return res;
12513
        }
12514
    }
12515
0
    try
12516
0
    {
12517
0
        res.resize(static_cast<size_t>(nBandCountToUse) * nBandCountToUse);
12518
0
    }
12519
0
    catch (const std::exception &)
12520
0
    {
12521
0
        CPLError(CE_Failure, CPLE_OutOfMemory,
12522
0
                 "Not enough memory to store result");
12523
0
        return res;
12524
0
    }
12525
12526
0
    if (GetInterBandCovarianceMatrix(res.data(), res.size(), nBandCount,
12527
0
                                     panBandList, bApproxOK, bForce,
12528
0
                                     bWriteIntoMetadata, nDeltaDegreeOfFreedom,
12529
0
                                     pfnProgress, pProgressData) != CE_None)
12530
0
    {
12531
0
        res.clear();
12532
0
    }
12533
0
    return res;
12534
0
}
12535
12536
/************************************************************************/
12537
/*             GDALDataset::GetInterBandCovarianceMatrix()              */
12538
/************************************************************************/
12539
12540
/**
12541
 \brief Fetch or compute the covariance matrix between bands of this dataset.
12542
12543
 The covariance indicates the level to which two bands vary together.
12544
12545
 If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12546
 and \f$ mean_i \f$ the mean value of all pixels of band i, then
12547
12548
 \f[
12549
    \mathrm{cov}[i,j] =
12550
    \frac{
12551
        \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12552
        \left( v_j[y,x] - \mathrm{mean}_j \right)
12553
    }{
12554
        \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12555
    }
12556
 \f]
12557
12558
 When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12559
 We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12560
 is symmetric.
12561
12562
 A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12563
 if the pixels in bands are considered to be a sample of the whole population.
12564
 This is consistent with the default of
12565
 https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12566
 matrix is consistent with what can be obtained with
12567
12568
 \verbatim embed:rst
12569
 .. code-block:: python
12570
12571
     numpy.cov(
12572
        [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12573
     )
12574
 \endverbatim
12575
12576
 Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12577
 to be the whole population.
12578
12579
 The caller must provide an already allocated array in padfCovMatrix of size
12580
 at least nBandCount * nBandCount.
12581
12582
 If STATISTICS_COVARIANCES metadata items are available in band metadata,
12583
 this method uses them.
12584
 Otherwise, if bForce is true, ComputeInterBandCovarianceMatrix() is called.
12585
 Otherwise, if bForce is false, an empty vector is returned
12586
12587
 This is the same as the C function GDALDatasetGetInterBandCovarianceMatrix()
12588
12589
 @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
12590
                      nBandCount * nBandCount.
12591
 @param nSize Number of elements in output array.
12592
 @param nBandCount Zero for all bands, or number of values in panBandList.
12593
                   Defaults to 0.
12594
 @param panBandList nullptr for all bands if nBandCount == 0, or array of
12595
                    nBandCount values such as panBandList[i] is the index
12596
                    between 1 and GetRasterCount() of a band that must be used
12597
                    in the covariance computation. Defaults to nullptr.
12598
 @param bApproxOK Whether it is acceptable to use a subsample of values in
12599
                  ComputeInterBandCovarianceMatrix().
12600
                  Defaults to false.
12601
 @param bForce Whether ComputeInterBandCovarianceMatrix() should be called
12602
               when the STATISTICS_COVARIANCES metadata items are missing.
12603
               Defaults to false.
12604
 @param bWriteIntoMetadata Whether ComputeInterBandCovarianceMatrix() must
12605
                           write STATISTICS_COVARIANCES band metadata items.
12606
                           Defaults to true.
12607
 @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12608
                              averaging phase of the covariance computation.
12609
                              Defaults to 1.
12610
 @param pfnProgress a function to call to report progress, or NULL.
12611
 @param pProgressData application data to pass to the progress function.
12612
12613
 @return CE_None if successful, CE_Warning if values are not available in
12614
         metadata and bForce is false, or CE_Failure in case of failure
12615
12616
 @since 3.13
12617
12618
 @see ComputeInterBandCovarianceMatrix()
12619
 */
12620
12621
CPLErr GDALDataset::GetInterBandCovarianceMatrix(
12622
    double *padfCovMatrix, size_t nSize, int nBandCount, const int *panBandList,
12623
    bool bApproxOK, bool bForce, bool bWriteIntoMetadata,
12624
    int nDeltaDegreeOfFreedom, GDALProgressFunc pfnProgress,
12625
    void *pProgressData)
12626
0
{
12627
0
    std::vector<int> anBandListTmp;  // keep in this scope
12628
0
    if (nBandCount == 0)
12629
0
    {
12630
0
        if (nBands == 0)
12631
0
            return CE_None;
12632
0
        for (int i = 0; i < nBands; ++i)
12633
0
            anBandListTmp.push_back(i + 1);
12634
0
        nBandCount = nBands;
12635
0
        panBandList = anBandListTmp.data();
12636
0
    }
12637
0
    else
12638
0
    {
12639
0
        if (nBandCount > nBands)
12640
0
        {
12641
0
            CPLError(CE_Failure, CPLE_AppDefined,
12642
0
                     "GetInterBandCovarianceMatrix(): nBandCount > nBands");
12643
0
            return CE_Failure;
12644
0
        }
12645
0
        for (int i = 0; i < nBandCount; ++i)
12646
0
        {
12647
0
            if (panBandList[i] <= 0 || panBandList[i] > nBands)
12648
0
            {
12649
0
                CPLError(CE_Failure, CPLE_AppDefined,
12650
0
                         "GetInterBandCovarianceMatrix(): invalid value "
12651
0
                         "panBandList[%d] = %d",
12652
0
                         i, panBandList[i]);
12653
0
                return CE_Failure;
12654
0
            }
12655
0
        }
12656
0
    }
12657
12658
0
    if (nSize < static_cast<uint64_t>(nBandCount) * nBandCount)
12659
0
    {
12660
0
        CPLError(
12661
0
            CE_Failure, CPLE_AppDefined,
12662
0
            "GetInterBandCovarianceMatrix(): too small result matrix provided");
12663
0
        return CE_Failure;
12664
0
    }
12665
0
    bool bGotFromMD = true;
12666
0
    size_t resIdx = 0;
12667
0
    for (int i = 0; bGotFromMD && i < nBandCount; ++i)
12668
0
    {
12669
0
        const char *pszCov = papoBands[panBandList[i] - 1]->GetMetadataItem(
12670
0
            "STATISTICS_COVARIANCES");
12671
0
        bGotFromMD = pszCov != nullptr;
12672
0
        if (bGotFromMD)
12673
0
        {
12674
0
            const CPLStringList aosTokens(CSLTokenizeString2(pszCov, ",", 0));
12675
0
            bGotFromMD = aosTokens.size() == nBands;
12676
0
            if (bGotFromMD)
12677
0
            {
12678
0
                for (int j = 0; j < nBandCount; ++j)
12679
0
                    padfCovMatrix[resIdx++] =
12680
0
                        CPLAtof(aosTokens[panBandList[j] - 1]);
12681
0
            }
12682
0
        }
12683
0
    }
12684
0
    if (bGotFromMD)
12685
0
        return CE_None;
12686
12687
0
    if (!bForce)
12688
0
        return CE_Warning;
12689
0
    return ComputeInterBandCovarianceMatrix(
12690
0
        padfCovMatrix, nSize, nBandCount, panBandList, bApproxOK,
12691
0
        bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress, pProgressData);
12692
0
}
12693
12694
/************************************************************************/
12695
/*              GDALDatasetGetInterBandCovarianceMatrix()               */
12696
/************************************************************************/
12697
12698
/**
12699
 \brief Fetch or compute the covariance matrix between bands of this dataset.
12700
12701
 The covariance indicates the level to which two bands vary together.
12702
12703
 If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12704
 and \f$ mean_i \f$ the mean value of all pixels of band i, then
12705
12706
 \f[
12707
    \mathrm{cov}[i,j] =
12708
    \frac{
12709
        \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12710
        \left( v_j[y,x] - \mathrm{mean}_j \right)
12711
    }{
12712
        \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12713
    }
12714
 \f]
12715
12716
 When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12717
 We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12718
 is symmetric.
12719
12720
 A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12721
 if the pixels in bands are considered to be a sample of the whole population.
12722
 This is consistent with the default of
12723
 https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12724
 matrix is consistent with what can be obtained with
12725
12726
 \verbatim embed:rst
12727
 .. code-block:: python
12728
12729
     numpy.cov(
12730
        [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12731
     )
12732
 \endverbatim
12733
12734
 Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12735
 to be the whole population.
12736
12737
 The caller must provide an already allocated array in padfCovMatrix of size
12738
 at least nBandCount * nBandCount.
12739
12740
 If STATISTICS_COVARIANCES metadata items are available in band metadata,
12741
 this method uses them.
12742
 Otherwise, if bForce is true, GDALDatasetComputeInterBandCovarianceMatrix() is called.
12743
 Otherwise, if bForce is false, an empty vector is returned
12744
12745
 This is the same as the C++ method GDALDataset::GetInterBandCovarianceMatrix()
12746
12747
 @param hDS Dataset handle.
12748
 @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
12749
                      nBandCount * nBandCount.
12750
 @param nSize Number of elements in output array.
12751
 @param nBandCount Zero for all bands, or number of values in panBandList.
12752
                   Defaults to 0.
12753
 @param panBandList nullptr for all bands if nBandCount == 0, or array of
12754
                    nBandCount values such as panBandList[i] is the index
12755
                    between 1 and GetRasterCount() of a band that must be used
12756
                    in the covariance computation. Defaults to nullptr.
12757
 @param bApproxOK Whether it is acceptable to use a subsample of values in
12758
                  GDALDatasetComputeInterBandCovarianceMatrix().
12759
                  Defaults to false.
12760
 @param bForce Whether GDALDatasetComputeInterBandCovarianceMatrix() should be called
12761
               when the STATISTICS_COVARIANCES metadata items are missing.
12762
               Defaults to false.
12763
 @param bWriteIntoMetadata Whether GDALDatasetComputeInterBandCovarianceMatrix() must
12764
                           write STATISTICS_COVARIANCES band metadata items.
12765
                           Defaults to true.
12766
 @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12767
                              averaging phase of the covariance computation.
12768
                              Defaults to 1.
12769
 @param pfnProgress a function to call to report progress, or NULL.
12770
 @param pProgressData application data to pass to the progress function.
12771
12772
 @return CE_None if successful, CE_Warning if values are not available in
12773
         metadata and bForce is false, or CE_Failure in case of failure
12774
12775
 @since 3.13
12776
12777
 @see GDALDatasetComputeInterBandCovarianceMatrix()
12778
 */
12779
CPLErr GDALDatasetGetInterBandCovarianceMatrix(
12780
    GDALDatasetH hDS, double *padfCovMatrix, size_t nSize, int nBandCount,
12781
    const int *panBandList, bool bApproxOK, bool bForce,
12782
    bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
12783
    GDALProgressFunc pfnProgress, void *pProgressData)
12784
0
{
12785
0
    VALIDATE_POINTER1(hDS, __func__, CE_Failure);
12786
0
    VALIDATE_POINTER1(padfCovMatrix, __func__, CE_Failure);
12787
0
    return GDALDataset::FromHandle(hDS)->GetInterBandCovarianceMatrix(
12788
0
        padfCovMatrix, nSize, nBandCount, panBandList, bApproxOK, bForce,
12789
0
        bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress, pProgressData);
12790
0
}
12791
12792
/************************************************************************/
12793
/*           GDALDataset::ComputeInterBandCovarianceMatrix()            */
12794
/************************************************************************/
12795
12796
/**
12797
 \brief Compute the covariance matrix between bands of this dataset.
12798
12799
 The covariance indicates the level to which two bands vary together.
12800
12801
 If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
12802
 and \f$ mean_i \f$ the mean value of all pixels of band i, then
12803
12804
 \f[
12805
    \mathrm{cov}[i,j] =
12806
    \frac{
12807
        \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
12808
        \left( v_j[y,x] - \mathrm{mean}_j \right)
12809
    }{
12810
        \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
12811
    }
12812
 \f]
12813
12814
 When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
12815
 We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
12816
 is symmetric.
12817
12818
 A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
12819
 if the pixels in bands are considered to be a sample of the whole population.
12820
 This is consistent with the default of
12821
 https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
12822
 matrix is consistent with what can be obtained with
12823
12824
 \verbatim embed:rst
12825
 .. code-block:: python
12826
12827
     numpy.cov(
12828
        [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
12829
     )
12830
 \endverbatim
12831
12832
 Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
12833
 to be the whole population.
12834
12835
 This method recomputes the covariance matrix, even if STATISTICS_COVARIANCES
12836
 metadata items are available in bands. See GetInterBandCovarianceMatrix()
12837
 to use them.
12838
12839
 @param nBandCount Zero for all bands, or number of values in panBandList.
12840
                   Defaults to 0.
12841
 @param panBandList nullptr for all bands if nBandCount == 0, or array of
12842
                    nBandCount values such as panBandList[i] is the index
12843
                    between 1 and GetRasterCount() of a band that must be used
12844
                    in the covariance computation. Defaults to nullptr.
12845
 @param bApproxOK Whether it is acceptable to use a subsample of values.
12846
                  Defaults to false.
12847
 @param bWriteIntoMetadata Whether this method must write
12848
                           STATISTICS_COVARIANCES band metadata items.
12849
                           Defaults to true.
12850
 @param nDeltaDegreeOfFreedom Correction term to subtract in the final
12851
                              averaging phase of the covariance computation.
12852
                              Defaults to 1.
12853
 @param pfnProgress a function to call to report progress, or NULL.
12854
 @param pProgressData application data to pass to the progress function.
12855
12856
 @return a vector of nBandCount * nBandCount values if successful,
12857
         in row-major order, or an empty vector in case of failure
12858
12859
 @since 3.13
12860
12861
 @see GetInterBandCovarianceMatrix()
12862
 */
12863
std::vector<double> GDALDataset::ComputeInterBandCovarianceMatrix(
12864
    int nBandCount, const int *panBandList, bool bApproxOK,
12865
    bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
12866
    GDALProgressFunc pfnProgress, void *pProgressData)
12867
0
{
12868
0
    std::vector<double> res;
12869
0
    const int nBandCountToUse = nBandCount == 0 ? nBands : nBandCount;
12870
0
    if (nBandCountToUse == 0)
12871
0
        return res;
12872
    if constexpr (sizeof(size_t) < sizeof(uint64_t))
12873
    {
12874
        // Check that nBandCountToUse * nBandCountToUse will not overflow size_t
12875
        if (static_cast<uint32_t>(nBandCountToUse) >
12876
            std::numeric_limits<uint16_t>::max())
12877
        {
12878
            CPLError(CE_Failure, CPLE_OutOfMemory,
12879
                     "Not enough memory to store result");
12880
            return res;
12881
        }
12882
    }
12883
0
    try
12884
0
    {
12885
0
        res.resize(static_cast<size_t>(nBandCountToUse) * nBandCountToUse);
12886
0
    }
12887
0
    catch (const std::exception &)
12888
0
    {
12889
0
        CPLError(CE_Failure, CPLE_OutOfMemory,
12890
0
                 "Not enough memory to store result");
12891
0
        return res;
12892
0
    }
12893
12894
0
    if (ComputeInterBandCovarianceMatrix(
12895
0
            res.data(), res.size(), nBandCount, panBandList, bApproxOK,
12896
0
            bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress,
12897
0
            pProgressData) != CE_None)
12898
0
        res.clear();
12899
0
    return res;
12900
0
}
12901
12902
/************************************************************************/
12903
/*              ComputeInterBandCovarianceMatrixInternal()              */
12904
/************************************************************************/
12905
12906
template <class T>
12907
// CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW because it seems the uses of openmp-simd
12908
// causes that to happen
12909
CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW static CPLErr
12910
ComputeInterBandCovarianceMatrixInternal(GDALDataset *poDS,
12911
                                         double *padfCovMatrix, int nBandCount,
12912
                                         const int *panBandList,
12913
                                         GDALRasterBand *const *papoBands,
12914
                                         int nDeltaDegreeOfFreedom,
12915
                                         GDALProgressFunc pfnProgress,
12916
                                         void *pProgressData)
12917
0
{
12918
    // We use the padfCovMatrix to accumulate co-moments
12919
    // Dimension = nBandCount * nBandCount
12920
0
    double *const padfComomentMatrix = padfCovMatrix;
12921
12922
    // Matrix of  nBandCount * nBandCount storing co-moments, in optimized
12923
    // case when the block has no nodata value
12924
    // Only used if T != double
12925
0
    [[maybe_unused]] std::vector<T> aCurBlockComomentMatrix;
12926
12927
    // Count number of valid values in padfComomentMatrix for each (i,j) tuple
12928
    // Updated while iterating over blocks
12929
    // Dimension = nBandCount * nBandCount
12930
0
    std::vector<uint64_t> anCount;
12931
12932
    // Mean of bands, for each (i,j) tuple.
12933
    // Updated while iterating over blocks.
12934
    // This is a matrix rather than a vector due to the fact when need to update
12935
    // it in sync with padfComomentMatrix
12936
    // Dimension = nBandCount * nBandCount
12937
0
    std::vector<T> adfMean;
12938
12939
    // Number of valid values when computing adfMean, for each (i,j) tuple.
12940
    // Updated while iterating over blocks.
12941
    // This is a matrix rather than a vector due to the fact when need to update
12942
    // it in sync with padfComomentMatrix
12943
    // Dimension = nBandCount * nBandCount
12944
0
    std::vector<uint64_t> anCountMean;
12945
12946
    // Mean of values for each band i. Refreshed for each block.
12947
    // Dimension = nBandCount
12948
0
    std::vector<T> adfCurBlockMean;
12949
12950
    // Number of values participating to the mean for each band i.
12951
    // Refreshed for each block. Dimension = nBandCount
12952
0
    std::vector<size_t> anCurBlockCount;
12953
12954
    // Pixel values for all selected values for the current block
12955
    // Dimension = nBlockXSize * nBlockYSize * nBandCount
12956
0
    std::vector<T> adfCurBlockPixelsAllBands;
12957
12958
    // Vector of nodata values for all bands. Dimension = nBandCount
12959
0
    std::vector<T> adfNoData;
12960
12961
    // Vector of mask bands for all bands. Dimension = nBandCount
12962
0
    std::vector<GDALRasterBand *> apoMaskBands;
12963
12964
    // Vector of vector of mask values. Dimension = nBandCount
12965
0
    std::vector<std::vector<GByte>> aabyCurBlockMask;
12966
12967
    // Vector of pointer to vector of mask values. Dimension = nBandCount
12968
0
    std::vector<std::vector<GByte> *> pabyCurBlockMask;
12969
12970
0
    int nBlockXSize = 0;
12971
0
    int nBlockYSize = 0;
12972
0
    papoBands[panBandList[0] - 1]->GetBlockSize(&nBlockXSize, &nBlockYSize);
12973
12974
0
    if (static_cast<uint64_t>(nBlockXSize) * nBlockYSize >
12975
0
        std::numeric_limits<size_t>::max() / nBandCount)
12976
0
    {
12977
0
        poDS->ReportError(CE_Failure, CPLE_OutOfMemory,
12978
0
                          "Not enough memory for intermediate computations");
12979
0
        return CE_Failure;
12980
0
    }
12981
0
    const size_t nPixelsInBlock =
12982
0
        static_cast<size_t>(nBlockXSize) * nBlockYSize;
12983
12984
    // Allocate temporary matrices and vectors
12985
0
    const auto nMatrixSize = static_cast<size_t>(nBandCount) * nBandCount;
12986
12987
0
    using MySignedSize_t = std::make_signed_t<size_t>;
12988
0
    const auto kMax =
12989
0
        static_cast<MySignedSize_t>(nBandCount) * (nBandCount + 1) / 2;
12990
0
    std::vector<std::pair<int, int>> anMapLinearIdxToIJ;
12991
0
    try
12992
0
    {
12993
0
        anCount.resize(nMatrixSize);
12994
0
        adfMean.resize(nMatrixSize);
12995
0
        anCountMean.resize(nMatrixSize);
12996
12997
        if constexpr (!std::is_same_v<T, double>)
12998
        {
12999
            aCurBlockComomentMatrix.resize(nMatrixSize);
13000
        }
13001
13002
0
        anMapLinearIdxToIJ.resize(kMax);
13003
13004
0
        adfCurBlockPixelsAllBands.resize(nPixelsInBlock * nBandCount);
13005
13006
0
        adfCurBlockMean.resize(nBandCount);
13007
0
        anCurBlockCount.resize(nBandCount);
13008
0
        adfNoData.resize(nBandCount);
13009
0
        apoMaskBands.resize(nBandCount);
13010
0
        aabyCurBlockMask.resize(nBandCount);
13011
0
        pabyCurBlockMask.resize(nBandCount);
13012
0
    }
13013
0
    catch (const std::exception &)
13014
0
    {
13015
0
        poDS->ReportError(CE_Failure, CPLE_OutOfMemory,
13016
0
                          "Not enough memory for intermediate computations");
13017
0
        return CE_Failure;
13018
0
    }
13019
13020
0
    constexpr T ZERO{0};
13021
0
    std::fill(padfComomentMatrix,
13022
0
              padfComomentMatrix + static_cast<size_t>(nBandCount) * nBandCount,
13023
0
              0);
13024
13025
0
    {
13026
0
        MySignedSize_t nLinearIdx = 0;
13027
0
        for (int i = 0; i < nBandCount; ++i)
13028
0
        {
13029
0
            for (int j = i; j < nBandCount; ++j)
13030
0
            {
13031
0
                anMapLinearIdxToIJ[nLinearIdx] = {i, j};
13032
0
                ++nLinearIdx;
13033
0
            }
13034
0
        }
13035
0
    }
13036
13037
    // Fetch nodata values and mask bands
13038
0
    bool bAllBandsSameMask = false;
13039
0
    bool bIsAllInteger = false;
13040
0
    bool bNoneHasMaskOrNodata = false;
13041
0
    for (int i = 0; i < nBandCount; ++i)
13042
0
    {
13043
0
        const auto poBand = papoBands[panBandList[i] - 1];
13044
0
        bIsAllInteger = (i == 0 || bIsAllInteger) &&
13045
0
                        GDALDataTypeIsInteger(poBand->GetRasterDataType());
13046
0
        int bHasNoData = FALSE;
13047
0
        double dfNoData = poBand->GetNoDataValue(&bHasNoData);
13048
0
        if (!bHasNoData)
13049
0
        {
13050
0
            dfNoData = std::numeric_limits<double>::quiet_NaN();
13051
13052
0
            if (poBand->GetMaskFlags() != GMF_ALL_VALID &&
13053
0
                poBand->GetColorInterpretation() != GCI_AlphaBand)
13054
0
            {
13055
0
                apoMaskBands[i] = poBand->GetMaskBand();
13056
0
                try
13057
0
                {
13058
0
                    aabyCurBlockMask[i].resize(nPixelsInBlock);
13059
0
                }
13060
0
                catch (const std::exception &)
13061
0
                {
13062
0
                    poDS->ReportError(
13063
0
                        CE_Failure, CPLE_OutOfMemory,
13064
0
                        "Not enough memory for intermediate computations");
13065
0
                    return CE_Failure;
13066
0
                }
13067
                // coverity[escape]
13068
0
                pabyCurBlockMask[i] = &aabyCurBlockMask[i];
13069
0
            }
13070
0
        }
13071
0
        adfNoData[i] = static_cast<T>(dfNoData);
13072
0
        if (i == 0)
13073
0
            bAllBandsSameMask = (apoMaskBands[0] != nullptr);
13074
0
        else if (bAllBandsSameMask)
13075
0
            bAllBandsSameMask = (apoMaskBands[i] == apoMaskBands[0]);
13076
13077
0
        bNoneHasMaskOrNodata = (i == 0 || bNoneHasMaskOrNodata) &&
13078
0
                               std::isnan(dfNoData) &&
13079
0
                               apoMaskBands[i] == nullptr;
13080
0
    }
13081
0
    if (bAllBandsSameMask)
13082
0
    {
13083
0
        for (int i = 1; i < nBandCount; ++i)
13084
0
        {
13085
0
            apoMaskBands[i] = nullptr;
13086
0
            aabyCurBlockMask[i].clear();
13087
0
            pabyCurBlockMask[i] = pabyCurBlockMask[0];
13088
0
        }
13089
0
    }
13090
13091
0
    const auto nIterCount =
13092
0
        static_cast<uint64_t>(
13093
0
            cpl::div_round_up(poDS->GetRasterXSize(), nBlockXSize)) *
13094
0
        cpl::div_round_up(poDS->GetRasterYSize(), nBlockYSize);
13095
0
    uint64_t nCurIter = 0;
13096
13097
0
    int nNumThreads = 1;
13098
#ifdef HAVE_OPENMP
13099
    if (nBandCount >= 100)
13100
    {
13101
        const int nMaxNumThreads = std::max(1, CPLGetNumCPUs() / 2);
13102
        nNumThreads =
13103
            GDALGetNumThreads(nMaxNumThreads, /* bDefaultToAllCPUs= */ false);
13104
    }
13105
#endif
13106
13107
0
#ifdef CAN_DETECT_AVX2_FMA_AT_RUNTIME
13108
0
    const bool bHasAVX2_FMA = CPLHaveRuntimeAVX() &&
13109
0
                              __builtin_cpu_supports("avx2") &&
13110
0
                              __builtin_cpu_supports("fma");
13111
0
#endif
13112
13113
    // Iterate over all blocks
13114
0
    for (const auto &window : papoBands[panBandList[0] - 1]->IterateWindows())
13115
0
    {
13116
0
        const auto nThisBlockPixelCount =
13117
0
            static_cast<size_t>(window.nXSize) * window.nYSize;
13118
13119
        // Extract pixel values and masks
13120
0
        CPLErr eErr = poDS->RasterIO(
13121
0
            GF_Read, window.nXOff, window.nYOff, window.nXSize, window.nYSize,
13122
0
            adfCurBlockPixelsAllBands.data(), window.nXSize, window.nYSize,
13123
0
            gdal::CXXTypeTraits<T>::gdal_type, nBandCount, panBandList, 0, 0, 0,
13124
0
            nullptr);
13125
0
        if (eErr == CE_None && bAllBandsSameMask)
13126
0
        {
13127
0
            eErr = apoMaskBands[0]->RasterIO(
13128
0
                GF_Read, window.nXOff, window.nYOff, window.nXSize,
13129
0
                window.nYSize, aabyCurBlockMask[0].data(), window.nXSize,
13130
0
                window.nYSize, GDT_Byte, 0, 0, nullptr);
13131
0
        }
13132
0
        else
13133
0
        {
13134
0
            for (int i = 0; eErr == CE_None && i < nBandCount; ++i)
13135
0
            {
13136
0
                if (apoMaskBands[i])
13137
0
                {
13138
0
                    eErr = apoMaskBands[i]->RasterIO(
13139
0
                        GF_Read, window.nXOff, window.nYOff, window.nXSize,
13140
0
                        window.nYSize, aabyCurBlockMask[i].data(),
13141
0
                        window.nXSize, window.nYSize, GDT_Byte, 0, 0, nullptr);
13142
0
                }
13143
0
            }
13144
0
        }
13145
0
        if (eErr != CE_None)
13146
0
            return eErr;
13147
13148
        // Compute the mean of all bands for this block
13149
0
        bool bAllBandsAreAllNodata = false;
13150
0
        bool bNoBandHasNodata = false;
13151
0
        for (int i = 0; i < nBandCount; ++i)
13152
0
        {
13153
0
            T dfSum = 0;
13154
0
            size_t nCount = 0;
13155
0
            const T dfNoDataI = adfNoData[i];
13156
0
            const T *padfI =
13157
0
                adfCurBlockPixelsAllBands.data() + i * nThisBlockPixelCount;
13158
0
#ifdef HAVE_OPENMP_SIMD
13159
0
#pragma omp simd reduction(+ : dfSum)
13160
0
#endif
13161
0
            for (size_t iPixel = 0; iPixel < nThisBlockPixelCount; ++iPixel)
13162
0
            {
13163
0
                const T dfI = padfI[iPixel];
13164
0
                const bool bIsValid =
13165
0
                    !std::isnan(dfI) && dfI != dfNoDataI &&
13166
0
                    (!pabyCurBlockMask[i] || (*pabyCurBlockMask[i])[iPixel]);
13167
0
                nCount += bIsValid;
13168
0
                dfSum += bIsValid ? dfI : ZERO;
13169
0
            }
13170
0
            adfCurBlockMean[i] = nCount > 0 ? dfSum / nCount : ZERO;
13171
0
            anCurBlockCount[i] = nCount;
13172
0
            bAllBandsAreAllNodata =
13173
0
                (i == 0 || bAllBandsAreAllNodata) && (nCount == 0);
13174
0
            bNoBandHasNodata = (i == 0 || bNoBandHasNodata) &&
13175
0
                               (nCount == nThisBlockPixelCount);
13176
0
        }
13177
13178
        // Modify the pixel values to shift them by minus the mean
13179
0
        if (!bAllBandsAreAllNodata)
13180
0
        {
13181
0
            for (int i = 0; i < nBandCount; ++i)
13182
0
            {
13183
0
                T *padfI =
13184
0
                    adfCurBlockPixelsAllBands.data() + i * nThisBlockPixelCount;
13185
0
                const T dfMeanI = adfCurBlockMean[i];
13186
0
                for (size_t iPixel = 0; iPixel < nThisBlockPixelCount; ++iPixel)
13187
0
                {
13188
0
                    padfI[iPixel] -= dfMeanI;
13189
0
                }
13190
0
            }
13191
0
        }
13192
13193
        // Update padfComomentMatrix, anCount, adfMean, anCountMean
13194
        // from dfComoment, nCount, adfCurBlockMean, anCurBlockCount
13195
0
        const auto UpdateGlobalValues =
13196
0
            [&anCount, &adfMean, &anCountMean, &adfCurBlockMean,
13197
0
             &anCurBlockCount, padfComomentMatrix,
13198
0
             nBandCount](int i, int j, size_t nCount, T dfComoment)
13199
0
        {
13200
0
            const auto idxInMatrixI = static_cast<size_t>(i) * nBandCount + j;
13201
0
            const auto idxInMatrixJ = static_cast<size_t>(j) * nBandCount + i;
13202
13203
            // Update the total comoment using last formula of paragraph
13204
            // https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Online :
13205
            // CoMoment(A+B) = CoMoment(A) + CoMoment(B) +
13206
            //                 (mean_I(A) - mean_I(B)) *
13207
            //                 (mean_J(A) - mean_J(B)) *
13208
            //                 (count(A) * count(B)) / (count(A) + count(B))
13209
            //
13210
            // There might be a small gotcha in the fact that the set of
13211
            // pixels on which the means are computed is not always the
13212
            // same as the the one on which the comoment is computed, if
13213
            // pixels are not valid/invalid at the same indices among bands
13214
            // It is not obvious (to me) what should be the correct behavior.
13215
            // The current approach has the benefit to avoid recomputing
13216
            // the mean for each (i,j) tuple, but only for all i.
13217
0
            if (nCount > 0)
13218
0
            {
13219
0
                padfComomentMatrix[idxInMatrixI] +=
13220
0
                    static_cast<double>(dfComoment);
13221
0
                padfComomentMatrix[idxInMatrixI] +=
13222
0
                    static_cast<double>(adfMean[idxInMatrixI] -
13223
0
                                        adfCurBlockMean[i]) *
13224
0
                    static_cast<double>(adfMean[idxInMatrixJ] -
13225
0
                                        adfCurBlockMean[j]) *
13226
0
                    (static_cast<double>(anCount[idxInMatrixI]) *
13227
0
                     static_cast<double>(nCount) /
13228
0
                     static_cast<double>(anCount[idxInMatrixI] + nCount));
13229
13230
0
                anCount[idxInMatrixI] += nCount;
13231
0
            }
13232
13233
            // Update means
13234
0
            if (anCurBlockCount[i] > 0)
13235
0
            {
13236
0
                adfMean[idxInMatrixI] +=
13237
0
                    (adfCurBlockMean[i] - adfMean[idxInMatrixI]) *
13238
0
                    static_cast<T>(
13239
0
                        static_cast<double>(anCurBlockCount[i]) /
13240
0
                        static_cast<double>(anCountMean[idxInMatrixI] +
13241
0
                                            anCurBlockCount[i]));
13242
13243
0
                anCountMean[idxInMatrixI] += anCurBlockCount[i];
13244
0
            }
13245
13246
0
            if (idxInMatrixI != idxInMatrixJ && anCurBlockCount[j] > 0)
13247
0
            {
13248
0
                adfMean[idxInMatrixJ] +=
13249
0
                    (adfCurBlockMean[j] - adfMean[idxInMatrixJ]) *
13250
0
                    static_cast<T>(
13251
0
                        static_cast<double>(anCurBlockCount[j]) /
13252
0
                        static_cast<double>(anCountMean[idxInMatrixJ] +
13253
0
                                            anCurBlockCount[j]));
13254
13255
0
                anCountMean[idxInMatrixJ] += anCurBlockCount[j];
13256
0
            }
13257
0
        };
13258
13259
0
        if (bAllBandsAreAllNodata)
13260
0
        {
13261
            // Optimized code path where all values in the current block
13262
            // are invalid
13263
13264
0
            for (int i = 0; i < nBandCount; ++i)
13265
0
            {
13266
0
                for (int j = i; j < nBandCount; ++j)
13267
0
                {
13268
0
                    UpdateGlobalValues(i, j, 0, ZERO);
13269
0
                }
13270
0
            }
13271
0
        }
13272
0
        else if (bNoBandHasNodata)
13273
0
        {
13274
            // Optimized code path where there are no invalid value in the
13275
            // current block
13276
13277
            if constexpr (!std::is_same_v<T, double>)
13278
            {
13279
                std::fill(aCurBlockComomentMatrix.begin(),
13280
                          aCurBlockComomentMatrix.end(), ZERO);
13281
13282
                GDALMatrixMultiplyAByTransposeAUpperTriangle(
13283
                    nNumThreads, adfCurBlockPixelsAllBands.data(),
13284
                    aCurBlockComomentMatrix.data(), nBandCount,
13285
                    nThisBlockPixelCount);
13286
            }
13287
#ifdef CAN_DETECT_AVX2_FMA_AT_RUNTIME
13288
0
            else if (bHasAVX2_FMA)
13289
0
            {
13290
0
                GDALMatrixMultiplyAByTransposeAUpperTriangle_AVX2_FMA(
13291
0
                    nNumThreads, adfCurBlockPixelsAllBands.data(),
13292
0
                    padfComomentMatrix, nBandCount, nThisBlockPixelCount);
13293
0
            }
13294
0
#endif
13295
0
            else
13296
0
            {
13297
0
                GDALMatrixMultiplyAByTransposeAUpperTriangle(
13298
0
                    nNumThreads, adfCurBlockPixelsAllBands.data(),
13299
0
                    padfComomentMatrix, nBandCount, nThisBlockPixelCount);
13300
0
            }
13301
13302
0
            for (int i = 0; i < nBandCount; ++i)
13303
0
            {
13304
0
                for (int j = i; j < nBandCount; ++j)
13305
0
                {
13306
                    if constexpr (!std::is_same_v<T, double>)
13307
                    {
13308
                        const auto idxInMatrixI =
13309
                            static_cast<size_t>(i) * nBandCount + j;
13310
                        UpdateGlobalValues(
13311
                            i, j, nThisBlockPixelCount,
13312
                            aCurBlockComomentMatrix[idxInMatrixI]);
13313
                    }
13314
                    else
13315
0
                    {
13316
0
                        UpdateGlobalValues(i, j, nThisBlockPixelCount, ZERO);
13317
0
                    }
13318
0
                }
13319
0
            }
13320
0
        }
13321
0
        else
13322
0
        {
13323
#ifdef HAVE_OPENMP
13324
#pragma omp parallel for schedule(static) num_threads(nNumThreads)
13325
#endif
13326
0
            for (MySignedSize_t k = 0; k < kMax; ++k)
13327
0
            {
13328
0
                int i, j;
13329
0
                std::tie(i, j) = anMapLinearIdxToIJ[k];
13330
13331
                // Now compute the moment of (i, j), but just for this block
13332
0
                size_t nCount = 0;
13333
0
                T dfComoment = 0;
13334
0
                const T *padfI =
13335
0
                    adfCurBlockPixelsAllBands.data() + i * nThisBlockPixelCount;
13336
0
                const T *padfJ =
13337
0
                    adfCurBlockPixelsAllBands.data() + j * nThisBlockPixelCount;
13338
13339
                // Use https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Two-pass
13340
                // for the current block
13341
0
                if ((anCurBlockCount[i] == nThisBlockPixelCount &&
13342
0
                     anCurBlockCount[j] == nThisBlockPixelCount) ||
13343
0
                    (bNoneHasMaskOrNodata && bIsAllInteger))
13344
0
                {
13345
                    // Most optimized code path: integer, no nodata, no mask
13346
0
#ifdef HAVE_OPENMP_SIMD
13347
0
#pragma omp simd reduction(+ : dfComoment)
13348
0
#endif
13349
0
                    for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13350
0
                         ++iPixel)
13351
0
                    {
13352
0
                        dfComoment += padfI[iPixel] * padfJ[iPixel];
13353
0
                    }
13354
0
                    nCount = nThisBlockPixelCount;
13355
0
                }
13356
0
                else if (bNoneHasMaskOrNodata)
13357
0
                {
13358
                    // Floating-point code path with no nodata and no mask
13359
0
#ifdef HAVE_OPENMP_SIMD
13360
0
#pragma omp simd reduction(+ : dfComoment)
13361
0
#endif
13362
0
                    for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13363
0
                         ++iPixel)
13364
0
                    {
13365
0
                        const T dfAcc = padfI[iPixel] * padfJ[iPixel];
13366
0
                        const bool bIsValid = !std::isnan(dfAcc);
13367
0
                        nCount += bIsValid;
13368
0
                        dfComoment += bIsValid ? dfAcc : ZERO;
13369
0
                    }
13370
0
                }
13371
0
                else if (!std::isnan(adfNoData[i]) && !std::isnan(adfNoData[j]))
13372
0
                {
13373
                    // Code path when there are both nodata values
13374
0
                    const T shiftedNoDataI = adfNoData[i] - adfCurBlockMean[i];
13375
0
                    const T shiftedNoDataJ = adfNoData[j] - adfCurBlockMean[j];
13376
13377
0
#ifdef HAVE_OPENMP_SIMD
13378
0
#pragma omp simd reduction(+ : dfComoment)
13379
0
#endif
13380
0
                    for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13381
0
                         ++iPixel)
13382
0
                    {
13383
0
                        const T dfI = padfI[iPixel];
13384
0
                        const T dfJ = padfJ[iPixel];
13385
0
                        const T dfAcc = dfI * dfJ;
13386
0
                        const bool bIsValid = !std::isnan(dfAcc) &&
13387
0
                                              dfI != shiftedNoDataI &&
13388
0
                                              dfJ != shiftedNoDataJ;
13389
0
                        nCount += bIsValid;
13390
0
                        dfComoment += bIsValid ? dfAcc : ZERO;
13391
0
                    }
13392
0
                }
13393
0
                else
13394
0
                {
13395
                    // Generic code path
13396
0
                    const T shiftedNoDataI = adfNoData[i] - adfCurBlockMean[i];
13397
0
                    const T shiftedNoDataJ = adfNoData[j] - adfCurBlockMean[j];
13398
13399
0
#ifdef HAVE_OPENMP_SIMD
13400
0
#pragma omp simd reduction(+ : dfComoment)
13401
0
#endif
13402
0
                    for (size_t iPixel = 0; iPixel < nThisBlockPixelCount;
13403
0
                         ++iPixel)
13404
0
                    {
13405
0
                        const T dfI = padfI[iPixel];
13406
0
                        const T dfJ = padfJ[iPixel];
13407
0
                        const T dfAcc = dfI * dfJ;
13408
0
                        const bool bIsValid =
13409
0
                            !std::isnan(dfAcc) && dfI != shiftedNoDataI &&
13410
0
                            dfJ != shiftedNoDataJ &&
13411
0
                            (!pabyCurBlockMask[i] ||
13412
0
                             (*pabyCurBlockMask[i])[iPixel]) &&
13413
0
                            (!pabyCurBlockMask[j] ||
13414
0
                             (*pabyCurBlockMask[j])[iPixel]);
13415
0
                        nCount += bIsValid;
13416
0
                        dfComoment += bIsValid ? dfAcc : ZERO;
13417
0
                    }
13418
0
                }
13419
13420
0
                UpdateGlobalValues(i, j, nCount, dfComoment);
13421
0
            }
13422
0
        }
13423
13424
0
        ++nCurIter;
13425
0
        if (pfnProgress &&
13426
0
            !pfnProgress(static_cast<double>(nCurIter) / nIterCount, "",
13427
0
                         pProgressData))
13428
0
        {
13429
0
            poDS->ReportError(CE_Failure, CPLE_UserInterrupt,
13430
0
                              "User terminated");
13431
0
            return CE_Failure;
13432
0
        }
13433
0
    }
13434
13435
    // Finalize by dividing co-moments by the number of contributing values
13436
    // (minus nDeltaDegreeOfFreedom) to compute final covariances.
13437
0
    for (int i = 0; i < nBandCount; ++i)
13438
0
    {
13439
        // The covariance matrix is symmetric. So start at i
13440
0
        for (int j = i; j < nBandCount; ++j)
13441
0
        {
13442
0
            const auto idxInMatrixI = static_cast<size_t>(i) * nBandCount + j;
13443
0
            const double dfCovariance =
13444
0
                (nDeltaDegreeOfFreedom < 0 ||
13445
0
                 anCount[idxInMatrixI] <=
13446
0
                     static_cast<uint64_t>(nDeltaDegreeOfFreedom))
13447
0
                    ? std::numeric_limits<double>::quiet_NaN()
13448
0
                    : padfComomentMatrix[idxInMatrixI] /
13449
0
                          static_cast<double>(anCount[idxInMatrixI] -
13450
0
                                              nDeltaDegreeOfFreedom);
13451
13452
0
            padfCovMatrix[idxInMatrixI] = dfCovariance;
13453
            // Fill lower triangle
13454
0
            padfCovMatrix[static_cast<size_t>(j) * nBandCount + i] =
13455
0
                dfCovariance;
13456
0
        }
13457
0
    }
13458
13459
0
    return CE_None;
13460
0
}
13461
13462
/************************************************************************/
13463
/*           GDALDataset::ComputeInterBandCovarianceMatrix()            */
13464
/************************************************************************/
13465
13466
/**
13467
 \brief Compute the covariance matrix between bands of this dataset.
13468
13469
 The covariance indicates the level to which two bands vary together.
13470
13471
 If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
13472
 and \f$ mean_i \f$ the mean value of all pixels of band i, then
13473
13474
 \f[
13475
    \mathrm{cov}[i,j] =
13476
    \frac{
13477
        \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
13478
        \left( v_j[y,x] - \mathrm{mean}_j \right)
13479
    }{
13480
        \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
13481
    }
13482
 \f]
13483
13484
 When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
13485
 We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
13486
 is symmetric.
13487
13488
 A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
13489
 if the pixels in bands are considered to be a sample of the whole population.
13490
 This is consistent with the default of
13491
 https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
13492
 matrix is consistent with what can be obtained with
13493
13494
 \verbatim embed:rst
13495
 .. code-block:: python
13496
13497
     numpy.cov(
13498
        [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
13499
     )
13500
 \endverbatim
13501
13502
 Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
13503
 to be the whole population.
13504
13505
 The caller must provide an already allocated array in padfCovMatrix of size
13506
 at least nBandCount * nBandCount.
13507
13508
 This method recomputes the covariance matrix, even if STATISTICS_COVARIANCES
13509
 metadata items are available in bands. See GetInterBandCovarianceMatrix()
13510
 to use them.
13511
13512
 The implementation is optimized to minimize the amount of pixel reading.
13513
13514
 This method is the same as the C function GDALDatasetComputeInterBandCovarianceMatrix()
13515
13516
 @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
13517
                      nBandCount * nBandCount.
13518
 @param nSize Number of elements in output array.
13519
 @param nBandCount Zero for all bands, or number of values in panBandList.
13520
                   Defaults to 0.
13521
 @param panBandList nullptr for all bands if nBandCount == 0, or array of
13522
                    nBandCount values such as panBandList[i] is the index
13523
                    between 1 and GetRasterCount() of a band that must be used
13524
                    in the covariance computation. Defaults to nullptr.
13525
 @param bApproxOK Whether it is acceptable to use a subsample of values.
13526
                  Defaults to false.
13527
 @param bWriteIntoMetadata Whether this method must write
13528
                           STATISTICS_COVARIANCES band metadata items.
13529
                           Defaults to true.
13530
 @param nDeltaDegreeOfFreedom Correction term to subtract in the final
13531
                              averaging phase of the covariance computation.
13532
                              Defaults to 1.
13533
 @param pfnProgress a function to call to report progress, or NULL.
13534
 @param pProgressData application data to pass to the progress function.
13535
13536
 @return CE_None if successful, or CE_Failure in case of failure
13537
13538
 @since 3.13
13539
13540
 @see GetInterBandCovarianceMatrix()
13541
 */
13542
CPLErr GDALDataset::ComputeInterBandCovarianceMatrix(
13543
    double *padfCovMatrix, size_t nSize, int nBandCount, const int *panBandList,
13544
    bool bApproxOK, bool bWriteIntoMetadata, int nDeltaDegreeOfFreedom,
13545
    GDALProgressFunc pfnProgress, void *pProgressData)
13546
0
{
13547
0
    std::vector<int> anBandListTmp;  // keep in this scope
13548
0
    if (nBandCount == 0)
13549
0
    {
13550
0
        if (nBands == 0)
13551
0
            return CE_None;
13552
0
        for (int i = 0; i < nBands; ++i)
13553
0
            anBandListTmp.push_back(i + 1);
13554
0
        nBandCount = nBands;
13555
0
        panBandList = anBandListTmp.data();
13556
0
    }
13557
0
    else
13558
0
    {
13559
0
        if (nBandCount > nBands)
13560
0
        {
13561
0
            CPLError(CE_Failure, CPLE_AppDefined,
13562
0
                     "ComputeInterBandCovarianceMatrix(): nBandCount > nBands");
13563
0
            return CE_Failure;
13564
0
        }
13565
0
        for (int i = 0; i < nBandCount; ++i)
13566
0
        {
13567
0
            if (panBandList[i] <= 0 || panBandList[i] > nBands)
13568
0
            {
13569
0
                CPLError(CE_Failure, CPLE_AppDefined,
13570
0
                         "ComputeInterBandCovarianceMatrix(): invalid value "
13571
0
                         "panBandList[%d] = %d",
13572
0
                         i, panBandList[i]);
13573
0
                return CE_Failure;
13574
0
            }
13575
0
        }
13576
13577
0
        if (bWriteIntoMetadata)
13578
0
        {
13579
0
            bool bOK = nBandCount == nBands;
13580
0
            for (int i = 0; bOK && i < nBandCount; ++i)
13581
0
            {
13582
0
                bOK = (panBandList[i] == i + 1);
13583
0
            }
13584
0
            if (!bOK)
13585
0
            {
13586
0
                CPLError(CE_Failure, CPLE_AppDefined,
13587
0
                         "ComputeInterBandCovarianceMatrix(): cannot write "
13588
0
                         "STATISTICS_COVARIANCES metadata since the input band "
13589
0
                         "list is not [1, 2, ... GetRasterCount()]");
13590
0
                return CE_Failure;
13591
0
            }
13592
0
        }
13593
0
    }
13594
13595
0
    const auto nMatrixSize = static_cast<size_t>(nBandCount) * nBandCount;
13596
0
    if (nSize < nMatrixSize)
13597
0
    {
13598
0
        CPLError(CE_Failure, CPLE_AppDefined,
13599
0
                 "ComputeInterBandCovarianceMatrix(): too small result matrix "
13600
0
                 "provided");
13601
0
        return CE_Failure;
13602
0
    }
13603
13604
    // Find appropriate overview dataset
13605
0
    GDALDataset *poActiveDS = this;
13606
0
    if (bApproxOK && papoBands[panBandList[0] - 1]->GetOverviewCount() > 0)
13607
0
    {
13608
0
        GDALDataset *poOvrDS = nullptr;
13609
0
        for (int i = 0; i < nBandCount; ++i)
13610
0
        {
13611
0
            const int nIdxBand = panBandList[i] - 1;
13612
0
            auto poOvrBand = papoBands[nIdxBand]->GetRasterSampleOverview(
13613
0
                GDALSTAT_APPROX_NUMSAMPLES);
13614
13615
0
            if (poOvrBand == papoBands[i] ||
13616
0
                poOvrBand->GetBand() != panBandList[i])
13617
0
            {
13618
0
                poOvrDS = nullptr;
13619
0
                break;
13620
0
            }
13621
0
            else if (i == 0)
13622
0
            {
13623
0
                if (poOvrBand->GetDataset() == this)
13624
0
                {
13625
0
                    break;
13626
0
                }
13627
0
                poOvrDS = poOvrBand->GetDataset();
13628
0
            }
13629
0
            else if (poOvrBand->GetDataset() != poOvrDS)
13630
0
            {
13631
0
                poOvrDS = nullptr;
13632
0
                break;
13633
0
            }
13634
0
        }
13635
0
        if (poOvrDS)
13636
0
        {
13637
0
            poActiveDS = poOvrDS;
13638
0
        }
13639
0
    }
13640
13641
#ifdef GDAL_COVARIANCE_CAN_USE_FLOAT32
13642
    const auto UseFloat32 = [](GDALDataType eDT)
13643
    {
13644
        return eDT == GDT_UInt8 || eDT == GDT_Int8 || eDT == GDT_UInt16 ||
13645
               eDT == GDT_Int16 || eDT == GDT_Float32;
13646
    };
13647
13648
    bool bUseFloat32 = UseFloat32(
13649
        poActiveDS->GetRasterBand(panBandList[0])->GetRasterDataType());
13650
    for (int i = 1; bUseFloat32 && i < nBandCount; ++i)
13651
    {
13652
        bUseFloat32 = UseFloat32(
13653
            poActiveDS->GetRasterBand(panBandList[i])->GetRasterDataType());
13654
    }
13655
#endif
13656
13657
0
    CPLErr eErr =
13658
#ifdef GDAL_COVARIANCE_CAN_USE_FLOAT32
13659
        bUseFloat32 ? ComputeInterBandCovarianceMatrixInternal<float>(
13660
                          poActiveDS, padfCovMatrix, nBandCount, panBandList,
13661
                          poActiveDS->papoBands, nDeltaDegreeOfFreedom,
13662
                          pfnProgress, pProgressData)
13663
                    :
13664
#endif
13665
0
                    ComputeInterBandCovarianceMatrixInternal<double>(
13666
0
                        poActiveDS, padfCovMatrix, nBandCount, panBandList,
13667
0
                        poActiveDS->papoBands, nDeltaDegreeOfFreedom,
13668
0
                        pfnProgress, pProgressData);
13669
13670
0
    if (bWriteIntoMetadata && eErr == CE_None)
13671
0
    {
13672
0
        CPLAssert(nBands == nBandCount);
13673
0
        std::string osStr;
13674
0
        size_t idx = 0;
13675
0
        for (int i = 0; i < nBands; ++i)
13676
0
        {
13677
0
            osStr.clear();
13678
0
            for (int j = 0; j < nBands; ++j, ++idx)
13679
0
            {
13680
0
                if (j > 0)
13681
0
                    osStr += ',';
13682
0
                osStr += CPLSPrintf("%.17g", padfCovMatrix[idx]);
13683
0
            }
13684
0
            papoBands[i]->SetMetadataItem("STATISTICS_COVARIANCES",
13685
0
                                          osStr.c_str());
13686
0
        }
13687
0
    }
13688
13689
0
    return eErr;
13690
0
}
13691
13692
/************************************************************************/
13693
/*            GDALDatasetComputeInterBandCovarianceMatrix()             */
13694
/************************************************************************/
13695
13696
/**
13697
 \brief Compute the covariance matrix between bands of this dataset.
13698
13699
 The covariance indicates the level to which two bands vary together.
13700
13701
 If we call \f$ v_i[y,x] \f$ the value of pixel at row=y and column=x for band i,
13702
 and \f$ mean_i \f$ the mean value of all pixels of band i, then
13703
13704
 \f[
13705
    \mathrm{cov}[i,j] =
13706
    \frac{
13707
        \sum_{y,x} \left( v_i[y,x] - \mathrm{mean}_i \right)
13708
        \left( v_j[y,x] - \mathrm{mean}_j \right)
13709
    }{
13710
        \mathrm{pixel\_count} - \mathrm{nDeltaDegreeOfFreedom}
13711
    }
13712
 \f]
13713
13714
 When there are no nodata values, \f$ pixel\_count = GetRasterXSize() * GetRasterYSize() \f$.
13715
 We can see that \f$ cov[i,j] = cov[j,i] \f$, and consequently the returned matrix
13716
 is symmetric.
13717
13718
 A value of nDeltaDegreeOfFreedom=1 (the default) will return a unbiased estimate
13719
 if the pixels in bands are considered to be a sample of the whole population.
13720
 This is consistent with the default of
13721
 https://numpy.org/doc/stable/reference/generated/numpy.cov.html and the returned
13722
 matrix is consistent with what can be obtained with
13723
13724
 \verbatim embed:rst
13725
 .. code-block:: python
13726
13727
     numpy.cov(
13728
        [ds.GetRasterBand(n + 1).ReadAsArray().ravel() for n in range(ds.RasterCount)]
13729
     )
13730
 \endverbatim
13731
13732
 Otherwise a value of nDeltaDegreeOfFreedom=0 can be used if they are considered
13733
 to be the whole population.
13734
13735
 The caller must provide an already allocated array in padfCovMatrix of size
13736
 at least GDALGetRasterCount() * GDALGetRasterCount().
13737
13738
 This method recomputes the covariance matrix, even if STATISTICS_COVARIANCES
13739
 metadata items are available in bands. See GDALDatasetGetInterBandCovarianceMatrix()
13740
 to use them.
13741
13742
 This function is the same as the C++ method GDALDataset::ComputeInterBandCovarianceMatrix()
13743
13744
 @param hDS Dataset handle.
13745
 @param[out] padfCovMatrix Pointer to an already allocated output array, of size at least
13746
                      nBandCount * nBandCount.
13747
 @param nSize Number of elements in output array.
13748
 @param nBandCount Zero for all bands, or number of values in panBandList.
13749
                   Defaults to 0.
13750
 @param panBandList nullptr for all bands if nBandCount == 0, or array of
13751
                    nBandCount values such as panBandList[i] is the index
13752
                    between 1 and GetRasterCount() of a band that must be used
13753
                    in the covariance computation. Defaults to nullptr.
13754
 @param bApproxOK Whether it is acceptable to use a subsample of values.
13755
                  Defaults to false.
13756
 @param bWriteIntoMetadata Whether this method must write
13757
                           STATISTICS_COVARIANCES band metadata items.
13758
                           Defaults to true.
13759
 @param nDeltaDegreeOfFreedom Correction term to subtract in the final
13760
                              averaging phase of the covariance computation.
13761
                              Defaults to 1.
13762
 @param pfnProgress a function to call to report progress, or NULL.
13763
 @param pProgressData application data to pass to the progress function.
13764
13765
 @return CE_None if successful, or CE_Failure in case of failure
13766
13767
 @since 3.13
13768
13769
 @see GDALDatasetGetInterBandCovarianceMatrix()
13770
 */
13771
CPLErr GDALDatasetComputeInterBandCovarianceMatrix(
13772
    GDALDatasetH hDS, double *padfCovMatrix, size_t nSize, int nBandCount,
13773
    const int *panBandList, bool bApproxOK, bool bWriteIntoMetadata,
13774
    int nDeltaDegreeOfFreedom, GDALProgressFunc pfnProgress,
13775
    void *pProgressData)
13776
0
{
13777
0
    VALIDATE_POINTER1(hDS, __func__, CE_Failure);
13778
0
    VALIDATE_POINTER1(padfCovMatrix, __func__, CE_Failure);
13779
0
    return GDALDataset::FromHandle(hDS)->ComputeInterBandCovarianceMatrix(
13780
0
        padfCovMatrix, nSize, nBandCount, panBandList, bApproxOK,
13781
0
        bWriteIntoMetadata, nDeltaDegreeOfFreedom, pfnProgress, pProgressData);
13782
0
}