Line data Source code
1 : /***********************************************************************
2 : * File : postgisraster.h
3 : * Project: PostGIS Raster driver
4 : * Purpose: Main header file for PostGIS Raster Driver
5 : * Author: Jorge Arevalo, jorge.arevalo@deimos-space.com
6 : * jorgearevalo@libregis.org
7 : *
8 : * Author: David Zwarg, dzwarg@azavea.com
9 : *
10 : *
11 : ***********************************************************************
12 : * Copyright (c) 2009 - 2013, Jorge Arevalo, David Zwarg
13 : * Copyright (c) 2013, Even Rouault
14 : *
15 : * SPDX-License-Identifier: MIT
16 : **********************************************************************/
17 :
18 : #ifndef POSTGISRASTER_H_INCLUDED
19 : #define POSTGISRASTER_H_INCLUDED
20 :
21 : #include "gdal_priv.h"
22 : #include "libpq-fe.h"
23 : #include "vrtdataset.h"
24 : #include "cpl_mem_cache.h"
25 : #include "cpl_quad_tree.h"
26 : #include <float.h>
27 : #include <map>
28 : #include <limits>
29 :
30 : // #define DEBUG_VERBOSE
31 : // #define DEBUG_QUERY
32 :
33 : #if defined(DEBUG_VERBOSE) && !defined(DEBUG_QUERY)
34 : #define DEBUG_QUERY
35 : #endif
36 :
37 : /**
38 : * The block size for the cache will be the minimum between the tile
39 : * size from sources and this value. So, please keep it at 2048 or
40 : * lower
41 : **/
42 : #define MAX_BLOCK_SIZE 2048
43 :
44 : #define NO_VALID_RES "-1234.56"
45 :
46 : /**
47 : * To move over the data return by queries
48 : **/
49 : #define POSTGIS_RASTER_VERSION static_cast<GUInt16>(0)
50 : #define RASTER_HEADER_SIZE 61
51 : #define RASTER_BAND_HEADER_FIXED_SIZE 1
52 :
53 : #define BAND_SIZE(nodatasize, datasize) \
54 : (RASTER_BAND_HEADER_FIXED_SIZE + (nodatasize) + (datasize))
55 :
56 : #define GET_BAND_DATA(raster, nband, nodatasize, datasize) \
57 : ((raster) + RASTER_HEADER_SIZE + \
58 : (nband) * BAND_SIZE(nodatasize, datasize) - (datasize))
59 :
60 : #define GEOTRSFRM_TOPLEFT_X 0
61 : #define GEOTRSFRM_WE_RES 1
62 : #define GEOTRSFRM_ROTATION_PARAM1 2
63 : #define GEOTRSFRM_TOPLEFT_Y 3
64 : #define GEOTRSFRM_ROTATION_PARAM2 4
65 : #define GEOTRSFRM_NS_RES 5
66 :
67 : // Number of results return by ST_Metadata PostGIS function
68 : #define ELEMENTS_OF_METADATA_RECORD 10
69 :
70 : // Positions of elements of ST_Metadata PostGIS function
71 : #define POS_UPPERLEFTX 0
72 : #define POS_UPPERLEFTY 1
73 : #define POS_WIDTH 2
74 : #define POS_HEIGHT 3
75 : #define POS_SCALEX 4
76 : #define POS_SCALEY 5
77 : #define POS_SKEWX 6
78 : #define POS_SKEWY 7
79 : #define POS_SRID 8
80 : #define POS_NBANDS 9
81 :
82 : // Number of results return by ST_BandMetadata PostGIS function
83 : #define ELEMENTS_OF_BAND_METADATA_RECORD 4
84 :
85 : // Positions of elements of ST_BandMetadata PostGIS function
86 : #define POS_PIXELTYPE 0
87 : #define POS_NODATAVALUE 1
88 : #define POS_ISOUTDB 2
89 : #define POS_PATH 3
90 :
91 : /**
92 : * The driver can work in these modes:
93 : * - NO_MODE: Error case
94 : * - ONE_RASTER_PER_ROW: Each row of the requested table is considered
95 : * as a separated raster object. This is the default mode, if
96 : * database and table name are provided, and no mode is specified.
97 : * - ONE_RASTER_PER_TABLE: All the rows of the requested table are
98 : * considered as tiles of a bigger raster coverage (the whole
99 : * table). If database and table name are specified and mode = 2
100 : * is present in the connection string, this is the selected mode.
101 : * - BROWSE_SCHEMA: If no table name is specified, just database and
102 : * schema names, the driver will yell of the schema's raster tables
103 : * as possible datasets.
104 : * - BROWSE_DATABASE: If no table name is specified, just database name,
105 : * the driver will yell of the database's raster tables as possible
106 : * datasets.
107 : **/
108 : typedef enum
109 : {
110 : NO_MODE,
111 : ONE_RASTER_PER_ROW,
112 : ONE_RASTER_PER_TABLE,
113 : BROWSE_SCHEMA,
114 : BROWSE_DATABASE
115 : } WorkingMode;
116 :
117 : enum class OutDBResolution
118 : {
119 : SERVER_SIDE,
120 : CLIENT_SIDE,
121 : CLIENT_SIDE_IF_POSSIBLE
122 : };
123 :
124 : /**
125 : * Important metadata of a PostGIS Raster band
126 : **/
127 : typedef struct
128 : {
129 : GDALDataType eDataType;
130 : int nBitsDepth;
131 : GBool bHasNoDataValue;
132 : GBool bIsOffline;
133 : char *path;
134 : double dfNoDataValue;
135 : } BandMetadata;
136 :
137 : typedef struct
138 : {
139 : char *pszSchema;
140 : char *pszTable;
141 : char *pszColumn;
142 : int nFactor;
143 : } PROverview;
144 :
145 : // Some tools definitions
146 : char *ReplaceQuotes(const char *, int);
147 : GBool TranslateDataType(const char *, GDALDataType *, int *);
148 :
149 : class PostGISRasterRasterBand;
150 : class PostGISRasterTileDataset;
151 :
152 : /***********************************************************************
153 : * PostGISRasterDriver: extends GDALDriver to support PostGIS Raster
154 : * connect.
155 : **********************************************************************/
156 : class PostGISRasterDriver final : public GDALDriver
157 : {
158 :
159 : private:
160 : CPLMutex *hMutex = nullptr;
161 : std::map<CPLString, PGconn *> oMapConnection{};
162 :
163 : CPL_DISALLOW_COPY_ASSIGN(PostGISRasterDriver)
164 : public:
165 : PostGISRasterDriver();
166 : ~PostGISRasterDriver() override;
167 : PGconn *GetConnection(const char *pszConnectionString,
168 : const char *pszServiceIn, const char *pszDbnameIn,
169 : const char *pszHostIn, const char *pszPortIn,
170 : const char *pszUserIn);
171 :
172 : static PostGISRasterDriver *gpoPostGISRasterDriver;
173 : };
174 :
175 : /***********************************************************************
176 : * PostGISRasterDataset: extends VRTDataset to support PostGIS Raster
177 : * datasets
178 : **********************************************************************/
179 : class PostGISRasterDataset final : public VRTDataset
180 : {
181 : friend class PostGISRasterRasterBand;
182 : friend class PostGISRasterTileRasterBand;
183 :
184 : private:
185 : typedef enum
186 : {
187 : LOWEST_RESOLUTION,
188 : HIGHEST_RESOLUTION,
189 : AVERAGE_RESOLUTION,
190 : USER_RESOLUTION,
191 : AVERAGE_APPROX_RESOLUTION
192 : } ResolutionStrategy;
193 :
194 : char **papszSubdatasets;
195 : int nSrid;
196 : int nOverviewFactor;
197 : int nBandsToCreate;
198 : PGconn *poConn;
199 : GBool bRegularBlocking;
200 : GBool bAllTilesSnapToSameGrid;
201 : GBool bCheckAllTiles;
202 : char *pszSchema;
203 : char *pszTable;
204 : char *pszColumn;
205 : char *pszWhere;
206 : char *pszPrimaryKeyName;
207 : GBool bIsFastPK;
208 : int bHasTriedFetchingPrimaryKeyName;
209 : mutable OGRSpatialReference m_oSRS{};
210 : ResolutionStrategy resolutionStrategy;
211 : WorkingMode nMode;
212 : OutDBResolution eOutDBResolution{OutDBResolution::SERVER_SIDE};
213 : bool bHasStBandFileSize = false;
214 : int m_nTiles;
215 : double xmin;
216 : double ymin;
217 : double xmax;
218 : double ymax;
219 : PostGISRasterTileDataset **papoSourcesHolders;
220 : CPLQuadTree *hQuadTree;
221 :
222 : GBool bHasBuiltOverviews;
223 : int nOverviewCount;
224 : PostGISRasterDataset *poParentDS;
225 : PostGISRasterDataset **papoOverviewDS;
226 :
227 : std::map<CPLString, PostGISRasterTileDataset *> oMapPKIDToRTDS{};
228 :
229 : GBool bAssumeMultiBandReadPattern;
230 : int nNextExpectedBand;
231 : int nXOffPrev;
232 : int nYOffPrev;
233 : int nXSizePrev;
234 : int nYSizePrev;
235 :
236 : GBool bHasTriedHasSpatialIndex;
237 : GBool bHasSpatialIndex;
238 :
239 : GBool bBuildQuadTreeDynamically;
240 :
241 : GBool bTilesSameDimension;
242 : int nTileWidth;
243 : int nTileHeight;
244 :
245 : int m_nLastLoadSourcesXOff = 0;
246 : int m_nLastLoadSourcesYOff = 0;
247 : int m_nLastLoadSourcesXSize = 0;
248 : int m_nLastLoadSourcesYSize = 0;
249 : int m_nLastLoadSourcesBand = 0;
250 :
251 : lru11::Cache<std::string, std::shared_ptr<GDALDataset>> oOutDBDatasetCache{
252 : 8, 0};
253 : lru11::Cache<std::string, bool> oOutDBFilenameUsable{100, 0};
254 :
255 : GBool ConstructOneDatasetFromTiles(PGresult *);
256 : GBool YieldSubdatasets(PGresult *, const char *);
257 : GBool SetRasterProperties(const char *);
258 : GBool BrowseDatabase(const char *, const char *);
259 : void AddComplexSource(PostGISRasterTileDataset *poRTDS);
260 : void GetDstWin(PostGISRasterTileDataset *, int *, int *, int *, int *);
261 : BandMetadata *GetBandsMetadata(int *);
262 : PROverview *GetOverviewTables(int *);
263 :
264 : PostGISRasterTileDataset *
265 : BuildRasterTileDataset(const char *pszMetadata, const char *pszPKID,
266 : int nBandsFetched, BandMetadata *poBandMetaData);
267 : void UpdateGlobalResolutionWithTileResolution(double tilePixelSizeX,
268 : double tilePixelSizeY);
269 : void BuildOverviews();
270 : void BuildBands(BandMetadata *poBandMetaData, int nBandsFetched);
271 :
272 0 : PostGISRasterTileDataset *GetMatchingSourceRef(const char *pszPKID)
273 : {
274 0 : return oMapPKIDToRTDS[pszPKID];
275 : }
276 :
277 : PostGISRasterTileDataset *GetMatchingSourceRef(double dfUpperLeftX,
278 : double dfUpperLeftY);
279 :
280 : bool CanUseClientSideOutDB(bool bAllBandCaching, int nBand,
281 : const CPLString &osWHERE);
282 :
283 : bool LoadOutdbRaster(int &nCurOffset, GDALDataType eDT, int nBand,
284 : const GByte *pbyData, int nWKBLength, void *pImage,
285 : double dfTileUpperLeftX, double dfTileUpperLeftY,
286 : double dfTileResX, double dfTileResY, int nTileXSize,
287 : int nTileYSize);
288 :
289 : CPL_DISALLOW_COPY_ASSIGN(PostGISRasterDataset)
290 :
291 : protected:
292 : int CloseDependentDatasets() override;
293 : CPLErr FlushCache(bool bAtClosing) override;
294 :
295 : public:
296 : PostGISRasterDataset();
297 : ~PostGISRasterDataset() override;
298 : static GDALDataset *Open(GDALOpenInfo *);
299 : static GDALDataset *CreateCopy(const char *, GDALDataset *, int,
300 : CSLConstList, GDALProgressFunc, void *);
301 : static GBool InsertRaster(PGconn *, PostGISRasterDataset *, const char *,
302 : const char *, const char *);
303 : static CPLErr Delete(const char *);
304 : char **GetMetadataDomainList() override;
305 : CSLConstList GetMetadata(const char *) override;
306 :
307 : const OGRSpatialReference *GetSpatialRef() const override;
308 : CPLErr SetSpatialRef(const OGRSpatialReference *poSRS) override;
309 :
310 : CPLErr SetGeoTransform(const GDALGeoTransform >) override;
311 : CPLErr GetGeoTransform(GDALGeoTransform >) const override;
312 : char **GetFileList() override;
313 :
314 : int GetOverviewCount();
315 : PostGISRasterDataset *GetOverviewDS(int iOvr);
316 :
317 : const char *GetPrimaryKeyRef();
318 : GBool HasSpatialIndex();
319 : GBool LoadSources(int nXOff, int nYOff, int nXSize, int nYSize, int nBand);
320 : GBool PolygonFromCoords(int nXOff, int nYOff, int nXEndOff, int nYEndOff,
321 : double adfProjWin[8]);
322 : void CacheTile(const char *pszMetadata, const char *pszRaster,
323 : const char *pszPKID, int nBand, bool bAllBandCaching);
324 : };
325 :
326 : /***********************************************************************
327 : * PostGISRasterRasterBand: extends VRTSourcedRasterBand to support
328 : * PostGIS Raster bands
329 : **********************************************************************/
330 : class PostGISRasterTileRasterBand;
331 :
332 : class PostGISRasterRasterBand final : public VRTSourcedRasterBand
333 : {
334 : friend class PostGISRasterDataset;
335 :
336 : private:
337 : // Store stats from ST_SummaryStatsAgg
338 : bool m_bStatsFetched = false;
339 : double m_dfStatsMin = std::numeric_limits<double>::quiet_NaN();
340 : double m_dfStatsMax = std::numeric_limits<double>::quiet_NaN();
341 : // Unused for now:
342 : double m_dfStatsMean = std::numeric_limits<double>::quiet_NaN();
343 : double m_dfStatsStdDev = std::numeric_limits<double>::quiet_NaN();
344 : double m_dfStatsSum = std::numeric_limits<double>::quiet_NaN();
345 : double m_dfStatsCount = std::numeric_limits<double>::quiet_NaN();
346 :
347 : // Call ST_SummaryStatsAgg to fetch stats for this band. Returns true if successful, false otherwise.
348 : bool QueryStats();
349 :
350 : /** Returns true if stats have been fetched and are valid (not NaN)
351 : * and the pixel count is > 0, false otherwise. */
352 : bool StatsFetchedAndValid() const;
353 :
354 : CPL_DISALLOW_COPY_ASSIGN(PostGISRasterRasterBand)
355 : protected:
356 : const char *pszSchema;
357 : const char *pszTable;
358 : const char *pszColumn;
359 :
360 : void NullBuffer(void *pData, int nBufXSize, int nBufYSize,
361 : GDALDataType eBufType, int nPixelSpace, int nLineSpace);
362 :
363 : public:
364 : PostGISRasterRasterBand(PostGISRasterDataset *poDSIn, int nBandIn,
365 : GDALDataType eDataTypeIn, GBool bNoDataValueSetIn,
366 : double dfNodata);
367 :
368 : ~PostGISRasterRasterBand() override;
369 :
370 : double GetNoDataValue(int *pbSuccess = nullptr) override;
371 : CPLErr SetNoDataValue(double) override;
372 : CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
373 : GDALDataType, GSpacing nPixelSpace, GSpacing nLineSpace,
374 : GDALRasterIOExtraArg *psExtraArg) override;
375 :
376 : int GetOverviewCount() override;
377 : GDALRasterBand *GetOverview(int) override;
378 : GDALColorInterp GetColorInterpretation() override;
379 :
380 : double GetMinimum(int *pbSuccess) override;
381 : double GetMaximum(int *pbSuccess) override;
382 :
383 : virtual CPLErr ComputeRasterMinMax(int bApproxOK,
384 : double *adfMinMax) override;
385 :
386 : virtual CPLErr ComputeStatistics(int bApproxOK, double *pdfMin,
387 : double *pdfMax, double *pdfMean,
388 : double *pdfStdDev,
389 : GDALProgressFunc pfnProgress,
390 : void *pProgressData,
391 : CSLConstList papszOptions) override;
392 : };
393 :
394 : /***********************************************************************
395 : * PostGISRasterTileDataset: it holds just a raster tile
396 : **********************************************************************/
397 : class PostGISRasterTileRasterBand;
398 :
399 : class PostGISRasterTileDataset final : public GDALDataset
400 : {
401 : friend class PostGISRasterDataset;
402 : friend class PostGISRasterRasterBand;
403 : friend class PostGISRasterTileRasterBand;
404 :
405 : private:
406 : PostGISRasterDataset *poRDS;
407 : char *pszPKID;
408 : GDALGeoTransform m_gt{};
409 :
410 : CPL_DISALLOW_COPY_ASSIGN(PostGISRasterTileDataset)
411 :
412 : public:
413 : PostGISRasterTileDataset(PostGISRasterDataset *poRDS, int nXSize,
414 : int nYSize);
415 : ~PostGISRasterTileDataset() override;
416 : CPLErr GetGeoTransform(GDALGeoTransform >) const override;
417 : void GetNativeExtent(double *pdfMinX, double *pdfMinY, double *pdfMaxX,
418 : double *pdfMaxY) const;
419 :
420 0 : const char *GetPKID() const
421 : {
422 0 : return pszPKID;
423 : }
424 : };
425 :
426 : /***********************************************************************
427 : * PostGISRasterTileRasterBand: it holds a raster tile band, that will
428 : * be used as a source for PostGISRasterRasterBand
429 : **********************************************************************/
430 : class PostGISRasterTileRasterBand final : public GDALRasterBand
431 : {
432 : friend class PostGISRasterRasterBand;
433 : friend class PostGISRasterDataset;
434 :
435 : private:
436 : GBool IsCached();
437 :
438 : VRTSource *poSource;
439 :
440 : CPL_DISALLOW_COPY_ASSIGN(PostGISRasterTileRasterBand)
441 :
442 : public:
443 : PostGISRasterTileRasterBand(PostGISRasterTileDataset *poRTDS, int nBand,
444 : GDALDataType eDataType);
445 : ~PostGISRasterTileRasterBand() override;
446 : CPLErr IReadBlock(int, int, void *) override;
447 : };
448 :
449 : #endif // POSTGISRASTER_H_INCLUDED
|