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