1 : /******************************************************************************
2 : * $Id: ogrpgeodatasource.cpp 20440 2010-08-25 17:35:49Z rouault $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Purpose: Implements OGRPGeoDataSource class.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2005, 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_pgeo.h"
31 : #include "cpl_conv.h"
32 : #include "cpl_string.h"
33 : #include <vector>
34 :
35 : CPL_CVSID("$Id: ogrpgeodatasource.cpp 20440 2010-08-25 17:35:49Z rouault $");
36 :
37 : /************************************************************************/
38 : /* OGRPGeoDataSource() */
39 : /************************************************************************/
40 :
41 1 : OGRPGeoDataSource::OGRPGeoDataSource()
42 :
43 : {
44 1 : pszName = NULL;
45 1 : papoLayers = NULL;
46 1 : nLayers = 0;
47 1 : }
48 :
49 : /************************************************************************/
50 : /* ~OGRPGeoDataSource() */
51 : /************************************************************************/
52 :
53 1 : OGRPGeoDataSource::~OGRPGeoDataSource()
54 :
55 : {
56 : int i;
57 :
58 1 : CPLFree( pszName );
59 :
60 1 : for( i = 0; i < nLayers; i++ )
61 0 : delete papoLayers[i];
62 :
63 1 : CPLFree( papoLayers );
64 1 : }
65 :
66 : /************************************************************************/
67 : /* CheckDSNStringTemplate() */
68 : /* The string will be used as the formatting argument of sprintf with */
69 : /* a string in vararg. So let's check there's only one '%s', and nothing*/
70 : /* else */
71 : /************************************************************************/
72 :
73 1 : static int CheckDSNStringTemplate(const char* pszStr)
74 : {
75 1 : int nPercentSFound = FALSE;
76 47 : while(*pszStr)
77 : {
78 45 : if (*pszStr == '%')
79 : {
80 1 : if (pszStr[1] != 's')
81 : {
82 0 : return FALSE;
83 : }
84 : else
85 : {
86 1 : if (nPercentSFound)
87 0 : return FALSE;
88 1 : nPercentSFound = TRUE;
89 : }
90 : }
91 45 : pszStr ++;
92 : }
93 1 : return TRUE;
94 : }
95 :
96 : /************************************************************************/
97 : /* Open() */
98 : /************************************************************************/
99 :
100 1 : int OGRPGeoDataSource::Open( const char * pszNewName, int bUpdate,
101 : int bTestOpen )
102 :
103 : {
104 1 : CPLAssert( nLayers == 0 );
105 :
106 : /* -------------------------------------------------------------------- */
107 : /* If this is the name of an MDB file, then construct the */
108 : /* appropriate connection string. Otherwise clip of PGEO: to */
109 : /* get the DSN. */
110 : /* */
111 : /* -------------------------------------------------------------------- */
112 : char *pszDSN;
113 1 : if( EQUALN(pszNewName,"PGEO:",5) )
114 0 : pszDSN = CPLStrdup( pszNewName + 5 );
115 : else
116 : {
117 1 : const char *pszDSNStringTemplate = NULL;
118 1 : pszDSNStringTemplate = CPLGetConfigOption( "PGEO_DRIVER_TEMPLATE", "DRIVER=Microsoft Access Driver (*.mdb);DBQ=%s");
119 1 : if (!CheckDSNStringTemplate(pszDSNStringTemplate))
120 : {
121 : CPLError( CE_Failure, CPLE_AppDefined,
122 0 : "Illegal value for PGEO_DRIVER_TEMPLATE option");
123 0 : return FALSE;
124 : }
125 1 : pszDSN = (char *) CPLMalloc(strlen(pszNewName)+strlen(pszDSNStringTemplate)+100);
126 1 : sprintf( pszDSN, pszDSNStringTemplate, pszNewName );
127 : }
128 :
129 : /* -------------------------------------------------------------------- */
130 : /* Initialize based on the DSN. */
131 : /* -------------------------------------------------------------------- */
132 1 : CPLDebug( "PGeo", "EstablishSession(%s)", pszDSN );
133 :
134 1 : if( !oSession.EstablishSession( pszDSN, NULL, NULL ) )
135 : {
136 : CPLError( CE_Failure, CPLE_AppDefined,
137 : "Unable to initialize ODBC connection to DSN for %s,\n"
138 1 : "%s", pszDSN, oSession.GetLastError() );
139 1 : CPLFree( pszDSN );
140 1 : return FALSE;
141 : }
142 :
143 0 : CPLFree( pszDSN );
144 :
145 0 : pszName = CPLStrdup( pszNewName );
146 :
147 0 : bDSUpdate = bUpdate;
148 :
149 : /* -------------------------------------------------------------------- */
150 : /* Collect list of tables and their supporting info from */
151 : /* GDB_GeomColumns. */
152 : /* -------------------------------------------------------------------- */
153 0 : std::vector<char **> apapszGeomColumns;
154 0 : CPLODBCStatement oStmt( &oSession );
155 :
156 0 : oStmt.Append( "SELECT TableName, FieldName, ShapeType, ExtentLeft, ExtentRight, ExtentBottom, ExtentTop, SRID, HasZ FROM GDB_GeomColumns" );
157 :
158 0 : if( !oStmt.ExecuteSQL() )
159 : {
160 : CPLDebug( "PGEO",
161 : "SELECT on GDB_GeomColumns fails, perhaps not a personal geodatabase?\n%s",
162 0 : oSession.GetLastError() );
163 0 : return FALSE;
164 : }
165 :
166 0 : while( oStmt.Fetch() )
167 : {
168 0 : int i, iNew = apapszGeomColumns.size();
169 0 : char **papszRecord = NULL;
170 0 : for( i = 0; i < 9; i++ )
171 : papszRecord = CSLAddString( papszRecord,
172 0 : oStmt.GetColData(i) );
173 0 : apapszGeomColumns.resize(iNew+1);
174 0 : apapszGeomColumns[iNew] = papszRecord;
175 : }
176 :
177 : /* -------------------------------------------------------------------- */
178 : /* Create a layer for each spatial table. */
179 : /* -------------------------------------------------------------------- */
180 : unsigned int iTable;
181 :
182 : papoLayers = (OGRPGeoLayer **) CPLCalloc(apapszGeomColumns.size(),
183 0 : sizeof(void*));
184 :
185 0 : for( iTable = 0; iTable < apapszGeomColumns.size(); iTable++ )
186 : {
187 0 : char **papszRecord = apapszGeomColumns[iTable];
188 : OGRPGeoTableLayer *poLayer;
189 :
190 0 : poLayer = new OGRPGeoTableLayer( this );
191 :
192 0 : if( poLayer->Initialize( papszRecord[0], // TableName
193 0 : papszRecord[1], // FieldName
194 0 : atoi(papszRecord[2]), // ShapeType
195 0 : atof(papszRecord[3]), // ExtentLeft
196 0 : atof(papszRecord[4]), // ExtentRight
197 0 : atof(papszRecord[5]), // ExtentBottom
198 0 : atof(papszRecord[6]), // ExtentTop
199 0 : atoi(papszRecord[7]), // SRID
200 0 : atoi(papszRecord[8])) // HasZ
201 : != CE_None )
202 : {
203 0 : delete poLayer;
204 : }
205 : else
206 0 : papoLayers[nLayers++] = poLayer;
207 :
208 0 : CSLDestroy( papszRecord );
209 : }
210 :
211 0 : return TRUE;
212 : }
213 :
214 : /************************************************************************/
215 : /* TestCapability() */
216 : /************************************************************************/
217 :
218 0 : int OGRPGeoDataSource::TestCapability( const char * pszCap )
219 :
220 : {
221 0 : return FALSE;
222 : }
223 :
224 : /************************************************************************/
225 : /* GetLayer() */
226 : /************************************************************************/
227 :
228 0 : OGRLayer *OGRPGeoDataSource::GetLayer( int iLayer )
229 :
230 : {
231 0 : if( iLayer < 0 || iLayer >= nLayers )
232 0 : return NULL;
233 : else
234 0 : return papoLayers[iLayer];
235 : }
236 :
237 :
238 : /************************************************************************/
239 : /* ExecuteSQL() */
240 : /************************************************************************/
241 :
242 0 : OGRLayer * OGRPGeoDataSource::ExecuteSQL( const char *pszSQLCommand,
243 : OGRGeometry *poSpatialFilter,
244 : const char *pszDialect )
245 :
246 : {
247 : /* -------------------------------------------------------------------- */
248 : /* Use generic imlplementation for OGRSQL dialect. */
249 : /* -------------------------------------------------------------------- */
250 0 : if( pszDialect != NULL && EQUAL(pszDialect,"OGRSQL") )
251 : return OGRDataSource::ExecuteSQL( pszSQLCommand,
252 : poSpatialFilter,
253 0 : pszDialect );
254 :
255 : /* -------------------------------------------------------------------- */
256 : /* Execute statement. */
257 : /* -------------------------------------------------------------------- */
258 0 : CPLODBCStatement *poStmt = new CPLODBCStatement( &oSession );
259 :
260 0 : poStmt->Append( pszSQLCommand );
261 0 : if( !poStmt->ExecuteSQL() )
262 : {
263 : CPLError( CE_Failure, CPLE_AppDefined,
264 0 : "%s", oSession.GetLastError() );
265 0 : return NULL;
266 : }
267 :
268 : /* -------------------------------------------------------------------- */
269 : /* Are there result columns for this statement? */
270 : /* -------------------------------------------------------------------- */
271 0 : if( poStmt->GetColCount() == 0 )
272 : {
273 0 : delete poStmt;
274 0 : CPLErrorReset();
275 0 : return NULL;
276 : }
277 :
278 : /* -------------------------------------------------------------------- */
279 : /* Create a results layer. It will take ownership of the */
280 : /* statement. */
281 : /* -------------------------------------------------------------------- */
282 0 : OGRPGeoSelectLayer *poLayer = NULL;
283 :
284 0 : poLayer = new OGRPGeoSelectLayer( this, poStmt );
285 :
286 0 : if( poSpatialFilter != NULL )
287 0 : poLayer->SetSpatialFilter( poSpatialFilter );
288 :
289 0 : return poLayer;
290 : }
291 :
292 : /************************************************************************/
293 : /* ReleaseResultSet() */
294 : /************************************************************************/
295 :
296 0 : void OGRPGeoDataSource::ReleaseResultSet( OGRLayer * poLayer )
297 :
298 : {
299 0 : delete poLayer;
300 0 : }
|