1 : /******************************************************************************
2 : * $Id: ogrodbclayer.cpp 17755 2009-10-04 21:04:10Z rouault $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Purpose: Implements OGRODBCLayer class, code shared between
6 : * the direct table access, and the generic SQL results.
7 : * Author: Frank Warmerdam, warmerdam@pobox.com
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2003, Frank Warmerdam <warmerdam@pobox.com>
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_odbc.h"
33 : #include "cpl_string.h"
34 :
35 : CPL_CVSID("$Id: ogrodbclayer.cpp 17755 2009-10-04 21:04:10Z rouault $");
36 :
37 : /************************************************************************/
38 : /* OGRODBCLayer() */
39 : /************************************************************************/
40 :
41 0 : OGRODBCLayer::OGRODBCLayer()
42 :
43 : {
44 0 : poDS = NULL;
45 :
46 0 : bGeomColumnWKB = FALSE;
47 0 : pszGeomColumn = NULL;
48 0 : pszFIDColumn = NULL;
49 0 : panFieldOrdinals = NULL;
50 :
51 0 : poStmt = NULL;
52 :
53 0 : iNextShapeId = 0;
54 :
55 0 : poSRS = NULL;
56 0 : nSRSId = -2; // we haven't even queried the database for it yet.
57 0 : }
58 :
59 : /************************************************************************/
60 : /* ~OGRODBCLayer() */
61 : /************************************************************************/
62 :
63 0 : OGRODBCLayer::~OGRODBCLayer()
64 :
65 : {
66 0 : if( m_nFeaturesRead > 0 && poFeatureDefn != NULL )
67 : {
68 : CPLDebug( "OGR_ODBC", "%d features read on layer '%s'.",
69 : (int) m_nFeaturesRead,
70 0 : poFeatureDefn->GetName() );
71 : }
72 :
73 0 : if( poStmt )
74 : {
75 0 : delete poStmt;
76 0 : poStmt = NULL;
77 : }
78 :
79 0 : if( pszGeomColumn )
80 0 : CPLFree( pszGeomColumn );
81 :
82 0 : if ( panFieldOrdinals )
83 0 : CPLFree( panFieldOrdinals );
84 :
85 0 : if( poFeatureDefn )
86 : {
87 0 : poFeatureDefn->Release();
88 0 : poFeatureDefn = NULL;
89 : }
90 :
91 0 : if( poSRS )
92 0 : poSRS->Release();
93 0 : }
94 :
95 : /************************************************************************/
96 : /* BuildFeatureDefn() */
97 : /* */
98 : /* Build feature definition from a set of column definitions */
99 : /* set on a statement. Sift out geometry and FID fields. */
100 : /************************************************************************/
101 :
102 0 : CPLErr OGRODBCLayer::BuildFeatureDefn( const char *pszLayerName,
103 : CPLODBCStatement *poStmt )
104 :
105 : {
106 0 : poFeatureDefn = new OGRFeatureDefn( pszLayerName );
107 0 : int nRawColumns = poStmt->GetColCount();
108 :
109 0 : poFeatureDefn->Reference();
110 :
111 0 : panFieldOrdinals = (int *) CPLMalloc( sizeof(int) * nRawColumns );
112 :
113 0 : for( int iCol = 0; iCol < nRawColumns; iCol++ )
114 : {
115 0 : OGRFieldDefn oField( poStmt->GetColName(iCol), OFTString );
116 :
117 0 : oField.SetWidth( MAX(0,poStmt->GetColSize( iCol )) );
118 :
119 0 : if( pszGeomColumn != NULL
120 : && EQUAL(poStmt->GetColName(iCol),pszGeomColumn) )
121 0 : continue;
122 :
123 0 : switch( CPLODBCStatement::GetTypeMapping(poStmt->GetColType(iCol)) )
124 : {
125 : case SQL_C_SSHORT:
126 : case SQL_C_USHORT:
127 : case SQL_C_SLONG:
128 : case SQL_C_ULONG:
129 0 : oField.SetType( OFTInteger );
130 0 : break;
131 :
132 : case SQL_C_BINARY:
133 0 : oField.SetType( OFTBinary );
134 0 : break;
135 :
136 : case SQL_C_NUMERIC:
137 0 : oField.SetType( OFTReal );
138 0 : oField.SetPrecision( poStmt->GetColPrecision(iCol) );
139 0 : break;
140 :
141 : case SQL_C_FLOAT:
142 : case SQL_C_DOUBLE:
143 0 : oField.SetType( OFTReal );
144 0 : oField.SetWidth( 0 );
145 0 : break;
146 :
147 : case SQL_C_DATE:
148 0 : oField.SetType( OFTDate );
149 0 : break;
150 :
151 : case SQL_C_TIME:
152 0 : oField.SetType( OFTTime );
153 0 : break;
154 :
155 : case SQL_C_TIMESTAMP:
156 0 : oField.SetType( OFTDateTime );
157 : break;
158 :
159 : default:
160 : /* leave it as OFTString */;
161 : }
162 :
163 0 : poFeatureDefn->AddFieldDefn( &oField );
164 0 : panFieldOrdinals[poFeatureDefn->GetFieldCount() - 1] = iCol+1;
165 : }
166 :
167 : /* -------------------------------------------------------------------- */
168 : /* If we don't already have an FID, check if there is a special */
169 : /* FID named column available. */
170 : /* -------------------------------------------------------------------- */
171 0 : if( pszFIDColumn == NULL )
172 : {
173 0 : const char *pszOGR_FID = CPLGetConfigOption("ODBC_OGR_FID","OGR_FID");
174 0 : if( poFeatureDefn->GetFieldIndex( pszOGR_FID ) != -1 )
175 0 : pszFIDColumn = CPLStrdup(pszOGR_FID);
176 : }
177 :
178 0 : if( pszFIDColumn != NULL )
179 : CPLDebug( "OGR_ODBC", "Using column %s as FID for table %s.",
180 0 : pszFIDColumn, poFeatureDefn->GetName() );
181 : else
182 : CPLDebug( "OGR_ODBC", "Table %s has no identified FID column.",
183 0 : poFeatureDefn->GetName() );
184 :
185 0 : return CE_None;
186 : }
187 :
188 :
189 : /************************************************************************/
190 : /* ResetReading() */
191 : /************************************************************************/
192 :
193 0 : void OGRODBCLayer::ResetReading()
194 :
195 : {
196 0 : iNextShapeId = 0;
197 0 : }
198 :
199 : /************************************************************************/
200 : /* GetNextFeature() */
201 : /************************************************************************/
202 :
203 0 : OGRFeature *OGRODBCLayer::GetNextFeature()
204 :
205 : {
206 0 : for( ; TRUE; )
207 : {
208 : OGRFeature *poFeature;
209 :
210 0 : poFeature = GetNextRawFeature();
211 0 : if( poFeature == NULL )
212 0 : return NULL;
213 :
214 0 : if( (m_poFilterGeom == NULL
215 : || FilterGeometry( poFeature->GetGeometryRef() ) )
216 : && (m_poAttrQuery == NULL
217 : || m_poAttrQuery->Evaluate( poFeature )) )
218 0 : return poFeature;
219 :
220 0 : delete poFeature;
221 : }
222 : }
223 :
224 : /************************************************************************/
225 : /* GetNextRawFeature() */
226 : /************************************************************************/
227 :
228 0 : OGRFeature *OGRODBCLayer::GetNextRawFeature()
229 :
230 : {
231 0 : if( GetStatement() == NULL )
232 0 : return NULL;
233 :
234 : /* -------------------------------------------------------------------- */
235 : /* If we are marked to restart then do so, and fetch a record. */
236 : /* -------------------------------------------------------------------- */
237 0 : if( !poStmt->Fetch() )
238 : {
239 0 : delete poStmt;
240 0 : poStmt = NULL;
241 0 : return NULL;
242 : }
243 :
244 : /* -------------------------------------------------------------------- */
245 : /* Create a feature from the current result. */
246 : /* -------------------------------------------------------------------- */
247 : int iField;
248 0 : OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
249 :
250 0 : if( pszFIDColumn != NULL && poStmt->GetColId(pszFIDColumn) > -1 )
251 : poFeature->SetFID(
252 0 : atoi(poStmt->GetColData(poStmt->GetColId(pszFIDColumn))) );
253 : else
254 0 : poFeature->SetFID( iNextShapeId );
255 :
256 0 : iNextShapeId++;
257 0 : m_nFeaturesRead++;
258 :
259 : /* -------------------------------------------------------------------- */
260 : /* Set the fields. */
261 : /* -------------------------------------------------------------------- */
262 0 : for( iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++ )
263 : {
264 0 : int iSrcField = panFieldOrdinals[iField]-1;
265 0 : const char *pszValue = poStmt->GetColData( iSrcField );
266 :
267 0 : if( pszValue == NULL )
268 : /* no value */;
269 0 : else if( poFeature->GetFieldDefnRef(iField)->GetType() == OFTBinary )
270 : poFeature->SetField( iField,
271 : poStmt->GetColDataLength(iSrcField),
272 0 : (GByte *) pszValue );
273 : else
274 0 : poFeature->SetField( iField, pszValue );
275 : }
276 :
277 : /* -------------------------------------------------------------------- */
278 : /* Try to extract a geometry. */
279 : /* -------------------------------------------------------------------- */
280 0 : if( pszGeomColumn != NULL )
281 : {
282 0 : int iField = poStmt->GetColId( pszGeomColumn );
283 0 : const char *pszGeomText = poStmt->GetColData( iField );
284 0 : OGRGeometry *poGeom = NULL;
285 0 : OGRErr eErr = OGRERR_NONE;
286 :
287 0 : if( pszGeomText != NULL && !bGeomColumnWKB )
288 : {
289 : eErr =
290 : OGRGeometryFactory::createFromWkt((char **) &pszGeomText,
291 0 : NULL, &poGeom);
292 : }
293 0 : else if( pszGeomText != NULL && bGeomColumnWKB )
294 : {
295 0 : int nLength = poStmt->GetColDataLength( iField );
296 :
297 : eErr =
298 : OGRGeometryFactory::createFromWkb((unsigned char *) pszGeomText,
299 0 : NULL, &poGeom, nLength);
300 : }
301 :
302 0 : if ( eErr != OGRERR_NONE )
303 : {
304 : const char *pszMessage;
305 :
306 0 : switch ( eErr )
307 : {
308 : case OGRERR_NOT_ENOUGH_DATA:
309 0 : pszMessage = "Not enough data to deserialize";
310 0 : break;
311 : case OGRERR_UNSUPPORTED_GEOMETRY_TYPE:
312 0 : pszMessage = "Unsupported geometry type";
313 0 : break;
314 : case OGRERR_CORRUPT_DATA:
315 0 : pszMessage = "Corrupt data";
316 0 : break;
317 : default:
318 0 : pszMessage = "Unrecognized error";
319 : }
320 : CPLError(CE_Failure, CPLE_AppDefined,
321 0 : "GetNextRawFeature(): %s", pszMessage);
322 : }
323 :
324 0 : if( poGeom != NULL )
325 0 : poFeature->SetGeometryDirectly( poGeom );
326 : }
327 :
328 0 : return poFeature;
329 : }
330 :
331 : /************************************************************************/
332 : /* GetFeature() */
333 : /************************************************************************/
334 :
335 0 : OGRFeature *OGRODBCLayer::GetFeature( long nFeatureId )
336 :
337 : {
338 : /* This should be implemented directly! */
339 :
340 0 : return OGRLayer::GetFeature( nFeatureId );
341 : }
342 :
343 : /************************************************************************/
344 : /* TestCapability() */
345 : /************************************************************************/
346 :
347 0 : int OGRODBCLayer::TestCapability( const char * pszCap )
348 :
349 : {
350 0 : return FALSE;
351 : }
352 :
353 : /************************************************************************/
354 : /* GetSpatialRef() */
355 : /************************************************************************/
356 :
357 0 : OGRSpatialReference *OGRODBCLayer::GetSpatialRef()
358 :
359 : {
360 0 : return poSRS;
361 : }
362 :
|