1 : /******************************************************************************
2 : * $Id: ogrmssqlspatiallayer.cpp 24967 2012-09-24 21:51:46Z 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 24967 2012-09-24 21:51:46Z 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 : case MSSQLGEOMETRY_WKBZM:
333 : eErr = OGRGeometryFactory::createFromWkb((unsigned char *) pszGeomText,
334 0 : NULL, &poGeom, nLength);
335 0 : break;
336 : case MSSQLGEOMETRY_WKT:
337 : eErr = OGRGeometryFactory::createFromWkt((char **) &pszGeomText,
338 0 : NULL, &poGeom);
339 : break;
340 : }
341 : }
342 0 : else if (nGeomColumnType == MSSQLCOLTYPE_TEXT)
343 : {
344 : eErr = OGRGeometryFactory::createFromWkt((char **) &pszGeomText,
345 0 : NULL, &poGeom);
346 : }
347 : }
348 :
349 0 : if ( eErr != OGRERR_NONE )
350 : {
351 : const char *pszMessage;
352 :
353 0 : switch ( eErr )
354 : {
355 : case OGRERR_NOT_ENOUGH_DATA:
356 0 : pszMessage = "Not enough data to deserialize";
357 0 : break;
358 : case OGRERR_UNSUPPORTED_GEOMETRY_TYPE:
359 0 : pszMessage = "Unsupported geometry type";
360 0 : break;
361 : case OGRERR_CORRUPT_DATA:
362 0 : pszMessage = "Corrupt data";
363 0 : break;
364 : default:
365 0 : pszMessage = "Unrecognized error";
366 : }
367 : CPLError(CE_Failure, CPLE_AppDefined,
368 0 : "GetNextRawFeature(): %s", pszMessage);
369 : }
370 :
371 0 : if( poGeom != NULL )
372 : {
373 0 : if ( GetSpatialRef() )
374 0 : poGeom->assignSpatialReference( poSRS );
375 :
376 0 : poFeature->SetGeometryDirectly( poGeom );
377 : }
378 : }
379 :
380 0 : return poFeature;
381 : }
382 :
383 : /************************************************************************/
384 : /* GetFeature() */
385 : /************************************************************************/
386 :
387 0 : OGRFeature *OGRMSSQLSpatialLayer::GetFeature( long nFeatureId )
388 :
389 : {
390 : /* This should be implemented directly! */
391 :
392 0 : return OGRLayer::GetFeature( nFeatureId );
393 : }
394 :
395 : /************************************************************************/
396 : /* TestCapability() */
397 : /************************************************************************/
398 :
399 0 : int OGRMSSQLSpatialLayer::TestCapability( const char * pszCap )
400 :
401 : {
402 0 : return FALSE;
403 : }
404 :
405 : /************************************************************************/
406 : /* StartTransaction() */
407 : /************************************************************************/
408 :
409 0 : OGRErr OGRMSSQLSpatialLayer::StartTransaction()
410 :
411 : {
412 0 : poDS->GetSession()->BeginTransaction();
413 0 : return OGRERR_NONE;
414 : }
415 :
416 : /************************************************************************/
417 : /* CommitTransaction() */
418 : /************************************************************************/
419 :
420 0 : OGRErr OGRMSSQLSpatialLayer::CommitTransaction()
421 :
422 : {
423 0 : poDS->GetSession()->CommitTransaction();
424 0 : return OGRERR_NONE;
425 : }
426 :
427 : /************************************************************************/
428 : /* RollbackTransaction() */
429 : /************************************************************************/
430 :
431 0 : OGRErr OGRMSSQLSpatialLayer::RollbackTransaction()
432 :
433 : {
434 0 : poDS->GetSession()->RollbackTransaction();
435 0 : return OGRERR_NONE;
436 : }
437 :
438 : /************************************************************************/
439 : /* GetSpatialRef() */
440 : /************************************************************************/
441 :
442 0 : OGRSpatialReference *OGRMSSQLSpatialLayer::GetSpatialRef()
443 :
444 : {
445 0 : if( poSRS == NULL && nSRSId > 0 )
446 : {
447 0 : poSRS = poDS->FetchSRS( nSRSId );
448 0 : if( poSRS != NULL )
449 0 : poSRS->Reference();
450 : else
451 0 : nSRSId = 0;
452 : }
453 :
454 0 : return poSRS;
455 : }
456 :
457 : /************************************************************************/
458 : /* GetFIDColumn() */
459 : /************************************************************************/
460 :
461 0 : const char *OGRMSSQLSpatialLayer::GetFIDColumn()
462 :
463 : {
464 0 : GetLayerDefn();
465 :
466 0 : if( pszFIDColumn != NULL )
467 0 : return pszFIDColumn;
468 : else
469 0 : return "";
470 : }
471 :
472 : /************************************************************************/
473 : /* GetGeometryColumn() */
474 : /************************************************************************/
475 :
476 0 : const char *OGRMSSQLSpatialLayer::GetGeometryColumn()
477 :
478 : {
479 0 : GetLayerDefn();
480 :
481 0 : if( pszGeomColumn != NULL )
482 0 : return pszGeomColumn;
483 : else
484 0 : return "";
485 : }
486 :
487 : /************************************************************************/
488 : /* GByteArrayToHexString() */
489 : /************************************************************************/
490 :
491 0 : char* OGRMSSQLSpatialLayer::GByteArrayToHexString( const GByte* pabyData, int nLen)
492 : {
493 : char* pszTextBuf;
494 :
495 0 : pszTextBuf = (char *) CPLMalloc(nLen*2+3);
496 :
497 0 : int iSrc, iDst=0;
498 :
499 0 : for( iSrc = 0; iSrc < nLen; iSrc++ )
500 : {
501 0 : if( iSrc == 0 )
502 : {
503 0 : sprintf( pszTextBuf+iDst, "0x%02x", pabyData[iSrc] );
504 0 : iDst += 4;
505 : }
506 : else
507 : {
508 0 : sprintf( pszTextBuf+iDst, "%02x", pabyData[iSrc] );
509 0 : iDst += 2;
510 : }
511 : }
512 0 : pszTextBuf[iDst] = 0;
513 :
514 0 : return pszTextBuf;
515 : }
516 :
|