1 /******************************************************************************
2 * $Id: ogrmysqlresultlayer.cpp 28375 2015-01-30 12:06:11Z rouault $
3 *
4 * Project: OpenGIS Simple Features Reference Implementation
5 * Purpose: Implements OGRMySQLResultLayer 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 * Copyright (c) 2008-2010, Even Rouault <even dot rouault at mines-paris dot org>
12 *
13 * Permission is hereby granted, free of charge, to any person obtaining a
14 * copy of this software and associated documentation files (the "Software"),
15 * to deal in the Software without restriction, including without limitation
16 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 * and/or sell copies of the Software, and to permit persons to whom the
18 * Software is furnished to do so, subject to the following conditions:
19 *
20 * The above copyright notice and this permission notice shall be included
21 * in all copies or substantial portions of the Software.
22 *
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 * DEALINGS IN THE SOFTWARE.
30 ****************************************************************************/
31
32 #include "cpl_conv.h"
33 #include "ogr_mysql.h"
34
35 CPL_CVSID("$Id: ogrmysqlresultlayer.cpp 28375 2015-01-30 12:06:11Z rouault $");
36
37 /************************************************************************/
38 /* OGRMySQLResultLayer() */
39 /************************************************************************/
40
OGRMySQLResultLayer(OGRMySQLDataSource * poDSIn,const char * pszRawQueryIn,MYSQL_RES * hResultSetIn)41 OGRMySQLResultLayer::OGRMySQLResultLayer( OGRMySQLDataSource *poDSIn,
42 const char * pszRawQueryIn,
43 MYSQL_RES *hResultSetIn )
44 {
45 poDS = poDSIn;
46
47 iNextShapeId = 0;
48
49 pszRawStatement = CPLStrdup(pszRawQueryIn);
50
51 hResultSet = hResultSetIn;
52
53 BuildFullQueryStatement();
54
55 poFeatureDefn = ReadResultDefinition();
56 }
57
58 /************************************************************************/
59 /* ~OGRMySQLResultLayer() */
60 /************************************************************************/
61
~OGRMySQLResultLayer()62 OGRMySQLResultLayer::~OGRMySQLResultLayer()
63
64 {
65 CPLFree( pszRawStatement );
66 }
67
68 /************************************************************************/
69 /* ReadResultDefinition() */
70 /* */
71 /* Build a schema from the current resultset. */
72 /************************************************************************/
73
ReadResultDefinition()74 OGRFeatureDefn *OGRMySQLResultLayer::ReadResultDefinition()
75
76 {
77
78 /* -------------------------------------------------------------------- */
79 /* Parse the returned table information. */
80 /* -------------------------------------------------------------------- */
81 OGRFeatureDefn *poDefn = new OGRFeatureDefn( "sql_statement" );
82 SetDescription( poDefn->GetName() );
83 int iRawField;
84
85 poDefn->Reference();
86 int width;
87 int precision;
88
89 mysql_field_seek( hResultSet, 0 );
90 for( iRawField = 0;
91 iRawField < (int) mysql_num_fields(hResultSet);
92 iRawField++ )
93 {
94 MYSQL_FIELD *psMSField = mysql_fetch_field( hResultSet );
95 OGRFieldDefn oField( psMSField->name, OFTString);
96
97 switch( psMSField->type )
98 {
99 case FIELD_TYPE_TINY:
100 case FIELD_TYPE_SHORT:
101 case FIELD_TYPE_LONG:
102 case FIELD_TYPE_INT24:
103 case FIELD_TYPE_LONGLONG:
104 oField.SetType( OFTInteger );
105 width = (int)psMSField->length;
106 oField.SetWidth(width);
107 poDefn->AddFieldDefn( &oField );
108 break;
109
110 case FIELD_TYPE_DECIMAL:
111 #ifdef FIELD_TYPE_NEWDECIMAL
112 case FIELD_TYPE_NEWDECIMAL:
113 #endif
114 oField.SetType( OFTReal );
115
116 // a bunch of hackery to munge the widths that MySQL gives
117 // us into corresponding widths and precisions for OGR
118 precision = (int)psMSField->decimals;
119 width = (int)psMSField->length;
120 if (!precision)
121 width = width - 1;
122 width = width - precision;
123
124 oField.SetWidth(width);
125 oField.SetPrecision(precision);
126 poDefn->AddFieldDefn( &oField );
127 break;
128
129 case FIELD_TYPE_FLOAT:
130 case FIELD_TYPE_DOUBLE:
131 /* MYSQL_FIELD is always reporting ->length = 22 and ->decimals = 31
132 for double type regardless of the data it returned. In an example,
133 the data it returned had only 5 or 6 decimal places which were
134 exactly as entered into the database but reported the decimals
135 as 31. */
136 /* Assuming that a length of 22 means no particular width and 31
137 decimals means no particular precision. */
138 width = (int)psMSField->length;
139 precision = (int)psMSField->decimals;
140 oField.SetType( OFTReal );
141 if( width != 22 )
142 oField.SetWidth(width);
143 if( precision != 31 )
144 oField.SetPrecision(precision);
145 poDefn->AddFieldDefn( &oField );
146 break;
147
148 case FIELD_TYPE_DATE:
149 oField.SetType( OFTDate );
150 oField.SetWidth(0);
151 poDefn->AddFieldDefn( &oField );
152 break;
153
154 case FIELD_TYPE_TIME:
155 oField.SetType( OFTTime );
156 oField.SetWidth(0);
157 poDefn->AddFieldDefn( &oField );
158 break;
159
160 case FIELD_TYPE_TIMESTAMP:
161 case FIELD_TYPE_DATETIME:
162 oField.SetType( OFTDateTime );
163 oField.SetWidth(0);
164 poDefn->AddFieldDefn( &oField );
165 break;
166
167 case FIELD_TYPE_YEAR:
168 case FIELD_TYPE_STRING:
169 case FIELD_TYPE_VAR_STRING:
170 oField.SetType( OFTString );
171 oField.SetWidth((int)psMSField->length);
172 poDefn->AddFieldDefn( &oField );
173 break;
174
175 case FIELD_TYPE_TINY_BLOB:
176 case FIELD_TYPE_MEDIUM_BLOB:
177 case FIELD_TYPE_LONG_BLOB:
178 case FIELD_TYPE_BLOB:
179 if( psMSField->charsetnr == 63 )
180 oField.SetType( OFTBinary );
181 else
182 oField.SetType( OFTString );
183 oField.SetWidth((int)psMSField->max_length);
184 poDefn->AddFieldDefn( &oField );
185 break;
186
187 case FIELD_TYPE_GEOMETRY:
188 if (pszGeomColumn == NULL)
189 {
190 pszGeomColumnTable = CPLStrdup( psMSField->table);
191 pszGeomColumn = CPLStrdup( psMSField->name);
192 }
193 break;
194
195 default:
196 // any other field we ignore.
197 break;
198 }
199
200 // assume a FID name first, and if it isn't there
201 // take a field that is not null, a primary key,
202 // and is an integer-like field
203 if( EQUAL(psMSField->name,"ogc_fid") )
204 {
205 bHasFid = TRUE;
206 pszFIDColumn = CPLStrdup(oField.GetNameRef());
207 continue;
208 } else
209 if (IS_NOT_NULL(psMSField->flags)
210 && IS_PRI_KEY(psMSField->flags)
211 &&
212 (
213 psMSField->type == FIELD_TYPE_TINY
214 || psMSField->type == FIELD_TYPE_SHORT
215 || psMSField->type == FIELD_TYPE_LONG
216 || psMSField->type == FIELD_TYPE_INT24
217 || psMSField->type == FIELD_TYPE_LONGLONG
218 )
219 )
220 {
221 bHasFid = TRUE;
222 pszFIDColumn = CPLStrdup(oField.GetNameRef());
223 continue;
224 }
225 }
226
227
228 poDefn->SetGeomType( wkbNone );
229
230 if (pszGeomColumn)
231 {
232 char* pszType=NULL;
233 CPLString osCommand;
234 char **papszRow;
235
236 // set to unknown first
237 poDefn->SetGeomType( wkbUnknown );
238
239 osCommand.Printf(
240 "SELECT type FROM geometry_columns WHERE f_table_name='%s'",
241 pszGeomColumnTable );
242
243 if( hResultSet != NULL )
244 mysql_free_result( hResultSet );
245 hResultSet = NULL;
246
247 if( !mysql_query( poDS->GetConn(), osCommand ) )
248 hResultSet = mysql_store_result( poDS->GetConn() );
249
250 papszRow = NULL;
251 if( hResultSet != NULL )
252 papszRow = mysql_fetch_row( hResultSet );
253
254
255 if( papszRow != NULL && papszRow[0] != NULL )
256 {
257 pszType = papszRow[0];
258
259 OGRwkbGeometryType nGeomType = OGRFromOGCGeomType(pszType);
260
261 poDefn->SetGeomType( nGeomType );
262
263 }
264
265 nSRSId = FetchSRSId();
266 }
267
268
269 return poDefn;
270 }
271
272 /************************************************************************/
273 /* BuildFullQueryStatement() */
274 /************************************************************************/
275
BuildFullQueryStatement()276 void OGRMySQLResultLayer::BuildFullQueryStatement()
277
278 {
279 if( pszQueryStatement != NULL )
280 {
281 CPLFree( pszQueryStatement );
282 pszQueryStatement = NULL;
283 }
284
285 pszQueryStatement = CPLStrdup(pszRawStatement);
286 }
287
288 /************************************************************************/
289 /* ResetReading() */
290 /************************************************************************/
291
ResetReading()292 void OGRMySQLResultLayer::ResetReading()
293
294 {
295 OGRMySQLLayer::ResetReading();
296 }
297
298 /************************************************************************/
299 /* GetFeatureCount() */
300 /************************************************************************/
301
GetFeatureCount(int bForce)302 GIntBig OGRMySQLResultLayer::GetFeatureCount( int bForce )
303
304 {
305 // I wonder if we could do anything smart here...
306 // ... not till MySQL grows up (HB)
307 return OGRMySQLLayer::GetFeatureCount( bForce );
308 }
309
310 /************************************************************************/
311 /* TestCapability() */
312 /************************************************************************/
313
TestCapability(CPL_UNUSED const char * pszCap)314 int OGRMySQLResultLayer::TestCapability( CPL_UNUSED const char * pszCap )
315 {
316 return FALSE;
317 }
318