/***************************************************** * \brief Read a natural block of raster band data *****************************************************/ CPLErr PostGISRasterTileRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, CPL_UNUSED int nBlockYOff, void * pImage) { CPLString osCommand; PGresult * poResult = NULL; int nWKBLength = 0; int nPixelSize = GDALGetDataTypeSize(eDataType)/8; PostGISRasterTileDataset * poRTDS = (PostGISRasterTileDataset *)poDS; // Get by PKID if (poRTDS->poRDS->pszPrimaryKeyName) { osCommand.Printf("select st_band(%s, %d) from %s.%s where " "%s = '%s'", poRTDS->poRDS->pszColumn, nBand, poRTDS->poRDS->pszSchema, poRTDS->poRDS->pszTable, poRTDS->poRDS->pszPrimaryKeyName, poRTDS->pszPKID); } // Get by upperleft else { osCommand.Printf("select st_band(%s, %d) from %s.%s where " "abs(ST_UpperLeftX(%s) - %.8f) < 1e-8 and abs(ST_UpperLeftY(%s) - %.8f) < 1e-8", poRTDS->poRDS->pszColumn, nBand, poRTDS->poRDS->pszSchema, poRTDS->poRDS->pszTable, poRTDS->poRDS->pszColumn, poRTDS->adfGeoTransform[GEOTRSFRM_TOPLEFT_X], poRTDS->poRDS->pszColumn, poRTDS->adfGeoTransform[GEOTRSFRM_TOPLEFT_Y]); } poResult = PQexec(poRTDS->poRDS->poConn, osCommand.c_str()); #ifdef DEBUG_QUERY CPLDebug("PostGIS_Raster", "PostGISRasterTileRasterBand::IReadBlock(): " "Query = \"%s\" --> number of rows = %d", osCommand.c_str(), poResult ? PQntuples(poResult) : 0 ); #endif if (poResult == NULL || PQresultStatus(poResult) != PGRES_TUPLES_OK || PQntuples(poResult) <= 0) { if (poResult) PQclear(poResult); ReportError(CE_Failure, CPLE_AppDefined, "Error getting block of data (upperpixel = %f, %f)", poRTDS->adfGeoTransform[GEOTRSFRM_TOPLEFT_X], poRTDS->adfGeoTransform[GEOTRSFRM_TOPLEFT_Y]); return CE_Failure; } // TODO: Check this if (bIsOffline) { CPLError(CE_Failure, CPLE_AppDefined, "This raster has outdb " "storage. This feature isn't still available"); PQclear(poResult); return CE_Failure; } /* Copy only data size, without payload */ int nExpectedDataSize = nBlockXSize * nBlockYSize * nPixelSize; GByte * pbyData = CPLHexToBinary(PQgetvalue(poResult, 0, 0), &nWKBLength); int nExpectedWKBLength = RASTER_HEADER_SIZE + BAND_SIZE(nPixelSize, nExpectedDataSize); CPLErr eRet = CE_None; if( nWKBLength != nExpectedWKBLength ) { CPLDebug("PostGIS_Raster", "nWKBLength=%d, nExpectedWKBLength=%d", nWKBLength, nExpectedWKBLength ); eRet = CE_Failure; } else { GByte * pbyDataToRead = (GByte*)GET_BAND_DATA(pbyData,1, nPixelSize, nExpectedDataSize); // Do byte-swapping if necessary */ int bIsLittleEndian = (pbyData[0] == 1); #ifdef CPL_LSB int bSwap = !bIsLittleEndian; #else int bSwap = bIsLittleEndian; #endif if( bSwap && nPixelSize > 1 ) { GDALSwapWords( pbyDataToRead, nPixelSize, nBlockXSize * nBlockYSize, nPixelSize ); } memcpy(pImage, pbyDataToRead, nExpectedDataSize); } CPLFree(pbyData); PQclear(poResult); return eRet; }
/***************************************************** * \brief Read a natural block of raster band data *****************************************************/ CPLErr PostGISRasterTileRasterBand::IReadBlock(int /*nBlockXOff*/, int /*nBlockYOff*/, void * pImage) { CPLString osCommand; PGresult * poResult = nullptr; int nWKBLength = 0; const int nPixelSize = GDALGetDataTypeSizeBytes(eDataType); PostGISRasterTileDataset * poRTDS = cpl::down_cast<PostGISRasterTileDataset *>(poDS); const double dfTileUpperLeftX = poRTDS->adfGeoTransform[GEOTRSFRM_TOPLEFT_X]; const double dfTileUpperLeftY = poRTDS->adfGeoTransform[GEOTRSFRM_TOPLEFT_Y]; const double dfTileResX = poRTDS->adfGeoTransform[1]; const double dfTileResY = poRTDS->adfGeoTransform[5]; const int nTileXSize = nBlockXSize; const int nTileYSize = nBlockYSize; CPLString osRasterToFetch; osRasterToFetch.Printf("ST_Band(%s, %d)", poRTDS->poRDS->pszColumn, nBand); // We don't honour CLIENT_SIDE_IF_POSSIBLE since it would be likely too // costly in that context. if( poRTDS->poRDS->eOutDBResolution != OutDBResolution::CLIENT_SIDE ) { osRasterToFetch = "encode(ST_AsBinary(" + osRasterToFetch + ",TRUE),'hex')"; } osCommand.Printf("SELECT %s FROM %s.%s WHERE ", osRasterToFetch.c_str(), poRTDS->poRDS->pszSchema, poRTDS->poRDS->pszTable); // Get by PKID if (poRTDS->poRDS->pszPrimaryKeyName) { osCommand += CPLSPrintf("%s = '%s'", poRTDS->poRDS->pszPrimaryKeyName, poRTDS->pszPKID); } // Get by upperleft else { osCommand += CPLSPrintf( "abs(ST_UpperLeftX(%s) - %.8f) < 1e-8 and abs(ST_UpperLeftY(%s) - %.8f) < 1e-8", poRTDS->poRDS->pszColumn, dfTileUpperLeftX, poRTDS->poRDS->pszColumn, dfTileUpperLeftY); } poResult = PQexec(poRTDS->poRDS->poConn, osCommand.c_str()); #ifdef DEBUG_QUERY CPLDebug("PostGIS_Raster", "PostGISRasterTileRasterBand::IReadBlock(): " "Query = \"%s\" --> number of rows = %d", osCommand.c_str(), poResult ? PQntuples(poResult) : 0 ); #endif if (poResult == nullptr || PQresultStatus(poResult) != PGRES_TUPLES_OK || PQntuples(poResult) <= 0) { CPLString osError; if( PQresultStatus(poResult) == PGRES_FATAL_ERROR ) { const char *pszError = PQerrorMessage( poRTDS->poRDS->poConn ); if( pszError ) osError = pszError; } if (poResult) PQclear(poResult); ReportError(CE_Failure, CPLE_AppDefined, "Error getting block of data (upperpixel = %f, %f): %s", dfTileUpperLeftX, dfTileUpperLeftY, osError.c_str()); return CE_Failure; } /* Copy only data size, without payload */ int nExpectedDataSize = nBlockXSize * nBlockYSize * nPixelSize; struct CPLFreer { void operator() (GByte* x) const { CPLFree(x); } }; std::unique_ptr<GByte, CPLFreer> pbyDataAutoFreed( CPLHexToBinary(PQgetvalue(poResult, 0, 0), &nWKBLength)); GByte* pbyData = pbyDataAutoFreed.get(); PQclear(poResult); const int nMinimumWKBLength = RASTER_HEADER_SIZE + BAND_SIZE(1, nPixelSize); if( nWKBLength < nMinimumWKBLength ) { CPLDebug("PostGIS_Raster", "nWKBLength=%d. too short. Expected at least %d", nWKBLength, nMinimumWKBLength ); return CE_Failure; } // Is it indb-raster ? if( (pbyData[RASTER_HEADER_SIZE] & 0x80) == 0 ) { int nExpectedWKBLength = RASTER_HEADER_SIZE + BAND_SIZE(nPixelSize, nExpectedDataSize); if( nWKBLength != nExpectedWKBLength ) { CPLDebug("PostGIS_Raster", "nWKBLength=%d, nExpectedWKBLength=%d", nWKBLength, nExpectedWKBLength ); return CE_Failure; } GByte * pbyDataToRead = GET_BAND_DATA(pbyData,1, nPixelSize,nExpectedDataSize); // Do byte-swapping if necessary */ const bool bIsLittleEndian = (pbyData[0] == 1); #ifdef CPL_LSB const bool bSwap = !bIsLittleEndian; #else const bool bSwap = bIsLittleEndian; #endif if( bSwap && nPixelSize > 1 ) { GDALSwapWords( pbyDataToRead, nPixelSize, nBlockXSize * nBlockYSize, nPixelSize ); } memcpy(pImage, pbyDataToRead, nExpectedDataSize); } else { int nCurOffset = RASTER_HEADER_SIZE; if( !poRTDS->poRDS->LoadOutdbRaster(nCurOffset, eDataType, nBand, pbyData, nWKBLength, pImage, dfTileUpperLeftX, dfTileUpperLeftY, dfTileResX, dfTileResY, nTileXSize, nTileYSize) ) { return CE_Failure; } } return CE_None; }