1 : /******************************************************************************
2 : * $Id: ogrodbctablelayer.cpp 24961 2012-09-23 18:06:49Z rouault $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Purpose: Implements OGRODBCTableLayer class, access to an existing table.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2003, Frank Warmerdam
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "cpl_conv.h"
31 : #include "ogr_odbc.h"
32 :
33 : CPL_CVSID("$Id: ogrodbctablelayer.cpp 24961 2012-09-23 18:06:49Z rouault $");
34 : /************************************************************************/
35 : /* OGRODBCTableLayer() */
36 : /************************************************************************/
37 :
38 0 : OGRODBCTableLayer::OGRODBCTableLayer( OGRODBCDataSource *poDSIn )
39 :
40 : {
41 0 : poDS = poDSIn;
42 :
43 0 : pszQuery = NULL;
44 :
45 0 : bUpdateAccess = TRUE;
46 0 : bHaveSpatialExtents = FALSE;
47 :
48 0 : iNextShapeId = 0;
49 :
50 0 : nSRSId = -1;
51 :
52 0 : poFeatureDefn = NULL;
53 :
54 0 : pszTableName = NULL;
55 0 : pszSchemaName = NULL;
56 0 : }
57 :
58 : /************************************************************************/
59 : /* ~OGRODBCTableLayer() */
60 : /************************************************************************/
61 :
62 0 : OGRODBCTableLayer::~OGRODBCTableLayer()
63 :
64 : {
65 0 : CPLFree( pszTableName );
66 0 : CPLFree( pszSchemaName );
67 :
68 0 : CPLFree( pszQuery );
69 0 : ClearStatement();
70 0 : }
71 :
72 : /************************************************************************/
73 : /* Initialize() */
74 : /************************************************************************/
75 :
76 0 : CPLErr OGRODBCTableLayer::Initialize( const char *pszLayerName,
77 : const char *pszGeomCol )
78 :
79 : {
80 0 : CPLODBCSession *poSession = poDS->GetSession();
81 :
82 0 : CPLFree( pszFIDColumn );
83 0 : pszFIDColumn = NULL;
84 :
85 : /* -------------------------------------------------------------------- */
86 : /* Parse out schema name if present in layer. We assume a */
87 : /* schema is provided if there is a dot in the name, and that */
88 : /* it is in the form <schema>.<tablename> */
89 : /* -------------------------------------------------------------------- */
90 0 : const char *pszDot = strstr(pszLayerName,".");
91 0 : if( pszDot != NULL )
92 : {
93 0 : pszTableName = CPLStrdup(pszDot + 1);
94 0 : pszSchemaName = CPLStrdup(pszLayerName);
95 0 : pszSchemaName[pszDot - pszLayerName] = '\0';
96 : }
97 : else
98 : {
99 0 : pszTableName = CPLStrdup(pszLayerName);
100 : }
101 :
102 : /* -------------------------------------------------------------------- */
103 : /* Do we have a simple primary key? */
104 : /* -------------------------------------------------------------------- */
105 0 : CPLODBCStatement oGetKey( poSession );
106 :
107 0 : if( oGetKey.GetPrimaryKeys( pszTableName, NULL, pszSchemaName )
108 : && oGetKey.Fetch() )
109 : {
110 0 : pszFIDColumn = CPLStrdup(oGetKey.GetColData( 3 ));
111 :
112 0 : if( oGetKey.Fetch() ) // more than one field in key!
113 : {
114 0 : CPLFree( pszFIDColumn );
115 0 : pszFIDColumn = NULL;
116 :
117 : CPLDebug( "OGR_ODBC", "Table %s has multiple primary key fields, "
118 0 : "ignoring them all.", pszTableName );
119 : }
120 : }
121 :
122 : /* -------------------------------------------------------------------- */
123 : /* Have we been provided a geometry column? */
124 : /* -------------------------------------------------------------------- */
125 0 : CPLFree( pszGeomColumn );
126 0 : if( pszGeomCol == NULL )
127 0 : pszGeomColumn = NULL;
128 : else
129 0 : pszGeomColumn = CPLStrdup( pszGeomCol );
130 :
131 : /* -------------------------------------------------------------------- */
132 : /* Get the column definitions for this table. */
133 : /* -------------------------------------------------------------------- */
134 0 : CPLODBCStatement oGetCol( poSession );
135 : CPLErr eErr;
136 :
137 0 : if( !oGetCol.GetColumns( pszTableName, NULL, pszSchemaName ) )
138 0 : return CE_Failure;
139 :
140 0 : eErr = BuildFeatureDefn( pszLayerName, &oGetCol );
141 0 : if( eErr != CE_None )
142 0 : return eErr;
143 :
144 0 : if( poFeatureDefn->GetFieldCount() == 0 )
145 : {
146 : CPLError( CE_Warning, CPLE_AppDefined,
147 : "No column definitions found for table '%s', layer not usable.",
148 0 : pszLayerName );
149 0 : return CE_Failure;
150 : }
151 :
152 : /* -------------------------------------------------------------------- */
153 : /* Do we have XMIN, YMIN, XMAX, YMAX extent fields? */
154 : /* -------------------------------------------------------------------- */
155 0 : if( poFeatureDefn->GetFieldIndex( "XMIN" ) != -1
156 : && poFeatureDefn->GetFieldIndex( "XMAX" ) != -1
157 : && poFeatureDefn->GetFieldIndex( "YMIN" ) != -1
158 : && poFeatureDefn->GetFieldIndex( "YMAX" ) != -1 )
159 : {
160 0 : bHaveSpatialExtents = TRUE;
161 : CPLDebug( "OGR_ODBC", "Table %s has geometry extent fields.",
162 0 : pszLayerName );
163 : }
164 :
165 : /* -------------------------------------------------------------------- */
166 : /* If we got a geometry column, does it exist? Is it binary? */
167 : /* -------------------------------------------------------------------- */
168 0 : if( pszGeomColumn != NULL )
169 : {
170 0 : int iColumn = oGetCol.GetColId( pszGeomColumn );
171 0 : if( iColumn < 0 )
172 : {
173 : CPLError( CE_Failure, CPLE_AppDefined,
174 : "Column %s requested for geometry, but it does not exist.",
175 0 : pszGeomColumn );
176 0 : CPLFree( pszGeomColumn );
177 0 : pszGeomColumn = NULL;
178 : }
179 : else
180 : {
181 0 : if( CPLODBCStatement::GetTypeMapping(
182 : oGetCol.GetColType( iColumn )) == SQL_C_BINARY )
183 0 : bGeomColumnWKB = TRUE;
184 : }
185 : }
186 :
187 :
188 0 : return CE_None;
189 : }
190 :
191 : /************************************************************************/
192 : /* ClearStatement() */
193 : /************************************************************************/
194 :
195 0 : void OGRODBCTableLayer::ClearStatement()
196 :
197 : {
198 0 : if( poStmt != NULL )
199 : {
200 0 : delete poStmt;
201 0 : poStmt = NULL;
202 : }
203 0 : }
204 :
205 : /************************************************************************/
206 : /* GetStatement() */
207 : /************************************************************************/
208 :
209 0 : CPLODBCStatement *OGRODBCTableLayer::GetStatement()
210 :
211 : {
212 0 : if( poStmt == NULL )
213 0 : ResetStatement();
214 :
215 0 : return poStmt;
216 : }
217 :
218 : /************************************************************************/
219 : /* ResetStatement() */
220 : /************************************************************************/
221 :
222 0 : OGRErr OGRODBCTableLayer::ResetStatement()
223 :
224 : {
225 0 : ClearStatement();
226 :
227 0 : iNextShapeId = 0;
228 :
229 0 : poStmt = new CPLODBCStatement( poDS->GetSession() );
230 0 : poStmt->Append( "SELECT * FROM " );
231 0 : poStmt->Append( poFeatureDefn->GetName() );
232 :
233 : /* Append attribute query if we have it */
234 0 : if( pszQuery != NULL )
235 0 : poStmt->Appendf( " WHERE %s", pszQuery );
236 :
237 : /* If we have a spatial filter, and per record extents, query on it */
238 0 : if( m_poFilterGeom != NULL && bHaveSpatialExtents )
239 : {
240 0 : if( pszQuery == NULL )
241 0 : poStmt->Append( " WHERE" );
242 : else
243 0 : poStmt->Append( " AND" );
244 :
245 : poStmt->Appendf( " XMAX > %.8f AND XMIN < %.8f"
246 : " AND YMAX > %.8f AND YMIN < %.8f",
247 : m_sFilterEnvelope.MinX, m_sFilterEnvelope.MaxX,
248 0 : m_sFilterEnvelope.MinY, m_sFilterEnvelope.MaxY );
249 : }
250 :
251 0 : CPLDebug( "OGR_ODBC", "ExecuteSQL(%s)", poStmt->GetCommand() );
252 0 : if( poStmt->ExecuteSQL() )
253 0 : return OGRERR_NONE;
254 : else
255 : {
256 0 : delete poStmt;
257 0 : poStmt = NULL;
258 0 : return OGRERR_FAILURE;
259 : }
260 : }
261 :
262 : /************************************************************************/
263 : /* ResetReading() */
264 : /************************************************************************/
265 :
266 0 : void OGRODBCTableLayer::ResetReading()
267 :
268 : {
269 0 : ClearStatement();
270 0 : OGRODBCLayer::ResetReading();
271 0 : }
272 :
273 : /************************************************************************/
274 : /* GetFeature() */
275 : /************************************************************************/
276 :
277 0 : OGRFeature *OGRODBCTableLayer::GetFeature( long nFeatureId )
278 :
279 : {
280 0 : if( pszFIDColumn == NULL )
281 0 : return OGRODBCLayer::GetFeature( nFeatureId );
282 :
283 0 : ClearStatement();
284 :
285 0 : iNextShapeId = nFeatureId;
286 :
287 0 : poStmt = new CPLODBCStatement( poDS->GetSession() );
288 0 : poStmt->Append( "SELECT * FROM " );
289 0 : poStmt->Append( poFeatureDefn->GetName() );
290 0 : poStmt->Appendf( " WHERE %s = %ld", pszFIDColumn, nFeatureId );
291 :
292 0 : if( !poStmt->ExecuteSQL() )
293 : {
294 0 : delete poStmt;
295 0 : poStmt = NULL;
296 0 : return NULL;
297 : }
298 :
299 0 : return GetNextRawFeature();
300 : }
301 :
302 : /************************************************************************/
303 : /* SetAttributeFilter() */
304 : /************************************************************************/
305 :
306 0 : OGRErr OGRODBCTableLayer::SetAttributeFilter( const char *pszQuery )
307 :
308 : {
309 0 : if( (pszQuery == NULL && this->pszQuery == NULL)
310 : || (pszQuery != NULL && this->pszQuery != NULL
311 : && EQUAL(pszQuery,this->pszQuery)) )
312 0 : return OGRERR_NONE;
313 :
314 0 : CPLFree( this->pszQuery );
315 0 : this->pszQuery = (pszQuery != NULL ) ? CPLStrdup( pszQuery ) : NULL;
316 :
317 0 : ClearStatement();
318 :
319 0 : return OGRERR_NONE;
320 : }
321 :
322 :
323 : /************************************************************************/
324 : /* TestCapability() */
325 : /************************************************************************/
326 :
327 0 : int OGRODBCTableLayer::TestCapability( const char * pszCap )
328 :
329 : {
330 0 : if( EQUAL(pszCap,OLCRandomRead) )
331 0 : return TRUE;
332 :
333 : else
334 0 : return OGRODBCLayer::TestCapability( pszCap );
335 : }
336 :
337 : /************************************************************************/
338 : /* GetFeatureCount() */
339 : /* */
340 : /* If a spatial filter is in effect, we turn control over to */
341 : /* the generic counter. Otherwise we return the total count. */
342 : /* Eventually we should consider implementing a more efficient */
343 : /* way of counting features matching a spatial query. */
344 : /************************************************************************/
345 :
346 0 : int OGRODBCTableLayer::GetFeatureCount( int bForce )
347 :
348 : {
349 0 : if( m_poFilterGeom != NULL )
350 0 : return OGRODBCLayer::GetFeatureCount( bForce );
351 :
352 0 : CPLODBCStatement oStmt( poDS->GetSession() );
353 0 : oStmt.Append( "SELECT COUNT(*) FROM " );
354 0 : oStmt.Append( poFeatureDefn->GetName() );
355 :
356 0 : if( pszQuery != NULL )
357 0 : oStmt.Appendf( " WHERE %s", pszQuery );
358 :
359 0 : if( !oStmt.ExecuteSQL() || !oStmt.Fetch() )
360 : {
361 : CPLError( CE_Failure, CPLE_AppDefined,
362 : "GetFeatureCount() failed on query %s.\n%s",
363 0 : oStmt.GetCommand(), poDS->GetSession()->GetLastError() );
364 0 : return OGRODBCLayer::GetFeatureCount(bForce);
365 : }
366 :
367 0 : return atoi(oStmt.GetColData(0));
368 : }
369 :
370 : /************************************************************************/
371 : /* GetSpatialRef() */
372 : /* */
373 : /* We override this to try and fetch the table SRID from the */
374 : /* geometry_columns table if the srsid is -2 (meaning we */
375 : /* haven't yet even looked for it). */
376 : /************************************************************************/
377 :
378 0 : OGRSpatialReference *OGRODBCTableLayer::GetSpatialRef()
379 :
380 : {
381 : #ifdef notdef
382 : if( nSRSId == -2 )
383 : {
384 : PGconn *hPGConn = poDS->GetPGConn();
385 : PGresult *hResult;
386 : char szCommand[1024];
387 :
388 : nSRSId = -1;
389 :
390 : poDS->SoftStartTransaction();
391 :
392 : sprintf( szCommand,
393 : "SELECT srid FROM geometry_columns "
394 : "WHERE f_table_name = '%s'",
395 : poFeatureDefn->GetName() );
396 : hResult = PQexec(hPGConn, szCommand );
397 :
398 : if( hResult
399 : && PQresultStatus(hResult) == PGRES_TUPLES_OK
400 : && PQntuples(hResult) == 1 )
401 : {
402 : nSRSId = atoi(PQgetvalue(hResult,0,0));
403 : }
404 :
405 : poDS->SoftCommit();
406 : }
407 : #endif
408 :
409 0 : return OGRODBCLayer::GetSpatialRef();
410 : }
411 :
|