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