Line data Source code
1 : /****************************************************************************** 2 : * 3 : * Project: OpenGIS Simple Features Reference Implementation 4 : * Purpose: Implements OGRMySQLLayer class. 5 : * Author: Frank Warmerdam, warmerdam@pobox.com 6 : * Author: Howard Butler, hobu@hobu.net 7 : * 8 : ****************************************************************************** 9 : * Copyright (c) 2004, Frank Warmerdam <warmerdam@pobox.com> 10 : * 11 : * SPDX-License-Identifier: MIT 12 : ****************************************************************************/ 13 : 14 : #include "ogr_mysql.h" 15 : #include "cpl_conv.h" 16 : #include "cpl_string.h" 17 : 18 : /************************************************************************/ 19 : /* OGRMySQLLayer() */ 20 : /************************************************************************/ 21 : 22 272 : OGRMySQLLayer::OGRMySQLLayer(OGRMySQLDataSource *poDSIn) : poDS(poDSIn) 23 : { 24 272 : } 25 : 26 : /************************************************************************/ 27 : /* ~OGRMySQLLayer() */ 28 : /************************************************************************/ 29 : 30 272 : OGRMySQLLayer::~OGRMySQLLayer() 31 : 32 : { 33 272 : if (m_nFeaturesRead > 0 && poFeatureDefn != nullptr) 34 : { 35 470 : CPLDebug("MySQL", "%d features read on layer '%s'.", 36 235 : (int)m_nFeaturesRead, poFeatureDefn->GetName()); 37 : } 38 : 39 272 : if (poFeatureDefn && poFeatureDefn->GetGeomFieldCount() > 0) 40 : { 41 0 : auto poGeomFieldDefn = dynamic_cast<OGRMySQLGeomFieldDefn *>( 42 194 : poFeatureDefn->GetGeomFieldDefn(0)); 43 194 : if (poGeomFieldDefn) 44 194 : poGeomFieldDefn->UnsetDataSource(); 45 : } 46 : 47 272 : OGRMySQLLayer::ResetReading(); 48 : 49 272 : CPLFree(pszGeomColumn); 50 272 : CPLFree(pszGeomColumnTable); 51 272 : CPLFree(pszFIDColumn); 52 272 : CPLFree(pszQueryStatement); 53 : 54 272 : if (poFeatureDefn) 55 272 : poFeatureDefn->Release(); 56 272 : } 57 : 58 : /************************************************************************/ 59 : /* ResetReading() */ 60 : /************************************************************************/ 61 : 62 1189 : void OGRMySQLLayer::ResetReading() 63 : 64 : { 65 1189 : iNextShapeId = 0; 66 : 67 1189 : if (hResultSet != nullptr) 68 : { 69 335 : mysql_free_result(hResultSet); 70 335 : hResultSet = nullptr; 71 : 72 335 : poDS->InterruptLongResult(); 73 : } 74 1189 : m_bEOF = false; 75 1189 : } 76 : 77 : /************************************************************************/ 78 : /* GetNextFeature() */ 79 : /************************************************************************/ 80 : 81 710 : OGRFeature *OGRMySQLLayer::GetNextFeature() 82 : 83 : { 84 710 : if (m_bEOF) 85 2 : return nullptr; 86 : 87 : while (true) 88 : { 89 : OGRFeature *poFeature; 90 : 91 712 : poFeature = GetNextRawFeature(); 92 712 : if (poFeature == nullptr) 93 : { 94 63 : m_bEOF = true; 95 63 : return nullptr; 96 : } 97 : 98 1380 : if ((m_poFilterGeom == nullptr || 99 1294 : FilterGeometry(poFeature->GetGeometryRef())) && 100 645 : (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(poFeature))) 101 645 : return poFeature; 102 : 103 4 : delete poFeature; 104 4 : } 105 : } 106 : 107 : /************************************************************************/ 108 : /* RecordToFeature() */ 109 : /* */ 110 : /* Convert the indicated record of the current result set into */ 111 : /* a feature. */ 112 : /************************************************************************/ 113 : 114 685 : OGRFeature *OGRMySQLLayer::RecordToFeature(char **papszRow, 115 : unsigned long *panLengths) 116 : 117 : { 118 685 : mysql_field_seek(hResultSet, 0); 119 : 120 : /* -------------------------------------------------------------------- */ 121 : /* Create a feature from the current result. */ 122 : /* -------------------------------------------------------------------- */ 123 685 : OGRFeature *poFeature = new OGRFeature(poFeatureDefn); 124 : 125 685 : poFeature->SetFID(iNextShapeId); 126 685 : m_nFeaturesRead++; 127 : 128 : /* ==================================================================== */ 129 : /* Transfer all result fields we can. */ 130 : /* ==================================================================== */ 131 4109 : for (int iField = 0; iField < (int)mysql_num_fields(hResultSet); iField++) 132 : { 133 3424 : MYSQL_FIELD *psMSField = mysql_fetch_field(hResultSet); 134 : 135 : /* -------------------------------------------------------------------- 136 : */ 137 : /* Handle FID. */ 138 : /* -------------------------------------------------------------------- 139 : */ 140 3424 : if (bHasFid && EQUAL(psMSField->name, pszFIDColumn)) 141 : { 142 569 : if (papszRow[iField] == nullptr) 143 : { 144 0 : CPLError(CE_Failure, CPLE_AppDefined, 145 : "NULL primary key in RecordToFeature()"); 146 0 : return nullptr; 147 : } 148 : 149 569 : poFeature->SetFID(CPLAtoGIntBig(papszRow[iField])); 150 : } 151 : 152 3424 : if (papszRow[iField] == nullptr) 153 : { 154 476 : const int iOGRField = poFeatureDefn->GetFieldIndex(psMSField->name); 155 476 : if (iOGRField >= 0) 156 474 : poFeature->SetFieldNull(iOGRField); 157 : 158 476 : continue; 159 : } 160 : 161 : /* -------------------------------------------------------------------- 162 : */ 163 : /* Handle MySQL geometry */ 164 : /* -------------------------------------------------------------------- 165 : */ 166 2948 : if (pszGeomColumn && EQUAL(psMSField->name, pszGeomColumn)) 167 : { 168 565 : OGRGeometry *poGeometry = nullptr; 169 : 170 : // Geometry columns will have the first 4 bytes contain the SRID. 171 565 : OGRGeometryFactory::createFromWkb( 172 565 : papszRow[iField] + 4, nullptr, &poGeometry, 173 565 : static_cast<int>(panLengths[iField] - 4)); 174 : 175 565 : if (poGeometry != nullptr) 176 : { 177 565 : poGeometry->assignSpatialReference(GetSpatialRef()); 178 565 : poFeature->SetGeometryDirectly(poGeometry); 179 : } 180 565 : continue; 181 : } 182 : 183 : /* -------------------------------------------------------------------- 184 : */ 185 : /* Transfer regular data fields. */ 186 : /* -------------------------------------------------------------------- 187 : */ 188 2383 : const int iOGRField = poFeatureDefn->GetFieldIndex(psMSField->name); 189 2383 : if (iOGRField < 0) 190 555 : continue; 191 : 192 1828 : OGRFieldDefn *psFieldDefn = poFeatureDefn->GetFieldDefn(iOGRField); 193 : 194 1828 : if (psFieldDefn->GetType() == OFTBinary) 195 : { 196 0 : poFeature->SetField(iOGRField, static_cast<int>(panLengths[iField]), 197 0 : (GByte *)papszRow[iField]); 198 : } 199 : else 200 : { 201 1828 : poFeature->SetField(iOGRField, papszRow[iField]); 202 : } 203 : } 204 : 205 685 : return poFeature; 206 : } 207 : 208 : /************************************************************************/ 209 : /* GetNextRawFeature() */ 210 : /************************************************************************/ 211 : 212 712 : OGRFeature *OGRMySQLLayer::GetNextRawFeature() 213 : 214 : { 215 : /* -------------------------------------------------------------------- */ 216 : /* Do we need to establish an initial query? */ 217 : /* -------------------------------------------------------------------- */ 218 712 : if (iNextShapeId == 0 && hResultSet == nullptr) 219 : { 220 256 : CPLAssert(pszQueryStatement != nullptr); 221 : 222 256 : poDS->RequestLongResult(this); 223 : 224 256 : if (mysql_query(poDS->GetConn(), pszQueryStatement)) 225 : { 226 1 : poDS->ReportError(pszQueryStatement); 227 1 : return nullptr; 228 : } 229 : 230 255 : hResultSet = mysql_use_result(poDS->GetConn()); 231 255 : if (hResultSet == nullptr) 232 : { 233 0 : poDS->ReportError("mysql_use_result() failed on query."); 234 0 : return nullptr; 235 : } 236 : } 237 : 238 : /* -------------------------------------------------------------------- */ 239 : /* Fetch next record. */ 240 : /* -------------------------------------------------------------------- */ 241 : char **papszRow; 242 : unsigned long *panLengths; 243 : 244 711 : papszRow = mysql_fetch_row(hResultSet); 245 711 : if (papszRow == nullptr) 246 : { 247 62 : ResetReading(); 248 62 : return nullptr; 249 : } 250 : 251 649 : panLengths = mysql_fetch_lengths(hResultSet); 252 : 253 : /* -------------------------------------------------------------------- */ 254 : /* Process record. */ 255 : /* -------------------------------------------------------------------- */ 256 649 : OGRFeature *poFeature = RecordToFeature(papszRow, panLengths); 257 : 258 649 : iNextShapeId++; 259 : 260 649 : return poFeature; 261 : } 262 : 263 : /************************************************************************/ 264 : /* GetFeature() */ 265 : /* */ 266 : /* Note that we actually override this in OGRMySQLTableLayer. */ 267 : /************************************************************************/ 268 : 269 0 : OGRFeature *OGRMySQLLayer::GetFeature(GIntBig nFeatureId) 270 : 271 : { 272 0 : return OGRLayer::GetFeature(nFeatureId); 273 : } 274 : 275 : /************************************************************************/ 276 : /* GetFIDColumn() */ 277 : /************************************************************************/ 278 : 279 24 : const char *OGRMySQLLayer::GetFIDColumn() 280 : 281 : { 282 24 : if (pszFIDColumn != nullptr) 283 24 : return pszFIDColumn; 284 : else 285 0 : return ""; 286 : } 287 : 288 : /************************************************************************/ 289 : /* FetchSRSId() */ 290 : /************************************************************************/ 291 : 292 194 : int OGRMySQLLayer::FetchSRSId() 293 : { 294 194 : CPLString osCommand; 295 : char **papszRow; 296 : 297 194 : if (hResultSet != nullptr) 298 11 : mysql_free_result(hResultSet); 299 194 : hResultSet = nullptr; 300 : 301 194 : if (poDS->GetMajorVersion() < 8 || poDS->IsMariaDB()) 302 : { 303 : osCommand.Printf("SELECT srid FROM geometry_columns " 304 : "WHERE f_table_name = '%s'", 305 63 : pszGeomColumnTable); 306 : } 307 : else 308 : { 309 : osCommand.Printf( 310 : "SELECT SRS_ID FROM INFORMATION_SCHEMA.ST_GEOMETRY_COLUMNS " 311 : "WHERE TABLE_NAME = '%s'", 312 131 : pszGeomColumnTable); 313 : } 314 : 315 194 : if (!mysql_query(poDS->GetConn(), osCommand)) 316 193 : hResultSet = mysql_store_result(poDS->GetConn()); 317 : 318 194 : papszRow = nullptr; 319 194 : if (hResultSet != nullptr) 320 193 : papszRow = mysql_fetch_row(hResultSet); 321 : 322 194 : if (papszRow != nullptr && papszRow[0] != nullptr) 323 : { 324 178 : nSRSId = atoi(papszRow[0]); 325 : } 326 : 327 : // make sure to free our results 328 194 : if (hResultSet != nullptr) 329 193 : mysql_free_result(hResultSet); 330 194 : hResultSet = nullptr; 331 : 332 388 : return nSRSId; 333 : } 334 : 335 : /************************************************************************/ 336 : /* GetSpatialRef() */ 337 : /************************************************************************/ 338 : 339 1077 : const OGRSpatialReference *OGRMySQLGeomFieldDefn::GetSpatialRef() const 340 : 341 : { 342 1077 : if (!poDS) 343 0 : return poSRS; 344 : 345 1077 : if (poSRS == nullptr && nSRSId > -1) 346 : { 347 172 : poSRS = poDS->FetchSRS(nSRSId); 348 172 : if (poSRS != nullptr) 349 168 : const_cast<OGRSpatialReference *>(poSRS)->Reference(); 350 : else 351 4 : nSRSId = poDS->GetUnknownSRID(); 352 : } 353 : 354 1077 : return poSRS; 355 : } 356 : 357 : /************************************************************************/ 358 : /* GetDataset() */ 359 : /************************************************************************/ 360 : 361 2 : GDALDataset *OGRMySQLLayer::GetDataset() 362 : { 363 2 : return poDS; 364 : }