Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: OpenGIS Simple Features Reference Implementation
4 : * Purpose: Implements OGRODBCLayer class, code shared between
5 : * the direct table access, and the generic SQL results.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2003, 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_odbc.h"
32 : #include "cpl_string.h"
33 :
34 : /************************************************************************/
35 : /* OGRODBCLayer() */
36 : /************************************************************************/
37 :
38 0 : OGRODBCLayer::OGRODBCLayer()
39 : : poFeatureDefn(nullptr), poStmt(nullptr), poSRS(nullptr),
40 : nSRSId(-2), // Have not queried the database for it yet.
41 : iNextShapeId(0), poDS(nullptr), bGeomColumnWKB(FALSE),
42 0 : pszGeomColumn(nullptr), pszFIDColumn(nullptr), panFieldOrdinals(nullptr)
43 : {
44 0 : }
45 :
46 : /************************************************************************/
47 : /* ~OGRODBCLayer() */
48 : /************************************************************************/
49 :
50 0 : OGRODBCLayer::~OGRODBCLayer()
51 :
52 : {
53 0 : if (m_nFeaturesRead > 0 && poFeatureDefn != nullptr)
54 : {
55 0 : CPLDebug("OGR_ODBC", "%d features read on layer '%s'.",
56 0 : (int)m_nFeaturesRead, poFeatureDefn->GetName());
57 : }
58 :
59 0 : if (poStmt)
60 : {
61 0 : delete poStmt;
62 0 : poStmt = nullptr;
63 : }
64 :
65 0 : if (pszGeomColumn)
66 0 : CPLFree(pszGeomColumn);
67 :
68 0 : if (panFieldOrdinals)
69 0 : CPLFree(panFieldOrdinals);
70 :
71 0 : if (poFeatureDefn)
72 : {
73 0 : poFeatureDefn->Release();
74 0 : poFeatureDefn = nullptr;
75 : }
76 :
77 0 : if (poSRS)
78 0 : poSRS->Release();
79 0 : }
80 :
81 : /************************************************************************/
82 : /* BuildFeatureDefn() */
83 : /* */
84 : /* Build feature definition from a set of column definitions */
85 : /* set on a statement. Sift out geometry and FID fields. */
86 : /************************************************************************/
87 :
88 0 : CPLErr OGRODBCLayer::BuildFeatureDefn(const char *pszLayerName,
89 : CPLODBCStatement *poStmtIn)
90 :
91 : {
92 0 : poFeatureDefn = new OGRFeatureDefn(pszLayerName);
93 0 : SetDescription(poFeatureDefn->GetName());
94 0 : int nRawColumns = poStmtIn->GetColCount();
95 :
96 0 : poFeatureDefn->Reference();
97 :
98 0 : panFieldOrdinals = (int *)CPLMalloc(sizeof(int) * nRawColumns);
99 :
100 0 : for (int iCol = 0; iCol < nRawColumns; iCol++)
101 : {
102 0 : OGRFieldDefn oField(poStmtIn->GetColName(iCol), OFTString);
103 :
104 0 : oField.SetWidth(MAX(0, poStmtIn->GetColSize(iCol)));
105 :
106 0 : if (pszGeomColumn != nullptr &&
107 0 : EQUAL(poStmtIn->GetColName(iCol), pszGeomColumn))
108 0 : continue;
109 :
110 0 : switch (CPLODBCStatement::GetTypeMapping(poStmtIn->GetColType(iCol)))
111 : {
112 0 : case SQL_C_SSHORT:
113 : case SQL_C_USHORT:
114 : case SQL_C_SLONG:
115 : case SQL_C_ULONG:
116 0 : oField.SetType(OFTInteger);
117 0 : break;
118 :
119 0 : case SQL_C_SBIGINT:
120 : case SQL_C_UBIGINT:
121 0 : oField.SetType(OFTInteger64);
122 0 : break;
123 :
124 0 : case SQL_C_BINARY:
125 0 : oField.SetType(OFTBinary);
126 0 : break;
127 :
128 0 : case SQL_C_NUMERIC:
129 0 : oField.SetType(OFTReal);
130 0 : oField.SetPrecision(poStmtIn->GetColPrecision(iCol));
131 0 : break;
132 :
133 0 : case SQL_C_FLOAT:
134 : case SQL_C_DOUBLE:
135 0 : oField.SetType(OFTReal);
136 0 : oField.SetWidth(0);
137 0 : break;
138 :
139 0 : case SQL_C_DATE:
140 0 : oField.SetType(OFTDate);
141 0 : break;
142 :
143 0 : case SQL_C_TIME:
144 0 : oField.SetType(OFTTime);
145 0 : break;
146 :
147 0 : case SQL_C_TIMESTAMP:
148 : case SQL_C_TYPE_TIMESTAMP:
149 0 : oField.SetType(OFTDateTime);
150 0 : break;
151 :
152 0 : default:
153 : /* leave it as OFTString */;
154 : }
155 :
156 0 : poFeatureDefn->AddFieldDefn(&oField);
157 0 : panFieldOrdinals[poFeatureDefn->GetFieldCount() - 1] = iCol + 1;
158 : }
159 :
160 : /* -------------------------------------------------------------------- */
161 : /* If we don't already have an FID, check if there is a special */
162 : /* FID named column available. */
163 : /* -------------------------------------------------------------------- */
164 0 : if (pszFIDColumn == nullptr)
165 : {
166 0 : const char *pszOGR_FID = CPLGetConfigOption("ODBC_OGR_FID", "OGR_FID");
167 0 : if (poFeatureDefn->GetFieldIndex(pszOGR_FID) != -1)
168 0 : pszFIDColumn = CPLStrdup(pszOGR_FID);
169 : }
170 :
171 0 : if (pszFIDColumn != nullptr)
172 0 : CPLDebug("OGR_ODBC", "Using column %s as FID for table %s.",
173 0 : pszFIDColumn, poFeatureDefn->GetName());
174 : else
175 0 : CPLDebug("OGR_ODBC", "Table %s has no identified FID column.",
176 0 : poFeatureDefn->GetName());
177 :
178 0 : return CE_None;
179 : }
180 :
181 : /************************************************************************/
182 : /* ResetReading() */
183 : /************************************************************************/
184 :
185 0 : void OGRODBCLayer::ResetReading()
186 :
187 : {
188 0 : iNextShapeId = 0;
189 0 : m_bEOF = false;
190 0 : }
191 :
192 : /************************************************************************/
193 : /* GetNextFeature() */
194 : /************************************************************************/
195 :
196 0 : OGRFeature *OGRODBCLayer::GetNextFeature()
197 :
198 : {
199 : while (true)
200 : {
201 0 : OGRFeature *poFeature = GetNextRawFeature();
202 0 : if (poFeature == nullptr)
203 0 : return nullptr;
204 :
205 0 : if ((m_poFilterGeom == nullptr ||
206 0 : FilterGeometry(poFeature->GetGeometryRef())) &&
207 0 : (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(poFeature)))
208 0 : return poFeature;
209 :
210 0 : delete poFeature;
211 0 : }
212 : }
213 :
214 : /************************************************************************/
215 : /* GetNextRawFeature() */
216 : /************************************************************************/
217 :
218 0 : OGRFeature *OGRODBCLayer::GetNextRawFeature()
219 :
220 : {
221 0 : if (m_bEOF || GetStatement() == nullptr)
222 0 : return nullptr;
223 :
224 : /* -------------------------------------------------------------------- */
225 : /* If we are marked to restart then do so, and fetch a record. */
226 : /* -------------------------------------------------------------------- */
227 0 : if (!poStmt->Fetch())
228 : {
229 0 : delete poStmt;
230 0 : poStmt = nullptr;
231 0 : m_bEOF = true;
232 0 : return nullptr;
233 : }
234 :
235 : /* -------------------------------------------------------------------- */
236 : /* Create a feature from the current result. */
237 : /* -------------------------------------------------------------------- */
238 0 : OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
239 :
240 0 : if (pszFIDColumn != nullptr && poStmt->GetColId(pszFIDColumn) > -1)
241 0 : poFeature->SetFID(
242 0 : atoi(poStmt->GetColData(poStmt->GetColId(pszFIDColumn))));
243 : else
244 0 : poFeature->SetFID(iNextShapeId);
245 :
246 0 : iNextShapeId++;
247 0 : m_nFeaturesRead++;
248 :
249 : /* -------------------------------------------------------------------- */
250 : /* Set the fields. */
251 : /* -------------------------------------------------------------------- */
252 0 : for (int iField = 0; iField < poFeatureDefn->GetFieldCount(); iField++)
253 : {
254 : const OGRFieldType eType =
255 0 : poFeatureDefn->GetFieldDefn(iField)->GetType();
256 0 : int iSrcField = panFieldOrdinals[iField] - 1;
257 :
258 0 : if (eType == OFTReal &&
259 0 : (poStmt->Flags() &
260 : CPLODBCStatement::Flag::RetrieveNumericColumnsAsDouble))
261 : {
262 : // for OFTReal fields we retrieve the value directly as a double
263 : // to avoid loss of precision associated with double/float->string
264 : // conversion
265 0 : const double dfValue = poStmt->GetColDataAsDouble(iSrcField);
266 0 : if (std::isnan(dfValue))
267 : {
268 0 : poFeature->SetFieldNull(iField);
269 : }
270 : else
271 : {
272 0 : poFeature->SetField(iField, dfValue);
273 : }
274 : }
275 : else
276 : {
277 0 : const char *pszValue = poStmt->GetColData(iSrcField);
278 :
279 0 : if (pszValue == nullptr)
280 0 : poFeature->SetFieldNull(iField);
281 0 : else if (poFeature->GetFieldDefnRef(iField)->GetType() == OFTBinary)
282 0 : poFeature->SetField(iField, poStmt->GetColDataLength(iSrcField),
283 : (GByte *)pszValue);
284 : else
285 0 : poFeature->SetField(iField, pszValue);
286 : }
287 : }
288 :
289 : /* -------------------------------------------------------------------- */
290 : /* Try to extract a geometry. */
291 : /* -------------------------------------------------------------------- */
292 0 : if (pszGeomColumn != nullptr)
293 : {
294 0 : int iField = poStmt->GetColId(pszGeomColumn);
295 0 : const char *pszGeomText = poStmt->GetColData(iField);
296 0 : OGRGeometry *poGeom = nullptr;
297 0 : OGRErr eErr = OGRERR_NONE;
298 :
299 0 : if (pszGeomText != nullptr && !bGeomColumnWKB)
300 : {
301 0 : eErr = OGRGeometryFactory::createFromWkt(pszGeomText, nullptr,
302 : &poGeom);
303 : }
304 0 : else if (pszGeomText != nullptr && bGeomColumnWKB)
305 : {
306 0 : int nLength = poStmt->GetColDataLength(iField);
307 :
308 0 : eErr = OGRGeometryFactory::createFromWkb(pszGeomText, nullptr,
309 : &poGeom, nLength);
310 : }
311 :
312 0 : if (eErr != OGRERR_NONE)
313 : {
314 0 : const char *pszMessage = nullptr;
315 :
316 0 : switch (eErr)
317 : {
318 0 : case OGRERR_NOT_ENOUGH_DATA:
319 0 : pszMessage = "Not enough data to deserialize";
320 0 : break;
321 0 : case OGRERR_UNSUPPORTED_GEOMETRY_TYPE:
322 0 : pszMessage = "Unsupported geometry type";
323 0 : break;
324 0 : case OGRERR_CORRUPT_DATA:
325 0 : pszMessage = "Corrupt data";
326 0 : break;
327 0 : default:
328 0 : pszMessage = "Unrecognized error";
329 : }
330 0 : CPLError(CE_Failure, CPLE_AppDefined, "GetNextRawFeature(): %s",
331 : pszMessage);
332 : }
333 :
334 0 : if (poGeom != nullptr)
335 0 : poFeature->SetGeometryDirectly(poGeom);
336 : }
337 :
338 0 : return poFeature;
339 : }
340 :
341 : /************************************************************************/
342 : /* GetFeature() */
343 : /************************************************************************/
344 :
345 0 : OGRFeature *OGRODBCLayer::GetFeature(GIntBig nFeatureId)
346 :
347 : {
348 : /* This should be implemented directly! */
349 :
350 0 : return OGRLayer::GetFeature(nFeatureId);
351 : }
352 :
353 : /************************************************************************/
354 : /* TestCapability() */
355 : /************************************************************************/
356 :
357 0 : int OGRODBCLayer::TestCapability(CPL_UNUSED const char *pszCap)
358 : {
359 0 : return FALSE;
360 : }
361 :
362 : /************************************************************************/
363 : /* GetSpatialRef() */
364 : /************************************************************************/
365 :
366 0 : OGRSpatialReference *OGRODBCLayer::GetSpatialRef()
367 :
368 : {
369 0 : return poSRS;
370 : }
|