1 /******************************************************************************
2 *
3 * Project: OpenGIS Simple Features Reference Implementation
4 * Purpose: Implements OGRWalkDatasource class.
5 * Author: Xian Chen, chenxian at walkinfo.com.cn
6 *
7 ******************************************************************************
8 * Copyright (c) 2013, ZJU Walkinfo Technology Corp., Ltd.
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a
11 * copy of this software and associated documentation files (the "Software"),
12 * to deal in the Software without restriction, including without limitation
13 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 * and/or sell copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included
18 * in all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
27 ****************************************************************************/
28
29 #include "ogrwalk.h"
30 #include <vector>
31
32 CPL_CVSID("$Id: ogrwalkdatasource.cpp 316de08882c4b40ed999aa6e37198a5168b8e93c 2021-08-23 11:12:04 +0200 Even Rouault $")
33
34 /************************************************************************/
35 /* OGRWalkDataSource() */
36 /************************************************************************/
37
OGRWalkDataSource()38 OGRWalkDataSource::OGRWalkDataSource() :
39 pszName(nullptr),
40 papoLayers(nullptr),
41 nLayers(0)
42 {}
43
44 /************************************************************************/
45 /* ~OGRWalkDataSource() */
46 /************************************************************************/
47
~OGRWalkDataSource()48 OGRWalkDataSource::~OGRWalkDataSource()
49
50 {
51 CPLFree( pszName );
52
53 for( int i = 0; i < nLayers; i++ )
54 {
55 CPLAssert( nullptr != papoLayers[i] );
56 delete papoLayers[i];
57 }
58
59 CPLFree( papoLayers );
60 }
61
62 /************************************************************************/
63 /* Open() */
64 /************************************************************************/
65
Open(const char * pszNewName,int)66 int OGRWalkDataSource::Open( const char * pszNewName, int /* bUpdate */ )
67 {
68 /* -------------------------------------------------------------------- */
69 /* If this is the name of an MDB file, then construct the */
70 /* appropriate connection string. Otherwise clip of WALK: to */
71 /* get the DSN. */
72 /* -------------------------------------------------------------------- */
73 if( STARTS_WITH_CI(pszNewName, "WALK:") )
74 {
75 char *pszDSN = CPLStrdup( pszNewName + 5 );
76 CPLDebug( "Walk", "EstablishSession(%s)", pszDSN );
77 if( !oSession.EstablishSession( pszDSN, nullptr, nullptr ) )
78 {
79 CPLError( CE_Failure, CPLE_AppDefined,
80 "Unable to initialize ODBC connection to DSN for %s,\n"
81 "%s", pszDSN, oSession.GetLastError() );
82 CPLFree( pszDSN );
83 return FALSE;
84 }
85 }
86 else
87 {
88 if ( !oSession.ConnectToMsAccess( pszNewName, nullptr ) )
89 {
90 return FALSE;
91 }
92 }
93
94 // check for WalkLayers table
95 {
96 bool bFoundWalkLayersTable = false;
97 CPLODBCStatement oTableList( &oSession );
98 if( oTableList.GetTables() )
99 {
100 while( oTableList.Fetch() )
101 {
102 const CPLString osTableName = CPLString( oTableList.GetColData(2, "") );
103 const CPLString osLCTableName(CPLString(osTableName).tolower());
104 if( osLCTableName == "walklayers" )
105 {
106 bFoundWalkLayersTable = true;
107 break;
108 }
109 }
110 }
111 if (!bFoundWalkLayersTable )
112 return FALSE;
113 }
114
115 pszName = CPLStrdup( pszNewName );
116
117 /* -------------------------------------------------------------------- */
118 /* Collect list of layers and their attributes. */
119 /* -------------------------------------------------------------------- */
120 std::vector<char **> apapszGeomColumns;
121 CPLODBCStatement oStmt( &oSession );
122
123 oStmt.Append( "SELECT LayerID, LayerName, minE, maxE, minN, maxN, Memo FROM WalkLayers" );
124
125 if( !oStmt.ExecuteSQL() )
126 {
127 CPLDebug( "Walk",
128 "SELECT on WalkLayers fails, perhaps not a walk database?\n%s",
129 oSession.GetLastError() );
130 return FALSE;
131 }
132
133 while( oStmt.Fetch() )
134 {
135 int i, iNew = static_cast<int>(apapszGeomColumns.size());
136 char **papszRecord = nullptr;
137
138 for( i = 1; i < 7; i++ )
139 papszRecord = CSLAddString( papszRecord, oStmt.GetColData(i) ); //Add LayerName, Extent and Memo
140
141 apapszGeomColumns.resize(iNew+1);
142 apapszGeomColumns[iNew] = papszRecord;
143 }
144
145 /* -------------------------------------------------------------------- */
146 /* Create a layer for each spatial table. */
147 /* -------------------------------------------------------------------- */
148 papoLayers = (OGRWalkLayer **) CPLCalloc(apapszGeomColumns.size(),
149 sizeof( void * ));
150
151 for( unsigned int iTable = 0; iTable < apapszGeomColumns.size(); iTable++ )
152 {
153 char **papszRecord = apapszGeomColumns[iTable];
154
155 OGRWalkTableLayer *poLayer = new OGRWalkTableLayer( this );
156
157 if( poLayer->Initialize( papszRecord[0], // LayerName
158 "Geometry", // Geometry Column Name
159 CPLAtof(papszRecord[1]), // Extent MinE
160 CPLAtof(papszRecord[2]), // Extent MaxE
161 CPLAtof(papszRecord[3]), // Extent MinN
162 CPLAtof(papszRecord[4]), // Extent MaxN
163 papszRecord[5]) // Memo for SpatialRef
164 != CE_None )
165 {
166 delete poLayer;
167 }
168 else
169 papoLayers[nLayers++] = poLayer;
170
171 CSLDestroy( papszRecord );
172 }
173
174 return TRUE;
175 }
176
177 /************************************************************************/
178 /* GetLayer() */
179 /************************************************************************/
180
GetLayer(int iLayer)181 OGRLayer *OGRWalkDataSource::GetLayer( int iLayer )
182
183 {
184 if( iLayer < 0 || iLayer >= nLayers )
185 return nullptr;
186 else
187 return papoLayers[iLayer];
188 }
189
190 /************************************************************************/
191 /* ExecuteSQL() */
192 /************************************************************************/
193
ExecuteSQL(const char * pszSQLCommand,OGRGeometry * poSpatialFilter,const char * pszDialect)194 OGRLayer * OGRWalkDataSource::ExecuteSQL( const char *pszSQLCommand,
195 OGRGeometry *poSpatialFilter,
196 const char *pszDialect )
197
198 {
199 /* -------------------------------------------------------------------- */
200 /* Use generic implementation for recognized dialects */
201 /* -------------------------------------------------------------------- */
202 if( IsGenericSQLDialect(pszDialect) )
203 return OGRDataSource::ExecuteSQL( pszSQLCommand,
204 poSpatialFilter,
205 pszDialect );
206
207 /* -------------------------------------------------------------------- */
208 /* Execute normal SQL statement in Walk. */
209 /* Table_name = Layer_name + Postfix */
210 /* Postfix: "Features", "Annotations" or "Styles" */
211 /* -------------------------------------------------------------------- */
212 CPLODBCStatement *poStmt = new CPLODBCStatement( &oSession );
213
214 CPLDebug( "Walk", "ExecuteSQL(%s) called.", pszSQLCommand );
215 poStmt->Append( pszSQLCommand );
216 if( !poStmt->ExecuteSQL() )
217 {
218 CPLError( CE_Failure, CPLE_AppDefined,
219 "%s", oSession.GetLastError() );
220 delete poStmt;
221 return nullptr;
222 }
223
224 /* -------------------------------------------------------------------- */
225 /* Are there result columns for this statement? */
226 /* -------------------------------------------------------------------- */
227 if( poStmt->GetColCount() == 0 )
228 {
229 delete poStmt;
230 CPLErrorReset();
231 return nullptr;
232 }
233
234 /* -------------------------------------------------------------------- */
235 /* Create a results layer. It will take ownership of the */
236 /* statement. */
237 /* -------------------------------------------------------------------- */
238 OGRWalkSelectLayer *poLayer = new OGRWalkSelectLayer( this, poStmt );
239
240 if( poSpatialFilter != nullptr )
241 poLayer->SetSpatialFilter( poSpatialFilter );
242
243 return poLayer;
244 }
245
246 /************************************************************************/
247 /* ReleaseResultSet() */
248 /************************************************************************/
249
ReleaseResultSet(OGRLayer * poLayer)250 void OGRWalkDataSource::ReleaseResultSet( OGRLayer * poLayer )
251
252 {
253 delete poLayer;
254 }
255