Line data Source code
1 : /***********************************************************************
2 : * File : postgisrastertilerasterband.cpp
3 : * Project: PostGIS Raster driver
4 : * Purpose: GDAL Tile RasterBand implementation for PostGIS Raster
5 : * driver
6 : * Author: Jorge Arevalo, jorge.arevalo@deimos-space.com
7 : * jorgearevalo@libregis.org
8 : * Last changes: $Id$
9 : *
10 : ***********************************************************************
11 : * Copyright (c) 2009 - 2013, Jorge Arevalo
12 : * Copyright (c) 2013-2018, Even Rouault
13 : *
14 : * Permission is hereby granted, free of charge, to any person obtaining
15 : * a copy of this software and associated documentation files (the
16 : * "Software"), to deal in the Software without restriction, including
17 : * without limitation the rights to use, copy, modify, merge, publish,
18 : * distribute, sublicense, and/or sell copies of the Software, and to
19 : * permit persons to whom the Software is furnished to do so, subject to
20 : * the following conditions:
21 : *
22 : * The above copyright notice and this permission notice shall be
23 : * included in all copies or substantial portions of the Software.
24 : *
25 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 : * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 : * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 : * NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 : * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30 : * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31 : * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32 : * SOFTWARE.
33 : **********************************************************************/
34 : #include "postgisraster.h"
35 : #include <memory>
36 :
37 : /************************
38 : * \brief Constructor
39 : ************************/
40 0 : PostGISRasterTileRasterBand::PostGISRasterTileRasterBand(
41 0 : PostGISRasterTileDataset *poRTDSIn, int nBandIn, GDALDataType eDataTypeIn)
42 0 : : poSource(nullptr)
43 : {
44 : // Basic properties.
45 0 : poDS = poRTDSIn;
46 0 : nBand = nBandIn;
47 :
48 : #if 0
49 : CPLDebug("PostGIS_Raster",
50 : "PostGISRasterTileRasterBand::Constructor: Raster tile dataset "
51 : "of dimensions %dx%d", poRTDS->GetRasterXSize(),
52 : poRTDS->GetRasterYSize());
53 : #endif
54 :
55 0 : eDataType = eDataTypeIn;
56 :
57 0 : nRasterXSize = poRTDSIn->GetRasterXSize();
58 0 : nRasterYSize = poRTDSIn->GetRasterYSize();
59 :
60 0 : nBlockXSize = nRasterXSize;
61 0 : nBlockYSize = nRasterYSize;
62 0 : }
63 :
64 : /************************
65 : * \brief Destructor
66 : ************************/
67 0 : PostGISRasterTileRasterBand::~PostGISRasterTileRasterBand()
68 : {
69 0 : }
70 :
71 : /***********************************************************************
72 : * \brief Returns true if the (only) block is stored in the cache
73 : **********************************************************************/
74 0 : GBool PostGISRasterTileRasterBand::IsCached()
75 : {
76 0 : GDALRasterBlock *poBlock = TryGetLockedBlockRef(0, 0);
77 0 : if (poBlock != nullptr)
78 : {
79 0 : poBlock->DropLock();
80 0 : return true;
81 : }
82 :
83 0 : return false;
84 : }
85 :
86 : /*****************************************************
87 : * \brief Read a natural block of raster band data
88 : *****************************************************/
89 0 : CPLErr PostGISRasterTileRasterBand::IReadBlock(int /*nBlockXOff*/,
90 : int /*nBlockYOff*/, void *pImage)
91 : {
92 0 : CPLString osCommand;
93 0 : PGresult *poResult = nullptr;
94 0 : int nWKBLength = 0;
95 :
96 0 : const int nPixelSize = GDALGetDataTypeSizeBytes(eDataType);
97 :
98 : PostGISRasterTileDataset *poRTDS =
99 0 : cpl::down_cast<PostGISRasterTileDataset *>(poDS);
100 :
101 0 : const double dfTileUpperLeftX =
102 : poRTDS->adfGeoTransform[GEOTRSFRM_TOPLEFT_X];
103 0 : const double dfTileUpperLeftY =
104 : poRTDS->adfGeoTransform[GEOTRSFRM_TOPLEFT_Y];
105 0 : const double dfTileResX = poRTDS->adfGeoTransform[1];
106 0 : const double dfTileResY = poRTDS->adfGeoTransform[5];
107 0 : const int nTileXSize = nBlockXSize;
108 0 : const int nTileYSize = nBlockYSize;
109 :
110 0 : CPLString osSchemaI(CPLQuotedSQLIdentifier(poRTDS->poRDS->pszSchema));
111 0 : CPLString osTableI(CPLQuotedSQLIdentifier(poRTDS->poRDS->pszTable));
112 0 : CPLString osColumnI(CPLQuotedSQLIdentifier(poRTDS->poRDS->pszColumn));
113 :
114 0 : CPLString osRasterToFetch;
115 0 : osRasterToFetch.Printf("ST_Band(%s, %d)", osColumnI.c_str(), nBand);
116 : // We don't honour CLIENT_SIDE_IF_POSSIBLE since it would be likely too
117 : // costly in that context.
118 0 : if (poRTDS->poRDS->eOutDBResolution != OutDBResolution::CLIENT_SIDE)
119 : {
120 : osRasterToFetch =
121 0 : "encode(ST_AsBinary(" + osRasterToFetch + ",TRUE),'hex')";
122 : }
123 :
124 : osCommand.Printf("SELECT %s FROM %s.%s WHERE ", osRasterToFetch.c_str(),
125 0 : osSchemaI.c_str(), osTableI.c_str());
126 :
127 : // Get by PKID
128 0 : if (poRTDS->poRDS->pszPrimaryKeyName)
129 : {
130 : CPLString osPrimaryKeyNameI(
131 0 : CPLQuotedSQLIdentifier(poRTDS->poRDS->pszPrimaryKeyName));
132 : osCommand +=
133 0 : CPLSPrintf("%s = '%s'", osPrimaryKeyNameI.c_str(), poRTDS->pszPKID);
134 : }
135 :
136 : // Get by upperleft
137 : else
138 : {
139 : osCommand += CPLSPrintf("abs(ST_UpperLeftX(%s) - %.8f) < 1e-8 and "
140 : "abs(ST_UpperLeftY(%s) - %.8f) < 1e-8",
141 : osColumnI.c_str(), dfTileUpperLeftX,
142 0 : osColumnI.c_str(), dfTileUpperLeftY);
143 : }
144 :
145 0 : poResult = PQexec(poRTDS->poRDS->poConn, osCommand.c_str());
146 :
147 : #ifdef DEBUG_QUERY
148 : CPLDebug("PostGIS_Raster",
149 : "PostGISRasterTileRasterBand::IReadBlock(): "
150 : "Query = \"%s\" --> number of rows = %d",
151 : osCommand.c_str(), poResult ? PQntuples(poResult) : 0);
152 : #endif
153 :
154 0 : if (poResult == nullptr || PQresultStatus(poResult) != PGRES_TUPLES_OK ||
155 0 : PQntuples(poResult) <= 0)
156 : {
157 :
158 0 : CPLString osError;
159 0 : if (PQresultStatus(poResult) == PGRES_FATAL_ERROR)
160 : {
161 0 : const char *pszError = PQerrorMessage(poRTDS->poRDS->poConn);
162 0 : if (pszError)
163 0 : osError = pszError;
164 : }
165 0 : if (poResult)
166 0 : PQclear(poResult);
167 :
168 0 : ReportError(CE_Failure, CPLE_AppDefined,
169 : "Error getting block of data (upperpixel = %f, %f): %s",
170 : dfTileUpperLeftX, dfTileUpperLeftY, osError.c_str());
171 :
172 0 : return CE_Failure;
173 : }
174 :
175 : /* Copy only data size, without payload */
176 0 : int nExpectedDataSize = nBlockXSize * nBlockYSize * nPixelSize;
177 :
178 : struct CPLFreer
179 : {
180 0 : void operator()(GByte *x) const
181 : {
182 0 : CPLFree(x);
183 0 : }
184 : };
185 :
186 : std::unique_ptr<GByte, CPLFreer> pbyDataAutoFreed(
187 0 : CPLHexToBinary(PQgetvalue(poResult, 0, 0), &nWKBLength));
188 0 : GByte *pbyData = pbyDataAutoFreed.get();
189 0 : PQclear(poResult);
190 :
191 0 : const int nMinimumWKBLength = RASTER_HEADER_SIZE + BAND_SIZE(1, nPixelSize);
192 0 : if (nWKBLength < nMinimumWKBLength)
193 : {
194 0 : CPLDebug("PostGIS_Raster",
195 : "nWKBLength=%d. too short. Expected at least %d", nWKBLength,
196 : nMinimumWKBLength);
197 0 : return CE_Failure;
198 : }
199 :
200 : // Is it indb-raster ?
201 0 : if ((pbyData[RASTER_HEADER_SIZE] & 0x80) == 0)
202 : {
203 0 : int nExpectedWKBLength =
204 0 : RASTER_HEADER_SIZE + BAND_SIZE(nPixelSize, nExpectedDataSize);
205 0 : if (nWKBLength != nExpectedWKBLength)
206 : {
207 0 : CPLDebug("PostGIS_Raster", "nWKBLength=%d, nExpectedWKBLength=%d",
208 : nWKBLength, nExpectedWKBLength);
209 0 : return CE_Failure;
210 : }
211 :
212 0 : GByte *pbyDataToRead =
213 0 : GET_BAND_DATA(pbyData, 1, nPixelSize, nExpectedDataSize);
214 :
215 : // Do byte-swapping if necessary */
216 0 : const bool bIsLittleEndian = (pbyData[0] == 1);
217 : #ifdef CPL_LSB
218 0 : const bool bSwap = !bIsLittleEndian;
219 : #else
220 : const bool bSwap = bIsLittleEndian;
221 : #endif
222 :
223 0 : if (bSwap && nPixelSize > 1)
224 : {
225 0 : GDALSwapWords(pbyDataToRead, nPixelSize, nBlockXSize * nBlockYSize,
226 : nPixelSize);
227 : }
228 :
229 0 : memcpy(pImage, pbyDataToRead, nExpectedDataSize);
230 : }
231 : else
232 : {
233 0 : int nCurOffset = RASTER_HEADER_SIZE;
234 0 : if (!poRTDS->poRDS->LoadOutdbRaster(
235 : nCurOffset, eDataType, nBand, pbyData, nWKBLength, pImage,
236 : dfTileUpperLeftX, dfTileUpperLeftY, dfTileResX, dfTileResY,
237 : nTileXSize, nTileYSize))
238 : {
239 0 : return CE_Failure;
240 : }
241 : }
242 :
243 0 : return CE_None;
244 : }
|