1 /******************************************************************************
2 * $Id: ogrwalkdatasource.cpp
3 *
4 * Project: OpenGIS Simple Features Reference Implementation
5 * Purpose: Implements OGRWalkDatasource class.
6 * Author: Xian Chen, chenxian at walkinfo.com.cn
7 *
8 ******************************************************************************
9 * Copyright (c) 2013, ZJU Walkinfo Technology Corp., Ltd.
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 "ogrwalk.h"
31 #include <vector>
32
33 /************************************************************************/
34 /* OGRWalkDataSource() */
35 /************************************************************************/
36
OGRWalkDataSource()37 OGRWalkDataSource::OGRWalkDataSource()
38
39 {
40 pszName = NULL;
41 papoLayers = NULL;
42 nLayers = 0;
43 }
44
45 /************************************************************************/
46 /* ~OGRWalkDataSource() */
47 /************************************************************************/
48
~OGRWalkDataSource()49 OGRWalkDataSource::~OGRWalkDataSource()
50
51 {
52 int i;
53
54 CPLFree( pszName );
55
56 for( i = 0; i < nLayers; i++ )
57 {
58 CPLAssert( NULL != papoLayers[i] );
59
60 delete papoLayers[i];
61 }
62
63 CPLFree( papoLayers );
64 }
65
66 /************************************************************************/
67 /* Open() */
68 /************************************************************************/
69
Open(const char * pszNewName,int bUpdate)70 int OGRWalkDataSource::Open( const char * pszNewName, int bUpdate )
71 {
72 /* -------------------------------------------------------------------- */
73 /* If this is the name of an MDB file, then construct the */
74 /* appropriate connection string. Otherwise clip of WALK: to */
75 /* get the DSN. */
76 /* -------------------------------------------------------------------- */
77 char *pszDSN;
78
79 if( EQUALN(pszNewName,"WALK:",5) )
80 pszDSN = CPLStrdup( pszNewName + 5 );
81 else
82 {
83 const char *pszDSNStringTemplate = "DRIVER=Microsoft Access Driver (*.mdb);DBQ=%s";
84 pszDSN = (char *) CPLMalloc(strlen(pszNewName)+strlen(pszDSNStringTemplate)+100);
85
86 sprintf( pszDSN, pszDSNStringTemplate, pszNewName );
87 }
88
89 /* -------------------------------------------------------------------- */
90 /* Initialize based on the DSN. */
91 /* -------------------------------------------------------------------- */
92 CPLDebug( "Walk", "EstablishSession(%s)", pszDSN );
93
94 if( !oSession.EstablishSession( pszDSN, NULL, NULL ) )
95 {
96 CPLError( CE_Failure, CPLE_AppDefined,
97 "Unable to initialize ODBC connection to DSN for %s,\n"
98 "%s", pszDSN, oSession.GetLastError() );
99 CPLFree( pszDSN );
100 return FALSE;
101 }
102
103 CPLFree( pszDSN );
104
105 pszName = CPLStrdup( pszNewName );
106
107 bDSUpdate = bUpdate;
108
109 /* -------------------------------------------------------------------- */
110 /* Collect list of layers and their attributes. */
111 /* -------------------------------------------------------------------- */
112 std::vector<char **> apapszGeomColumns;
113 CPLODBCStatement oStmt( &oSession );
114
115 oStmt.Append( "SELECT LayerID, LayerName, minE, maxE, minN, maxN, Memo FROM WalkLayers" );
116
117 if( !oStmt.ExecuteSQL() )
118 {
119 CPLDebug( "Walk",
120 "SELECT on WalkLayers fails, perhaps not a walk database?\n%s",
121 oSession.GetLastError() );
122 return FALSE;
123 }
124
125 while( oStmt.Fetch() )
126 {
127 int i, iNew = apapszGeomColumns.size();
128 char **papszRecord = NULL;
129
130 for( i = 1; i < 7; i++ )
131 papszRecord = CSLAddString( papszRecord, oStmt.GetColData(i) ); //Add LayerName, Extent and Memo
132
133 apapszGeomColumns.resize(iNew+1);
134 apapszGeomColumns[iNew] = papszRecord;
135 }
136
137 /* -------------------------------------------------------------------- */
138 /* Create a layer for each spatial table. */
139 /* -------------------------------------------------------------------- */
140 unsigned int iTable;
141
142 papoLayers = (OGRWalkLayer **) CPLCalloc(apapszGeomColumns.size(),
143 sizeof( void * ));
144
145 for( iTable = 0; iTable < apapszGeomColumns.size(); iTable++ )
146 {
147 char **papszRecord = apapszGeomColumns[iTable];
148
149 OGRWalkTableLayer *poLayer = new OGRWalkTableLayer( this );
150
151 if( poLayer->Initialize( papszRecord[0], // LayerName
152 "Geometry", // Geometry Column Name
153 CPLAtof(papszRecord[1]), // Extent MinE
154 CPLAtof(papszRecord[2]), // Extent MaxE
155 CPLAtof(papszRecord[3]), // Extent MinN
156 CPLAtof(papszRecord[4]), // Extent MaxN
157 papszRecord[5]) // Memo for SpatialRef
158 != CE_None )
159 {
160 delete poLayer;
161 }
162 else
163 papoLayers[nLayers++] = poLayer;
164
165 CSLDestroy( papszRecord );
166 }
167
168 return TRUE;
169 }
170
171 /************************************************************************/
172 /* GetLayer() */
173 /************************************************************************/
174
GetLayer(int iLayer)175 OGRLayer *OGRWalkDataSource::GetLayer( int iLayer )
176
177 {
178 if( iLayer < 0 || iLayer >= nLayers )
179 return NULL;
180 else
181 return papoLayers[iLayer];
182 }
183
184 /************************************************************************/
185 /* ExecuteSQL() */
186 /************************************************************************/
187
ExecuteSQL(const char * pszSQLCommand,OGRGeometry * poSpatialFilter,const char * pszDialect)188 OGRLayer * OGRWalkDataSource::ExecuteSQL( const char *pszSQLCommand,
189 OGRGeometry *poSpatialFilter,
190 const char *pszDialect )
191
192 {
193 /* -------------------------------------------------------------------- */
194 /* Use generic implementation for recognized dialects */
195 /* -------------------------------------------------------------------- */
196 if( IsGenericSQLDialect(pszDialect) )
197 return OGRDataSource::ExecuteSQL( pszSQLCommand,
198 poSpatialFilter,
199 pszDialect );
200
201 /* -------------------------------------------------------------------- */
202 /* Execute normal SQL statement in Walk. */
203 /* Table_name = Layer_name + Postfix */
204 /* Postfix: "Features", "Annotations" or "Styles" */
205 /* -------------------------------------------------------------------- */
206 CPLODBCStatement *poStmt = new CPLODBCStatement( &oSession );
207
208 CPLDebug( "Walk", "ExecuteSQL(%s) called.", pszSQLCommand );
209 poStmt->Append( pszSQLCommand );
210 if( !poStmt->ExecuteSQL() )
211 {
212 CPLError( CE_Failure, CPLE_AppDefined,
213 "%s", oSession.GetLastError() );
214 return NULL;
215 }
216
217 /* -------------------------------------------------------------------- */
218 /* Are there result columns for this statement? */
219 /* -------------------------------------------------------------------- */
220 if( poStmt->GetColCount() == 0 )
221 {
222 delete poStmt;
223 CPLErrorReset();
224 return NULL;
225 }
226
227 /* -------------------------------------------------------------------- */
228 /* Create a results layer. It will take ownership of the */
229 /* statement. */
230 /* -------------------------------------------------------------------- */
231 OGRWalkSelectLayer *poLayer = NULL;
232
233 poLayer = new OGRWalkSelectLayer( this, poStmt );
234
235 if( poSpatialFilter != NULL )
236 poLayer->SetSpatialFilter( poSpatialFilter );
237
238 return poLayer;
239 }
240
241 /************************************************************************/
242 /* ReleaseResultSet() */
243 /************************************************************************/
244
ReleaseResultSet(OGRLayer * poLayer)245 void OGRWalkDataSource::ReleaseResultSet( OGRLayer * poLayer )
246
247 {
248 delete poLayer;
249 }
250