1 : /******************************************************************************
2 : * $Id: ogrmysqlresultlayer.cpp 20460 2010-08-27 20:06:26Z 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 : *
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_mysql.h"
33 :
34 : CPL_CVSID("$Id: ogrmysqlresultlayer.cpp 20460 2010-08-27 20:06:26Z rouault $");
35 :
36 : /************************************************************************/
37 : /* OGRMySQLResultLayer() */
38 : /************************************************************************/
39 :
40 4 : OGRMySQLResultLayer::OGRMySQLResultLayer( OGRMySQLDataSource *poDSIn,
41 : const char * pszRawQueryIn,
42 4 : MYSQL_RES *hResultSetIn )
43 : {
44 4 : poDS = poDSIn;
45 :
46 4 : iNextShapeId = 0;
47 :
48 4 : pszRawStatement = CPLStrdup(pszRawQueryIn);
49 :
50 4 : hResultSet = hResultSetIn;
51 :
52 4 : BuildFullQueryStatement();
53 :
54 4 : poFeatureDefn = ReadResultDefinition();
55 4 : }
56 :
57 : /************************************************************************/
58 : /* ~OGRMySQLResultLayer() */
59 : /************************************************************************/
60 :
61 4 : OGRMySQLResultLayer::~OGRMySQLResultLayer()
62 :
63 : {
64 4 : CPLFree( pszRawStatement );
65 4 : }
66 :
67 : /************************************************************************/
68 : /* ReadResultDefinition() */
69 : /* */
70 : /* Build a schema from the current resultset. */
71 : /************************************************************************/
72 :
73 4 : OGRFeatureDefn *OGRMySQLResultLayer::ReadResultDefinition()
74 :
75 : {
76 :
77 : /* -------------------------------------------------------------------- */
78 : /* Parse the returned table information. */
79 : /* -------------------------------------------------------------------- */
80 4 : OGRFeatureDefn *poDefn = new OGRFeatureDefn( "sql_statement" );
81 : int iRawField;
82 :
83 4 : poDefn->Reference();
84 : int width;
85 : int precision;
86 :
87 4 : mysql_field_seek( hResultSet, 0 );
88 4 : for( iRawField = 0;
89 : iRawField < (int) mysql_num_fields(hResultSet);
90 : iRawField++ )
91 : {
92 13 : MYSQL_FIELD *psMSField = mysql_fetch_field( hResultSet );
93 13 : OGRFieldDefn oField( psMSField->name, OFTString);
94 :
95 13 : switch( psMSField->type )
96 : {
97 : case FIELD_TYPE_TINY:
98 : case FIELD_TYPE_SHORT:
99 : case FIELD_TYPE_LONG:
100 : case FIELD_TYPE_INT24:
101 : case FIELD_TYPE_LONGLONG:
102 4 : oField.SetType( OFTInteger );
103 4 : width = (int)psMSField->length;
104 4 : oField.SetWidth(width);
105 4 : poDefn->AddFieldDefn( &oField );
106 4 : break;
107 :
108 : case FIELD_TYPE_DECIMAL:
109 : #ifdef FIELD_TYPE_NEWDECIMAL
110 : case FIELD_TYPE_NEWDECIMAL:
111 : #endif
112 4 : oField.SetType( OFTReal );
113 :
114 : // a bunch of hackery to munge the widths that MySQL gives
115 : // us into corresponding widths and precisions for OGR
116 4 : precision = (int)psMSField->decimals;
117 4 : width = (int)psMSField->length;
118 4 : if (!precision)
119 2 : width = width - 1;
120 4 : width = width - precision;
121 :
122 4 : oField.SetWidth(width);
123 4 : oField.SetPrecision(precision);
124 4 : poDefn->AddFieldDefn( &oField );
125 4 : break;
126 :
127 : case FIELD_TYPE_FLOAT:
128 : case FIELD_TYPE_DOUBLE:
129 : /* MYSQL_FIELD is always reporting ->length = 22 and ->decimals = 31
130 : for double type regardless of the data it returned. In an example,
131 : the data it returned had only 5 or 6 decimal places which were
132 : exactly as entered into the database but reported the decimals
133 : as 31. */
134 : /* Assuming that a length of 22 means no particular width and 31
135 : decimals means no particular precision. */
136 1 : width = (int)psMSField->length;
137 1 : precision = (int)psMSField->decimals;
138 1 : oField.SetType( OFTReal );
139 1 : if( width != 22 )
140 0 : oField.SetWidth(width);
141 1 : if( precision != 31 )
142 0 : oField.SetPrecision(precision);
143 1 : poDefn->AddFieldDefn( &oField );
144 1 : break;
145 :
146 : case FIELD_TYPE_DATE:
147 0 : oField.SetType( OFTDate );
148 0 : oField.SetWidth(0);
149 0 : poDefn->AddFieldDefn( &oField );
150 0 : break;
151 :
152 : case FIELD_TYPE_TIME:
153 0 : oField.SetType( OFTTime );
154 0 : oField.SetWidth(0);
155 0 : poDefn->AddFieldDefn( &oField );
156 0 : break;
157 :
158 : case FIELD_TYPE_TIMESTAMP:
159 : case FIELD_TYPE_DATETIME:
160 0 : oField.SetType( OFTDateTime );
161 0 : oField.SetWidth(0);
162 0 : poDefn->AddFieldDefn( &oField );
163 0 : break;
164 :
165 : case FIELD_TYPE_YEAR:
166 : case FIELD_TYPE_STRING:
167 : case FIELD_TYPE_VAR_STRING:
168 1 : oField.SetType( OFTString );
169 1 : oField.SetWidth((int)psMSField->length);
170 1 : poDefn->AddFieldDefn( &oField );
171 1 : break;
172 :
173 : case FIELD_TYPE_TINY_BLOB:
174 : case FIELD_TYPE_MEDIUM_BLOB:
175 : case FIELD_TYPE_LONG_BLOB:
176 : case FIELD_TYPE_BLOB:
177 1 : if( psMSField->charsetnr == 63 )
178 0 : oField.SetType( OFTBinary );
179 : else
180 1 : oField.SetType( OFTString );
181 1 : oField.SetWidth((int)psMSField->max_length);
182 1 : poDefn->AddFieldDefn( &oField );
183 1 : break;
184 :
185 : case FIELD_TYPE_GEOMETRY:
186 2 : if (pszGeomColumn == NULL)
187 : {
188 2 : pszGeomColumnTable = CPLStrdup( psMSField->table);
189 2 : pszGeomColumn = CPLStrdup( psMSField->name);
190 : }
191 : break;
192 :
193 : default:
194 : // any other field we ignore.
195 : break;
196 : }
197 :
198 : // assume a FID name first, and if it isn't there
199 : // take a field that is not null, a primary key,
200 : // and is an integer-like field
201 13 : if( EQUAL(psMSField->name,"ogc_fid") )
202 : {
203 0 : bHasFid = TRUE;
204 0 : pszFIDColumn = CPLStrdup(oField.GetNameRef());
205 0 : continue;
206 : } else
207 13 : if (IS_NOT_NULL(psMSField->flags)
208 : && IS_PRI_KEY(psMSField->flags)
209 : &&
210 : (
211 : psMSField->type == FIELD_TYPE_TINY
212 : || psMSField->type == FIELD_TYPE_SHORT
213 : || psMSField->type == FIELD_TYPE_LONG
214 : || psMSField->type == FIELD_TYPE_INT24
215 : || psMSField->type == FIELD_TYPE_LONGLONG
216 : )
217 : )
218 : {
219 1 : bHasFid = TRUE;
220 1 : pszFIDColumn = CPLStrdup(oField.GetNameRef());
221 1 : continue;
222 : }
223 : }
224 :
225 :
226 4 : poDefn->SetGeomType( wkbNone );
227 :
228 4 : if (pszGeomColumn)
229 : {
230 2 : char* pszType=NULL;
231 2 : CPLString osCommand;
232 : char **papszRow;
233 :
234 : // set to unknown first
235 2 : poDefn->SetGeomType( wkbUnknown );
236 :
237 : osCommand.Printf(
238 : "SELECT type FROM geometry_columns WHERE f_table_name='%s'",
239 2 : pszGeomColumnTable );
240 :
241 2 : if( hResultSet != NULL )
242 2 : mysql_free_result( hResultSet );
243 2 : hResultSet = NULL;
244 :
245 2 : if( !mysql_query( poDS->GetConn(), osCommand ) )
246 2 : hResultSet = mysql_store_result( poDS->GetConn() );
247 :
248 2 : papszRow = NULL;
249 2 : if( hResultSet != NULL )
250 2 : papszRow = mysql_fetch_row( hResultSet );
251 :
252 :
253 2 : if( papszRow != NULL && papszRow[0] != NULL )
254 : {
255 1 : pszType = papszRow[0];
256 :
257 1 : OGRwkbGeometryType nGeomType = OGRFromOGCGeomType(pszType);
258 :
259 1 : poDefn->SetGeomType( nGeomType );
260 :
261 : }
262 :
263 2 : nSRSId = FetchSRSId();
264 : }
265 :
266 :
267 4 : return poDefn;
268 : }
269 :
270 : /************************************************************************/
271 : /* BuildFullQueryStatement() */
272 : /************************************************************************/
273 :
274 4 : void OGRMySQLResultLayer::BuildFullQueryStatement()
275 :
276 : {
277 4 : if( pszQueryStatement != NULL )
278 : {
279 0 : CPLFree( pszQueryStatement );
280 0 : pszQueryStatement = NULL;
281 : }
282 :
283 4 : pszQueryStatement = CPLStrdup(pszRawStatement);
284 4 : }
285 :
286 : /************************************************************************/
287 : /* ResetReading() */
288 : /************************************************************************/
289 :
290 19 : void OGRMySQLResultLayer::ResetReading()
291 :
292 : {
293 19 : OGRMySQLLayer::ResetReading();
294 19 : }
295 :
296 : /************************************************************************/
297 : /* GetFeatureCount() */
298 : /************************************************************************/
299 :
300 2 : int OGRMySQLResultLayer::GetFeatureCount( int bForce )
301 :
302 : {
303 : // I wonder if we could do anything smart here...
304 : // ... not till MySQL grows up (HB)
305 2 : return OGRMySQLLayer::GetFeatureCount( bForce );
306 : }
307 :
308 : /************************************************************************/
309 : /* TestCapability() */
310 : /************************************************************************/
311 :
312 0 : int OGRMySQLResultLayer::TestCapability( const char * pszCap )
313 :
314 : {
315 0 : return FALSE;
316 : }
317 :
|