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