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 : int nSrid;
195 : int nOverviewFactor;
196 : int nBandsToCreate;
197 : PGconn *poConn;
198 : GBool bRegularBlocking;
199 : GBool bAllTilesSnapToSameGrid;
200 : GBool bCheckAllTiles;
201 : char *pszSchema;
202 : char *pszTable;
203 : char *pszColumn;
204 : char *pszWhere;
205 : char *pszPrimaryKeyName;
206 : GBool bIsFastPK;
207 : int bHasTriedFetchingPrimaryKeyName;
208 : mutable OGRSpatialReference m_oSRS{};
209 : ResolutionStrategy resolutionStrategy;
210 : WorkingMode nMode;
211 : OutDBResolution eOutDBResolution{OutDBResolution::SERVER_SIDE};
212 : bool bHasStBandFileSize = false;
213 : int m_nTiles;
214 : double xmin;
215 : double ymin;
216 : double xmax;
217 : double ymax;
218 : PostGISRasterTileDataset **papoSourcesHolders;
219 : CPLQuadTree *hQuadTree;
220 :
221 : GBool bHasBuiltOverviews;
222 : int nOverviewCount;
223 : PostGISRasterDataset *poParentDS;
224 : PostGISRasterDataset **papoOverviewDS;
225 :
226 : std::map<CPLString, PostGISRasterTileDataset *> oMapPKIDToRTDS{};
227 :
228 : GBool bAssumeMultiBandReadPattern;
229 : int nNextExpectedBand;
230 : int nXOffPrev;
231 : int nYOffPrev;
232 : int nXSizePrev;
233 : int nYSizePrev;
234 :
235 : GBool bHasTriedHasSpatialIndex;
236 : GBool bHasSpatialIndex;
237 :
238 : GBool bBuildQuadTreeDynamically;
239 :
240 : GBool bTilesSameDimension;
241 : int nTileWidth;
242 : int nTileHeight;
243 :
244 : int m_nLastLoadSourcesXOff = 0;
245 : int m_nLastLoadSourcesYOff = 0;
246 : int m_nLastLoadSourcesXSize = 0;
247 : int m_nLastLoadSourcesYSize = 0;
248 : int m_nLastLoadSourcesBand = 0;
249 :
250 : lru11::Cache<std::string, std::shared_ptr<GDALDataset>> oOutDBDatasetCache{
251 : 8, 0};
252 : lru11::Cache<std::string, bool> oOutDBFilenameUsable{100, 0};
253 :
254 : GBool ConstructOneDatasetFromTiles(PGresult *);
255 : GBool YieldSubdatasets(PGresult *, const char *);
256 : GBool SetRasterProperties(const char *);
257 : GBool BrowseDatabase(const char *, const char *);
258 : void AddComplexSource(PostGISRasterTileDataset *poRTDS);
259 : void GetDstWin(PostGISRasterTileDataset *, int *, int *, int *, int *);
260 : BandMetadata *GetBandsMetadata(int *);
261 : PROverview *GetOverviewTables(int *);
262 :
263 : PostGISRasterTileDataset *
264 : BuildRasterTileDataset(const char *pszMetadata, const char *pszPKID,
265 : int nBandsFetched, BandMetadata *poBandMetaData);
266 : void UpdateGlobalResolutionWithTileResolution(double tilePixelSizeX,
267 : double tilePixelSizeY);
268 : void BuildOverviews();
269 : void BuildBands(BandMetadata *poBandMetaData, int nBandsFetched);
270 :
271 0 : PostGISRasterTileDataset *GetMatchingSourceRef(const char *pszPKID)
272 : {
273 0 : return oMapPKIDToRTDS[pszPKID];
274 : }
275 :
276 : PostGISRasterTileDataset *GetMatchingSourceRef(double dfUpperLeftX,
277 : double dfUpperLeftY);
278 :
279 : bool CanUseClientSideOutDB(bool bAllBandCaching, int nBand,
280 : const CPLString &osWHERE);
281 :
282 : bool LoadOutdbRaster(int &nCurOffset, GDALDataType eDT, int nBand,
283 : const GByte *pbyData, int nWKBLength, void *pImage,
284 : double dfTileUpperLeftX, double dfTileUpperLeftY,
285 : double dfTileResX, double dfTileResY, int nTileXSize,
286 : int nTileYSize);
287 :
288 : CPL_DISALLOW_COPY_ASSIGN(PostGISRasterDataset)
289 :
290 : protected:
291 : virtual int CloseDependentDatasets() override;
292 : virtual CPLErr FlushCache(bool bAtClosing) override;
293 :
294 : public:
295 : PostGISRasterDataset();
296 : virtual ~PostGISRasterDataset();
297 : static GDALDataset *Open(GDALOpenInfo *);
298 : static GDALDataset *CreateCopy(const char *, GDALDataset *, int, char **,
299 : GDALProgressFunc, void *);
300 : static GBool InsertRaster(PGconn *, PostGISRasterDataset *, const char *,
301 : const char *, const char *);
302 : static CPLErr Delete(const char *);
303 : virtual char **GetMetadataDomainList() override;
304 : char **GetMetadata(const char *) override;
305 :
306 : const OGRSpatialReference *GetSpatialRef() const override;
307 : CPLErr SetSpatialRef(const OGRSpatialReference *poSRS) override;
308 :
309 : CPLErr SetGeoTransform(const GDALGeoTransform >) override;
310 : CPLErr GetGeoTransform(GDALGeoTransform >) const override;
311 : char **GetFileList() override;
312 :
313 : int GetOverviewCount();
314 : PostGISRasterDataset *GetOverviewDS(int iOvr);
315 :
316 : const char *GetPrimaryKeyRef();
317 : GBool HasSpatialIndex();
318 : GBool LoadSources(int nXOff, int nYOff, int nXSize, int nYSize, int nBand);
319 : GBool PolygonFromCoords(int nXOff, int nYOff, int nXEndOff, int nYEndOff,
320 : double adfProjWin[8]);
321 : void CacheTile(const char *pszMetadata, const char *pszRaster,
322 : const char *pszPKID, int nBand, bool bAllBandCaching);
323 : };
324 :
325 : /***********************************************************************
326 : * PostGISRasterRasterBand: extends VRTSourcedRasterBand to support
327 : * PostGIS Raster bands
328 : **********************************************************************/
329 : class PostGISRasterTileRasterBand;
330 :
331 : class PostGISRasterRasterBand final : public VRTSourcedRasterBand
332 : {
333 : friend class PostGISRasterDataset;
334 :
335 : CPL_DISALLOW_COPY_ASSIGN(PostGISRasterRasterBand)
336 : protected:
337 : const char *pszSchema;
338 : const char *pszTable;
339 : const char *pszColumn;
340 :
341 : void NullBuffer(void *pData, int nBufXSize, int nBufYSize,
342 : GDALDataType eBufType, int nPixelSpace, int nLineSpace);
343 :
344 : public:
345 : PostGISRasterRasterBand(PostGISRasterDataset *poDSIn, int nBandIn,
346 : GDALDataType eDataTypeIn, GBool bNoDataValueSetIn,
347 : double dfNodata);
348 :
349 : virtual ~PostGISRasterRasterBand();
350 :
351 : virtual double GetNoDataValue(int *pbSuccess = nullptr) override;
352 : virtual CPLErr SetNoDataValue(double) override;
353 : virtual CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
354 : GDALDataType, GSpacing nPixelSpace,
355 : GSpacing nLineSpace,
356 : GDALRasterIOExtraArg *psExtraArg) override;
357 :
358 : virtual int GetOverviewCount() override;
359 : virtual GDALRasterBand *GetOverview(int) override;
360 : virtual GDALColorInterp GetColorInterpretation() override;
361 :
362 : virtual double GetMinimum(int *pbSuccess) override;
363 : virtual double GetMaximum(int *pbSuccess) override;
364 : virtual CPLErr ComputeRasterMinMax(int bApproxOK,
365 : double *adfMinMax) override;
366 : };
367 :
368 : /***********************************************************************
369 : * PostGISRasterTileDataset: it holds just a raster tile
370 : **********************************************************************/
371 : class PostGISRasterTileRasterBand;
372 :
373 : class PostGISRasterTileDataset final : public GDALDataset
374 : {
375 : friend class PostGISRasterDataset;
376 : friend class PostGISRasterRasterBand;
377 : friend class PostGISRasterTileRasterBand;
378 :
379 : private:
380 : PostGISRasterDataset *poRDS;
381 : char *pszPKID;
382 : GDALGeoTransform m_gt{};
383 :
384 : CPL_DISALLOW_COPY_ASSIGN(PostGISRasterTileDataset)
385 :
386 : public:
387 : PostGISRasterTileDataset(PostGISRasterDataset *poRDS, int nXSize,
388 : int nYSize);
389 : ~PostGISRasterTileDataset();
390 : CPLErr GetGeoTransform(GDALGeoTransform >) const override;
391 : void GetNativeExtent(double *pdfMinX, double *pdfMinY, double *pdfMaxX,
392 : double *pdfMaxY) const;
393 :
394 0 : const char *GetPKID() const
395 : {
396 0 : return pszPKID;
397 : }
398 : };
399 :
400 : /***********************************************************************
401 : * PostGISRasterTileRasterBand: it holds a raster tile band, that will
402 : * be used as a source for PostGISRasterRasterBand
403 : **********************************************************************/
404 : class PostGISRasterTileRasterBand final : public GDALRasterBand
405 : {
406 : friend class PostGISRasterRasterBand;
407 : friend class PostGISRasterDataset;
408 :
409 : private:
410 : GBool IsCached();
411 :
412 : VRTSource *poSource;
413 :
414 : CPL_DISALLOW_COPY_ASSIGN(PostGISRasterTileRasterBand)
415 :
416 : public:
417 : PostGISRasterTileRasterBand(PostGISRasterTileDataset *poRTDS, int nBand,
418 : GDALDataType eDataType);
419 : virtual ~PostGISRasterTileRasterBand();
420 : virtual CPLErr IReadBlock(int, int, void *) override;
421 : };
422 :
423 : #endif // POSTGISRASTER_H_INCLUDED
|