1 : /******************************************************************************
2 : * $Id: ogrodbcdatasource.cpp 17870 2009-10-22 04:47:29Z warmerdam $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Purpose: Implements OGRODBCDataSource 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_odbc.h"
31 : #include "cpl_conv.h"
32 : #include "cpl_string.h"
33 :
34 : CPL_CVSID("$Id: ogrodbcdatasource.cpp 17870 2009-10-22 04:47:29Z warmerdam $");
35 : /************************************************************************/
36 : /* OGRODBCDataSource() */
37 : /************************************************************************/
38 :
39 0 : OGRODBCDataSource::OGRODBCDataSource()
40 :
41 : {
42 0 : pszName = NULL;
43 0 : papoLayers = NULL;
44 0 : nLayers = 0;
45 :
46 0 : nKnownSRID = 0;
47 0 : panSRID = NULL;
48 0 : papoSRS = NULL;
49 0 : }
50 :
51 : /************************************************************************/
52 : /* ~OGRODBCDataSource() */
53 : /************************************************************************/
54 :
55 0 : OGRODBCDataSource::~OGRODBCDataSource()
56 :
57 : {
58 : int i;
59 :
60 0 : CPLFree( pszName );
61 :
62 0 : for( i = 0; i < nLayers; i++ )
63 0 : delete papoLayers[i];
64 :
65 0 : CPLFree( papoLayers );
66 :
67 0 : for( i = 0; i < nKnownSRID; i++ )
68 : {
69 0 : if( papoSRS[i] != NULL )
70 0 : papoSRS[i]->Release();
71 : }
72 0 : CPLFree( panSRID );
73 0 : CPLFree( papoSRS );
74 0 : }
75 :
76 : /************************************************************************/
77 : /* Open() */
78 : /************************************************************************/
79 :
80 : int OGRODBCDataSource::Open( const char * pszNewName, int bUpdate,
81 0 : int bTestOpen )
82 :
83 : {
84 0 : CPLAssert( nLayers == 0 );
85 :
86 : /* -------------------------------------------------------------------- */
87 : /* Start parsing dataset name from the end of string, fetching */
88 : /* the name of spatial reference table and names for SRID and */
89 : /* SRTEXT columns first. */
90 : /* -------------------------------------------------------------------- */
91 0 : char *pszWrkName = CPLStrdup( pszNewName + 5 ); // Skip the 'ODBC:' part
92 0 : char **papszTables = NULL;
93 0 : char **papszGeomCol = NULL;
94 0 : char *pszSRSTableName = NULL;
95 0 : char *pszSRIDCol = NULL, *pszSRTextCol = NULL;
96 : char *pszDelimiter;
97 :
98 0 : if ( (pszDelimiter = strrchr( pszWrkName, ':' )) != NULL )
99 : {
100 0 : char *pszOBracket = strchr( pszDelimiter + 1, '(' );
101 :
102 0 : if( strchr(pszDelimiter,'\\') != NULL
103 : || strchr(pszDelimiter,'/') != NULL )
104 : {
105 : /*
106 : ** if there are special tokens then this isn't really
107 : ** the srs table name, so avoid further processing.
108 : */
109 : }
110 0 : else if( pszOBracket == NULL )
111 : {
112 0 : pszSRSTableName = CPLStrdup( pszDelimiter + 1 );
113 0 : *pszDelimiter = '\0';
114 : }
115 : else
116 : {
117 0 : char *pszCBracket = strchr( pszOBracket, ')' );
118 0 : if( pszCBracket != NULL )
119 0 : *pszCBracket = '\0';
120 :
121 0 : char *pszComma = strchr( pszOBracket, ',' );
122 0 : if( pszComma != NULL )
123 : {
124 0 : *pszComma = '\0';
125 0 : pszSRIDCol = CPLStrdup( pszComma + 1 );
126 : }
127 :
128 0 : *pszOBracket = '\0';
129 0 : pszSRSTableName = CPLStrdup( pszDelimiter + 1 );
130 0 : pszSRTextCol = CPLStrdup( pszOBracket + 1 );
131 :
132 0 : *pszDelimiter = '\0';
133 : }
134 : }
135 :
136 : /* -------------------------------------------------------------------- */
137 : /* Strip off any comma delimeted set of tables names to access */
138 : /* from the end of the string first. Also allow an optional */
139 : /* bracketed geometry column name after the table name. */
140 : /* -------------------------------------------------------------------- */
141 0 : while( (pszDelimiter = strrchr( pszWrkName, ',' )) != NULL )
142 : {
143 0 : char *pszOBracket = strstr( pszDelimiter + 1, "(" );
144 0 : if( pszOBracket == NULL )
145 : {
146 0 : papszTables = CSLAddString( papszTables, pszDelimiter + 1 );
147 0 : papszGeomCol = CSLAddString( papszGeomCol, "" );
148 : }
149 : else
150 : {
151 0 : char *pszCBracket = strstr(pszOBracket,")");
152 :
153 0 : if( pszCBracket != NULL )
154 0 : *pszCBracket = '\0';
155 :
156 0 : *pszOBracket = '\0';
157 0 : papszTables = CSLAddString( papszTables, pszDelimiter + 1 );
158 0 : papszGeomCol = CSLAddString( papszGeomCol, pszOBracket+1 );
159 : }
160 0 : *pszDelimiter = '\0';
161 : }
162 :
163 : /* -------------------------------------------------------------------- */
164 : /* Split out userid, password and DSN. The general form is */
165 : /* user/password@dsn. But if there are no @ characters the */
166 : /* whole thing is assumed to be a DSN. */
167 : /* -------------------------------------------------------------------- */
168 0 : char *pszUserid = NULL;
169 0 : char *pszPassword = NULL;
170 0 : char *pszDSN = NULL;
171 :
172 0 : if( strstr(pszWrkName,"@") == NULL )
173 : {
174 0 : pszDSN = CPLStrdup( pszWrkName );
175 : }
176 : else
177 : {
178 : char *pszTarget;
179 :
180 0 : pszDSN = CPLStrdup(strstr(pszWrkName, "@") + 1);
181 0 : if( *pszWrkName == '/' )
182 : {
183 0 : pszPassword = CPLStrdup(pszWrkName + 1);
184 0 : pszTarget = strstr(pszPassword,"@");
185 0 : *pszTarget = '\0';
186 : }
187 : else
188 : {
189 0 : pszUserid = CPLStrdup(pszWrkName);
190 0 : pszTarget = strstr(pszUserid,"@");
191 0 : *pszTarget = '\0';
192 :
193 0 : pszTarget = strstr(pszUserid,"/");
194 0 : if( pszTarget != NULL )
195 : {
196 0 : *pszTarget = '\0';
197 0 : pszPassword = CPLStrdup(pszTarget+1);
198 : }
199 : }
200 : }
201 :
202 0 : CPLFree( pszWrkName );
203 :
204 : /* -------------------------------------------------------------------- */
205 : /* Initialize based on the DSN. */
206 : /* -------------------------------------------------------------------- */
207 : CPLDebug( "OGR_ODBC",
208 : "EstablishSession(DSN:\"%s\", userid:\"%s\", password:\"%s\")",
209 : pszDSN, pszUserid ? pszUserid : "",
210 0 : pszPassword ? pszPassword : "" );
211 :
212 0 : if( !oSession.EstablishSession( pszDSN, pszUserid, pszPassword ) )
213 : {
214 : CPLError( CE_Failure, CPLE_AppDefined,
215 : "Unable to initialize ODBC connection to DSN for %s,\n"
216 : "%s",
217 0 : pszNewName+5, oSession.GetLastError() );
218 0 : CSLDestroy( papszTables );
219 0 : CSLDestroy( papszGeomCol );
220 0 : CPLFree( pszDSN );
221 0 : CPLFree( pszUserid );
222 0 : CPLFree( pszPassword );
223 0 : return FALSE;
224 : }
225 :
226 0 : CPLFree( pszDSN );
227 0 : CPLFree( pszUserid );
228 0 : CPLFree( pszPassword );
229 :
230 0 : pszName = CPLStrdup( pszNewName );
231 :
232 0 : bDSUpdate = bUpdate;
233 :
234 : /* -------------------------------------------------------------------- */
235 : /* If no explicit list of tables was given, check for a list in */
236 : /* a geometry_columns table. */
237 : /* -------------------------------------------------------------------- */
238 0 : if( papszTables == NULL )
239 : {
240 0 : CPLODBCStatement oStmt( &oSession );
241 :
242 : oStmt.Append( "SELECT f_table_name, f_geometry_column, geometry_type"
243 0 : " FROM geometry_columns" );
244 0 : if( oStmt.ExecuteSQL() )
245 : {
246 0 : while( oStmt.Fetch() )
247 : {
248 : papszTables =
249 0 : CSLAddString( papszTables, oStmt.GetColData(0) );
250 : papszGeomCol =
251 0 : CSLAddString( papszGeomCol, oStmt.GetColData(1) );
252 : }
253 0 : }
254 : }
255 :
256 : /* -------------------------------------------------------------------- */
257 : /* Otherwise our final resort is to return all tables as */
258 : /* non-spatial tables. */
259 : /* -------------------------------------------------------------------- */
260 0 : if( papszTables == NULL )
261 : {
262 0 : CPLODBCStatement oTableList( &oSession );
263 :
264 0 : if( oTableList.GetTables() )
265 : {
266 0 : while( oTableList.Fetch() )
267 : {
268 0 : const char *pszSchema = oTableList.GetColData(1);
269 0 : CPLString osLayerName;
270 :
271 0 : if( pszSchema != NULL && strlen(pszSchema) > 0 )
272 : {
273 0 : osLayerName = pszSchema;
274 0 : osLayerName += ".";
275 : }
276 :
277 0 : osLayerName += oTableList.GetColData(2);
278 :
279 0 : papszTables = CSLAddString( papszTables, osLayerName );
280 :
281 0 : papszGeomCol = CSLAddString(papszGeomCol,"");
282 : }
283 0 : }
284 : }
285 :
286 : /* -------------------------------------------------------------------- */
287 : /* If we have an explicit list of requested tables, use them */
288 : /* (non-spatial). */
289 : /* -------------------------------------------------------------------- */
290 0 : for( int iTable = 0;
291 : papszTables != NULL && papszTables[iTable] != NULL;
292 : iTable++ )
293 : {
294 0 : if( strlen(papszGeomCol[iTable]) > 0 )
295 0 : OpenTable( papszTables[iTable], papszGeomCol[iTable], bUpdate );
296 : else
297 0 : OpenTable( papszTables[iTable], NULL, bUpdate );
298 : }
299 :
300 0 : CSLDestroy( papszTables );
301 0 : CSLDestroy( papszGeomCol );
302 :
303 : /* -------------------------------------------------------------------- */
304 : /* If no explicit list of tables was given, check for a list in */
305 : /* a geometry_columns table. */
306 : /* -------------------------------------------------------------------- */
307 0 : if ( pszSRSTableName )
308 : {
309 0 : CPLODBCStatement oSRSList( &oSession );
310 :
311 0 : if ( !pszSRTextCol )
312 0 : pszSRTextCol = CPLStrdup( "srtext" );
313 0 : if ( !pszSRIDCol )
314 0 : pszSRIDCol = CPLStrdup( "srid" );
315 :
316 0 : oSRSList.Append( "SELECT " );
317 0 : oSRSList.Append( pszSRIDCol );
318 0 : oSRSList.Append( "," );
319 0 : oSRSList.Append( pszSRTextCol );
320 0 : oSRSList.Append( " FROM " );
321 0 : oSRSList.Append( pszSRSTableName );
322 :
323 : CPLDebug( "OGR_ODBC", "ExecuteSQL(%s) to read SRS table",
324 0 : oSRSList.GetCommand() );
325 0 : if ( oSRSList.ExecuteSQL() )
326 : {
327 0 : int nRows = 256; // A reasonable number of SRIDs to start from
328 0 : panSRID = (int *)CPLMalloc( nRows * sizeof(int) );
329 : papoSRS = (OGRSpatialReference **)
330 0 : CPLMalloc( nRows * sizeof(OGRSpatialReference*) );
331 :
332 0 : while ( oSRSList.Fetch() )
333 : {
334 0 : char *pszSRID = (char *) oSRSList.GetColData( pszSRIDCol );
335 0 : if ( !pszSRID )
336 0 : continue;
337 :
338 0 : char *pszSRText = (char *) oSRSList.GetColData( pszSRTextCol );
339 :
340 0 : if ( pszSRText )
341 : {
342 0 : if ( nKnownSRID > nRows )
343 : {
344 0 : nRows *= 2;
345 : panSRID = (int *)CPLRealloc( panSRID,
346 0 : nRows * sizeof(int) );
347 : papoSRS = (OGRSpatialReference **)
348 : CPLRealloc( papoSRS,
349 0 : nRows * sizeof(OGRSpatialReference*) );
350 : }
351 0 : panSRID[nKnownSRID] = atoi( pszSRID );
352 0 : papoSRS[nKnownSRID] = new OGRSpatialReference();
353 0 : if ( papoSRS[nKnownSRID]->importFromWkt( &pszSRText )
354 : != OGRERR_NONE )
355 : {
356 0 : delete papoSRS[nKnownSRID];
357 0 : continue;
358 : }
359 0 : nKnownSRID++;
360 : }
361 : }
362 0 : }
363 : }
364 :
365 0 : if ( pszSRIDCol )
366 0 : CPLFree( pszSRIDCol );
367 0 : if ( pszSRTextCol )
368 0 : CPLFree( pszSRTextCol );
369 0 : if ( pszSRSTableName )
370 0 : CPLFree( pszSRSTableName );
371 :
372 0 : return TRUE;
373 : }
374 :
375 : /************************************************************************/
376 : /* OpenTable() */
377 : /************************************************************************/
378 :
379 : int OGRODBCDataSource::OpenTable( const char *pszNewName,
380 : const char *pszGeomCol,
381 0 : int bUpdate )
382 :
383 : {
384 : /* -------------------------------------------------------------------- */
385 : /* Create the layer object. */
386 : /* -------------------------------------------------------------------- */
387 : OGRODBCTableLayer *poLayer;
388 :
389 0 : poLayer = new OGRODBCTableLayer( this );
390 :
391 0 : if( poLayer->Initialize( pszNewName, pszGeomCol ) )
392 : {
393 0 : delete poLayer;
394 0 : return FALSE;
395 : }
396 :
397 : /* -------------------------------------------------------------------- */
398 : /* Add layer to data source layer list. */
399 : /* -------------------------------------------------------------------- */
400 : papoLayers = (OGRODBCLayer **)
401 0 : CPLRealloc( papoLayers, sizeof(OGRODBCLayer *) * (nLayers+1) );
402 0 : papoLayers[nLayers++] = poLayer;
403 :
404 0 : return TRUE;
405 : }
406 :
407 : /************************************************************************/
408 : /* TestCapability() */
409 : /************************************************************************/
410 :
411 0 : int OGRODBCDataSource::TestCapability( const char * pszCap )
412 :
413 : {
414 0 : return FALSE;
415 : }
416 :
417 : /************************************************************************/
418 : /* GetLayer() */
419 : /************************************************************************/
420 :
421 0 : OGRLayer *OGRODBCDataSource::GetLayer( int iLayer )
422 :
423 : {
424 0 : if( iLayer < 0 || iLayer >= nLayers )
425 0 : return NULL;
426 : else
427 0 : return papoLayers[iLayer];
428 : }
429 : /************************************************************************/
430 : /* ExecuteSQL() */
431 : /************************************************************************/
432 :
433 : OGRLayer * OGRODBCDataSource::ExecuteSQL( const char *pszSQLCommand,
434 : OGRGeometry *poSpatialFilter,
435 0 : const char *pszDialect )
436 :
437 : {
438 : /* -------------------------------------------------------------------- */
439 : /* Use generic imlplementation for OGRSQL dialect. */
440 : /* -------------------------------------------------------------------- */
441 0 : if( pszDialect != NULL && EQUAL(pszDialect,"OGRSQL") )
442 : return OGRDataSource::ExecuteSQL( pszSQLCommand,
443 : poSpatialFilter,
444 0 : pszDialect );
445 :
446 : /* -------------------------------------------------------------------- */
447 : /* Execute statement. */
448 : /* -------------------------------------------------------------------- */
449 0 : CPLODBCStatement *poStmt = new CPLODBCStatement( &oSession );
450 :
451 0 : CPLDebug( "ODBC", "ExecuteSQL(%s) called.", pszSQLCommand );
452 0 : poStmt->Append( pszSQLCommand );
453 0 : if( !poStmt->ExecuteSQL() )
454 : {
455 : CPLError( CE_Failure, CPLE_AppDefined,
456 0 : "%s", oSession.GetLastError() );
457 0 : return NULL;
458 : }
459 :
460 : /* -------------------------------------------------------------------- */
461 : /* Are there result columns for this statement? */
462 : /* -------------------------------------------------------------------- */
463 0 : if( poStmt->GetColCount() == 0 )
464 : {
465 0 : delete poStmt;
466 0 : CPLErrorReset();
467 0 : return NULL;
468 : }
469 :
470 : /* -------------------------------------------------------------------- */
471 : /* Create a results layer. It will take ownership of the */
472 : /* statement. */
473 : /* -------------------------------------------------------------------- */
474 0 : OGRODBCSelectLayer *poLayer = NULL;
475 :
476 0 : poLayer = new OGRODBCSelectLayer( this, poStmt );
477 :
478 0 : if( poSpatialFilter != NULL )
479 0 : poLayer->SetSpatialFilter( poSpatialFilter );
480 :
481 0 : return poLayer;
482 : }
483 :
484 : /************************************************************************/
485 : /* ReleaseResultSet() */
486 : /************************************************************************/
487 :
488 0 : void OGRODBCDataSource::ReleaseResultSet( OGRLayer * poLayer )
489 :
490 : {
491 0 : delete poLayer;
492 0 : }
|