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 :
29 : // #define DEBUG_VERBOSE
30 : // #define DEBUG_QUERY
31 :
32 : #if defined(DEBUG_VERBOSE) && !defined(DEBUG_QUERY)
33 : #define DEBUG_QUERY
34 : #endif
35 :
36 : /**
37 : * The block size for the cache will be the minimum between the tile
38 : * size from sources and this value. So, please keep it at 2048 or
39 : * lower
40 : **/
41 : #define MAX_BLOCK_SIZE 2048
42 :
43 : #define NO_VALID_RES "-1234.56"
44 :
45 : /**
46 : * To move over the data return by queries
47 : **/
48 : #define POSTGIS_RASTER_VERSION static_cast<GUInt16>(0)
49 : #define RASTER_HEADER_SIZE 61
50 : #define RASTER_BAND_HEADER_FIXED_SIZE 1
51 :
52 : #define BAND_SIZE(nodatasize, datasize) \
53 : (RASTER_BAND_HEADER_FIXED_SIZE + (nodatasize) + (datasize))
54 :
55 : #define GET_BAND_DATA(raster, nband, nodatasize, datasize) \
56 : ((raster) + RASTER_HEADER_SIZE + (nband)*BAND_SIZE(nodatasize, datasize) - \
57 : (datasize))
58 :
59 : #define GEOTRSFRM_TOPLEFT_X 0
60 : #define GEOTRSFRM_WE_RES 1
61 : #define GEOTRSFRM_ROTATION_PARAM1 2
62 : #define GEOTRSFRM_TOPLEFT_Y 3
63 : #define GEOTRSFRM_ROTATION_PARAM2 4
64 : #define GEOTRSFRM_NS_RES 5
65 :
66 : // Number of results return by ST_Metadata PostGIS function
67 : #define ELEMENTS_OF_METADATA_RECORD 10
68 :
69 : // Positions of elements of ST_Metadata PostGIS function
70 : #define POS_UPPERLEFTX 0
71 : #define POS_UPPERLEFTY 1
72 : #define POS_WIDTH 2
73 : #define POS_HEIGHT 3
74 : #define POS_SCALEX 4
75 : #define POS_SCALEY 5
76 : #define POS_SKEWX 6
77 : #define POS_SKEWY 7
78 : #define POS_SRID 8
79 : #define POS_NBANDS 9
80 :
81 : // Number of results return by ST_BandMetadata PostGIS function
82 : #define ELEMENTS_OF_BAND_METADATA_RECORD 4
83 :
84 : // Positions of elements of ST_BandMetadata PostGIS function
85 : #define POS_PIXELTYPE 0
86 : #define POS_NODATAVALUE 1
87 : #define POS_ISOUTDB 2
88 : #define POS_PATH 3
89 :
90 : /**
91 : * The driver can work in these modes:
92 : * - NO_MODE: Error case
93 : * - ONE_RASTER_PER_ROW: Each row of the requested table is considered
94 : * as a separated raster object. This is the default mode, if
95 : * database and table name are provided, and no mode is specified.
96 : * - ONE_RASTER_PER_TABLE: All the rows of the requested table are
97 : * considered as tiles of a bigger raster coverage (the whole
98 : * table). If database and table name are specified and mode = 2
99 : * is present in the connection string, this is the selected mode.
100 : * - BROWSE_SCHEMA: If no table name is specified, just database and
101 : * schema names, the driver will yell of the schema's raster tables
102 : * as possible datasets.
103 : * - BROWSE_DATABASE: If no table name is specified, just database name,
104 : * the driver will yell of the database's raster tables as possible
105 : * datasets.
106 : **/
107 : typedef enum
108 : {
109 : NO_MODE,
110 : ONE_RASTER_PER_ROW,
111 : ONE_RASTER_PER_TABLE,
112 : BROWSE_SCHEMA,
113 : BROWSE_DATABASE
114 : } WorkingMode;
115 :
116 : enum class OutDBResolution
117 : {
118 : SERVER_SIDE,
119 : CLIENT_SIDE,
120 : CLIENT_SIDE_IF_POSSIBLE
121 : };
122 :
123 : /**
124 : * Important metadata of a PostGIS Raster band
125 : **/
126 : typedef struct
127 : {
128 : GDALDataType eDataType;
129 : int nBitsDepth;
130 : GBool bHasNoDataValue;
131 : GBool bIsOffline;
132 : char *path;
133 : double dfNoDataValue;
134 : } BandMetadata;
135 :
136 : typedef struct
137 : {
138 : char *pszSchema;
139 : char *pszTable;
140 : char *pszColumn;
141 : int nFactor;
142 : } PROverview;
143 :
144 : // Some tools definitions
145 : char *ReplaceQuotes(const char *, int);
146 : GBool TranslateDataType(const char *, GDALDataType *, int *);
147 :
148 : class PostGISRasterRasterBand;
149 : class PostGISRasterTileDataset;
150 :
151 : /***********************************************************************
152 : * PostGISRasterDriver: extends GDALDriver to support PostGIS Raster
153 : * connect.
154 : **********************************************************************/
155 : class PostGISRasterDriver final : public GDALDriver
156 : {
157 :
158 : private:
159 : CPLMutex *hMutex = nullptr;
160 : std::map<CPLString, PGconn *> oMapConnection{};
161 :
162 : CPL_DISALLOW_COPY_ASSIGN(PostGISRasterDriver)
163 : public:
164 : PostGISRasterDriver();
165 : virtual ~PostGISRasterDriver();
166 : PGconn *GetConnection(const char *pszConnectionString,
167 : const char *pszServiceIn, const char *pszDbnameIn,
168 : const char *pszHostIn, const char *pszPortIn,
169 : const char *pszUserIn);
170 :
171 : static PostGISRasterDriver *gpoPostGISRasterDriver;
172 : };
173 :
174 : /***********************************************************************
175 : * PostGISRasterDataset: extends VRTDataset to support PostGIS Raster
176 : * datasets
177 : **********************************************************************/
178 : class PostGISRasterDataset final : public VRTDataset
179 : {
180 : friend class PostGISRasterRasterBand;
181 : friend class PostGISRasterTileRasterBand;
182 :
183 : private:
184 : typedef enum
185 : {
186 : LOWEST_RESOLUTION,
187 : HIGHEST_RESOLUTION,
188 : AVERAGE_RESOLUTION,
189 : USER_RESOLUTION,
190 : AVERAGE_APPROX_RESOLUTION
191 : } ResolutionStrategy;
192 :
193 : char **papszSubdatasets;
194 : double adfGeoTransform[6];
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 : virtual int CloseDependentDatasets() override;
293 : virtual CPLErr FlushCache(bool bAtClosing) override;
294 :
295 : public:
296 : PostGISRasterDataset();
297 : virtual ~PostGISRasterDataset();
298 : static GDALDataset *Open(GDALOpenInfo *);
299 : static GDALDataset *CreateCopy(const char *, GDALDataset *, int, char **,
300 : GDALProgressFunc, void *);
301 : static GBool InsertRaster(PGconn *, PostGISRasterDataset *, const char *,
302 : const char *, const char *);
303 : static CPLErr Delete(const char *);
304 : virtual char **GetMetadataDomainList() override;
305 : char **GetMetadata(const char *) override;
306 :
307 : const OGRSpatialReference *GetSpatialRef() const override;
308 : CPLErr SetSpatialRef(const OGRSpatialReference *poSRS) override;
309 :
310 : CPLErr SetGeoTransform(double *) override;
311 : CPLErr GetGeoTransform(double *) 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 : CPL_DISALLOW_COPY_ASSIGN(PostGISRasterRasterBand)
337 : protected:
338 : const char *pszSchema;
339 : const char *pszTable;
340 : const char *pszColumn;
341 :
342 : void NullBuffer(void *pData, int nBufXSize, int nBufYSize,
343 : GDALDataType eBufType, int nPixelSpace, int nLineSpace);
344 :
345 : public:
346 : PostGISRasterRasterBand(PostGISRasterDataset *poDSIn, int nBandIn,
347 : GDALDataType eDataTypeIn, GBool bNoDataValueSetIn,
348 : double dfNodata);
349 :
350 : virtual ~PostGISRasterRasterBand();
351 :
352 : virtual double GetNoDataValue(int *pbSuccess = nullptr) override;
353 : virtual CPLErr SetNoDataValue(double) override;
354 : virtual CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
355 : GDALDataType, GSpacing nPixelSpace,
356 : GSpacing nLineSpace,
357 : GDALRasterIOExtraArg *psExtraArg) override;
358 :
359 : virtual int GetOverviewCount() override;
360 : virtual GDALRasterBand *GetOverview(int) override;
361 : virtual GDALColorInterp GetColorInterpretation() override;
362 :
363 : virtual double GetMinimum(int *pbSuccess) override;
364 : virtual double GetMaximum(int *pbSuccess) override;
365 : virtual CPLErr ComputeRasterMinMax(int bApproxOK,
366 : double *adfMinMax) override;
367 : };
368 :
369 : /***********************************************************************
370 : * PostGISRasterTileDataset: it holds just a raster tile
371 : **********************************************************************/
372 : class PostGISRasterTileRasterBand;
373 :
374 : class PostGISRasterTileDataset final : public GDALDataset
375 : {
376 : friend class PostGISRasterDataset;
377 : friend class PostGISRasterRasterBand;
378 : friend class PostGISRasterTileRasterBand;
379 :
380 : private:
381 : PostGISRasterDataset *poRDS;
382 : char *pszPKID;
383 : double adfGeoTransform[6];
384 :
385 : CPL_DISALLOW_COPY_ASSIGN(PostGISRasterTileDataset)
386 :
387 : public:
388 : PostGISRasterTileDataset(PostGISRasterDataset *poRDS, int nXSize,
389 : int nYSize);
390 : ~PostGISRasterTileDataset();
391 : CPLErr GetGeoTransform(double *) override;
392 : void GetExtent(double *pdfMinX, double *pdfMinY, double *pdfMaxX,
393 : double *pdfMaxY) const;
394 :
395 0 : const char *GetPKID() const
396 : {
397 0 : return pszPKID;
398 : }
399 : };
400 :
401 : /***********************************************************************
402 : * PostGISRasterTileRasterBand: it holds a raster tile band, that will
403 : * be used as a source for PostGISRasterRasterBand
404 : **********************************************************************/
405 : class PostGISRasterTileRasterBand final : public GDALRasterBand
406 : {
407 : friend class PostGISRasterRasterBand;
408 : friend class PostGISRasterDataset;
409 :
410 : private:
411 : GBool IsCached();
412 :
413 : VRTSource *poSource;
414 :
415 : CPL_DISALLOW_COPY_ASSIGN(PostGISRasterTileRasterBand)
416 :
417 : public:
418 : PostGISRasterTileRasterBand(PostGISRasterTileDataset *poRTDS, int nBand,
419 : GDALDataType eDataType);
420 : virtual ~PostGISRasterTileRasterBand();
421 : virtual CPLErr IReadBlock(int, int, void *) override;
422 : };
423 :
424 : #endif // POSTGISRASTER_H_INCLUDED
|