1 : /******************************************************************************
2 : * $Id: ogrmysqllayer.cpp 14272 2008-04-12 13:47:54Z rouault $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Purpose: Implements OGRMySQLLayer class.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : * Author: Howard Butler, hobu@hobu.net
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2004, 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 "ogr_mysql.h"
32 : #include "cpl_conv.h"
33 : #include "cpl_string.h"
34 :
35 : CPL_CVSID("$Id: ogrmysqllayer.cpp 14272 2008-04-12 13:47:54Z rouault $");
36 :
37 : /************************************************************************/
38 : /* OGRMySQLLayer() */
39 : /************************************************************************/
40 :
41 7 : OGRMySQLLayer::OGRMySQLLayer()
42 :
43 : {
44 7 : poDS = NULL;
45 :
46 7 : pszGeomColumn = NULL;
47 7 : pszGeomColumnTable = NULL;
48 7 : pszFIDColumn = NULL;
49 7 : pszQueryStatement = NULL;
50 :
51 7 : bHasFid = FALSE;
52 7 : pszFIDColumn = NULL;
53 :
54 7 : iNextShapeId = 0;
55 7 : nResultOffset = 0;
56 :
57 7 : poSRS = NULL;
58 7 : nSRSId = -2; // we haven't even queried the database for it yet.
59 :
60 7 : poFeatureDefn = NULL;
61 :
62 7 : hResultSet = NULL;
63 7 : }
64 :
65 : /************************************************************************/
66 : /* ~OGRMySQLLayer() */
67 : /************************************************************************/
68 :
69 7 : OGRMySQLLayer::~OGRMySQLLayer()
70 :
71 : {
72 7 : if( m_nFeaturesRead > 0 && poFeatureDefn != NULL )
73 : {
74 : CPLDebug( "MySQL", "%d features read on layer '%s'.",
75 : (int) m_nFeaturesRead,
76 6 : poFeatureDefn->GetName() );
77 : }
78 :
79 7 : ResetReading();
80 :
81 7 : CPLFree( pszGeomColumn );
82 7 : CPLFree( pszGeomColumnTable );
83 7 : CPLFree( pszFIDColumn );
84 7 : CPLFree( pszQueryStatement );
85 :
86 7 : if( poSRS != NULL )
87 1 : poSRS->Release();
88 :
89 7 : if( poFeatureDefn )
90 7 : poFeatureDefn->Release();
91 7 : }
92 :
93 : /************************************************************************/
94 : /* ResetReading() */
95 : /************************************************************************/
96 :
97 82 : void OGRMySQLLayer::ResetReading()
98 :
99 : {
100 82 : iNextShapeId = 0;
101 :
102 82 : if( hResultSet != NULL )
103 : {
104 25 : mysql_free_result( hResultSet );
105 25 : hResultSet = NULL;
106 :
107 25 : poDS->InterruptLongResult();
108 : }
109 82 : }
110 :
111 : /************************************************************************/
112 : /* GetNextFeature() */
113 : /************************************************************************/
114 :
115 66 : OGRFeature *OGRMySQLLayer::GetNextFeature()
116 :
117 : {
118 :
119 2 : for( ; TRUE; )
120 : {
121 : OGRFeature *poFeature;
122 :
123 66 : poFeature = GetNextRawFeature();
124 66 : if( poFeature == NULL )
125 11 : return NULL;
126 :
127 55 : if( (m_poFilterGeom == NULL
128 : || FilterGeometry( poFeature->GetGeometryRef() ) )
129 : && (m_poAttrQuery == NULL
130 : || m_poAttrQuery->Evaluate( poFeature )) )
131 53 : return poFeature;
132 :
133 2 : delete poFeature;
134 : }
135 : }
136 : /************************************************************************/
137 : /* RecordToFeature() */
138 : /* */
139 : /* Convert the indicated record of the current result set into */
140 : /* a feature. */
141 : /************************************************************************/
142 :
143 56 : OGRFeature *OGRMySQLLayer::RecordToFeature( char **papszRow,
144 : unsigned long *panLengths )
145 :
146 : {
147 56 : mysql_field_seek( hResultSet, 0 );
148 :
149 : /* -------------------------------------------------------------------- */
150 : /* Create a feature from the current result. */
151 : /* -------------------------------------------------------------------- */
152 : int iField;
153 56 : OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
154 :
155 56 : poFeature->SetFID( iNextShapeId );
156 56 : m_nFeaturesRead++;
157 :
158 : /* ==================================================================== */
159 : /* Transfer all result fields we can. */
160 : /* ==================================================================== */
161 272 : for( iField = 0;
162 : iField < (int) mysql_num_fields(hResultSet);
163 : iField++ )
164 : {
165 : int iOGRField;
166 216 : MYSQL_FIELD *psMSField = mysql_fetch_field(hResultSet);
167 :
168 : /* -------------------------------------------------------------------- */
169 : /* Handle FID. */
170 : /* -------------------------------------------------------------------- */
171 216 : if( bHasFid && EQUAL(psMSField->name,pszFIDColumn) )
172 : {
173 33 : if( papszRow[iField] == NULL )
174 : {
175 : CPLError( CE_Failure, CPLE_AppDefined,
176 0 : "NULL primary key in RecordToFeature()" );
177 0 : return NULL;
178 : }
179 :
180 33 : poFeature->SetFID( atoi(papszRow[iField]) );
181 : }
182 :
183 216 : if( papszRow[iField] == NULL )
184 : {
185 : // CPLDebug("MYSQL", "%s was null for %d", psMSField->name,
186 : // iNextShapeId);
187 57 : continue;
188 : }
189 :
190 : /* -------------------------------------------------------------------- */
191 : /* Handle MySQL geometry */
192 : /* -------------------------------------------------------------------- */
193 159 : if( pszGeomColumn && EQUAL(psMSField->name,pszGeomColumn))
194 : {
195 33 : OGRGeometry *poGeometry = NULL;
196 :
197 : // Geometry columns will have the first 4 bytes contain the SRID.
198 : OGRGeometryFactory::createFromWkb(
199 33 : ((GByte *)papszRow[iField]) + 4,
200 : NULL,
201 : &poGeometry,
202 66 : panLengths[iField] - 4 );
203 :
204 33 : if( poGeometry != NULL )
205 : {
206 32 : poGeometry->assignSpatialReference( poSRS );
207 32 : poFeature->SetGeometryDirectly( poGeometry );
208 : }
209 33 : continue;
210 : }
211 :
212 :
213 : /* -------------------------------------------------------------------- */
214 : /* Transfer regular data fields. */
215 : /* -------------------------------------------------------------------- */
216 126 : iOGRField = poFeatureDefn->GetFieldIndex(psMSField->name);
217 126 : if( iOGRField < 0 )
218 29 : continue;
219 :
220 97 : OGRFieldDefn *psFieldDefn = poFeatureDefn->GetFieldDefn( iOGRField );
221 :
222 97 : if( psFieldDefn->GetType() == OFTBinary )
223 : {
224 0 : poFeature->SetField( iOGRField, panLengths[iField],
225 0 : (GByte *) papszRow[iField] );
226 : }
227 : else
228 : {
229 97 : poFeature->SetField( iOGRField, papszRow[iField] );
230 : }
231 : }
232 :
233 56 : return poFeature;
234 : }
235 :
236 : /************************************************************************/
237 : /* GetNextRawFeature() */
238 : /************************************************************************/
239 :
240 66 : OGRFeature *OGRMySQLLayer::GetNextRawFeature()
241 :
242 : {
243 : /* -------------------------------------------------------------------- */
244 : /* Do we need to establish an initial query? */
245 : /* -------------------------------------------------------------------- */
246 66 : if( iNextShapeId == 0 && hResultSet == NULL )
247 : {
248 : CPLAssert( pszQueryStatement != NULL );
249 :
250 23 : poDS->RequestLongResult( this );
251 :
252 23 : if( mysql_query( poDS->GetConn(), pszQueryStatement ) )
253 : {
254 0 : poDS->ReportError( pszQueryStatement );
255 0 : return NULL;
256 : }
257 :
258 23 : hResultSet = mysql_use_result( poDS->GetConn() );
259 23 : if( hResultSet == NULL )
260 : {
261 0 : poDS->ReportError( "mysql_use_result() failed on query." );
262 0 : return FALSE;
263 : }
264 : }
265 :
266 : /* -------------------------------------------------------------------- */
267 : /* Fetch next record. */
268 : /* -------------------------------------------------------------------- */
269 : char **papszRow;
270 : unsigned long *panLengths;
271 :
272 66 : papszRow = mysql_fetch_row( hResultSet );
273 66 : if( papszRow == NULL )
274 : {
275 11 : ResetReading();
276 11 : return NULL;
277 : }
278 :
279 55 : panLengths = mysql_fetch_lengths( hResultSet );
280 :
281 : /* -------------------------------------------------------------------- */
282 : /* Process record. */
283 : /* -------------------------------------------------------------------- */
284 55 : OGRFeature *poFeature = RecordToFeature( papszRow, panLengths );
285 :
286 55 : iNextShapeId++;
287 :
288 55 : return poFeature;
289 : }
290 :
291 : /************************************************************************/
292 : /* GetFeature() */
293 : /* */
294 : /* Note that we actually override this in OGRMySQLTableLayer. */
295 : /************************************************************************/
296 :
297 0 : OGRFeature *OGRMySQLLayer::GetFeature( long nFeatureId )
298 :
299 : {
300 0 : return OGRLayer::GetFeature( nFeatureId );
301 : }
302 :
303 : /************************************************************************/
304 : /* GetFIDColumn() */
305 : /************************************************************************/
306 :
307 0 : const char *OGRMySQLLayer::GetFIDColumn()
308 :
309 : {
310 0 : if( pszFIDColumn != NULL )
311 0 : return pszFIDColumn;
312 : else
313 0 : return "";
314 : }
315 :
316 : /************************************************************************/
317 : /* GetGeometryColumn() */
318 : /************************************************************************/
319 :
320 0 : const char *OGRMySQLLayer::GetGeometryColumn()
321 :
322 : {
323 0 : if( pszGeomColumn != NULL )
324 0 : return pszGeomColumn;
325 : else
326 0 : return "";
327 : }
328 :
329 :
330 : /************************************************************************/
331 : /* FetchSRSId() */
332 : /************************************************************************/
333 :
334 5 : int OGRMySQLLayer::FetchSRSId()
335 : {
336 : char szCommand[1024];
337 : char **papszRow;
338 :
339 5 : if( hResultSet != NULL )
340 1 : mysql_free_result( hResultSet );
341 5 : hResultSet = NULL;
342 :
343 : sprintf( szCommand,
344 : "SELECT srid FROM geometry_columns "
345 : "WHERE f_table_name = '%s'",
346 5 : pszGeomColumnTable );
347 :
348 5 : if( !mysql_query( poDS->GetConn(), szCommand ) )
349 5 : hResultSet = mysql_store_result( poDS->GetConn() );
350 :
351 5 : papszRow = NULL;
352 5 : if( hResultSet != NULL )
353 5 : papszRow = mysql_fetch_row( hResultSet );
354 :
355 :
356 5 : if( papszRow != NULL && papszRow[0] != NULL )
357 : {
358 2 : nSRSId = atoi(papszRow[0]);
359 : }
360 :
361 : // make sure to free our results
362 5 : if( hResultSet != NULL )
363 5 : mysql_free_result( hResultSet );
364 5 : hResultSet = NULL;
365 :
366 5 : return nSRSId;
367 : }
368 :
369 : /************************************************************************/
370 : /* GetSpatialRef() */
371 : /************************************************************************/
372 :
373 1 : OGRSpatialReference *OGRMySQLLayer::GetSpatialRef()
374 :
375 : {
376 :
377 :
378 1 : if( poSRS == NULL && nSRSId > -1 )
379 : {
380 1 : poSRS = poDS->FetchSRS( nSRSId );
381 1 : if( poSRS != NULL )
382 1 : poSRS->Reference();
383 : else
384 0 : nSRSId = -1;
385 : }
386 :
387 1 : return poSRS;
388 :
389 : }
|