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