1 : /******************************************************************************
2 : * $Id: ogrsqlitelayer.cpp 17772 2009-10-07 20:54:45Z rouault $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Purpose: Implements OGRSQLiteLayer class, code shared between
6 : * the direct table access, and the generic SQL results.
7 : * Author: Frank Warmerdam, warmerdam@pobox.com
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 "cpl_string.h"
33 : #include "ogr_sqlite.h"
34 : #include <cassert>
35 :
36 : CPL_CVSID("$Id: ogrsqlitelayer.cpp 17772 2009-10-07 20:54:45Z rouault $");
37 :
38 : /************************************************************************/
39 : /* OGRSQLiteLayer() */
40 : /************************************************************************/
41 :
42 132 : OGRSQLiteLayer::OGRSQLiteLayer()
43 :
44 : {
45 132 : poDS = NULL;
46 :
47 132 : pszFIDColumn = NULL;
48 :
49 132 : eGeomFormat = OSGF_None;
50 :
51 132 : hStmt = NULL;
52 :
53 132 : iNextShapeId = 0;
54 :
55 132 : poSRS = NULL;
56 132 : nSRSId = -2; // we haven't even queried the database for it yet.
57 :
58 132 : panFieldOrdinals = NULL;
59 :
60 132 : bTriedAsSpatiaLite = FALSE;
61 132 : bHasSpatialIndex = FALSE;
62 132 : }
63 :
64 : /************************************************************************/
65 : /* ~OGRSQLiteLayer() */
66 : /************************************************************************/
67 :
68 132 : OGRSQLiteLayer::~OGRSQLiteLayer()
69 :
70 : {
71 132 : if( m_nFeaturesRead > 0 && poFeatureDefn != NULL )
72 : {
73 : CPLDebug( "SQLite", "%d features read on layer '%s'.",
74 : (int) m_nFeaturesRead,
75 29 : poFeatureDefn->GetName() );
76 : }
77 :
78 132 : if( hStmt != NULL )
79 : {
80 0 : sqlite3_finalize( hStmt );
81 0 : hStmt = NULL;
82 : }
83 :
84 132 : if( poFeatureDefn != NULL )
85 : {
86 132 : poFeatureDefn->Release();
87 132 : poFeatureDefn = NULL;
88 : }
89 :
90 132 : if( poSRS != NULL )
91 16 : poSRS->Dereference();
92 :
93 132 : CPLFree( pszFIDColumn );
94 132 : CPLFree( panFieldOrdinals );
95 132 : }
96 :
97 : /************************************************************************/
98 : /* BuildFeatureDefn() */
99 : /* */
100 : /* Build feature definition from a set of column definitions */
101 : /* set on a statement. Sift out geometry and FID fields. */
102 : /************************************************************************/
103 :
104 132 : CPLErr OGRSQLiteLayer::BuildFeatureDefn( const char *pszLayerName,
105 : sqlite3_stmt *hStmt )
106 :
107 : {
108 132 : poFeatureDefn = new OGRFeatureDefn( pszLayerName );
109 132 : int nRawColumns = sqlite3_column_count( hStmt );
110 :
111 132 : poFeatureDefn->Reference();
112 :
113 132 : panFieldOrdinals = (int *) CPLMalloc( sizeof(int) * nRawColumns );
114 :
115 132 : for( int iCol = 0; iCol < nRawColumns; iCol++ )
116 : {
117 : OGRFieldDefn oField( sqlite3_column_name( hStmt, iCol ),
118 639 : OFTString );
119 :
120 : // In some cases, particularly when there is a real name for
121 : // the primary key/_rowid_ column we will end up getting the
122 : // primary key column appearing twice. Ignore any repeated names.
123 639 : if( poFeatureDefn->GetFieldIndex( oField.GetNameRef() ) != -1 )
124 0 : continue;
125 :
126 639 : if( pszFIDColumn != NULL && EQUAL(pszFIDColumn, oField.GetNameRef()))
127 177 : continue;
128 :
129 : //oField.SetWidth( MAX(0,poStmt->GetColSize( iCol )) );
130 :
131 462 : if( osGeomColumn.size()
132 : && EQUAL(oField.GetNameRef(),osGeomColumn) )
133 45 : continue;
134 :
135 417 : int nColType = sqlite3_column_type( hStmt, iCol );
136 417 : const char * pszDeclType = sqlite3_column_decltype(hStmt, iCol);
137 : //CPLDebug("SQLITE", "decltype(%s) = %s",
138 : // oField.GetNameRef(), pszDeclType ? pszDeclType : "null");
139 417 : if (pszDeclType != NULL)
140 : {
141 388 : if (EQUAL(pszDeclType, "INTEGER"))
142 159 : nColType = SQLITE_INTEGER;
143 229 : else if (EQUAL(pszDeclType, "FLOAT"))
144 11 : nColType = SQLITE_FLOAT;
145 218 : else if (EQUAL(pszDeclType, "BLOB"))
146 34 : nColType = SQLITE_BLOB;
147 184 : else if (EQUAL(pszDeclType, "TEXT") ||
148 : EQUAL(pszDeclType, "VARCHAR"))
149 108 : nColType = SQLITE_TEXT;
150 : }
151 :
152 : // Recognise some common geometry column names.
153 417 : if( (EQUAL(oField.GetNameRef(),"wkt_geometry")
154 : || EQUAL(oField.GetNameRef(),"geometry")
155 : || EQUALN(oField.GetNameRef(), "asbinary(", 9)
156 : || EQUALN(oField.GetNameRef(), "astext(", 7))
157 : && osGeomColumn.size() == 0 )
158 : {
159 13 : if( nColType == SQLITE_BLOB )
160 : {
161 12 : osGeomColumn = oField.GetNameRef();
162 12 : eGeomFormat = OSGF_WKB;
163 : /* This could also be a SpatialLite geometry, so */
164 : /* we'll also try to decode as SpatialLite if */
165 : /* bTriedAsSpatiaLite is not FALSE */
166 12 : continue;
167 : }
168 1 : else if( nColType == SQLITE_TEXT )
169 : {
170 1 : osGeomColumn = oField.GetNameRef();
171 1 : eGeomFormat = OSGF_WKT;
172 1 : continue;
173 : }
174 : }
175 :
176 : // SpatialLite / Gaia
177 404 : if( EQUAL(oField.GetNameRef(),"GaiaGeometry")
178 : && osGeomColumn.size() == 0 )
179 : {
180 0 : osGeomColumn = oField.GetNameRef();
181 0 : eGeomFormat = OSGF_SpatiaLite;
182 0 : continue;
183 : }
184 :
185 : // The rowid is for internal use, not a real column.
186 404 : if( EQUAL(oField.GetNameRef(),"_rowid_") )
187 0 : continue;
188 :
189 : // The OGC_FID is for internal use, not a real user visible column.
190 404 : if( EQUAL(oField.GetNameRef(),"OGC_FID") )
191 3 : continue;
192 :
193 401 : switch( nColType )
194 : {
195 : case SQLITE_INTEGER:
196 165 : oField.SetType( OFTInteger );
197 165 : break;
198 :
199 : case SQLITE_FLOAT:
200 45 : oField.SetType( OFTReal );
201 45 : break;
202 :
203 : case SQLITE_BLOB:
204 32 : oField.SetType( OFTBinary );
205 : break;
206 :
207 : default:
208 : /* leave it as OFTString */;
209 : }
210 :
211 401 : poFeatureDefn->AddFieldDefn( &oField );
212 401 : panFieldOrdinals[poFeatureDefn->GetFieldCount() - 1] = iCol+1;
213 : }
214 :
215 : /* -------------------------------------------------------------------- */
216 : /* If we have no geometry source, we know our geometry type is */
217 : /* none. */
218 : /* -------------------------------------------------------------------- */
219 132 : if( osGeomColumn.size() == 0 )
220 74 : poFeatureDefn->SetGeomType( wkbNone );
221 :
222 132 : return CE_None;
223 : }
224 :
225 : /************************************************************************/
226 : /* GetFIDColumn() */
227 : /************************************************************************/
228 :
229 0 : const char *OGRSQLiteLayer::GetFIDColumn()
230 :
231 : {
232 0 : if( pszFIDColumn != NULL )
233 0 : return pszFIDColumn;
234 : else
235 0 : return "";
236 : }
237 :
238 : /************************************************************************/
239 : /* GetGeometryColumn() */
240 : /************************************************************************/
241 :
242 0 : const char *OGRSQLiteLayer::GetGeometryColumn()
243 :
244 : {
245 0 : if( osGeomColumn.size() != 0 )
246 0 : return osGeomColumn.c_str();
247 : else
248 0 : return "";
249 : }
250 :
251 : /************************************************************************/
252 : /* ResetReading() */
253 : /************************************************************************/
254 :
255 103 : void OGRSQLiteLayer::ResetReading()
256 :
257 : {
258 103 : iNextShapeId = 0;
259 103 : }
260 :
261 : /************************************************************************/
262 : /* GetNextFeature() */
263 : /************************************************************************/
264 :
265 171 : OGRFeature *OGRSQLiteLayer::GetNextFeature()
266 :
267 : {
268 32 : for( ; TRUE; )
269 : {
270 : OGRFeature *poFeature;
271 :
272 171 : poFeature = GetNextRawFeature();
273 171 : if( poFeature == NULL )
274 24 : return NULL;
275 :
276 147 : if( (m_poFilterGeom == NULL
277 : || FilterGeometry( poFeature->GetGeometryRef() ) )
278 : && (m_poAttrQuery == NULL
279 : || m_poAttrQuery->Evaluate( poFeature )) )
280 115 : return poFeature;
281 :
282 32 : delete poFeature;
283 : }
284 : }
285 :
286 : /************************************************************************/
287 : /* GetNextRawFeature() */
288 : /************************************************************************/
289 :
290 172 : OGRFeature *OGRSQLiteLayer::GetNextRawFeature()
291 :
292 : {
293 172 : if( GetStatement() == NULL )
294 0 : return NULL;
295 :
296 : /* -------------------------------------------------------------------- */
297 : /* If we are marked to restart then do so, and fetch a record. */
298 : /* -------------------------------------------------------------------- */
299 : int rc;
300 :
301 172 : rc = sqlite3_step( hStmt );
302 172 : if( rc != SQLITE_ROW )
303 : {
304 24 : if ( rc != SQLITE_DONE )
305 : {
306 : CPLError( CE_Failure, CPLE_AppDefined,
307 : "In GetNextRawFeature(): sqlite3_step() : %s",
308 0 : sqlite3_errmsg(poDS->GetDB()) );
309 : }
310 :
311 24 : ClearStatement();
312 :
313 24 : return NULL;
314 : }
315 :
316 : /* -------------------------------------------------------------------- */
317 : /* Create a feature from the current result. */
318 : /* -------------------------------------------------------------------- */
319 : int iField;
320 148 : OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
321 :
322 : /* -------------------------------------------------------------------- */
323 : /* Set FID if we have a column to set it from. */
324 : /* -------------------------------------------------------------------- */
325 148 : if( pszFIDColumn != NULL )
326 : {
327 : int iFIDCol;
328 :
329 103 : for( iFIDCol = 0; iFIDCol < sqlite3_column_count(hStmt); iFIDCol++ )
330 : {
331 103 : if( EQUAL(sqlite3_column_name(hStmt,iFIDCol),
332 : pszFIDColumn) )
333 103 : break;
334 : }
335 :
336 103 : if( iFIDCol == sqlite3_column_count(hStmt) )
337 : {
338 : CPLError( CE_Failure, CPLE_AppDefined,
339 : "Unable to find FID column '%s'.",
340 0 : pszFIDColumn );
341 0 : return NULL;
342 : }
343 :
344 103 : poFeature->SetFID( sqlite3_column_int( hStmt, iFIDCol ) );
345 : }
346 : else
347 45 : poFeature->SetFID( iNextShapeId );
348 :
349 148 : iNextShapeId++;
350 :
351 148 : m_nFeaturesRead++;
352 :
353 : /* -------------------------------------------------------------------- */
354 : /* Process Geometry if we have a column. */
355 : /* -------------------------------------------------------------------- */
356 148 : if( osGeomColumn.size() )
357 : {
358 : int iGeomCol;
359 :
360 353 : for( iGeomCol = 0; iGeomCol < sqlite3_column_count(hStmt); iGeomCol++ )
361 : {
362 353 : if( EQUAL(sqlite3_column_name(hStmt,iGeomCol),
363 : osGeomColumn) )
364 109 : break;
365 : }
366 :
367 109 : if( iGeomCol == sqlite3_column_count(hStmt) )
368 : {
369 : CPLError( CE_Failure, CPLE_AppDefined,
370 : "Unable to find Geometry column '%s'.",
371 0 : osGeomColumn.c_str() );
372 0 : return NULL;
373 : }
374 :
375 109 : OGRGeometry *poGeometry = NULL;
376 109 : if ( eGeomFormat == OSGF_WKT )
377 : {
378 3 : char *pszWKTCopy, *pszWKT = NULL;
379 :
380 3 : pszWKT = (char *) sqlite3_column_text( hStmt, iGeomCol );
381 3 : pszWKTCopy = pszWKT;
382 3 : if( OGRGeometryFactory::createFromWkt(
383 : &pszWKTCopy, NULL, &poGeometry ) == OGRERR_NONE )
384 3 : poFeature->SetGeometryDirectly( poGeometry );
385 : }
386 106 : else if ( eGeomFormat == OSGF_WKB )
387 : {
388 74 : const int nBytes = sqlite3_column_bytes( hStmt, iGeomCol );
389 :
390 74 : if( OGRGeometryFactory::createFromWkb(
391 : (GByte*)sqlite3_column_blob( hStmt, iGeomCol ),
392 : NULL, &poGeometry, nBytes ) == OGRERR_NONE )
393 65 : poFeature->SetGeometryDirectly( poGeometry );
394 9 : else if (!bTriedAsSpatiaLite)
395 : {
396 : /* If the layer is the result of a sql select, we cannot be sure if it is */
397 : /* WKB or SpatialLite format */
398 7 : if( ImportSpatiaLiteGeometry(
399 : (GByte*)sqlite3_column_blob( hStmt, iGeomCol ), nBytes,
400 : &poGeometry ) == OGRERR_NONE )
401 : {
402 6 : poFeature->SetGeometryDirectly( poGeometry );
403 6 : eGeomFormat = OSGF_SpatiaLite;
404 : }
405 7 : bTriedAsSpatiaLite = TRUE;
406 : }
407 : }
408 32 : else if ( eGeomFormat == OSGF_FGF )
409 : {
410 8 : const int nBytes = sqlite3_column_bytes( hStmt, iGeomCol );
411 :
412 8 : if( OGRGeometryFactory::createFromFgf(
413 : (GByte*)sqlite3_column_blob( hStmt, iGeomCol ),
414 : NULL, &poGeometry, nBytes, NULL ) == OGRERR_NONE )
415 8 : poFeature->SetGeometryDirectly( poGeometry );
416 : }
417 24 : else if ( eGeomFormat == OSGF_SpatiaLite )
418 : {
419 24 : const int nBytes = sqlite3_column_bytes( hStmt, iGeomCol );
420 :
421 24 : if( ImportSpatiaLiteGeometry(
422 : (GByte*)sqlite3_column_blob( hStmt, iGeomCol ), nBytes,
423 : &poGeometry ) == OGRERR_NONE )
424 21 : poFeature->SetGeometryDirectly( poGeometry );
425 : }
426 :
427 109 : if (poGeometry != NULL && poSRS != NULL)
428 5 : poGeometry->assignSpatialReference(poSRS);
429 : }
430 :
431 : /* -------------------------------------------------------------------- */
432 : /* set the fields. */
433 : /* -------------------------------------------------------------------- */
434 530 : for( iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++ )
435 : {
436 382 : OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn( iField );
437 382 : int iRawField = panFieldOrdinals[iField] - 1;
438 :
439 382 : if( sqlite3_column_type( hStmt, iRawField ) == SQLITE_NULL )
440 117 : continue;
441 :
442 265 : switch( poFieldDefn->GetType() )
443 : {
444 : case OFTInteger:
445 : poFeature->SetField( iField,
446 100 : sqlite3_column_int( hStmt, iRawField ) );
447 100 : break;
448 :
449 : case OFTReal:
450 : poFeature->SetField( iField,
451 77 : sqlite3_column_double( hStmt, iRawField ) );
452 77 : break;
453 :
454 : case OFTBinary:
455 : {
456 13 : const int nBytes = sqlite3_column_bytes( hStmt, iRawField );
457 :
458 : poFeature->SetField( iField, nBytes,
459 13 : (GByte*)sqlite3_column_blob( hStmt, iRawField ) );
460 : }
461 13 : break;
462 :
463 : case OFTString:
464 : poFeature->SetField( iField,
465 : (const char *)
466 75 : sqlite3_column_text( hStmt, iRawField ) );
467 : break;
468 :
469 : default:
470 : break;
471 : }
472 : }
473 :
474 148 : return poFeature;
475 : }
476 :
477 : /************************************************************************/
478 : /* GetFeature() */
479 : /************************************************************************/
480 :
481 2 : OGRFeature *OGRSQLiteLayer::GetFeature( long nFeatureId )
482 :
483 : {
484 2 : return OGRLayer::GetFeature( nFeatureId );
485 : }
486 :
487 :
488 : /************************************************************************/
489 : /* createFromSpatialiteInternal() */
490 : /************************************************************************/
491 :
492 : /* See http://www.gaia-gis.it/spatialite/spatialite-manual-2.3.0.html#t3.3 */
493 : /* for the specification of the spatialite BLOB geometry format */
494 : /* Derived from WKB, but unfortunately it is not practical to reuse existing */
495 : /* WKB encoding/decoding code */
496 :
497 : #ifdef CPL_LSB
498 : #define NEED_SWAP_SPATIALITE() (eByteOrder != wkbNDR)
499 : #else
500 : #define NEED_SWAP_SPATIALITE() (eByteOrder == wkbNDR)
501 : #endif
502 :
503 :
504 37 : OGRErr OGRSQLiteLayer::createFromSpatialiteInternal(const GByte *pabyData,
505 : OGRGeometry **ppoReturn,
506 : int nBytes,
507 : OGRwkbByteOrder eByteOrder,
508 : int* pnBytesConsumed)
509 : {
510 37 : OGRErr eErr = OGRERR_NONE;
511 37 : OGRGeometry *poGeom = NULL;
512 : GInt32 nGType;
513 :
514 37 : *ppoReturn = NULL;
515 :
516 37 : if (nBytes < 4)
517 0 : return OGRERR_NOT_ENOUGH_DATA;
518 :
519 : /* -------------------------------------------------------------------- */
520 : /* Decode the geometry type. */
521 : /* -------------------------------------------------------------------- */
522 37 : memcpy( &nGType, pabyData, 4 );
523 37 : if (NEED_SWAP_SPATIALITE())
524 0 : CPL_SWAP32PTR( &nGType );
525 :
526 37 : if( nGType < 1 || nGType > 7 )
527 0 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
528 :
529 : /* -------------------------------------------------------------------- */
530 : /* Point */
531 : /* -------------------------------------------------------------------- */
532 37 : if( nGType == 1 )
533 : {
534 : double adfTuple[2];
535 :
536 7 : if( nBytes < 4 + 2 * 8 )
537 0 : return OGRERR_NOT_ENOUGH_DATA;
538 :
539 7 : memcpy( adfTuple, pabyData + 4, 2*8 );
540 7 : if (NEED_SWAP_SPATIALITE())
541 : {
542 0 : CPL_SWAP64PTR( adfTuple );
543 0 : CPL_SWAP64PTR( adfTuple + 1 );
544 : }
545 :
546 7 : poGeom = new OGRPoint( adfTuple[0], adfTuple[1] );
547 :
548 7 : if( pnBytesConsumed )
549 3 : *pnBytesConsumed = 4 + 2 * 8;
550 : }
551 :
552 : /* -------------------------------------------------------------------- */
553 : /* LineString */
554 : /* -------------------------------------------------------------------- */
555 30 : else if( nGType == 2 )
556 : {
557 : double adfTuple[2];
558 : GInt32 nPointCount;
559 : int iPoint;
560 : OGRLineString *poLS;
561 :
562 4 : if( nBytes < 8 )
563 0 : return OGRERR_NOT_ENOUGH_DATA;
564 :
565 4 : memcpy( &nPointCount, pabyData + 4, 4 );
566 4 : if (NEED_SWAP_SPATIALITE())
567 0 : CPL_SWAP32PTR( &nPointCount );
568 :
569 4 : if( nPointCount < 0 || nPointCount > INT_MAX / (2 * 8))
570 0 : return OGRERR_CORRUPT_DATA;
571 :
572 4 : if (nBytes - 8 < 2 * 8 * nPointCount )
573 0 : return OGRERR_NOT_ENOUGH_DATA;
574 :
575 4 : poGeom = poLS = new OGRLineString();
576 4 : poLS->setNumPoints( nPointCount );
577 :
578 10 : for( iPoint = 0; iPoint < nPointCount; iPoint++ )
579 : {
580 6 : memcpy( adfTuple, pabyData + 8 + 2*8*iPoint, 2*8 );
581 6 : if (NEED_SWAP_SPATIALITE())
582 : {
583 0 : CPL_SWAP64PTR( adfTuple );
584 0 : CPL_SWAP64PTR( adfTuple + 1 );
585 : }
586 :
587 6 : poLS->setPoint( iPoint, adfTuple[0], adfTuple[1] );
588 : }
589 :
590 4 : if( pnBytesConsumed )
591 2 : *pnBytesConsumed = 8 + 2 * 8 * nPointCount;
592 : }
593 :
594 : /* -------------------------------------------------------------------- */
595 : /* Polygon */
596 : /* -------------------------------------------------------------------- */
597 26 : else if( nGType == 3 )
598 : {
599 : double adfTuple[2];
600 : GInt32 nPointCount;
601 : GInt32 nRingCount;
602 : int iPoint, iRing;
603 : OGRLinearRing *poLR;
604 : OGRPolygon *poPoly;
605 : int nNextByte;
606 :
607 17 : if( nBytes < 8 )
608 0 : return OGRERR_NOT_ENOUGH_DATA;
609 :
610 17 : memcpy( &nRingCount, pabyData + 4, 4 );
611 17 : if (NEED_SWAP_SPATIALITE())
612 0 : CPL_SWAP32PTR( &nRingCount );
613 :
614 17 : if (nRingCount < 0 || nRingCount > INT_MAX / 4)
615 0 : return OGRERR_CORRUPT_DATA;
616 :
617 : /* Each ring has a minimum of 4 bytes */
618 17 : if (nBytes - 8 < nRingCount * 4)
619 0 : return OGRERR_NOT_ENOUGH_DATA;
620 :
621 17 : nNextByte = 8;
622 :
623 17 : poGeom = poPoly = new OGRPolygon();
624 :
625 34 : for( iRing = 0; iRing < nRingCount; iRing++ )
626 : {
627 17 : if( nBytes - nNextByte < 4 )
628 0 : return OGRERR_NOT_ENOUGH_DATA;
629 :
630 17 : memcpy( &nPointCount, pabyData + nNextByte, 4 );
631 17 : if (NEED_SWAP_SPATIALITE())
632 0 : CPL_SWAP32PTR( &nPointCount );
633 :
634 17 : if (nPointCount < 0 || nPointCount > INT_MAX / (2 * 8))
635 0 : return OGRERR_CORRUPT_DATA;
636 :
637 17 : nNextByte += 4;
638 :
639 17 : if( nBytes - nNextByte < 2 * 8 * nPointCount )
640 0 : return OGRERR_NOT_ENOUGH_DATA;
641 :
642 17 : poLR = new OGRLinearRing();
643 17 : poLR->setNumPoints( nPointCount );
644 :
645 78 : for( iPoint = 0; iPoint < nPointCount; iPoint++ )
646 : {
647 61 : memcpy( adfTuple, pabyData + nNextByte, 2*8 );
648 61 : nNextByte += 2 * 8;
649 :
650 61 : if (NEED_SWAP_SPATIALITE())
651 : {
652 0 : CPL_SWAP64PTR( adfTuple );
653 0 : CPL_SWAP64PTR( adfTuple + 1 );
654 : }
655 :
656 61 : poLR->setPoint( iPoint, adfTuple[0], adfTuple[1] );
657 : }
658 :
659 17 : poPoly->addRingDirectly( poLR );
660 : }
661 :
662 17 : if( pnBytesConsumed )
663 5 : *pnBytesConsumed = nNextByte;
664 : }
665 :
666 : /* -------------------------------------------------------------------- */
667 : /* GeometryCollections of various kinds. */
668 : /* -------------------------------------------------------------------- */
669 18 : else if( nGType == 4 // MultiPoint
670 : || nGType == 5 // MultiLineString
671 : || nGType == 6 // MultiPolygon
672 : || nGType == 7 ) // MultiGeometry
673 : {
674 9 : OGRGeometryCollection *poGC = NULL;
675 9 : GInt32 nGeomCount = 0;
676 9 : int iGeom = 0;
677 9 : int nBytesUsed = 0;
678 :
679 9 : if( nGType == 4 )
680 2 : poGC = new OGRMultiPoint();
681 7 : else if( nGType == 5 )
682 2 : poGC = new OGRMultiLineString();
683 5 : else if( nGType == 6 )
684 2 : poGC = new OGRMultiPolygon();
685 3 : else if( nGType == 7 )
686 3 : poGC = new OGRGeometryCollection();
687 :
688 9 : assert(NULL != poGC);
689 :
690 9 : if( nBytes < 8 )
691 0 : return OGRERR_NOT_ENOUGH_DATA;
692 :
693 9 : memcpy( &nGeomCount, pabyData + 4, 4 );
694 9 : if (NEED_SWAP_SPATIALITE())
695 0 : CPL_SWAP32PTR( &nGeomCount );
696 :
697 9 : if (nGeomCount < 0 || nGeomCount > INT_MAX / 9)
698 0 : return OGRERR_CORRUPT_DATA;
699 :
700 : /* Each sub geometry takes at least 9 bytes */
701 9 : if (nBytes - 8 < nGeomCount * 9)
702 0 : return OGRERR_NOT_ENOUGH_DATA;
703 :
704 9 : nBytesUsed = 8;
705 :
706 19 : for( iGeom = 0; iGeom < nGeomCount; iGeom++ )
707 : {
708 : int nThisGeomSize;
709 10 : OGRGeometry *poThisGeom = NULL;
710 :
711 10 : if (nBytes - nBytesUsed < 5)
712 0 : return OGRERR_NOT_ENOUGH_DATA;
713 :
714 10 : if (pabyData[nBytesUsed] != 0x69)
715 0 : return OGRERR_CORRUPT_DATA;
716 :
717 10 : nBytesUsed ++;
718 :
719 : eErr = createFromSpatialiteInternal( pabyData + nBytesUsed,
720 : &poThisGeom, nBytes - nBytesUsed,
721 10 : eByteOrder, &nThisGeomSize);
722 10 : if( eErr != OGRERR_NONE )
723 : {
724 0 : delete poGC;
725 0 : return eErr;
726 : }
727 :
728 10 : nBytesUsed += nThisGeomSize;
729 10 : eErr = poGC->addGeometryDirectly( poThisGeom );
730 10 : if( eErr != OGRERR_NONE )
731 : {
732 0 : delete poGC;
733 0 : return eErr;
734 : }
735 : }
736 :
737 9 : poGeom = poGC;
738 9 : if( pnBytesConsumed )
739 0 : *pnBytesConsumed = nBytesUsed;
740 : }
741 :
742 : /* -------------------------------------------------------------------- */
743 : /* Currently unsupported geometry. */
744 : /* -------------------------------------------------------------------- */
745 : else
746 : {
747 0 : return OGRERR_UNSUPPORTED_GEOMETRY_TYPE;
748 : }
749 :
750 : /* -------------------------------------------------------------------- */
751 : /* Assign spatial reference system. */
752 : /* -------------------------------------------------------------------- */
753 37 : if( eErr == OGRERR_NONE )
754 : {
755 37 : *ppoReturn = poGeom;
756 : }
757 : else
758 : {
759 0 : delete poGeom;
760 : }
761 :
762 37 : return eErr;
763 : }
764 :
765 : /************************************************************************/
766 : /* ImportSpatiaLiteGeometry() */
767 : /************************************************************************/
768 :
769 31 : OGRErr OGRSQLiteLayer::ImportSpatiaLiteGeometry( const GByte *pabyData,
770 : int nBytes,
771 : OGRGeometry **ppoGeometry )
772 :
773 : {
774 : OGRwkbByteOrder eByteOrder;
775 :
776 31 : *ppoGeometry = NULL;
777 :
778 112 : if( nBytes < 44
779 27 : || pabyData[0] != 0
780 27 : || pabyData[38] != 0x7C
781 27 : || pabyData[nBytes-1] != 0xFE )
782 4 : return OGRERR_CORRUPT_DATA;
783 :
784 27 : eByteOrder = (OGRwkbByteOrder) pabyData[1];
785 :
786 : return createFromSpatialiteInternal(pabyData + 39, ppoGeometry,
787 27 : nBytes - 39, eByteOrder, NULL);
788 : }
789 :
790 : /************************************************************************/
791 : /* ComputeSpatiaLiteGeometrySize() */
792 : /************************************************************************/
793 :
794 34 : int OGRSQLiteLayer::ComputeSpatiaLiteGeometrySize(const OGRGeometry *poGeometry)
795 : {
796 34 : switch (wkbFlatten(poGeometry->getGeometryType()))
797 : {
798 : case wkbPoint:
799 5 : return 16;
800 :
801 : case wkbLineString:
802 : case wkbLinearRing:
803 12 : return 4 + 16 * ((OGRLineString*)poGeometry)->getNumPoints();
804 :
805 : case wkbPolygon:
806 : {
807 8 : int nSize = 4;
808 8 : OGRPolygon* poPoly = (OGRPolygon*) poGeometry;
809 8 : if (poPoly->getExteriorRing() != NULL)
810 : {
811 7 : nSize += ComputeSpatiaLiteGeometrySize(poPoly->getExteriorRing());
812 :
813 7 : int nInteriorRingCount = poPoly->getNumInteriorRings();
814 8 : for(int i=0;i<nInteriorRingCount;i++)
815 1 : nSize += ComputeSpatiaLiteGeometrySize(poPoly->getInteriorRing(i));
816 : }
817 8 : return nSize;
818 : }
819 :
820 : case wkbMultiPoint:
821 : case wkbMultiLineString:
822 : case wkbMultiPolygon:
823 : case wkbGeometryCollection:
824 : {
825 9 : int nSize = 4;
826 9 : OGRGeometryCollection* poGeomCollection = (OGRGeometryCollection*) poGeometry;
827 9 : int nParts = poGeomCollection->getNumGeometries();
828 19 : for(int i=0;i<nParts;i++)
829 10 : nSize += 5 + ComputeSpatiaLiteGeometrySize(poGeomCollection->getGeometryRef(i));
830 9 : return nSize;
831 : }
832 :
833 : default:
834 0 : CPLError(CE_Failure, CPLE_AppDefined, "Unexpected geometry type");
835 0 : return 0;
836 : }
837 : }
838 :
839 : /************************************************************************/
840 : /* ExportSpatiaLiteGeometry() */
841 : /************************************************************************/
842 :
843 34 : int OGRSQLiteLayer::ExportSpatiaLiteGeometryInternal(const OGRGeometry *poGeometry,
844 : OGRwkbByteOrder eByteOrder,
845 : GByte* pabyData)
846 : {
847 34 : switch (wkbFlatten(poGeometry->getGeometryType()))
848 : {
849 : case wkbPoint:
850 : {
851 5 : OGRPoint* poPoint = (OGRPoint*) poGeometry;
852 5 : double x = poPoint->getX();
853 5 : double y = poPoint->getY();
854 5 : memcpy(pabyData, &x, 8);
855 5 : memcpy(pabyData + 8, &y, 8);
856 5 : if (NEED_SWAP_SPATIALITE())
857 : {
858 0 : CPL_SWAP64PTR( pabyData );
859 0 : CPL_SWAP64PTR( pabyData + 8 );
860 : }
861 5 : return 16;
862 : }
863 :
864 : case wkbLineString:
865 : case wkbLinearRing:
866 : {
867 12 : OGRLineString* poLineString = (OGRLineString*) poGeometry;
868 12 : int nTotalSize = 4;
869 12 : int nPointCount = poLineString->getNumPoints();
870 12 : memcpy(pabyData, &nPointCount, 4);
871 12 : if (NEED_SWAP_SPATIALITE())
872 0 : CPL_SWAP32PTR( pabyData );
873 34 : for(int i=0;i<nPointCount;i++)
874 : {
875 22 : double x = poLineString->getX(i);
876 22 : double y = poLineString->getY(i);
877 22 : memcpy(pabyData + nTotalSize, &x, 8);
878 22 : memcpy(pabyData + nTotalSize + 8, &y, 8);
879 22 : if (NEED_SWAP_SPATIALITE())
880 : {
881 0 : CPL_SWAP64PTR( pabyData + nTotalSize );
882 0 : CPL_SWAP64PTR( pabyData + nTotalSize + 8 );
883 : }
884 22 : nTotalSize += 16;
885 : }
886 12 : return nTotalSize;
887 : }
888 :
889 : case wkbPolygon:
890 : {
891 8 : OGRPolygon* poPoly = (OGRPolygon*) poGeometry;
892 8 : int nParts = 0;
893 8 : int nTotalSize = 4;
894 8 : if (poPoly->getExteriorRing() != NULL)
895 : {
896 7 : int nInteriorRingCount = poPoly->getNumInteriorRings();
897 7 : nParts = 1 + nInteriorRingCount;
898 7 : memcpy(pabyData, &nParts, 4);
899 7 : if (NEED_SWAP_SPATIALITE())
900 0 : CPL_SWAP32PTR( pabyData );
901 :
902 : nTotalSize += ExportSpatiaLiteGeometryInternal(poPoly->getExteriorRing(),
903 7 : eByteOrder, pabyData + nTotalSize);
904 :
905 8 : for(int i=0;i<nInteriorRingCount;i++)
906 : {
907 : nTotalSize += ExportSpatiaLiteGeometryInternal(poPoly->getInteriorRing(i),
908 1 : eByteOrder, pabyData + nTotalSize);
909 : }
910 : }
911 : else
912 : {
913 1 : memset(pabyData, 0, 4);
914 : }
915 8 : return nTotalSize;
916 : }
917 :
918 : case wkbMultiPoint:
919 : case wkbMultiLineString:
920 : case wkbMultiPolygon:
921 : case wkbGeometryCollection:
922 : {
923 9 : OGRGeometryCollection* poGeomCollection = (OGRGeometryCollection*) poGeometry;
924 9 : int nTotalSize = 4;
925 9 : int nParts = poGeomCollection->getNumGeometries();
926 9 : memcpy(pabyData, &nParts, 4);
927 9 : if (NEED_SWAP_SPATIALITE())
928 0 : CPL_SWAP32PTR( pabyData );
929 :
930 19 : for(int i=0;i<nParts;i++)
931 : {
932 10 : pabyData[nTotalSize] = 0x69;
933 10 : nTotalSize ++;
934 : int nCode;
935 10 : switch (wkbFlatten(poGeomCollection->getGeometryRef(i)->getGeometryType()))
936 : {
937 3 : case wkbPoint: nCode = 1; break;
938 2 : case wkbLineString: nCode = 2; break;
939 5 : case wkbPolygon: nCode = 3; break;
940 0 : default: CPLError(CE_Failure, CPLE_AppDefined, "Unexpected geometry type"); return 0;
941 : }
942 10 : memcpy(pabyData + nTotalSize, &nCode, 4);
943 10 : if (NEED_SWAP_SPATIALITE())
944 0 : CPL_SWAP32PTR( pabyData + nTotalSize );
945 10 : nTotalSize += 4;
946 : nTotalSize += ExportSpatiaLiteGeometryInternal(poGeomCollection->getGeometryRef(i),
947 10 : eByteOrder, pabyData + nTotalSize);
948 : }
949 9 : return nTotalSize;
950 : }
951 :
952 : default:
953 0 : return 0;
954 : }
955 : }
956 :
957 :
958 16 : OGRErr OGRSQLiteLayer::ExportSpatiaLiteGeometry( const OGRGeometry *poGeometry,
959 : GInt32 nSRID,
960 : OGRwkbByteOrder eByteOrder,
961 : GByte **ppabyData,
962 : int *pnDataLenght )
963 :
964 : {
965 16 : int nDataLen = 44 + ComputeSpatiaLiteGeometrySize(poGeometry);
966 16 : OGREnvelope sEnvelope;
967 :
968 16 : *ppabyData = (GByte *) CPLMalloc( nDataLen );
969 :
970 16 : (*ppabyData)[0] = 0x00;
971 16 : (*ppabyData)[1] = eByteOrder;
972 :
973 : // Write out SRID
974 16 : memcpy( *ppabyData + 2, &nSRID, 4 );
975 :
976 : // Write out the geometry bounding rectangle
977 16 : poGeometry->getEnvelope( &sEnvelope );
978 16 : memcpy( *ppabyData + 6, &sEnvelope.MinX, 8 );
979 16 : memcpy( *ppabyData + 14, &sEnvelope.MinY, 8 );
980 16 : memcpy( *ppabyData + 22, &sEnvelope.MaxX, 8 );
981 16 : memcpy( *ppabyData + 30, &sEnvelope.MaxY, 8 );
982 :
983 16 : (*ppabyData)[38] = 0x7C;
984 :
985 16 : int nCode = 0;
986 16 : switch (wkbFlatten(poGeometry->getGeometryType()))
987 : {
988 : case wkbPoint:
989 2 : nCode = 1;
990 2 : break;
991 :
992 : case wkbLineString:
993 : case wkbLinearRing:
994 2 : nCode = 2;
995 2 : break;
996 :
997 : case wkbPolygon:
998 3 : nCode = 3;
999 3 : break;
1000 :
1001 : case wkbMultiPoint:
1002 2 : nCode = 4;
1003 2 : break;
1004 :
1005 : case wkbMultiLineString:
1006 2 : nCode = 5;
1007 2 : break;
1008 :
1009 : case wkbMultiPolygon:
1010 2 : nCode = 6;
1011 2 : break;
1012 :
1013 : case wkbGeometryCollection:
1014 3 : nCode = 7;
1015 3 : break;
1016 :
1017 : default:
1018 0 : CPLError(CE_Failure, CPLE_AppDefined, "Unexpected geometry type");
1019 0 : CPLFree(*ppabyData);
1020 0 : *ppabyData = NULL;
1021 0 : *pnDataLenght = 0;
1022 0 : return CE_Failure;
1023 : }
1024 16 : memcpy( *ppabyData + 39, &nCode, 4 );
1025 :
1026 16 : int nWritten = ExportSpatiaLiteGeometryInternal(poGeometry, eByteOrder, *ppabyData + 43);
1027 16 : if (nWritten == 0)
1028 : {
1029 0 : CPLFree(*ppabyData);
1030 0 : *ppabyData = NULL;
1031 0 : *pnDataLenght = 0;
1032 0 : return CE_Failure;
1033 : }
1034 :
1035 16 : (*ppabyData)[nDataLen - 1] = 0xFE;
1036 :
1037 16 : if( NEED_SWAP_SPATIALITE() )
1038 : {
1039 0 : CPL_SWAP32PTR( *ppabyData + 2 );
1040 0 : CPL_SWAP64PTR( *ppabyData + 6 );
1041 0 : CPL_SWAP64PTR( *ppabyData + 14 );
1042 0 : CPL_SWAP64PTR( *ppabyData + 22 );
1043 0 : CPL_SWAP64PTR( *ppabyData + 30 );
1044 0 : CPL_SWAP32PTR( *ppabyData + 39 );
1045 : }
1046 :
1047 16 : *pnDataLenght = nDataLen;
1048 :
1049 16 : return CE_None;
1050 : }
1051 :
1052 : /************************************************************************/
1053 : /* TestCapability() */
1054 : /************************************************************************/
1055 :
1056 0 : int OGRSQLiteLayer::TestCapability( const char * pszCap )
1057 :
1058 : {
1059 0 : if( EQUAL(pszCap,OLCRandomRead) )
1060 0 : return FALSE;
1061 :
1062 0 : else if( EQUAL(pszCap,OLCFastFeatureCount) )
1063 0 : return FALSE;
1064 :
1065 0 : else if( EQUAL(pszCap,OLCFastSpatialFilter) )
1066 0 : return FALSE;
1067 :
1068 0 : else if( EQUAL(pszCap,OLCTransactions) )
1069 0 : return FALSE;
1070 :
1071 : else
1072 0 : return FALSE;
1073 : }
1074 :
1075 : /************************************************************************/
1076 : /* GetSpatialRef() */
1077 : /************************************************************************/
1078 :
1079 5 : OGRSpatialReference *OGRSQLiteLayer::GetSpatialRef()
1080 :
1081 : {
1082 5 : return poSRS;
1083 : }
1084 :
1085 : /************************************************************************/
1086 : /* StartTransaction() */
1087 : /************************************************************************/
1088 :
1089 4 : OGRErr OGRSQLiteLayer::StartTransaction()
1090 :
1091 : {
1092 4 : return poDS->SoftStartTransaction();
1093 : }
1094 :
1095 : /************************************************************************/
1096 : /* CommitTransaction() */
1097 : /************************************************************************/
1098 :
1099 3 : OGRErr OGRSQLiteLayer::CommitTransaction()
1100 :
1101 : {
1102 3 : return poDS->SoftCommit();
1103 : }
1104 :
1105 : /************************************************************************/
1106 : /* RollbackTransaction() */
1107 : /************************************************************************/
1108 :
1109 1 : OGRErr OGRSQLiteLayer::RollbackTransaction()
1110 :
1111 : {
1112 1 : return poDS->SoftRollback();
1113 : }
|