1 /******************************************************************************
2  *
3  * Project:  OpenGIS Simple Features Reference Implementation
4  * Purpose:  Implements OGRGeomediaTableLayer class, access to an existing table.
5  * Author:   Even Rouault, <even dot rouault at spatialys.com>
6  *
7  ******************************************************************************
8  * Copyright (c) 2011, Even Rouault <even dot rouault at spatialys.com>
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 "cpl_conv.h"
31 #include "ogr_geomedia.h"
32 
33 CPL_CVSID("$Id: ogrgeomediatablelayer.cpp 355b41831cd2685c85d1aabe5b95665a2c6e99b7 2019-06-19 17:07:04 +0200 Even Rouault $")
34 
35 /************************************************************************/
36 /*                          OGRGeomediaTableLayer()                     */
37 /************************************************************************/
38 
OGRGeomediaTableLayer(OGRGeomediaDataSource * poDSIn)39 OGRGeomediaTableLayer::OGRGeomediaTableLayer( OGRGeomediaDataSource *poDSIn ) :
40     pszQuery(nullptr)
41 {
42     poDS = poDSIn;
43     iNextShapeId = 0;
44     nSRSId = -1;
45     poFeatureDefn = nullptr;
46 }
47 
48 /************************************************************************/
49 /*                       ~OGRGeomediaTableLayer()                       */
50 /************************************************************************/
51 
~OGRGeomediaTableLayer()52 OGRGeomediaTableLayer::~OGRGeomediaTableLayer()
53 
54 {
55     CPLFree( pszQuery );
56     ClearStatement();
57 }
58 
59 /************************************************************************/
60 /*                             Initialize()                             */
61 /************************************************************************/
62 
Initialize(const char * pszTableName,const char * pszGeomCol,OGRSpatialReference * poSRSIn)63 CPLErr OGRGeomediaTableLayer::Initialize( const char *pszTableName,
64                                           const char *pszGeomCol,
65                                           OGRSpatialReference* poSRSIn )
66 
67 {
68     CPLODBCSession *poSession = poDS->GetSession();
69 
70     CPLFree( pszGeomColumn );
71     if( pszGeomCol == nullptr )
72         pszGeomColumn = nullptr;
73     else
74         pszGeomColumn = CPLStrdup( pszGeomCol );
75 
76     CPLFree( pszFIDColumn );
77     pszFIDColumn = nullptr;
78 
79     poSRS = poSRSIn;
80 
81 /* -------------------------------------------------------------------- */
82 /*      Do we have a simple primary key?                                */
83 /* -------------------------------------------------------------------- */
84     {
85     CPLODBCStatement oGetKey( poSession );
86 
87     if( oGetKey.GetPrimaryKeys( pszTableName ) && oGetKey.Fetch() )
88     {
89         pszFIDColumn = CPLStrdup(oGetKey.GetColData( 3 ));
90 
91         if( oGetKey.Fetch() ) // more than one field in key!
92         {
93             CPLFree( pszFIDColumn );
94             pszFIDColumn = nullptr;
95             CPLDebug( "Geomedia", "%s: Compound primary key, ignoring.",
96                       pszTableName );
97         }
98         else
99             CPLDebug( "Geomedia",
100                       "%s: Got primary key %s.",
101                       pszTableName, pszFIDColumn );
102     }
103     else
104         CPLDebug( "Geomedia", "%s: no primary key", pszTableName );
105     }
106 /* -------------------------------------------------------------------- */
107 /*      Get the column definitions for this table.                      */
108 /* -------------------------------------------------------------------- */
109     CPLODBCStatement oGetCol( poSession );
110     CPLErr eErr;
111 
112     if( !oGetCol.GetColumns( pszTableName ) )
113     {
114         CPLError( CE_Failure, CPLE_AppDefined,
115                   "GetColumns() failed on %s.\n%s",
116                   pszTableName, poSession->GetLastError() );
117         return CE_Failure;
118     }
119 
120     eErr = BuildFeatureDefn( pszTableName, &oGetCol );
121     if( eErr != CE_None )
122         return eErr;
123 
124     if( poFeatureDefn->GetFieldCount() == 0 )
125     {
126         CPLError( CE_Failure, CPLE_AppDefined,
127                   "No column definitions found for table '%s', layer not usable.",
128                   pszTableName );
129         return CE_Failure;
130     }
131 
132     return CE_None;
133 }
134 
135 /************************************************************************/
136 /*                           ClearStatement()                           */
137 /************************************************************************/
138 
ClearStatement()139 void OGRGeomediaTableLayer::ClearStatement()
140 
141 {
142     if( poStmt != nullptr )
143     {
144         delete poStmt;
145         poStmt = nullptr;
146     }
147 }
148 
149 /************************************************************************/
150 /*                            GetStatement()                            */
151 /************************************************************************/
152 
GetStatement()153 CPLODBCStatement *OGRGeomediaTableLayer::GetStatement()
154 
155 {
156     if( poStmt == nullptr )
157         ResetStatement();
158 
159     return poStmt;
160 }
161 
162 /************************************************************************/
163 /*                           ResetStatement()                           */
164 /************************************************************************/
165 
ResetStatement()166 OGRErr OGRGeomediaTableLayer::ResetStatement()
167 
168 {
169     ClearStatement();
170 
171     iNextShapeId = 0;
172 
173     poStmt = new CPLODBCStatement( poDS->GetSession() );
174     poStmt->Append( "SELECT * FROM " );
175     poStmt->Append( poFeatureDefn->GetName() );
176     if( pszQuery != nullptr )
177         poStmt->Appendf( " WHERE %s", pszQuery );
178 
179     if( poStmt->ExecuteSQL() )
180         return OGRERR_NONE;
181     else
182     {
183         delete poStmt;
184         poStmt = nullptr;
185         return OGRERR_FAILURE;
186     }
187 }
188 
189 /************************************************************************/
190 /*                            ResetReading()                            */
191 /************************************************************************/
192 
ResetReading()193 void OGRGeomediaTableLayer::ResetReading()
194 
195 {
196     ClearStatement();
197     OGRGeomediaLayer::ResetReading();
198 }
199 
200 /************************************************************************/
201 /*                             GetFeature()                             */
202 /************************************************************************/
203 
GetFeature(GIntBig nFeatureId)204 OGRFeature *OGRGeomediaTableLayer::GetFeature( GIntBig nFeatureId )
205 
206 {
207     if( pszFIDColumn == nullptr )
208         return OGRGeomediaLayer::GetFeature( nFeatureId );
209 
210     ClearStatement();
211 
212     iNextShapeId = nFeatureId;
213 
214     poStmt = new CPLODBCStatement( poDS->GetSession() );
215     poStmt->Append( "SELECT * FROM " );
216     poStmt->Append( poFeatureDefn->GetName() );
217     poStmt->Appendf( " WHERE %s = " CPL_FRMT_GIB, pszFIDColumn, nFeatureId );
218 
219     if( !poStmt->ExecuteSQL() )
220     {
221         delete poStmt;
222         poStmt = nullptr;
223         return nullptr;
224     }
225 
226     return GetNextRawFeature();
227 }
228 
229 /************************************************************************/
230 /*                         SetAttributeFilter()                         */
231 /************************************************************************/
232 
SetAttributeFilter(const char * pszQueryIn)233 OGRErr OGRGeomediaTableLayer::SetAttributeFilter( const char *pszQueryIn )
234 
235 {
236     if( (pszQueryIn == nullptr && pszQuery == nullptr)
237         || (pszQueryIn != nullptr && pszQuery != nullptr
238             && EQUAL(pszQueryIn, pszQuery)) )
239         return OGRERR_NONE;
240 
241     CPLFree( pszQuery );
242     pszQuery = pszQueryIn ? CPLStrdup( pszQueryIn ) : nullptr;
243 
244     ClearStatement();
245 
246     return OGRERR_NONE;
247 }
248 
249 /************************************************************************/
250 /*                           TestCapability()                           */
251 /************************************************************************/
252 
TestCapability(const char * pszCap)253 int OGRGeomediaTableLayer::TestCapability( const char * pszCap )
254 
255 {
256     if( EQUAL(pszCap,OLCRandomRead) )
257         return TRUE;
258 
259     else if( EQUAL(pszCap,OLCFastFeatureCount) )
260         return m_poFilterGeom == nullptr;
261 
262     else if( EQUAL(pszCap,OLCFastSpatialFilter) )
263         return FALSE;
264 
265     else
266         return OGRGeomediaLayer::TestCapability( pszCap );
267 }
268 
269 /************************************************************************/
270 /*                          GetFeatureCount()                           */
271 /*                                                                      */
272 /*      If a spatial filter is in effect, we turn control over to       */
273 /*      the generic counter.  Otherwise we return the total count.      */
274 /*      Eventually we should consider implementing a more efficient     */
275 /*      way of counting features matching a spatial query.              */
276 /************************************************************************/
277 
GetFeatureCount(int bForce)278 GIntBig OGRGeomediaTableLayer::GetFeatureCount( int bForce )
279 
280 {
281     if( m_poFilterGeom != nullptr )
282         return OGRGeomediaLayer::GetFeatureCount( bForce );
283 
284     CPLODBCStatement oStmt( poDS->GetSession() );
285     oStmt.Append( "SELECT COUNT(*) FROM " );
286     oStmt.Append( poFeatureDefn->GetName() );
287 
288     if( pszQuery != nullptr )
289         oStmt.Appendf( " WHERE %s", pszQuery );
290 
291     if( !oStmt.ExecuteSQL() || !oStmt.Fetch() )
292     {
293         CPLError( CE_Failure, CPLE_AppDefined,
294                   "GetFeatureCount() failed on query %s.\n%s",
295                   oStmt.GetCommand(), poDS->GetSession()->GetLastError() );
296         return OGRGeomediaLayer::GetFeatureCount(bForce);
297     }
298 
299     return atoi(oStmt.GetColData(0));
300 }
301