1 : /******************************************************************************
2 : * $Id: ogrsqlitedatasource.cpp 19800 2010-06-04 21:38:03Z rouault $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Purpose: Implements OGRSQLiteDataSource class.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2003, Frank Warmerdam <warmerdam@pobox.com>
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_sqlite.h"
31 : #include "cpl_conv.h"
32 : #include "cpl_string.h"
33 : #include "cpl_hash_set.h"
34 :
35 : #ifdef HAVE_SPATIALITE
36 : #include "spatialite.h"
37 : #endif
38 :
39 : static int bSpatialiteLoaded = FALSE;
40 :
41 : CPL_CVSID("$Id: ogrsqlitedatasource.cpp 19800 2010-06-04 21:38:03Z rouault $");
42 :
43 : /************************************************************************/
44 : /* OGRSQLiteDataSource() */
45 : /************************************************************************/
46 :
47 89 : OGRSQLiteDataSource::OGRSQLiteDataSource()
48 :
49 : {
50 89 : pszName = NULL;
51 89 : papoLayers = NULL;
52 89 : nLayers = 0;
53 :
54 89 : nSoftTransactionLevel = 0;
55 :
56 89 : nKnownSRID = 0;
57 89 : panSRID = NULL;
58 89 : papoSRS = NULL;
59 :
60 89 : bHaveGeometryColumns = FALSE;
61 89 : bIsSpatiaLite = FALSE;
62 89 : }
63 :
64 : /************************************************************************/
65 : /* ~OGRSQLiteDataSource() */
66 : /************************************************************************/
67 :
68 89 : OGRSQLiteDataSource::~OGRSQLiteDataSource()
69 :
70 : {
71 : int i;
72 :
73 89 : CPLFree( pszName );
74 :
75 669 : for( i = 0; i < nLayers; i++ )
76 580 : delete papoLayers[i];
77 :
78 89 : CPLFree( papoLayers );
79 :
80 164 : for( i = 0; i < nKnownSRID; i++ )
81 : {
82 75 : if( papoSRS[i] != NULL )
83 75 : papoSRS[i]->Release();
84 : }
85 89 : CPLFree( panSRID );
86 89 : CPLFree( papoSRS );
87 :
88 89 : if( hDB != NULL )
89 89 : sqlite3_close( hDB );
90 89 : }
91 :
92 : /************************************************************************/
93 : /* SpatiaLiteToOGRGeomType() */
94 : /* Map SpatiaLite geometry format strings to corresponding */
95 : /* OGR constants. */
96 : /************************************************************************/
97 :
98 : OGRwkbGeometryType
99 70 : OGRSQLiteDataSource::SpatiaLiteToOGRGeomType( const char *pszGeomType )
100 : {
101 70 : if ( EQUAL(pszGeomType, "POINT") )
102 0 : return wkbPoint;
103 70 : else if ( EQUAL(pszGeomType, "LINESTRING") )
104 0 : return wkbLineString;
105 70 : else if ( EQUAL(pszGeomType, "POLYGON") )
106 46 : return wkbPolygon;
107 24 : else if ( EQUAL(pszGeomType, "MULTIPOINT") )
108 0 : return wkbMultiPoint;
109 24 : else if ( EQUAL(pszGeomType, "MULTILINESTRING") )
110 0 : return wkbMultiLineString;
111 24 : else if ( EQUAL(pszGeomType, "MULTIPOLYGON") )
112 0 : return wkbMultiPolygon;
113 24 : else if ( EQUAL(pszGeomType, "GEOMETRYCOLLECTION") )
114 0 : return wkbGeometryCollection;
115 : else
116 24 : return wkbUnknown;
117 : }
118 :
119 : /************************************************************************/
120 : /* OGRToSpatiaLiteGeomType() */
121 : /* Map OGR geometry format constants to corresponding */
122 : /* SpatiaLite strings */
123 : /************************************************************************/
124 :
125 : const char *
126 4 : OGRSQLiteDataSource::OGRToSpatiaLiteGeomType( OGRwkbGeometryType eGeomType )
127 : {
128 4 : switch ( wkbFlatten(eGeomType) )
129 : {
130 : case wkbUnknown:
131 4 : return "GEOMETRY";
132 : case wkbPoint:
133 0 : return "POINT";
134 : case wkbLineString:
135 0 : return "LINESTRING";
136 : case wkbPolygon:
137 0 : return "POLYGON";
138 : case wkbMultiPoint:
139 0 : return "MULTIPOINT";
140 : case wkbMultiLineString:
141 0 : return "MULTILINESTRING";
142 : case wkbMultiPolygon:
143 0 : return "MULTIPOLYGON";
144 : case wkbGeometryCollection:
145 0 : return "GEOMETRYCOLLECTION";
146 : default:
147 0 : return "";
148 : }
149 : }
150 :
151 : /************************************************************************/
152 : /* Open() */
153 : /* */
154 : /* Note, the Open() will implicitly create the database if it */
155 : /* does not already exist. */
156 : /************************************************************************/
157 :
158 89 : int OGRSQLiteDataSource::Open( const char * pszNewName )
159 :
160 : {
161 89 : CPLAssert( nLayers == 0 );
162 :
163 89 : pszName = CPLStrdup( pszNewName );
164 :
165 : /* -------------------------------------------------------------------- */
166 : /* Try loading SpatiaLite. */
167 : /* -------------------------------------------------------------------- */
168 : #ifdef HAVE_SPATIALITE
169 89 : if (!bSpatialiteLoaded && CSLTestBoolean(CPLGetConfigOption("SPATIALITE_LOAD", "TRUE")))
170 : {
171 1 : bSpatialiteLoaded = TRUE;
172 1 : spatialite_init(CSLTestBoolean(CPLGetConfigOption("SPATIALITE_INIT_VERBOSE", "FALSE")));
173 : }
174 : #endif
175 :
176 89 : int bListAllTables = CSLTestBoolean(CPLGetConfigOption("SQLITE_LIST_ALL_TABLES", "NO"));
177 :
178 : /* -------------------------------------------------------------------- */
179 : /* Try to open the sqlite database properly now. */
180 : /* -------------------------------------------------------------------- */
181 : int rc;
182 :
183 89 : hDB = NULL;
184 89 : rc = sqlite3_open( pszNewName, &hDB );
185 89 : if( rc != SQLITE_OK )
186 : {
187 : CPLError( CE_Failure, CPLE_OpenFailed,
188 : "sqlite3_open(%s) failed: %s",
189 0 : pszNewName, sqlite3_errmsg( hDB ) );
190 :
191 0 : return FALSE;
192 : }
193 :
194 89 : CPLHashSet* hSet = CPLHashSetNew(CPLHashSetHashStr, CPLHashSetEqualStr, CPLFree);
195 :
196 : /* -------------------------------------------------------------------- */
197 : /* If we have a GEOMETRY_COLUMNS tables, initialize on the basis */
198 : /* of that. */
199 : /* -------------------------------------------------------------------- */
200 : char **papszResult;
201 : int nRowCount, iRow, nColCount;
202 : char *pszErrMsg;
203 :
204 : rc = sqlite3_get_table(
205 : hDB,
206 : "SELECT f_table_name, f_geometry_column, geometry_type, coord_dimension, geometry_format, srid"
207 : " FROM geometry_columns",
208 89 : &papszResult, &nRowCount, &nColCount, &pszErrMsg );
209 :
210 89 : if( rc == SQLITE_OK )
211 : {
212 11 : CPLDebug("SQLITE", "OGR style SQLite DB found !");
213 :
214 11 : bHaveGeometryColumns = TRUE;
215 :
216 43 : for( iRow = 0; iRow < nRowCount; iRow++ )
217 : {
218 32 : char **papszRow = papszResult + iRow * 6 + 6;
219 32 : OGRwkbGeometryType eGeomType = wkbUnknown;
220 32 : int nSRID = 0;
221 :
222 32 : if (papszRow[0] == NULL ||
223 : papszRow[1] == NULL ||
224 : papszRow[2] == NULL ||
225 : papszRow[3] == NULL)
226 0 : continue;
227 :
228 32 : eGeomType = (OGRwkbGeometryType) atoi(papszRow[2]);
229 :
230 32 : if( atoi(papszRow[3]) > 2 )
231 0 : eGeomType = (OGRwkbGeometryType) (((int)eGeomType) | wkb25DBit);
232 :
233 32 : if( papszRow[5] != NULL )
234 8 : nSRID = atoi(papszRow[5]);
235 :
236 : OpenTable( papszRow[0], papszRow[1], eGeomType, papszRow[4],
237 32 : FetchSRS( nSRID ) );
238 :
239 32 : if (bListAllTables)
240 0 : CPLHashSetInsert(hSet, CPLStrdup(papszRow[0]));
241 : }
242 :
243 11 : sqlite3_free_table(papszResult);
244 :
245 11 : if (bListAllTables)
246 0 : goto all_tables;
247 :
248 11 : CPLHashSetDestroy(hSet);
249 :
250 11 : return TRUE;
251 : }
252 :
253 : /* -------------------------------------------------------------------- */
254 : /* Otherwise we can deal with SpatiaLite database. */
255 : /* -------------------------------------------------------------------- */
256 78 : sqlite3_free( pszErrMsg );
257 : rc = sqlite3_get_table( hDB,
258 : "SELECT f_table_name, f_geometry_column, "
259 : "type, coord_dimension, srid, "
260 : "spatial_index_enabled FROM geometry_columns",
261 : &papszResult, &nRowCount,
262 78 : &nColCount, &pszErrMsg );
263 :
264 78 : if ( rc == SQLITE_OK )
265 : {
266 78 : CPLDebug("SQLITE", "SpatiaLite-style SQLite DB found !");
267 :
268 78 : bIsSpatiaLite = TRUE;
269 78 : bHaveGeometryColumns = TRUE;
270 :
271 148 : for ( iRow = 0; iRow < nRowCount; iRow++ )
272 : {
273 70 : char **papszRow = papszResult + iRow * 6 + 6;
274 : OGRwkbGeometryType eGeomType;
275 70 : int nSRID = 0;
276 70 : int bHasSpatialIndex = FALSE;
277 :
278 70 : if (papszRow[0] == NULL ||
279 : papszRow[1] == NULL ||
280 : papszRow[2] == NULL ||
281 : papszRow[3] == NULL)
282 0 : continue;
283 :
284 70 : eGeomType = SpatiaLiteToOGRGeomType(papszRow[2]);
285 :
286 70 : if( atoi(papszRow[3]) > 2 )
287 0 : eGeomType = (OGRwkbGeometryType) (((int)eGeomType) | wkb25DBit);
288 :
289 70 : if( papszRow[4] != NULL )
290 70 : nSRID = atoi(papszRow[4]);
291 :
292 : /* Only look for presence of a spatial index if linked against SpatiaLite */
293 70 : if( bSpatialiteLoaded && papszRow[5] != NULL )
294 70 : bHasSpatialIndex = atoi(papszRow[5]);
295 :
296 : OpenTable( papszRow[0], papszRow[1], eGeomType, "SpatiaLite",
297 70 : FetchSRS( nSRID ), nSRID, bHasSpatialIndex );
298 :
299 70 : if (bListAllTables)
300 46 : CPLHashSetInsert(hSet, CPLStrdup(papszRow[0]));
301 : }
302 :
303 78 : sqlite3_free_table(papszResult);
304 :
305 : /* -------------------------------------------------------------------- */
306 : /* Detect VirtualShape layers */
307 : /* -------------------------------------------------------------------- */
308 : #ifdef HAVE_SPATIALITE
309 78 : if (bSpatialiteLoaded)
310 : {
311 : rc = sqlite3_get_table( hDB,
312 : "SELECT name FROM sqlite_master WHERE sql LIKE 'CREATE VIRTUAL TABLE % USING %VirtualShape%'",
313 : &papszResult, &nRowCount,
314 78 : &nColCount, &pszErrMsg );
315 :
316 78 : if ( rc == SQLITE_OK )
317 : {
318 80 : for( iRow = 0; iRow < nRowCount; iRow++ )
319 : {
320 2 : OpenTable( papszResult[iRow+1] );
321 :
322 2 : if (bListAllTables)
323 0 : CPLHashSetInsert(hSet, CPLStrdup(papszResult[iRow+1]));
324 : }
325 : }
326 : else
327 : {
328 : CPLError( CE_Failure, CPLE_AppDefined,
329 : "Unable to fetch list of tables: %s",
330 0 : pszErrMsg );
331 0 : sqlite3_free( pszErrMsg );
332 : }
333 :
334 78 : sqlite3_free_table(papszResult);
335 : }
336 : #endif
337 :
338 78 : if (bListAllTables)
339 64 : goto all_tables;
340 :
341 14 : CPLHashSetDestroy(hSet);
342 :
343 14 : return TRUE;
344 : }
345 :
346 : /* -------------------------------------------------------------------- */
347 : /* Otherwise our final resort is to return all tables and views */
348 : /* as non-spatial tables. */
349 : /* -------------------------------------------------------------------- */
350 0 : sqlite3_free( pszErrMsg );
351 :
352 64 : all_tables:
353 : rc = sqlite3_get_table( hDB,
354 : "SELECT name FROM sqlite_master "
355 : "WHERE type IN ('table','view') "
356 : "UNION ALL "
357 : "SELECT name FROM sqlite_temp_master "
358 : "WHERE type IN ('table','view') "
359 : "ORDER BY 1",
360 : &papszResult, &nRowCount,
361 64 : &nColCount, &pszErrMsg );
362 :
363 64 : if( rc != SQLITE_OK )
364 : {
365 : CPLError( CE_Failure, CPLE_AppDefined,
366 : "Unable to fetch list of tables: %s",
367 0 : pszErrMsg );
368 0 : sqlite3_free( pszErrMsg );
369 0 : CPLHashSetDestroy(hSet);
370 0 : return FALSE;
371 : }
372 :
373 582 : for( iRow = 0; iRow < nRowCount; iRow++ )
374 : {
375 518 : if (CPLHashSetLookup(hSet, papszResult[iRow+1]) == NULL)
376 472 : OpenTable( papszResult[iRow+1] );
377 : }
378 :
379 64 : sqlite3_free_table(papszResult);
380 64 : CPLHashSetDestroy(hSet);
381 :
382 64 : return TRUE;
383 : }
384 :
385 : /************************************************************************/
386 : /* OpenTable() */
387 : /************************************************************************/
388 :
389 : int OGRSQLiteDataSource::OpenTable( const char *pszNewName,
390 : const char *pszGeomCol,
391 : OGRwkbGeometryType eGeomType,
392 : const char *pszGeomFormat,
393 : OGRSpatialReference *poSRS, int nSRID,
394 576 : int bHasSpatialIndex)
395 :
396 : {
397 : /* -------------------------------------------------------------------- */
398 : /* Create the layer object. */
399 : /* -------------------------------------------------------------------- */
400 : OGRSQLiteTableLayer *poLayer;
401 :
402 576 : poLayer = new OGRSQLiteTableLayer( this );
403 :
404 576 : if( poLayer->Initialize( pszNewName, pszGeomCol,
405 : eGeomType, pszGeomFormat,
406 : poSRS, nSRID, bHasSpatialIndex ) )
407 : {
408 0 : delete poLayer;
409 0 : return FALSE;
410 : }
411 :
412 : /* -------------------------------------------------------------------- */
413 : /* Add layer to data source layer list. */
414 : /* -------------------------------------------------------------------- */
415 : papoLayers = (OGRSQLiteLayer **)
416 576 : CPLRealloc( papoLayers, sizeof(OGRSQLiteLayer *) * (nLayers+1) );
417 576 : papoLayers[nLayers++] = poLayer;
418 :
419 576 : return TRUE;
420 : }
421 :
422 : /************************************************************************/
423 : /* TestCapability() */
424 : /************************************************************************/
425 :
426 2 : int OGRSQLiteDataSource::TestCapability( const char * pszCap )
427 :
428 : {
429 2 : if( EQUAL(pszCap,ODsCCreateLayer) )
430 2 : return TRUE;
431 : else
432 0 : return FALSE;
433 : }
434 :
435 : /************************************************************************/
436 : /* GetLayer() */
437 : /************************************************************************/
438 :
439 1188 : OGRLayer *OGRSQLiteDataSource::GetLayer( int iLayer )
440 :
441 : {
442 1188 : if( iLayer < 0 || iLayer >= nLayers )
443 0 : return NULL;
444 : else
445 1188 : return papoLayers[iLayer];
446 : }
447 :
448 : /************************************************************************/
449 : /* ExecuteSQL() */
450 : /************************************************************************/
451 :
452 : static const char* apszSpatialiteFuncs[] =
453 : {
454 : "InitSpatialMetaData",
455 : "AddGeometryColumn",
456 : "RecoverGeometryColumn",
457 : "DiscardGeometryColumn",
458 : "CreateSpatialIndex",
459 : "CreateMbrCache",
460 : "DisableSpatialIndex"
461 : };
462 :
463 : OGRLayer * OGRSQLiteDataSource::ExecuteSQL( const char *pszSQLCommand,
464 : OGRGeometry *poSpatialFilter,
465 301 : const char *pszDialect )
466 :
467 : {
468 301 : if( pszDialect != NULL && EQUAL(pszDialect,"OGRSQL") )
469 : return OGRDataSource::ExecuteSQL( pszSQLCommand,
470 : poSpatialFilter,
471 0 : pszDialect );
472 :
473 : /* -------------------------------------------------------------------- */
474 : /* Special case DELLAYER: command. */
475 : /* -------------------------------------------------------------------- */
476 301 : if( EQUALN(pszSQLCommand,"DELLAYER:",9) )
477 : {
478 11 : const char *pszLayerName = pszSQLCommand + 9;
479 :
480 22 : while( *pszLayerName == ' ' )
481 0 : pszLayerName++;
482 :
483 11 : DeleteLayer( pszLayerName );
484 11 : return NULL;
485 : }
486 :
487 : /* -------------------------------------------------------------------- */
488 : /* Prepare statement. */
489 : /* -------------------------------------------------------------------- */
490 : int rc;
491 290 : sqlite3_stmt *hSQLStmt = NULL;
492 :
493 : rc = sqlite3_prepare( GetDB(), pszSQLCommand, strlen(pszSQLCommand),
494 290 : &hSQLStmt, NULL );
495 :
496 290 : if( rc != SQLITE_OK )
497 : {
498 : CPLError( CE_Failure, CPLE_AppDefined,
499 : "In ExecuteSQL(): sqlite3_prepare(%s):\n %s",
500 0 : pszSQLCommand, sqlite3_errmsg(GetDB()) );
501 :
502 0 : if( hSQLStmt != NULL )
503 : {
504 0 : sqlite3_finalize( hSQLStmt );
505 : }
506 :
507 0 : return NULL;
508 : }
509 :
510 : /* -------------------------------------------------------------------- */
511 : /* Do we get a resultset? */
512 : /* -------------------------------------------------------------------- */
513 290 : rc = sqlite3_step( hSQLStmt );
514 290 : if( rc != SQLITE_ROW )
515 : {
516 135 : if ( rc != SQLITE_DONE )
517 : {
518 : CPLError( CE_Failure, CPLE_AppDefined,
519 : "In ExecuteSQL(): sqlite3_step(%s):\n %s",
520 0 : pszSQLCommand, sqlite3_errmsg(GetDB()) );
521 : }
522 135 : sqlite3_finalize( hSQLStmt );
523 135 : return NULL;
524 : }
525 :
526 : /* -------------------------------------------------------------------- */
527 : /* Special case for some spatialite functions which must be run */
528 : /* only once */
529 : /* -------------------------------------------------------------------- */
530 155 : if( EQUALN(pszSQLCommand,"SELECT ",7) &&
531 : bIsSpatiaLite && bSpatialiteLoaded )
532 : {
533 : unsigned int i;
534 1021 : for(i=0;i<sizeof(apszSpatialiteFuncs)/
535 : sizeof(apszSpatialiteFuncs[0]);i++)
536 : {
537 910 : if( EQUALN(apszSpatialiteFuncs[i], pszSQLCommand + 7,
538 : strlen(apszSpatialiteFuncs[i])) )
539 : {
540 37 : if (sqlite3_column_count( hSQLStmt ) == 1 &&
541 : sqlite3_column_type( hSQLStmt, 0 ) == SQLITE_INTEGER )
542 : {
543 37 : int ret = sqlite3_column_int( hSQLStmt, 0 );
544 :
545 37 : sqlite3_finalize( hSQLStmt );
546 :
547 : return new OGRSQLiteSingleFeatureLayer
548 37 : ( apszSpatialiteFuncs[i], ret );
549 : }
550 : }
551 : }
552 : }
553 :
554 : /* -------------------------------------------------------------------- */
555 : /* Create layer. */
556 : /* -------------------------------------------------------------------- */
557 118 : OGRSQLiteSelectLayer *poLayer = NULL;
558 :
559 118 : CPLString osSQL = pszSQLCommand;
560 118 : poLayer = new OGRSQLiteSelectLayer( this, osSQL, hSQLStmt );
561 :
562 118 : if( poSpatialFilter != NULL )
563 0 : poLayer->SetSpatialFilter( poSpatialFilter );
564 :
565 118 : return poLayer;
566 : }
567 :
568 : /************************************************************************/
569 : /* ReleaseResultSet() */
570 : /************************************************************************/
571 :
572 155 : void OGRSQLiteDataSource::ReleaseResultSet( OGRLayer * poLayer )
573 :
574 : {
575 155 : delete poLayer;
576 155 : }
577 :
578 : /************************************************************************/
579 : /* CreateLayer() */
580 : /************************************************************************/
581 :
582 : OGRLayer *
583 : OGRSQLiteDataSource::CreateLayer( const char * pszLayerNameIn,
584 : OGRSpatialReference *poSRS,
585 : OGRwkbGeometryType eType,
586 14 : char ** papszOptions )
587 :
588 : {
589 : char *pszLayerName;
590 : const char *pszGeomFormat;
591 :
592 14 : if( CSLFetchBoolean(papszOptions,"LAUNDER",TRUE) )
593 14 : pszLayerName = LaunderName( pszLayerNameIn );
594 : else
595 0 : pszLayerName = CPLStrdup( pszLayerNameIn );
596 :
597 14 : pszGeomFormat = CSLFetchNameValue( papszOptions, "FORMAT" );
598 14 : if( pszGeomFormat == NULL )
599 : {
600 11 : if ( !bIsSpatiaLite )
601 7 : pszGeomFormat = "WKB";
602 : else
603 4 : pszGeomFormat = "SpatiaLite";
604 : }
605 :
606 14 : if( !EQUAL(pszGeomFormat,"WKT")
607 : && !EQUAL(pszGeomFormat,"WKB")
608 : && !EQUAL(pszGeomFormat, "SpatiaLite") )
609 : {
610 : CPLError( CE_Failure, CPLE_AppDefined,
611 : "FORMAT=%s not recognised or supported.",
612 0 : pszGeomFormat );
613 0 : return NULL;
614 : }
615 :
616 : /* -------------------------------------------------------------------- */
617 : /* Do we already have this layer? If so, should we blow it */
618 : /* away? */
619 : /* -------------------------------------------------------------------- */
620 : int iLayer;
621 :
622 55 : for( iLayer = 0; iLayer < nLayers; iLayer++ )
623 : {
624 41 : if( EQUAL(pszLayerName,papoLayers[iLayer]->GetLayerDefn()->GetName()) )
625 : {
626 0 : if( CSLFetchNameValue( papszOptions, "OVERWRITE" ) != NULL
627 : && !EQUAL(CSLFetchNameValue(papszOptions,"OVERWRITE"),"NO") )
628 : {
629 0 : DeleteLayer( pszLayerName );
630 : }
631 : else
632 : {
633 : CPLError( CE_Failure, CPLE_AppDefined,
634 : "Layer %s already exists, CreateLayer failed.\n"
635 : "Use the layer creation option OVERWRITE=YES to "
636 : "replace it.",
637 0 : pszLayerName );
638 0 : CPLFree( pszLayerName );
639 0 : return NULL;
640 : }
641 : }
642 : }
643 :
644 : /* -------------------------------------------------------------------- */
645 : /* Try to get the SRS Id of this spatial reference system, */
646 : /* adding to the srs table if needed. */
647 : /* -------------------------------------------------------------------- */
648 14 : int nSRSId = -1;
649 :
650 14 : if( poSRS != NULL )
651 7 : nSRSId = FetchSRSId( poSRS );
652 :
653 : /* -------------------------------------------------------------------- */
654 : /* Create a basic table with the FID. Also include the */
655 : /* geometry if this is not a PostGIS enabled table. */
656 : /* -------------------------------------------------------------------- */
657 : int rc;
658 : char *pszErrMsg;
659 14 : const char *pszGeomCol = NULL;
660 14 : CPLString osCommand;
661 :
662 14 : if( eType == wkbNone )
663 : osCommand.Printf(
664 : "CREATE TABLE '%s' ( OGC_FID INTEGER PRIMARY KEY )",
665 0 : pszLayerName );
666 : else
667 : {
668 14 : if( EQUAL(pszGeomFormat,"WKT") )
669 : {
670 1 : pszGeomCol = "WKT_GEOMETRY";
671 : osCommand.Printf(
672 : "CREATE TABLE '%s' ( "
673 : " OGC_FID INTEGER PRIMARY KEY,"
674 : " %s VARCHAR )",
675 1 : pszLayerName, pszGeomCol );
676 : }
677 : else
678 : {
679 13 : pszGeomCol = "GEOMETRY";
680 : osCommand.Printf(
681 : "CREATE TABLE '%s' ( "
682 : " OGC_FID INTEGER PRIMARY KEY,"
683 : " %s BLOB )",
684 13 : pszLayerName, pszGeomCol );
685 : }
686 : }
687 :
688 : #ifdef DEBUG
689 14 : CPLDebug( "OGR_SQLITE", "exec(%s)", osCommand.c_str() );
690 : #endif
691 :
692 14 : rc = sqlite3_exec( hDB, osCommand, NULL, NULL, &pszErrMsg );
693 14 : if( rc != SQLITE_OK )
694 : {
695 : CPLError( CE_Failure, CPLE_AppDefined,
696 : "Unable to create table %s: %s",
697 0 : pszLayerName, pszErrMsg );
698 0 : sqlite3_free( pszErrMsg );
699 14 : return FALSE;
700 : }
701 :
702 : /* -------------------------------------------------------------------- */
703 : /* Eventually we should be adding this table to a table of */
704 : /* "geometric layers", capturing the WKT projection, and */
705 : /* perhaps some other housekeeping. */
706 : /* -------------------------------------------------------------------- */
707 14 : if( bHaveGeometryColumns && eType != wkbNone )
708 : {
709 : int nCoordDim;
710 :
711 : /* Sometimes there is an old cruft entry in the geometry_columns
712 : * table if things were not properly cleaned up before. We make
713 : * an effort to clean out such cruft.
714 : */
715 : osCommand.Printf(
716 : "DELETE FROM geometry_columns WHERE f_table_name = '%s'",
717 14 : pszLayerName );
718 :
719 : #ifdef DEBUG
720 14 : CPLDebug( "OGR_SQLITE", "exec(%s)", osCommand.c_str() );
721 : #endif
722 :
723 14 : rc = sqlite3_exec( hDB, osCommand, NULL, NULL, &pszErrMsg );
724 14 : if( rc != SQLITE_OK )
725 : {
726 0 : sqlite3_free( pszErrMsg );
727 0 : return FALSE;
728 : }
729 :
730 14 : if( eType == wkbFlatten(eType) )
731 14 : nCoordDim = 2;
732 : else
733 0 : nCoordDim = 3;
734 :
735 14 : if( nSRSId > 0 )
736 : {
737 7 : if ( bIsSpatiaLite )
738 : osCommand.Printf(
739 : "INSERT INTO geometry_columns "
740 : "(f_table_name, f_geometry_column, type, "
741 : "coord_dimension, srid, spatial_index_enabled) "
742 : "VALUES ('%s','%s', '%s', %d, %d, 0)",
743 : pszLayerName, pszGeomCol, OGRToSpatiaLiteGeomType(eType),
744 4 : nCoordDim, nSRSId );
745 : else
746 : osCommand.Printf(
747 : "INSERT INTO geometry_columns "
748 : "(f_table_name, f_geometry_column, geometry_format, "
749 : "geometry_type, coord_dimension, srid) VALUES "
750 : "('%s','%s','%s', %d, %d, %d)",
751 : pszLayerName, pszGeomCol, pszGeomFormat,
752 3 : (int) wkbFlatten(eType), nCoordDim, nSRSId );
753 : }
754 : else
755 : {
756 7 : if ( bIsSpatiaLite )
757 : osCommand.Printf(
758 : "INSERT INTO geometry_columns "
759 : "(f_table_name, f_geometry_column, type, "
760 : "coord_dimension, spatial_index_enabled) "
761 : "VALUES ('%s','%s', '%s', %d, 0)",
762 : pszLayerName, pszGeomCol, OGRToSpatiaLiteGeomType(eType),
763 0 : nCoordDim );
764 : else
765 : osCommand.Printf(
766 : "INSERT INTO geometry_columns "
767 : "(f_table_name, f_geometry_column, geometry_format, "
768 : "geometry_type, coord_dimension) VALUES "
769 : "('%s','%s','%s', %d, %d)",
770 : pszLayerName, pszGeomCol, pszGeomFormat,
771 7 : (int) wkbFlatten(eType), nCoordDim );
772 : }
773 :
774 : #ifdef DEBUG
775 14 : CPLDebug( "OGR_SQLITE", "exec(%s)", osCommand.c_str() );
776 : #endif
777 :
778 14 : rc = sqlite3_exec( hDB, osCommand, NULL, NULL, &pszErrMsg );
779 14 : if( rc != SQLITE_OK )
780 : {
781 : CPLError( CE_Failure, CPLE_AppDefined,
782 : "Unable to add %s table to geometry_columns:\n%s",
783 0 : pszLayerName, pszErrMsg );
784 0 : sqlite3_free( pszErrMsg );
785 0 : return FALSE;
786 : }
787 :
788 : /* -------------------------------------------------------------------- */
789 : /* Create the spatial index. */
790 : /* */
791 : /* We're doing this before we add geometry and record to the table */
792 : /* so this may not be exactly the best way to do it. */
793 : /* -------------------------------------------------------------------- */
794 : #ifdef HAVE_SPATIALITE
795 : /* Only if linked against SpatiaLite and the datasource was created as a SpatiaLite DB */
796 14 : if ( bIsSpatiaLite && bSpatialiteLoaded )
797 : #else
798 : if ( 0 )
799 : #endif
800 : {
801 4 : const char* pszSI = CSLFetchNameValue( papszOptions, "SPATIAL_INDEX" );
802 4 : if( pszSI == NULL || CSLTestBoolean(pszSI) )
803 : {
804 : osCommand.Printf("SELECT CreateSpatialIndex('%s', '%s')",
805 4 : pszLayerName, pszGeomCol);
806 :
807 4 : rc = sqlite3_exec( hDB, osCommand, NULL, NULL, &pszErrMsg );
808 4 : if( rc != SQLITE_OK )
809 : {
810 : CPLError( CE_Failure, CPLE_AppDefined,
811 0 : "Unable to create spatial index:\n%s", pszErrMsg );
812 0 : sqlite3_free( pszErrMsg );
813 0 : return FALSE;
814 : }
815 : }
816 : }
817 : }
818 :
819 : /* -------------------------------------------------------------------- */
820 : /* Create the layer object. */
821 : /* -------------------------------------------------------------------- */
822 : OGRSQLiteTableLayer *poLayer;
823 :
824 14 : poLayer = new OGRSQLiteTableLayer( this );
825 :
826 : poLayer->Initialize( pszLayerName, pszGeomCol, eType, pszGeomFormat,
827 28 : FetchSRS(nSRSId), nSRSId );
828 :
829 14 : poLayer->SetLaunderFlag( CSLFetchBoolean(papszOptions,"LAUNDER",TRUE) );
830 :
831 : /* -------------------------------------------------------------------- */
832 : /* Add layer to data source layer list. */
833 : /* -------------------------------------------------------------------- */
834 : papoLayers = (OGRSQLiteLayer **)
835 14 : CPLRealloc( papoLayers, sizeof(OGRSQLiteLayer *) * (nLayers+1) );
836 :
837 14 : papoLayers[nLayers++] = poLayer;
838 :
839 14 : CPLFree( pszLayerName );
840 :
841 14 : return poLayer;
842 : }
843 :
844 : /************************************************************************/
845 : /* LaunderName() */
846 : /************************************************************************/
847 :
848 33 : char *OGRSQLiteDataSource::LaunderName( const char *pszSrcName )
849 :
850 : {
851 33 : char *pszSafeName = CPLStrdup( pszSrcName );
852 : int i;
853 :
854 280 : for( i = 0; pszSafeName[i] != '\0'; i++ )
855 : {
856 247 : pszSafeName[i] = (char) tolower( pszSafeName[i] );
857 247 : if( pszSafeName[i] == '-' || pszSafeName[i] == '#' )
858 0 : pszSafeName[i] = '_';
859 : }
860 :
861 33 : return pszSafeName;
862 : }
863 :
864 : /************************************************************************/
865 : /* DeleteLayer() */
866 : /************************************************************************/
867 :
868 11 : void OGRSQLiteDataSource::DeleteLayer( const char *pszLayerName )
869 :
870 : {
871 : int iLayer;
872 :
873 : /* -------------------------------------------------------------------- */
874 : /* Try to find layer. */
875 : /* -------------------------------------------------------------------- */
876 28 : for( iLayer = 0; iLayer < nLayers; iLayer++ )
877 : {
878 27 : if( EQUAL(pszLayerName,papoLayers[iLayer]->GetLayerDefn()->GetName()) )
879 10 : break;
880 : }
881 :
882 11 : if( iLayer == nLayers )
883 : {
884 : CPLError( CE_Failure, CPLE_AppDefined,
885 : "Attempt to delete layer '%s', but this layer is not known to OGR.",
886 1 : pszLayerName );
887 1 : return;
888 : }
889 :
890 : /* -------------------------------------------------------------------- */
891 : /* Blow away our OGR structures related to the layer. This is */
892 : /* pretty dangerous if anything has a reference to this layer! */
893 : /* -------------------------------------------------------------------- */
894 10 : CPLDebug( "OGR_SQLITE", "DeleteLayer(%s)", pszLayerName );
895 :
896 10 : delete papoLayers[iLayer];
897 : memmove( papoLayers + iLayer, papoLayers + iLayer + 1,
898 10 : sizeof(void *) * (nLayers - iLayer - 1) );
899 10 : nLayers--;
900 :
901 : /* -------------------------------------------------------------------- */
902 : /* Remove from the database. */
903 : /* -------------------------------------------------------------------- */
904 : int rc;
905 : char *pszErrMsg;
906 :
907 : rc = sqlite3_exec( hDB, CPLSPrintf( "DROP TABLE '%s'", pszLayerName ),
908 10 : NULL, NULL, &pszErrMsg );
909 10 : if( rc != SQLITE_OK )
910 : {
911 : CPLError( CE_Failure, CPLE_AppDefined,
912 : "Unable to drop table %s: %s",
913 0 : pszLayerName, pszErrMsg );
914 0 : sqlite3_free( pszErrMsg );
915 0 : return;
916 : }
917 :
918 : /* -------------------------------------------------------------------- */
919 : /* Drop from geometry_columns table. */
920 : /* -------------------------------------------------------------------- */
921 10 : if( bHaveGeometryColumns )
922 : {
923 10 : CPLString osCommand;
924 :
925 : osCommand.Printf(
926 : "DELETE FROM geometry_columns WHERE f_table_name = '%s'",
927 10 : pszLayerName );
928 :
929 10 : rc = sqlite3_exec( hDB, osCommand, NULL, NULL, &pszErrMsg );
930 10 : if( rc != SQLITE_OK )
931 : {
932 : CPLError( CE_Warning, CPLE_AppDefined,
933 : "Removal from geometry_columns failed.\n%s: %s",
934 0 : osCommand.c_str(), pszErrMsg );
935 0 : sqlite3_free( pszErrMsg );
936 10 : }
937 : }
938 : }
939 :
940 : /************************************************************************/
941 : /* SoftStartTransaction() */
942 : /* */
943 : /* Create a transaction scope. If we already have a */
944 : /* transaction active this isn't a real transaction, but just */
945 : /* an increment to the scope count. */
946 : /************************************************************************/
947 :
948 27 : OGRErr OGRSQLiteDataSource::SoftStartTransaction()
949 :
950 : {
951 27 : nSoftTransactionLevel++;
952 :
953 27 : if( nSoftTransactionLevel == 1 )
954 : {
955 : int rc;
956 : char *pszErrMsg;
957 :
958 : #ifdef DEBUG
959 27 : CPLDebug( "OGR_SQLITE", "BEGIN Transaction" );
960 : #endif
961 :
962 27 : rc = sqlite3_exec( hDB, "BEGIN", NULL, NULL, &pszErrMsg );
963 27 : if( rc != SQLITE_OK )
964 : {
965 0 : nSoftTransactionLevel--;
966 : CPLError( CE_Failure, CPLE_AppDefined,
967 : "BEGIN transaction failed: %s",
968 0 : pszErrMsg );
969 0 : sqlite3_free( pszErrMsg );
970 0 : return OGRERR_FAILURE;
971 : }
972 : }
973 :
974 27 : return OGRERR_NONE;
975 : }
976 :
977 : /************************************************************************/
978 : /* SoftCommit() */
979 : /* */
980 : /* Commit the current transaction if we are at the outer */
981 : /* scope. */
982 : /************************************************************************/
983 :
984 26 : OGRErr OGRSQLiteDataSource::SoftCommit()
985 :
986 : {
987 26 : if( nSoftTransactionLevel <= 0 )
988 : {
989 0 : CPLDebug( "OGR_SQLITE", "SoftCommit() with no transaction active." );
990 0 : return OGRERR_FAILURE;
991 : }
992 :
993 26 : nSoftTransactionLevel--;
994 :
995 26 : if( nSoftTransactionLevel == 0 )
996 : {
997 : int rc;
998 : char *pszErrMsg;
999 :
1000 : #ifdef DEBUG
1001 26 : CPLDebug( "OGR_SQLITE", "COMMIT Transaction" );
1002 : #endif
1003 :
1004 26 : rc = sqlite3_exec( hDB, "COMMIT", NULL, NULL, &pszErrMsg );
1005 26 : if( rc != SQLITE_OK )
1006 : {
1007 : CPLError( CE_Failure, CPLE_AppDefined,
1008 : "COMMIT transaction failed: %s",
1009 0 : pszErrMsg );
1010 0 : sqlite3_free( pszErrMsg );
1011 0 : return OGRERR_FAILURE;
1012 : }
1013 : }
1014 :
1015 26 : return OGRERR_NONE;
1016 : }
1017 :
1018 : /************************************************************************/
1019 : /* SoftRollback() */
1020 : /* */
1021 : /* Force a rollback of the current transaction if there is one, */
1022 : /* even if we are nested several levels deep. */
1023 : /************************************************************************/
1024 :
1025 1 : OGRErr OGRSQLiteDataSource::SoftRollback()
1026 :
1027 : {
1028 1 : if( nSoftTransactionLevel <= 0 )
1029 : {
1030 0 : CPLDebug( "OGR_SQLITE", "SoftRollback() with no transaction active." );
1031 0 : return OGRERR_FAILURE;
1032 : }
1033 :
1034 1 : nSoftTransactionLevel = 0;
1035 :
1036 : int rc;
1037 : char *pszErrMsg;
1038 :
1039 : #ifdef DEBUG
1040 1 : CPLDebug( "OGR_SQLITE", "ROLLBACK Transaction" );
1041 : #endif
1042 :
1043 1 : rc = sqlite3_exec( hDB, "ROLLBACK", NULL, NULL, &pszErrMsg );
1044 1 : if( rc != SQLITE_OK )
1045 : {
1046 : CPLError( CE_Failure, CPLE_AppDefined,
1047 : "ROLLBACK transaction failed: %s",
1048 0 : pszErrMsg );
1049 0 : sqlite3_free( pszErrMsg );
1050 0 : return OGRERR_FAILURE;
1051 : }
1052 :
1053 1 : return OGRERR_NONE;
1054 : }
1055 :
1056 : /************************************************************************/
1057 : /* FlushSoftTransaction() */
1058 : /* */
1059 : /* Force the unwinding of any active transaction, and it's */
1060 : /* commit. */
1061 : /************************************************************************/
1062 :
1063 0 : OGRErr OGRSQLiteDataSource::FlushSoftTransaction()
1064 :
1065 : {
1066 0 : if( nSoftTransactionLevel <= 0 )
1067 0 : return OGRERR_NONE;
1068 :
1069 0 : nSoftTransactionLevel = 1;
1070 :
1071 0 : return SoftCommit();
1072 : }
1073 :
1074 : /************************************************************************/
1075 : /* FetchSRSId() */
1076 : /* */
1077 : /* Fetch the id corresponding to an SRS, and if not found, add */
1078 : /* it to the table. */
1079 : /************************************************************************/
1080 :
1081 7 : int OGRSQLiteDataSource::FetchSRSId( OGRSpatialReference * poSRS )
1082 :
1083 : {
1084 7 : int nSRSId = -1;
1085 7 : const char *pszAuthorityName, *pszAuthorityCode = NULL;
1086 7 : CPLString osCommand;
1087 : char *pszErrMsg;
1088 : int rc;
1089 : char **papszResult;
1090 : int nRowCount, nColCount;
1091 :
1092 7 : if( poSRS == NULL )
1093 0 : return -1;
1094 :
1095 7 : OGRSpatialReference oSRS(*poSRS);
1096 7 : poSRS = NULL;
1097 :
1098 7 : pszAuthorityName = oSRS.GetAuthorityName(NULL);
1099 :
1100 7 : if( pszAuthorityName == NULL || strlen(pszAuthorityName) == 0 )
1101 : {
1102 : /* -------------------------------------------------------------------- */
1103 : /* Try to identify an EPSG code */
1104 : /* -------------------------------------------------------------------- */
1105 2 : oSRS.AutoIdentifyEPSG();
1106 :
1107 2 : pszAuthorityName = oSRS.GetAuthorityName(NULL);
1108 2 : if (pszAuthorityName != NULL && EQUAL(pszAuthorityName, "EPSG"))
1109 : {
1110 1 : pszAuthorityCode = oSRS.GetAuthorityCode(NULL);
1111 1 : if ( pszAuthorityCode != NULL && strlen(pszAuthorityCode) > 0 )
1112 : {
1113 : /* Import 'clean' SRS */
1114 1 : oSRS.importFromEPSG( atoi(pszAuthorityCode) );
1115 :
1116 1 : pszAuthorityName = oSRS.GetAuthorityName(NULL);
1117 1 : pszAuthorityCode = oSRS.GetAuthorityCode(NULL);
1118 : }
1119 : }
1120 : }
1121 :
1122 : /* -------------------------------------------------------------------- */
1123 : /* Check whether the EPSG authority code is already mapped to a */
1124 : /* SRS ID. */
1125 : /* -------------------------------------------------------------------- */
1126 7 : if( pszAuthorityName != NULL && strlen(pszAuthorityName) > 0 )
1127 : {
1128 6 : pszAuthorityCode = oSRS.GetAuthorityCode(NULL);
1129 :
1130 6 : if ( pszAuthorityCode != NULL && strlen(pszAuthorityCode) > 0 )
1131 : {
1132 : // XXX: We are using case insensitive comparison for "auth_name"
1133 : // values, because there are variety of options exist. By default
1134 : // the driver uses 'EPSG' in upper case, but SpatiaLite extension
1135 : // uses 'epsg' in lower case.
1136 : osCommand.Printf( "SELECT srid FROM spatial_ref_sys WHERE "
1137 : "auth_name = '%s' COLLATE NOCASE AND auth_srid = '%s'",
1138 6 : pszAuthorityName, pszAuthorityCode );
1139 :
1140 : rc = sqlite3_get_table( hDB, osCommand, &papszResult,
1141 6 : &nRowCount, &nColCount, &pszErrMsg );
1142 6 : if( rc != SQLITE_OK )
1143 : {
1144 : /* Retry without COLLATE NOCASE which may not be understood by older sqlite3 */
1145 0 : sqlite3_free( pszErrMsg );
1146 :
1147 : osCommand.Printf( "SELECT srid FROM spatial_ref_sys WHERE "
1148 : "auth_name = '%s' AND auth_srid = '%s'",
1149 0 : pszAuthorityName, pszAuthorityCode );
1150 :
1151 : rc = sqlite3_get_table( hDB, osCommand, &papszResult,
1152 0 : &nRowCount, &nColCount, &pszErrMsg );
1153 :
1154 : /* Retry in lower case for SpatiaLite */
1155 0 : if( rc != SQLITE_OK )
1156 : {
1157 0 : sqlite3_free( pszErrMsg );
1158 : }
1159 0 : else if ( nRowCount == 0 &&
1160 : strcmp(pszAuthorityName, "EPSG") == 0)
1161 : {
1162 : /* If it's in upper case, look for lower case */
1163 0 : sqlite3_free_table(papszResult);
1164 :
1165 : osCommand.Printf( "SELECT srid FROM spatial_ref_sys WHERE "
1166 : "auth_name = 'epsg' AND auth_srid = '%s'",
1167 0 : pszAuthorityCode );
1168 :
1169 : rc = sqlite3_get_table( hDB, osCommand, &papszResult,
1170 0 : &nRowCount, &nColCount, &pszErrMsg );
1171 :
1172 0 : if( rc != SQLITE_OK )
1173 : {
1174 0 : sqlite3_free( pszErrMsg );
1175 : }
1176 : }
1177 : }
1178 :
1179 6 : if( rc == SQLITE_OK && nRowCount == 1 )
1180 : {
1181 4 : nSRSId = (papszResult[1] != NULL) ? atoi(papszResult[1]) : -1;
1182 4 : sqlite3_free_table(papszResult);
1183 4 : return nSRSId;
1184 : }
1185 2 : sqlite3_free_table(papszResult);
1186 : }
1187 : }
1188 :
1189 : /* -------------------------------------------------------------------- */
1190 : /* Search for existing record using either WKT definition or */
1191 : /* PROJ.4 string (SpatiaLite variant). */
1192 : /* -------------------------------------------------------------------- */
1193 3 : CPLString osSRS;
1194 :
1195 3 : if ( !bIsSpatiaLite )
1196 : {
1197 : /* -------------------------------------------------------------------- */
1198 : /* Translate SRS to WKT. */
1199 : /* -------------------------------------------------------------------- */
1200 1 : char *pszWKT = NULL;
1201 :
1202 1 : if( oSRS.exportToWkt( &pszWKT ) != OGRERR_NONE )
1203 : {
1204 0 : CPLFree(pszWKT);
1205 0 : return -1;
1206 : }
1207 :
1208 1 : osSRS = pszWKT;
1209 1 : CPLFree( pszWKT );
1210 1 : pszWKT = NULL;
1211 :
1212 : /* -------------------------------------------------------------------- */
1213 : /* Try to find based on the WKT match. */
1214 : /* -------------------------------------------------------------------- */
1215 1 : osCommand.Printf( "SELECT srid FROM spatial_ref_sys WHERE srtext = ?");
1216 : }
1217 :
1218 : /* -------------------------------------------------------------------- */
1219 : /* Handle SpatiaLite flavour of the spatial_ref_sys. */
1220 : /* -------------------------------------------------------------------- */
1221 : else
1222 : {
1223 : /* -------------------------------------------------------------------- */
1224 : /* Translate SRS to PROJ.4 string. */
1225 : /* -------------------------------------------------------------------- */
1226 2 : char *pszProj4 = NULL;
1227 :
1228 2 : if( oSRS.exportToProj4( &pszProj4 ) != OGRERR_NONE )
1229 : {
1230 0 : CPLFree(pszProj4);
1231 0 : return -1;
1232 : }
1233 :
1234 2 : osSRS = pszProj4;
1235 2 : CPLFree( pszProj4 );
1236 2 : pszProj4 = NULL;
1237 :
1238 : /* -------------------------------------------------------------------- */
1239 : /* Try to find based on the PROJ.4 match. */
1240 : /* -------------------------------------------------------------------- */
1241 : osCommand.Printf(
1242 2 : "SELECT srid FROM spatial_ref_sys WHERE proj4text = ?");
1243 : }
1244 :
1245 3 : sqlite3_stmt *hSelectStmt = NULL;
1246 3 : rc = sqlite3_prepare( hDB, osCommand, -1, &hSelectStmt, NULL );
1247 :
1248 3 : if( rc == SQLITE_OK)
1249 3 : rc = sqlite3_bind_text( hSelectStmt, 1, osSRS.c_str(), -1, SQLITE_STATIC );
1250 :
1251 3 : if( rc == SQLITE_OK)
1252 3 : rc = sqlite3_step( hSelectStmt );
1253 :
1254 3 : if (rc == SQLITE_ROW)
1255 : {
1256 0 : if (sqlite3_column_type( hSelectStmt, 0 ) == SQLITE_INTEGER)
1257 0 : nSRSId = sqlite3_column_int( hSelectStmt, 0 );
1258 : else
1259 0 : nSRSId = -1;
1260 :
1261 0 : sqlite3_finalize( hSelectStmt );
1262 0 : return nSRSId;
1263 : }
1264 :
1265 : /* -------------------------------------------------------------------- */
1266 : /* If the command actually failed, then the metadata table is */
1267 : /* likely missing, so we give up. */
1268 : /* -------------------------------------------------------------------- */
1269 3 : if (rc != SQLITE_DONE && rc != SQLITE_ROW)
1270 : {
1271 0 : sqlite3_finalize( hSelectStmt );
1272 0 : return -1;
1273 : }
1274 :
1275 3 : sqlite3_finalize( hSelectStmt );
1276 :
1277 : /* -------------------------------------------------------------------- */
1278 : /* If we have an authority code try to assign SRS ID the same */
1279 : /* as that code. */
1280 : /* -------------------------------------------------------------------- */
1281 3 : if ( pszAuthorityCode != NULL && strlen(pszAuthorityCode) > 0 )
1282 : {
1283 : osCommand.Printf( "SELECT * FROM spatial_ref_sys WHERE auth_srid='%s'",
1284 2 : pszAuthorityCode );
1285 : rc = sqlite3_get_table( hDB, osCommand, &papszResult,
1286 2 : &nRowCount, &nColCount, &pszErrMsg );
1287 :
1288 2 : if( rc != SQLITE_OK )
1289 : {
1290 : CPLError( CE_Failure, CPLE_AppDefined,
1291 : "exec(SELECT '%s' FROM spatial_ref_sys) failed: %s",
1292 0 : pszAuthorityCode, pszErrMsg );
1293 0 : sqlite3_free( pszErrMsg );
1294 : }
1295 :
1296 : /* -------------------------------------------------------------------- */
1297 : /* If there is no SRS ID with such auth_srid, use it as SRS ID. */
1298 : /* -------------------------------------------------------------------- */
1299 2 : if ( nRowCount < 1 )
1300 2 : nSRSId = atoi(pszAuthorityCode);
1301 2 : sqlite3_free_table(papszResult);
1302 : }
1303 :
1304 : /* -------------------------------------------------------------------- */
1305 : /* Otherwise get the current maximum srid in the srs table. */
1306 : /* -------------------------------------------------------------------- */
1307 3 : if ( nSRSId == -1 )
1308 : {
1309 : rc = sqlite3_get_table( hDB, "SELECT MAX(srid) FROM spatial_ref_sys",
1310 : &papszResult, &nRowCount, &nColCount,
1311 1 : &pszErrMsg );
1312 :
1313 1 : if( rc != SQLITE_OK )
1314 : {
1315 : CPLError( CE_Failure, CPLE_AppDefined,
1316 0 : "SELECT of the maximum SRS ID failed: %s", pszErrMsg );
1317 0 : sqlite3_free( pszErrMsg );
1318 0 : return -1;
1319 : }
1320 :
1321 1 : if ( nRowCount < 1 || !papszResult[1] )
1322 0 : nSRSId = 50000;
1323 : else
1324 1 : nSRSId = atoi(papszResult[1]) + 1; // Insert as the next SRS ID
1325 1 : sqlite3_free_table(papszResult);
1326 : }
1327 :
1328 : /* -------------------------------------------------------------------- */
1329 : /* Try adding the SRS to the SRS table. */
1330 : /* -------------------------------------------------------------------- */
1331 :
1332 3 : const char* apszToInsert[] = { NULL, NULL, NULL, NULL, NULL };
1333 :
1334 3 : if ( !bIsSpatiaLite )
1335 : {
1336 1 : if( pszAuthorityName != NULL )
1337 : {
1338 : osCommand.Printf(
1339 : "INSERT INTO spatial_ref_sys (srid,srtext,auth_name,auth_srid) "
1340 : " VALUES (%d, ?, ?, ?)",
1341 1 : nSRSId );
1342 1 : apszToInsert[0] = osSRS.c_str();
1343 1 : apszToInsert[1] = pszAuthorityName;
1344 1 : apszToInsert[2] = pszAuthorityCode;
1345 : }
1346 : else
1347 : {
1348 : osCommand.Printf(
1349 : "INSERT INTO spatial_ref_sys (srid,srtext) "
1350 : " VALUES (%d, ?)",
1351 0 : nSRSId );
1352 0 : apszToInsert[0] = osSRS.c_str();
1353 : }
1354 : }
1355 : else
1356 : {
1357 2 : const char *pszProjCS = oSRS.GetAttrValue("PROJCS");
1358 2 : if (pszProjCS == NULL)
1359 1 : pszProjCS = oSRS.GetAttrValue("GEOGCS");
1360 :
1361 2 : if( pszAuthorityName != NULL )
1362 : {
1363 1 : if ( pszProjCS )
1364 : {
1365 : osCommand.Printf(
1366 : "INSERT INTO spatial_ref_sys "
1367 : "(srid, auth_name, auth_srid, ref_sys_name, proj4text) "
1368 : "VALUES (%d, ?, ?, ?, ?)",
1369 1 : nSRSId );
1370 1 : apszToInsert[0] = pszAuthorityName;
1371 1 : apszToInsert[1] = pszAuthorityCode;
1372 1 : apszToInsert[2] = pszProjCS;
1373 1 : apszToInsert[3] = osSRS.c_str();
1374 : }
1375 : else
1376 : {
1377 : osCommand.Printf(
1378 : "INSERT INTO spatial_ref_sys "
1379 : "(srid, auth_name, auth_srid, proj4text) "
1380 : "VALUES (%d, ?, ?, ?)",
1381 0 : nSRSId );
1382 0 : apszToInsert[0] = pszAuthorityName;
1383 0 : apszToInsert[1] = pszAuthorityCode;
1384 0 : apszToInsert[2] = osSRS.c_str();
1385 : }
1386 : }
1387 : else
1388 : {
1389 : /* SpatiaLite spatial_ref_sys auth_name and auth_srid columns must be NOT NULL */
1390 : /* so insert within a fake OGR "authority" */
1391 1 : if ( pszProjCS )
1392 : {
1393 : osCommand.Printf(
1394 : "INSERT INTO spatial_ref_sys "
1395 : "(srid, auth_name, auth_srid, ref_sys_name, proj4text) VALUES (%d, 'OGR', %d, ?, ?)",
1396 1 : nSRSId, nSRSId );
1397 1 : apszToInsert[0] = pszProjCS;
1398 1 : apszToInsert[1] = osSRS.c_str();
1399 : }
1400 : else
1401 : {
1402 : osCommand.Printf(
1403 : "INSERT INTO spatial_ref_sys "
1404 : "(srid, auth_name, auth_srid, proj4text) VALUES (%d, 'OGR', %d, ?)",
1405 0 : nSRSId, nSRSId );
1406 0 : apszToInsert[0] = osSRS.c_str();
1407 : }
1408 : }
1409 : }
1410 :
1411 3 : sqlite3_stmt *hInsertStmt = NULL;
1412 3 : rc = sqlite3_prepare( hDB, osCommand, -1, &hInsertStmt, NULL );
1413 :
1414 : int i;
1415 12 : for(i=0;apszToInsert[i]!=NULL;i++)
1416 : {
1417 9 : if( rc == SQLITE_OK)
1418 9 : rc = sqlite3_bind_text( hInsertStmt, i+1, apszToInsert[i], -1, SQLITE_STATIC );
1419 : }
1420 :
1421 3 : if( rc == SQLITE_OK)
1422 3 : rc = sqlite3_step( hInsertStmt );
1423 :
1424 3 : if( rc != SQLITE_OK && rc != SQLITE_DONE )
1425 : {
1426 : CPLError( CE_Failure, CPLE_AppDefined,
1427 : "Unable to insert SRID (%s): %s",
1428 0 : osCommand.c_str(), sqlite3_errmsg(hDB) );
1429 :
1430 0 : sqlite3_finalize( hInsertStmt );
1431 0 : return FALSE;
1432 : }
1433 :
1434 3 : sqlite3_finalize( hInsertStmt );
1435 :
1436 3 : return nSRSId;
1437 : }
1438 :
1439 : /************************************************************************/
1440 : /* FetchSRS() */
1441 : /* */
1442 : /* Return a SRS corresponding to a particular id. Note that */
1443 : /* reference counting should be honoured on the returned */
1444 : /* OGRSpatialReference, as handles may be cached. */
1445 : /************************************************************************/
1446 :
1447 116 : OGRSpatialReference *OGRSQLiteDataSource::FetchSRS( int nId )
1448 :
1449 : {
1450 116 : if( nId <= 0 )
1451 31 : return NULL;
1452 :
1453 : /* -------------------------------------------------------------------- */
1454 : /* First, we look through our SRID cache, is it there? */
1455 : /* -------------------------------------------------------------------- */
1456 : int i;
1457 :
1458 94 : for( i = 0; i < nKnownSRID; i++ )
1459 : {
1460 19 : if( panSRID[i] == nId )
1461 10 : return papoSRS[i];
1462 : }
1463 :
1464 : /* -------------------------------------------------------------------- */
1465 : /* Try looking up in spatial_ref_sys table. */
1466 : /* -------------------------------------------------------------------- */
1467 : char *pszErrMsg;
1468 : int rc;
1469 : char **papszResult;
1470 : int nRowCount, nColCount;
1471 75 : CPLString osCommand;
1472 75 : OGRSpatialReference *poSRS = NULL;
1473 :
1474 : osCommand.Printf( "SELECT srtext FROM spatial_ref_sys WHERE srid = %d",
1475 75 : nId );
1476 : rc = sqlite3_get_table( hDB, osCommand,
1477 75 : &papszResult, &nRowCount, &nColCount, &pszErrMsg );
1478 :
1479 75 : if ( rc == SQLITE_OK )
1480 : {
1481 7 : if( nRowCount < 1 )
1482 : {
1483 0 : sqlite3_free_table(papszResult);
1484 75 : return NULL;
1485 : }
1486 :
1487 7 : char** papszRow = papszResult + nColCount;
1488 7 : if (papszRow[0] != NULL)
1489 : {
1490 7 : CPLString osWKT = papszRow[0];
1491 :
1492 : /* -------------------------------------------------------------------- */
1493 : /* Translate into a spatial reference. */
1494 : /* -------------------------------------------------------------------- */
1495 7 : char *pszWKT = (char *) osWKT.c_str();
1496 :
1497 7 : poSRS = new OGRSpatialReference();
1498 14 : if( poSRS->importFromWkt( &pszWKT ) != OGRERR_NONE )
1499 : {
1500 0 : delete poSRS;
1501 0 : poSRS = NULL;
1502 7 : }
1503 : }
1504 :
1505 7 : sqlite3_free_table(papszResult);
1506 : }
1507 :
1508 : /* -------------------------------------------------------------------- */
1509 : /* Next try SpatiaLite flavour. SpatiaLite uses PROJ.4 strings */
1510 : /* in 'proj4text' column instead of WKT in 'srtext'. */
1511 : /* -------------------------------------------------------------------- */
1512 : else
1513 : {
1514 68 : sqlite3_free( pszErrMsg );
1515 68 : pszErrMsg = NULL;
1516 :
1517 : osCommand.Printf(
1518 68 : "SELECT proj4text, auth_name, auth_srid FROM spatial_ref_sys WHERE srid = %d", nId );
1519 : rc = sqlite3_get_table( hDB, osCommand,
1520 : &papszResult, &nRowCount,
1521 68 : &nColCount, &pszErrMsg );
1522 68 : if ( rc == SQLITE_OK )
1523 : {
1524 68 : if( nRowCount < 1 )
1525 : {
1526 0 : sqlite3_free_table(papszResult);
1527 0 : return NULL;
1528 : }
1529 :
1530 : /* -------------------------------------------------------------------- */
1531 : /* Translate into a spatial reference. */
1532 : /* -------------------------------------------------------------------- */
1533 68 : char** papszRow = papszResult + nColCount;
1534 :
1535 68 : const char* pszProj4Text = papszRow[0];
1536 68 : if (pszProj4Text != NULL)
1537 : {
1538 68 : const char* pszAuthName = papszRow[1];
1539 68 : int nAuthSRID = (papszRow[2] != NULL) ? atoi(papszRow[2]) : 0;
1540 :
1541 68 : poSRS = new OGRSpatialReference();
1542 :
1543 : /* Try first from EPSG code */
1544 136 : if (pszAuthName != NULL &&
1545 : EQUAL(pszAuthName, "EPSG") &&
1546 : poSRS->importFromEPSG( nAuthSRID ) == OGRERR_NONE)
1547 : {
1548 : /* Do nothing */
1549 : }
1550 : /* Then from Proj4 string */
1551 9 : else if( poSRS->importFromProj4( pszProj4Text ) != OGRERR_NONE )
1552 : {
1553 0 : delete poSRS;
1554 0 : poSRS = NULL;
1555 : }
1556 : }
1557 :
1558 68 : sqlite3_free_table(papszResult);
1559 : }
1560 :
1561 : /* -------------------------------------------------------------------- */
1562 : /* No success, report an error. */
1563 : /* -------------------------------------------------------------------- */
1564 : else
1565 : {
1566 : CPLError( CE_Failure, CPLE_AppDefined,
1567 0 : "%s: %s", osCommand.c_str(), pszErrMsg );
1568 0 : sqlite3_free( pszErrMsg );
1569 0 : return NULL;
1570 : }
1571 : }
1572 :
1573 : /* -------------------------------------------------------------------- */
1574 : /* Add to the cache. */
1575 : /* -------------------------------------------------------------------- */
1576 75 : panSRID = (int *) CPLRealloc(panSRID,sizeof(int) * (nKnownSRID+1) );
1577 : papoSRS = (OGRSpatialReference **)
1578 75 : CPLRealloc(papoSRS, sizeof(void*) * (nKnownSRID + 1) );
1579 75 : panSRID[nKnownSRID] = nId;
1580 75 : papoSRS[nKnownSRID] = poSRS;
1581 75 : nKnownSRID++;
1582 :
1583 75 : return poSRS;
1584 : }
|