1 : /******************************************************************************
2 : * $Id: ogrpgresultlayer.cpp 24334 2012-04-28 14:32:29Z rouault $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Purpose: Implements OGRPGResultLayer class, access the resultset from
6 : * a particular select query done via ExecuteSQL().
7 : * Author: Frank Warmerdam, warmerdam@pobox.com
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2002, Frank Warmerdam
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "cpl_conv.h"
32 : #include "ogr_pg.h"
33 :
34 : CPL_CVSID("$Id: ogrpgresultlayer.cpp 24334 2012-04-28 14:32:29Z rouault $");
35 :
36 : #define PQexec this_is_an_error
37 :
38 : /************************************************************************/
39 : /* OGRPGResultLayer() */
40 : /************************************************************************/
41 :
42 70 : OGRPGResultLayer::OGRPGResultLayer( OGRPGDataSource *poDSIn,
43 : const char * pszRawQueryIn,
44 70 : PGresult *hInitialResultIn )
45 : {
46 70 : poDS = poDSIn;
47 :
48 70 : iNextShapeId = 0;
49 :
50 70 : pszRawStatement = CPLStrdup(pszRawQueryIn);
51 :
52 70 : osWHERE = "";
53 :
54 70 : BuildFullQueryStatement();
55 :
56 70 : poFeatureDefn = ReadResultDefinition(hInitialResultIn);
57 :
58 70 : if (bHasPostGISGeography)
59 : {
60 : // FIXME? But for the moment, PostGIS 1.5 only handles SRID:4326.
61 2 : nSRSId = 4326;
62 : }
63 70 : }
64 :
65 : /************************************************************************/
66 : /* ~OGRPGResultLayer() */
67 : /************************************************************************/
68 :
69 70 : OGRPGResultLayer::~OGRPGResultLayer()
70 :
71 : {
72 70 : CPLFree( pszRawStatement );
73 70 : }
74 :
75 :
76 : /************************************************************************/
77 : /* BuildFullQueryStatement() */
78 : /************************************************************************/
79 :
80 76 : void OGRPGResultLayer::BuildFullQueryStatement()
81 :
82 : {
83 76 : if( pszQueryStatement != NULL )
84 : {
85 6 : CPLFree( pszQueryStatement );
86 6 : pszQueryStatement = NULL;
87 : }
88 :
89 76 : pszQueryStatement = (char*) CPLMalloc(strlen(pszRawStatement) + strlen(osWHERE) + 40);
90 :
91 76 : if (strlen(osWHERE) == 0)
92 72 : strcpy(pszQueryStatement, pszRawStatement);
93 : else
94 : sprintf(pszQueryStatement, "SELECT * FROM (%s) AS ogrpgsubquery %s",
95 4 : pszRawStatement, osWHERE.c_str());
96 76 : }
97 :
98 : /************************************************************************/
99 : /* ResetReading() */
100 : /************************************************************************/
101 :
102 140 : void OGRPGResultLayer::ResetReading()
103 :
104 : {
105 140 : OGRPGLayer::ResetReading();
106 140 : }
107 :
108 : /************************************************************************/
109 : /* GetFeatureCount() */
110 : /************************************************************************/
111 :
112 48 : int OGRPGResultLayer::GetFeatureCount( int bForce )
113 :
114 : {
115 48 : if( TestCapability(OLCFastFeatureCount) == FALSE )
116 20 : return OGRPGLayer::GetFeatureCount( bForce );
117 :
118 28 : PGconn *hPGConn = poDS->GetPGConn();
119 28 : PGresult *hResult = NULL;
120 28 : CPLString osCommand;
121 28 : int nCount = 0;
122 :
123 : osCommand.Printf(
124 : "SELECT count(*) FROM (%s) AS ogrpgcount",
125 28 : pszQueryStatement );
126 :
127 28 : hResult = OGRPG_PQexec(hPGConn, osCommand);
128 28 : if( hResult != NULL && PQresultStatus(hResult) == PGRES_TUPLES_OK )
129 28 : nCount = atoi(PQgetvalue(hResult,0,0));
130 : else
131 0 : CPLDebug( "PG", "%s; failed.", osCommand.c_str() );
132 28 : OGRPGClearResult( hResult );
133 :
134 28 : return nCount;
135 : }
136 :
137 :
138 : /************************************************************************/
139 : /* TestCapability() */
140 : /************************************************************************/
141 :
142 104 : int OGRPGResultLayer::TestCapability( const char * pszCap )
143 :
144 : {
145 104 : if( EQUAL(pszCap,OLCFastFeatureCount) ||
146 : EQUAL(pszCap,OLCFastSetNextByIndex) )
147 : return (m_poFilterGeom == NULL ||
148 64 : ((bHasPostGISGeometry || bHasPostGISGeography) && nSRSId != UNDETERMINED_SRID)) && m_poAttrQuery == NULL;
149 :
150 40 : else if( EQUAL(pszCap,OLCFastSpatialFilter) )
151 0 : return ((bHasPostGISGeometry || bHasPostGISGeography) && nSRSId != UNDETERMINED_SRID) && m_poAttrQuery == NULL;
152 :
153 40 : else if( EQUAL(pszCap,OLCFastGetExtent) )
154 20 : return (bHasPostGISGeometry && nSRSId != UNDETERMINED_SRID) && m_poAttrQuery == NULL;
155 :
156 20 : else if( EQUAL(pszCap,OLCStringsAsUTF8) )
157 4 : return TRUE;
158 :
159 : else
160 16 : return FALSE;
161 : }
162 :
163 :
164 : /************************************************************************/
165 : /* GetNextFeature() */
166 : /************************************************************************/
167 :
168 5090 : OGRFeature *OGRPGResultLayer::GetNextFeature()
169 :
170 : {
171 :
172 200 : for( ; TRUE; )
173 : {
174 : OGRFeature *poFeature;
175 :
176 5090 : poFeature = GetNextRawFeature();
177 5090 : if( poFeature == NULL )
178 68 : return NULL;
179 :
180 5022 : if( (m_poFilterGeom == NULL
181 : || ((bHasPostGISGeometry || bHasPostGISGeography) && nSRSId != UNDETERMINED_SRID)
182 : || FilterGeometry( poFeature->GetGeometryRef() ) )
183 : && (m_poAttrQuery == NULL
184 : || m_poAttrQuery->Evaluate( poFeature )) )
185 4822 : return poFeature;
186 :
187 200 : delete poFeature;
188 : }
189 : }
190 :
191 : /************************************************************************/
192 : /* SetSpatialFilter() */
193 : /************************************************************************/
194 :
195 32 : void OGRPGResultLayer::SetSpatialFilter( OGRGeometry * poGeomIn )
196 :
197 : {
198 32 : if( InstallFilter( poGeomIn ) )
199 : {
200 20 : if ((bHasPostGISGeometry || bHasPostGISGeography) && nSRSId != UNDETERMINED_SRID)
201 : {
202 6 : if( m_poFilterGeom != NULL)
203 : {
204 : char szBox3D_1[128];
205 : char szBox3D_2[128];
206 : char* pszComma;
207 4 : OGREnvelope sEnvelope;
208 :
209 4 : m_poFilterGeom->getEnvelope( &sEnvelope );
210 4 : snprintf(szBox3D_1, sizeof(szBox3D_1), "%.12f %.12f", sEnvelope.MinX, sEnvelope.MinY);
211 8 : while((pszComma = strchr(szBox3D_1, ',')) != NULL)
212 0 : *pszComma = '.';
213 4 : snprintf(szBox3D_2, sizeof(szBox3D_2), "%.12f %.12f", sEnvelope.MaxX, sEnvelope.MaxY);
214 8 : while((pszComma = strchr(szBox3D_2, ',')) != NULL)
215 0 : *pszComma = '.';
216 : osWHERE.Printf("WHERE %s && %s('BOX3D(%s, %s)'::box3d,%d) ",
217 : OGRPGEscapeColumnName(pszGeomColumn).c_str(),
218 : (poDS->sPostGISVersion.nMajor >= 2) ? "ST_SetSRID" : "SetSRID",
219 4 : szBox3D_1, szBox3D_2, nSRSId );
220 : }
221 : else
222 : {
223 2 : osWHERE = "";
224 : }
225 :
226 6 : BuildFullQueryStatement();
227 : }
228 :
229 20 : ResetReading();
230 : }
231 :
232 32 : }
233 :
234 : /************************************************************************/
235 : /* GetExtent() */
236 : /* */
237 : /* For PostGIS use internal Extend(geometry) function */
238 : /* in other cases we use standard OGRLayer::GetExtent() */
239 : /************************************************************************/
240 :
241 10 : OGRErr OGRPGResultLayer::GetExtent( OGREnvelope *psExtent, int bForce )
242 : {
243 10 : CPLString osCommand;
244 :
245 : const char* pszExtentFct;
246 10 : if (poDS->sPostGISVersion.nMajor >= 2)
247 0 : pszExtentFct = "ST_Extent";
248 : else
249 10 : pszExtentFct = "Extent";
250 :
251 10 : if ( TestCapability(OLCFastGetExtent) )
252 : {
253 : /* Do not take the spatial filter into account */
254 : osCommand.Printf( "SELECT %s(%s) FROM (%s) AS ogrpgextent",
255 : pszExtentFct, OGRPGEscapeColumnName(pszGeomColumn).c_str(),
256 2 : pszRawStatement );
257 : }
258 8 : else if ( bHasPostGISGeography )
259 : {
260 : /* Probably not very efficient, but more efficient than client-side implementation */
261 : osCommand.Printf( "SELECT %s(ST_GeomFromWKB(ST_AsBinary(%s))) FROM (%s) AS ogrpgextent",
262 : pszExtentFct, OGRPGEscapeColumnName(pszGeomColumn).c_str(),
263 2 : pszRawStatement );
264 : }
265 :
266 10 : return RunGetExtentRequest(psExtent, bForce, osCommand);
267 : }
268 :
269 : /************************************************************************/
270 : /* GetSpatialRef() */
271 : /* */
272 : /* We override this to try and fetch the table SRID from the */
273 : /* geometry_columns table if the srsid is UNDETERMINED_SRID */
274 : /* (meaning we haven't yet even looked for it). */
275 : /************************************************************************/
276 :
277 6 : OGRSpatialReference *OGRPGResultLayer::GetSpatialRef()
278 :
279 : {
280 6 : if( nSRSId == UNDETERMINED_SRID )
281 : {
282 : /* We have to get the SRID of the geometry column, so to be able */
283 : /* to do spatial filtering */
284 6 : if (bHasPostGISGeometry)
285 : {
286 4 : CPLString osGetSRID;
287 4 : osGetSRID += "SELECT getsrid(";
288 4 : osGetSRID += OGRPGEscapeColumnName(pszGeomColumn);
289 4 : osGetSRID += ") FROM (";
290 4 : osGetSRID += pszRawStatement;
291 4 : osGetSRID += ") AS ogrpggetsrid LIMIT 1";
292 :
293 4 : PGresult* hSRSIdResult = OGRPG_PQexec(poDS->GetPGConn(), osGetSRID );
294 :
295 4 : nSRSId = -1;
296 :
297 4 : if( hSRSIdResult && PQresultStatus(hSRSIdResult) == PGRES_TUPLES_OK)
298 : {
299 4 : if ( PQntuples(hSRSIdResult) > 0 )
300 4 : nSRSId = atoi(PQgetvalue(hSRSIdResult, 0, 0));
301 : }
302 : else
303 : {
304 : CPLError( CE_Failure, CPLE_AppDefined,
305 0 : "%s", PQerrorMessage(poDS->GetPGConn()) );
306 : }
307 :
308 4 : OGRPGClearResult(hSRSIdResult);
309 : }
310 : }
311 :
312 6 : return OGRPGLayer::GetSpatialRef();
313 : }
|