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