1 : /******************************************************************************
2 : * $Id: ogrmssqlspatiallayer.cpp 24330 2012-04-28 11:46:49Z tamas $
3 : *
4 : * Project: MSSQL Spatial driver
5 : * Purpose: Definition of classes for OGR MSSQL Spatial driver.
6 : * Author: Tamas Szekeres, szekerest at gmail.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2010, Tamas Szekeres
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_mssqlspatial.h"
31 :
32 : CPL_CVSID("$Id: ogrmssqlspatiallayer.cpp 24330 2012-04-28 11:46:49Z tamas $");
33 : /************************************************************************/
34 : /* OGRMSSQLSpatialLayer() */
35 : /************************************************************************/
36 :
37 0 : OGRMSSQLSpatialLayer::OGRMSSQLSpatialLayer()
38 :
39 : {
40 0 : poDS = NULL;
41 :
42 0 : nGeomColumnType = -1;
43 0 : pszGeomColumn = NULL;
44 0 : pszFIDColumn = NULL;
45 0 : panFieldOrdinals = NULL;
46 :
47 0 : poStmt = NULL;
48 :
49 0 : iNextShapeId = 0;
50 :
51 0 : poSRS = NULL;
52 0 : nSRSId = -1; // we haven't even queried the database for it yet.
53 0 : }
54 :
55 : /************************************************************************/
56 : /* ~OGRMSSQLSpatialLayer() */
57 : /************************************************************************/
58 :
59 0 : OGRMSSQLSpatialLayer::~OGRMSSQLSpatialLayer()
60 :
61 : {
62 0 : if( m_nFeaturesRead > 0 && poFeatureDefn != NULL )
63 : {
64 : CPLDebug( "OGR_MSSQLSpatial", "%d features read on layer '%s'.",
65 : (int) m_nFeaturesRead,
66 0 : poFeatureDefn->GetName() );
67 : }
68 :
69 0 : if( poStmt )
70 : {
71 0 : delete poStmt;
72 0 : poStmt = NULL;
73 : }
74 :
75 0 : CPLFree( pszGeomColumn );
76 0 : CPLFree( pszFIDColumn );
77 0 : CPLFree( panFieldOrdinals );
78 :
79 0 : if( poFeatureDefn )
80 : {
81 0 : poFeatureDefn->Release();
82 0 : poFeatureDefn = NULL;
83 : }
84 :
85 0 : if( poSRS )
86 0 : poSRS->Release();
87 0 : }
88 :
89 : /************************************************************************/
90 : /* BuildFeatureDefn() */
91 : /* */
92 : /* Build feature definition from a set of column definitions */
93 : /* set on a statement. Sift out geometry and FID fields. */
94 : /************************************************************************/
95 :
96 0 : CPLErr OGRMSSQLSpatialLayer::BuildFeatureDefn( const char *pszLayerName,
97 : CPLODBCStatement *poStmt )
98 :
99 : {
100 0 : poFeatureDefn = new OGRFeatureDefn( pszLayerName );
101 0 : int nRawColumns = poStmt->GetColCount();
102 :
103 0 : poFeatureDefn->Reference();
104 :
105 0 : CPLFree(panFieldOrdinals);
106 0 : panFieldOrdinals = (int *) CPLMalloc( sizeof(int) * nRawColumns );
107 :
108 0 : for( int iCol = 0; iCol < nRawColumns; iCol++ )
109 : {
110 0 : if ( pszGeomColumn == NULL )
111 : {
112 : /* need to identify the geometry column */
113 0 : if ( EQUAL(poStmt->GetColTypeName( iCol ), "geometry") )
114 : {
115 0 : nGeomColumnType = MSSQLCOLTYPE_GEOMETRY;
116 0 : pszGeomColumn = CPLStrdup( poStmt->GetColName(iCol) );
117 0 : continue;
118 : }
119 0 : else if ( EQUAL(poStmt->GetColTypeName( iCol ), "geography") )
120 : {
121 0 : nGeomColumnType = MSSQLCOLTYPE_GEOGRAPHY;
122 0 : pszGeomColumn = CPLStrdup( poStmt->GetColName(iCol) );
123 0 : continue;
124 : }
125 0 : else if ( EQUAL(poStmt->GetColTypeName( iCol ), "image") )
126 : {
127 : /* for the select layers we get image type */
128 0 : nGeomColumnType = MSSQLCOLTYPE_BINARY;
129 0 : pszGeomColumn = CPLStrdup( poStmt->GetColName(iCol) );
130 0 : continue;
131 : }
132 : }
133 : else
134 : {
135 0 : if( EQUAL(poStmt->GetColName(iCol),pszGeomColumn) )
136 0 : continue;
137 : }
138 :
139 0 : if( pszFIDColumn != NULL &&
140 : EQUAL(poStmt->GetColName(iCol), pszFIDColumn) )
141 : {
142 : /* skip FID */
143 0 : continue;
144 : }
145 :
146 0 : OGRFieldDefn oField( poStmt->GetColName(iCol), OFTString );
147 0 : oField.SetWidth( MAX(0,poStmt->GetColSize( iCol )) );
148 :
149 0 : switch( CPLODBCStatement::GetTypeMapping(poStmt->GetColType(iCol)) )
150 : {
151 : case SQL_C_SSHORT:
152 : case SQL_C_USHORT:
153 : case SQL_C_SLONG:
154 : case SQL_C_ULONG:
155 0 : oField.SetType( OFTInteger );
156 0 : break;
157 :
158 : case SQL_C_BINARY:
159 0 : oField.SetType( OFTBinary );
160 0 : break;
161 :
162 : case SQL_C_NUMERIC:
163 0 : oField.SetType( OFTReal );
164 0 : oField.SetPrecision( poStmt->GetColPrecision(iCol) );
165 0 : break;
166 :
167 : case SQL_C_FLOAT:
168 : case SQL_C_DOUBLE:
169 0 : oField.SetType( OFTReal );
170 0 : oField.SetWidth( 0 );
171 0 : break;
172 :
173 : case SQL_C_DATE:
174 0 : oField.SetType( OFTDate );
175 0 : break;
176 :
177 : case SQL_C_TIME:
178 0 : oField.SetType( OFTTime );
179 0 : break;
180 :
181 : case SQL_C_TIMESTAMP:
182 0 : oField.SetType( OFTDateTime );
183 : break;
184 :
185 : default:
186 : /* leave it as OFTString */;
187 : }
188 :
189 0 : poFeatureDefn->AddFieldDefn( &oField );
190 0 : panFieldOrdinals[poFeatureDefn->GetFieldCount() - 1] = iCol;
191 : }
192 :
193 : /* -------------------------------------------------------------------- */
194 : /* If we don't already have an FID, check if there is a special */
195 : /* FID named column available. */
196 : /* -------------------------------------------------------------------- */
197 0 : if( pszFIDColumn == NULL )
198 : {
199 0 : const char *pszOGR_FID = CPLGetConfigOption("MSSQLSPATIAL_OGR_FID","OGR_FID");
200 0 : if( poFeatureDefn->GetFieldIndex( pszOGR_FID ) != -1 )
201 0 : pszFIDColumn = CPLStrdup(pszOGR_FID);
202 : }
203 :
204 0 : if( pszFIDColumn != NULL )
205 : CPLDebug( "OGR_MSSQLSpatial", "Using column %s as FID for table %s.",
206 0 : pszFIDColumn, poFeatureDefn->GetName() );
207 : else
208 : CPLDebug( "OGR_MSSQLSpatial", "Table %s has no identified FID column.",
209 0 : poFeatureDefn->GetName() );
210 :
211 0 : return CE_None;
212 : }
213 :
214 :
215 : /************************************************************************/
216 : /* ResetReading() */
217 : /************************************************************************/
218 :
219 0 : void OGRMSSQLSpatialLayer::ResetReading()
220 :
221 : {
222 0 : iNextShapeId = 0;
223 0 : }
224 :
225 : /************************************************************************/
226 : /* GetNextFeature() */
227 : /************************************************************************/
228 :
229 0 : OGRFeature *OGRMSSQLSpatialLayer::GetNextFeature()
230 :
231 : {
232 0 : while( TRUE )
233 : {
234 : OGRFeature *poFeature;
235 :
236 0 : poFeature = GetNextRawFeature();
237 0 : if( poFeature == NULL )
238 0 : return NULL;
239 :
240 0 : if( (m_poFilterGeom == NULL
241 : || FilterGeometry( poFeature->GetGeometryRef() ) )
242 : && (m_poAttrQuery == NULL
243 : || m_poAttrQuery->Evaluate( poFeature )) )
244 0 : return poFeature;
245 :
246 0 : delete poFeature;
247 : }
248 : }
249 :
250 : /************************************************************************/
251 : /* GetNextRawFeature() */
252 : /************************************************************************/
253 :
254 0 : OGRFeature *OGRMSSQLSpatialLayer::GetNextRawFeature()
255 :
256 : {
257 0 : if( GetStatement() == NULL )
258 0 : return NULL;
259 :
260 : /* -------------------------------------------------------------------- */
261 : /* If we are marked to restart then do so, and fetch a record. */
262 : /* -------------------------------------------------------------------- */
263 0 : if( !poStmt->Fetch() )
264 : {
265 0 : delete poStmt;
266 0 : poStmt = NULL;
267 0 : return NULL;
268 : }
269 :
270 : /* -------------------------------------------------------------------- */
271 : /* Create a feature from the current result. */
272 : /* -------------------------------------------------------------------- */
273 : int iField;
274 0 : OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
275 :
276 0 : if( pszFIDColumn != NULL && poStmt->GetColId(pszFIDColumn) > -1 )
277 : poFeature->SetFID(
278 0 : atoi(poStmt->GetColData(poStmt->GetColId(pszFIDColumn))) );
279 : else
280 0 : poFeature->SetFID( iNextShapeId );
281 :
282 0 : iNextShapeId++;
283 0 : m_nFeaturesRead++;
284 :
285 : /* -------------------------------------------------------------------- */
286 : /* Set the fields. */
287 : /* -------------------------------------------------------------------- */
288 0 : for( iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++ )
289 : {
290 0 : int iSrcField = panFieldOrdinals[iField];
291 0 : const char *pszValue = poStmt->GetColData( iSrcField );
292 :
293 0 : if( pszValue == NULL )
294 : /* no value */;
295 0 : else if( poFeature->GetFieldDefnRef(iField)->GetType() == OFTBinary )
296 : poFeature->SetField( iField,
297 : poStmt->GetColDataLength(iSrcField),
298 0 : (GByte *) pszValue );
299 : else
300 0 : poFeature->SetField( iField, pszValue );
301 : }
302 :
303 : /* -------------------------------------------------------------------- */
304 : /* Try to extract a geometry. */
305 : /* -------------------------------------------------------------------- */
306 0 : if( pszGeomColumn != NULL )
307 : {
308 0 : int iField = poStmt->GetColId( pszGeomColumn );
309 0 : const char *pszGeomText = poStmt->GetColData( iField );
310 0 : OGRGeometry *poGeom = NULL;
311 0 : OGRErr eErr = OGRERR_NONE;
312 :
313 0 : if( pszGeomText != NULL )
314 : {
315 0 : int nLength = poStmt->GetColDataLength( iField );
316 :
317 0 : if ( nGeomColumnType == MSSQLCOLTYPE_GEOMETRY ||
318 : nGeomColumnType == MSSQLCOLTYPE_GEOGRAPHY ||
319 : nGeomColumnType == MSSQLCOLTYPE_BINARY)
320 : {
321 0 : switch ( poDS->GetGeometryFormat() )
322 : {
323 : case MSSQLGEOMETRY_NATIVE:
324 : {
325 0 : OGRMSSQLGeometryParser oParser( nGeomColumnType );
326 : eErr = oParser.ParseSqlGeometry(
327 0 : (unsigned char *) pszGeomText, nLength, &poGeom );
328 0 : nSRSId = oParser.GetSRSId();
329 : }
330 0 : break;
331 : case MSSQLGEOMETRY_WKB:
332 : eErr = OGRGeometryFactory::createFromWkb((unsigned char *) pszGeomText,
333 0 : NULL, &poGeom, nLength);
334 0 : break;
335 : case MSSQLGEOMETRY_WKT:
336 : eErr = OGRGeometryFactory::createFromWkt((char **) &pszGeomText,
337 0 : NULL, &poGeom);
338 : break;
339 : }
340 : }
341 0 : else if (nGeomColumnType == MSSQLCOLTYPE_TEXT)
342 : {
343 : eErr = OGRGeometryFactory::createFromWkt((char **) &pszGeomText,
344 0 : NULL, &poGeom);
345 : }
346 : }
347 :
348 0 : if ( eErr != OGRERR_NONE )
349 : {
350 : const char *pszMessage;
351 :
352 0 : switch ( eErr )
353 : {
354 : case OGRERR_NOT_ENOUGH_DATA:
355 0 : pszMessage = "Not enough data to deserialize";
356 0 : break;
357 : case OGRERR_UNSUPPORTED_GEOMETRY_TYPE:
358 0 : pszMessage = "Unsupported geometry type";
359 0 : break;
360 : case OGRERR_CORRUPT_DATA:
361 0 : pszMessage = "Corrupt data";
362 0 : break;
363 : default:
364 0 : pszMessage = "Unrecognized error";
365 : }
366 : CPLError(CE_Failure, CPLE_AppDefined,
367 0 : "GetNextRawFeature(): %s", pszMessage);
368 : }
369 :
370 0 : if( poGeom != NULL )
371 : {
372 0 : if ( GetSpatialRef() )
373 0 : poGeom->assignSpatialReference( poSRS );
374 :
375 0 : poFeature->SetGeometryDirectly( poGeom );
376 : }
377 : }
378 :
379 0 : return poFeature;
380 : }
381 :
382 : /************************************************************************/
383 : /* GetFeature() */
384 : /************************************************************************/
385 :
386 0 : OGRFeature *OGRMSSQLSpatialLayer::GetFeature( long nFeatureId )
387 :
388 : {
389 : /* This should be implemented directly! */
390 :
391 0 : return OGRLayer::GetFeature( nFeatureId );
392 : }
393 :
394 : /************************************************************************/
395 : /* TestCapability() */
396 : /************************************************************************/
397 :
398 0 : int OGRMSSQLSpatialLayer::TestCapability( const char * pszCap )
399 :
400 : {
401 0 : return FALSE;
402 : }
403 :
404 : /************************************************************************/
405 : /* StartTransaction() */
406 : /************************************************************************/
407 :
408 0 : OGRErr OGRMSSQLSpatialLayer::StartTransaction()
409 :
410 : {
411 0 : poDS->GetSession()->BeginTransaction();
412 0 : return OGRERR_NONE;
413 : }
414 :
415 : /************************************************************************/
416 : /* CommitTransaction() */
417 : /************************************************************************/
418 :
419 0 : OGRErr OGRMSSQLSpatialLayer::CommitTransaction()
420 :
421 : {
422 0 : poDS->GetSession()->CommitTransaction();
423 0 : return OGRERR_NONE;
424 : }
425 :
426 : /************************************************************************/
427 : /* RollbackTransaction() */
428 : /************************************************************************/
429 :
430 0 : OGRErr OGRMSSQLSpatialLayer::RollbackTransaction()
431 :
432 : {
433 0 : poDS->GetSession()->RollbackTransaction();
434 0 : return OGRERR_NONE;
435 : }
436 :
437 : /************************************************************************/
438 : /* GetSpatialRef() */
439 : /************************************************************************/
440 :
441 0 : OGRSpatialReference *OGRMSSQLSpatialLayer::GetSpatialRef()
442 :
443 : {
444 0 : if( poSRS == NULL && nSRSId > 0 )
445 : {
446 0 : poSRS = poDS->FetchSRS( nSRSId );
447 0 : if( poSRS != NULL )
448 0 : poSRS->Reference();
449 : else
450 0 : nSRSId = 0;
451 : }
452 :
453 0 : return poSRS;
454 : }
455 :
456 : /************************************************************************/
457 : /* GetFIDColumn() */
458 : /************************************************************************/
459 :
460 0 : const char *OGRMSSQLSpatialLayer::GetFIDColumn()
461 :
462 : {
463 0 : GetLayerDefn();
464 :
465 0 : if( pszFIDColumn != NULL )
466 0 : return pszFIDColumn;
467 : else
468 0 : return "";
469 : }
470 :
471 : /************************************************************************/
472 : /* GetGeometryColumn() */
473 : /************************************************************************/
474 :
475 0 : const char *OGRMSSQLSpatialLayer::GetGeometryColumn()
476 :
477 : {
478 0 : GetLayerDefn();
479 :
480 0 : if( pszGeomColumn != NULL )
481 0 : return pszGeomColumn;
482 : else
483 0 : return "";
484 : }
485 :
486 : /************************************************************************/
487 : /* GByteArrayToHexString() */
488 : /************************************************************************/
489 :
490 0 : char* OGRMSSQLSpatialLayer::GByteArrayToHexString( const GByte* pabyData, int nLen)
491 : {
492 : char* pszTextBuf;
493 :
494 0 : pszTextBuf = (char *) CPLMalloc(nLen*2+3);
495 :
496 0 : int iSrc, iDst=0;
497 :
498 0 : for( iSrc = 0; iSrc < nLen; iSrc++ )
499 : {
500 0 : if( iSrc == 0 )
501 : {
502 0 : sprintf( pszTextBuf+iDst, "0x%02x", pabyData[iSrc] );
503 0 : iDst += 4;
504 : }
505 : else
506 : {
507 0 : sprintf( pszTextBuf+iDst, "%02x", pabyData[iSrc] );
508 0 : iDst += 2;
509 : }
510 : }
511 0 : pszTextBuf[iDst] = 0;
512 :
513 0 : return pszTextBuf;
514 : }
515 :
|