LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/odbc - ogrodbctablelayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 0 150 0.0 %
Date: 2024-11-21 22:18:42 Functions: 0 14 0.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Implements OGRODBCTableLayer class, access to an existing table.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2003, Frank Warmerdam
       9             :  * Copyright (c) 2009-2012, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_conv.h"
      15             : #include "ogr_odbc.h"
      16             : 
      17             : /************************************************************************/
      18             : /*                          OGRODBCTableLayer()                         */
      19             : /************************************************************************/
      20             : 
      21           0 : OGRODBCTableLayer::OGRODBCTableLayer(OGRODBCDataSource *poDSIn,
      22           0 :                                      int nODBCStatementFlags)
      23             :     : pszQuery(nullptr), bHaveSpatialExtents(FALSE), pszTableName(nullptr),
      24           0 :       pszSchemaName(nullptr)
      25             : {
      26           0 :     m_nStatementFlags = nODBCStatementFlags;
      27           0 :     poDS = poDSIn;
      28           0 :     iNextShapeId = 0;
      29             : 
      30           0 :     nSRSId = -1;
      31             : 
      32           0 :     poFeatureDefn = nullptr;
      33           0 : }
      34             : 
      35             : /************************************************************************/
      36             : /*                          ~OGRODBCTableLayer()                          */
      37             : /************************************************************************/
      38             : 
      39           0 : OGRODBCTableLayer::~OGRODBCTableLayer()
      40             : 
      41             : {
      42           0 :     CPLFree(pszTableName);
      43           0 :     CPLFree(pszSchemaName);
      44             : 
      45           0 :     CPLFree(pszQuery);
      46           0 :     ClearStatement();
      47           0 : }
      48             : 
      49             : /************************************************************************/
      50             : /*                             Initialize()                             */
      51             : /************************************************************************/
      52             : 
      53           0 : CPLErr OGRODBCTableLayer::Initialize(const char *pszLayerName,
      54             :                                      const char *pszGeomCol)
      55             : 
      56             : {
      57           0 :     CPLODBCSession *poSession = poDS->GetSession();
      58             : 
      59           0 :     CPLFree(pszFIDColumn);
      60           0 :     pszFIDColumn = nullptr;
      61             : 
      62           0 :     SetDescription(pszLayerName);
      63             : 
      64             :     /* -------------------------------------------------------------------- */
      65             :     /*      Parse out schema name if present in layer.  We assume a         */
      66             :     /*      schema is provided if there is a dot in the name, and that      */
      67             :     /*      it is in the form <schema>.<tablename>                          */
      68             :     /* -------------------------------------------------------------------- */
      69           0 :     const char *pszDot = strstr(pszLayerName, ".");
      70           0 :     if (pszDot != nullptr)
      71             :     {
      72           0 :         pszTableName = CPLStrdup(pszDot + 1);
      73           0 :         pszSchemaName = CPLStrdup(pszLayerName);
      74           0 :         pszSchemaName[pszDot - pszLayerName] = '\0';
      75             :     }
      76             :     else
      77             :     {
      78           0 :         pszTableName = CPLStrdup(pszLayerName);
      79             :     }
      80             : 
      81             :     /* -------------------------------------------------------------------- */
      82             :     /*      Do we have a simple primary key?                                */
      83             :     /* -------------------------------------------------------------------- */
      84           0 :     CPLODBCStatement oGetKey(poSession);
      85             : 
      86           0 :     if (oGetKey.GetPrimaryKeys(pszTableName, nullptr, pszSchemaName) &&
      87           0 :         oGetKey.Fetch())
      88             :     {
      89           0 :         pszFIDColumn = CPLStrdup(oGetKey.GetColData(3));
      90             : 
      91           0 :         if (oGetKey.Fetch())  // more than one field in key!
      92             :         {
      93           0 :             CPLFree(pszFIDColumn);
      94           0 :             pszFIDColumn = nullptr;
      95             : 
      96           0 :             CPLDebug("OGR_ODBC",
      97             :                      "Table %s has multiple primary key fields, "
      98             :                      "ignoring them all.",
      99             :                      pszTableName);
     100             :         }
     101             :     }
     102             : 
     103             :     /* -------------------------------------------------------------------- */
     104             :     /*      Have we been provided a geometry column?                        */
     105             :     /* -------------------------------------------------------------------- */
     106           0 :     CPLFree(pszGeomColumn);
     107           0 :     if (pszGeomCol == nullptr)
     108           0 :         pszGeomColumn = nullptr;
     109             :     else
     110           0 :         pszGeomColumn = CPLStrdup(pszGeomCol);
     111             : 
     112             :     /* -------------------------------------------------------------------- */
     113             :     /*      Get the column definitions for this table.                      */
     114             :     /* -------------------------------------------------------------------- */
     115           0 :     CPLODBCStatement oGetCol(poSession);
     116             :     CPLErr eErr;
     117             : 
     118           0 :     if (!oGetCol.GetColumns(pszTableName, nullptr, pszSchemaName))
     119           0 :         return CE_Failure;
     120             : 
     121           0 :     eErr = BuildFeatureDefn(pszLayerName, &oGetCol);
     122           0 :     if (eErr != CE_None)
     123           0 :         return eErr;
     124             : 
     125           0 :     if (poFeatureDefn->GetFieldCount() == 0)
     126             :     {
     127           0 :         CPLError(
     128             :             CE_Warning, CPLE_AppDefined,
     129             :             "No column definitions found for table '%s', layer not usable.",
     130             :             pszLayerName);
     131           0 :         return CE_Failure;
     132             :     }
     133             : 
     134             :     /* -------------------------------------------------------------------- */
     135             :     /*      Do we have XMIN, YMIN, XMAX, YMAX extent fields?                */
     136             :     /* -------------------------------------------------------------------- */
     137           0 :     if (poFeatureDefn->GetFieldIndex("XMIN") != -1 &&
     138           0 :         poFeatureDefn->GetFieldIndex("XMAX") != -1 &&
     139           0 :         poFeatureDefn->GetFieldIndex("YMIN") != -1 &&
     140           0 :         poFeatureDefn->GetFieldIndex("YMAX") != -1)
     141             :     {
     142           0 :         bHaveSpatialExtents = TRUE;
     143           0 :         CPLDebug("OGR_ODBC", "Table %s has geometry extent fields.",
     144             :                  pszLayerName);
     145             :     }
     146             : 
     147             :     /* -------------------------------------------------------------------- */
     148             :     /*      If we got a geometry column, does it exist?  Is it binary?      */
     149             :     /* -------------------------------------------------------------------- */
     150           0 :     if (pszGeomColumn != nullptr)
     151             :     {
     152           0 :         int iColumn = oGetCol.GetColId(pszGeomColumn);
     153           0 :         if (iColumn < 0)
     154             :         {
     155           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     156             :                      "Column %s requested for geometry, but it does not exist.",
     157             :                      pszGeomColumn);
     158           0 :             CPLFree(pszGeomColumn);
     159           0 :             pszGeomColumn = nullptr;
     160             :         }
     161             :         else
     162             :         {
     163           0 :             if (CPLODBCStatement::GetTypeMapping(oGetCol.GetColType(iColumn)) ==
     164             :                 SQL_C_BINARY)
     165           0 :                 bGeomColumnWKB = TRUE;
     166             :         }
     167             :     }
     168             : 
     169           0 :     return CE_None;
     170             : }
     171             : 
     172             : /************************************************************************/
     173             : /*                           ClearStatement()                           */
     174             : /************************************************************************/
     175             : 
     176           0 : void OGRODBCTableLayer::ClearStatement()
     177             : 
     178             : {
     179           0 :     if (poStmt != nullptr)
     180             :     {
     181           0 :         delete poStmt;
     182           0 :         poStmt = nullptr;
     183             :     }
     184           0 : }
     185             : 
     186             : /************************************************************************/
     187             : /*                            GetStatement()                            */
     188             : /************************************************************************/
     189             : 
     190           0 : CPLODBCStatement *OGRODBCTableLayer::GetStatement()
     191             : 
     192             : {
     193           0 :     if (poStmt == nullptr)
     194           0 :         ResetStatement();
     195             : 
     196           0 :     return poStmt;
     197             : }
     198             : 
     199             : /************************************************************************/
     200             : /*                      EscapeAndQuoteIdentifier()                      */
     201             : /************************************************************************/
     202             : 
     203           0 : static CPLString EscapeAndQuoteIdentifier(const CPLString &osStr)
     204             : {
     205           0 :     CPLString osRet;
     206           0 :     int num_dots = 0;
     207           0 :     for (size_t i = 0; i < osStr.size(); i++)
     208             :     {
     209           0 :         if (osStr[i] == '"')
     210             :         {
     211           0 :             osRet += "\\\"";
     212             :         }
     213           0 :         else if (osStr[i] == '.' && num_dots == 0)
     214             :         {
     215             :             /* It's schema qualified, so first segment we assume is the schema
     216             :              * and should be quoted separately */
     217           0 :             osRet += "\".\"";
     218           0 :             num_dots += 1;
     219             :         }
     220             :         else
     221             :         {
     222           0 :             osRet += osStr[i];
     223             :         }
     224             :     }
     225           0 :     return '"' + osRet + '"';
     226             : }
     227             : 
     228             : /************************************************************************/
     229             : /*                           ResetStatement()                           */
     230             : /************************************************************************/
     231             : 
     232           0 : OGRErr OGRODBCTableLayer::ResetStatement()
     233             : 
     234             : {
     235           0 :     ClearStatement();
     236             : 
     237           0 :     iNextShapeId = 0;
     238             : 
     239           0 :     poStmt = new CPLODBCStatement(poDS->GetSession(), m_nStatementFlags);
     240           0 :     poStmt->Append("SELECT * FROM ");
     241           0 :     poStmt->Append(EscapeAndQuoteIdentifier(poFeatureDefn->GetName()));
     242             : 
     243             :     /* Append attribute query if we have it */
     244           0 :     if (pszQuery != nullptr)
     245           0 :         poStmt->Appendf(" WHERE %s", pszQuery);
     246             : 
     247             :     /* If we have a spatial filter, and per record extents, query on it */
     248           0 :     if (m_poFilterGeom != nullptr && bHaveSpatialExtents)
     249             :     {
     250           0 :         if (pszQuery == nullptr)
     251           0 :             poStmt->Append(" WHERE");
     252             :         else
     253           0 :             poStmt->Append(" AND");
     254             : 
     255           0 :         poStmt->Appendf(" XMAX > %.8f AND XMIN < %.8f"
     256             :                         " AND YMAX > %.8f AND YMIN < %.8f",
     257             :                         m_sFilterEnvelope.MinX, m_sFilterEnvelope.MaxX,
     258             :                         m_sFilterEnvelope.MinY, m_sFilterEnvelope.MaxY);
     259             :     }
     260             : 
     261           0 :     CPLDebug("OGR_ODBC", "ExecuteSQL(%s)", poStmt->GetCommand());
     262           0 :     if (poStmt->ExecuteSQL())
     263           0 :         return OGRERR_NONE;
     264             :     else
     265             :     {
     266           0 :         delete poStmt;
     267           0 :         poStmt = nullptr;
     268           0 :         return OGRERR_FAILURE;
     269             :     }
     270             : }
     271             : 
     272             : /************************************************************************/
     273             : /*                            ResetReading()                            */
     274             : /************************************************************************/
     275             : 
     276           0 : void OGRODBCTableLayer::ResetReading()
     277             : 
     278             : {
     279           0 :     ClearStatement();
     280           0 :     OGRODBCLayer::ResetReading();
     281           0 : }
     282             : 
     283             : /************************************************************************/
     284             : /*                             GetFeature()                             */
     285             : /************************************************************************/
     286             : 
     287           0 : OGRFeature *OGRODBCTableLayer::GetFeature(GIntBig nFeatureId)
     288             : 
     289             : {
     290           0 :     if (pszFIDColumn == nullptr)
     291           0 :         return OGRODBCLayer::GetFeature(nFeatureId);
     292             : 
     293           0 :     ClearStatement();
     294             : 
     295           0 :     iNextShapeId = nFeatureId;
     296             : 
     297           0 :     poStmt = new CPLODBCStatement(poDS->GetSession(), m_nStatementFlags);
     298           0 :     poStmt->Append("SELECT * FROM ");
     299           0 :     poStmt->Append(EscapeAndQuoteIdentifier(poFeatureDefn->GetName()));
     300           0 :     poStmt->Appendf(" WHERE %s = " CPL_FRMT_GIB,
     301           0 :                     EscapeAndQuoteIdentifier(pszFIDColumn).c_str(), nFeatureId);
     302             : 
     303           0 :     if (!poStmt->ExecuteSQL())
     304             :     {
     305           0 :         delete poStmt;
     306           0 :         poStmt = nullptr;
     307           0 :         return nullptr;
     308             :     }
     309             : 
     310           0 :     return GetNextRawFeature();
     311             : }
     312             : 
     313             : /************************************************************************/
     314             : /*                         SetAttributeFilter()                         */
     315             : /************************************************************************/
     316             : 
     317           0 : OGRErr OGRODBCTableLayer::SetAttributeFilter(const char *pszQueryIn)
     318             : 
     319             : {
     320           0 :     CPLFree(m_pszAttrQueryString);
     321           0 :     m_pszAttrQueryString = (pszQueryIn) ? CPLStrdup(pszQueryIn) : nullptr;
     322             : 
     323           0 :     if ((pszQueryIn == nullptr && pszQuery == nullptr) ||
     324           0 :         (pszQueryIn != nullptr && pszQuery != nullptr &&
     325           0 :          EQUAL(pszQueryIn, pszQuery)))
     326           0 :         return OGRERR_NONE;
     327             : 
     328           0 :     CPLFree(pszQuery);
     329           0 :     pszQuery = pszQueryIn != nullptr ? CPLStrdup(pszQueryIn) : nullptr;
     330             : 
     331           0 :     ClearStatement();
     332             : 
     333           0 :     return OGRERR_NONE;
     334             : }
     335             : 
     336             : /************************************************************************/
     337             : /*                           TestCapability()                           */
     338             : /************************************************************************/
     339             : 
     340           0 : int OGRODBCTableLayer::TestCapability(const char *pszCap)
     341             : 
     342             : {
     343           0 :     if (EQUAL(pszCap, OLCRandomRead))
     344           0 :         return TRUE;
     345             : 
     346             :     else
     347           0 :         return OGRODBCLayer::TestCapability(pszCap);
     348             : }
     349             : 
     350             : /************************************************************************/
     351             : /*                          GetFeatureCount()                           */
     352             : /*                                                                      */
     353             : /*      If a spatial filter is in effect, we turn control over to       */
     354             : /*      the generic counter.  Otherwise we return the total count.      */
     355             : /*      Eventually we should consider implementing a more efficient     */
     356             : /*      way of counting features matching a spatial query.              */
     357             : /************************************************************************/
     358             : 
     359           0 : GIntBig OGRODBCTableLayer::GetFeatureCount(int bForce)
     360             : 
     361             : {
     362           0 :     if (m_poFilterGeom != nullptr)
     363           0 :         return OGRODBCLayer::GetFeatureCount(bForce);
     364             : 
     365           0 :     CPLODBCStatement oStmt(poDS->GetSession());
     366           0 :     oStmt.Append("SELECT COUNT(*) FROM ");
     367           0 :     oStmt.Append(EscapeAndQuoteIdentifier(poFeatureDefn->GetName()));
     368             : 
     369           0 :     if (pszQuery != nullptr)
     370           0 :         oStmt.Appendf(" WHERE %s", pszQuery);
     371             : 
     372           0 :     if (!oStmt.ExecuteSQL() || !oStmt.Fetch())
     373             :     {
     374           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     375             :                  "GetFeatureCount() failed on query %s.\n%s",
     376           0 :                  oStmt.GetCommand(), poDS->GetSession()->GetLastError());
     377           0 :         return OGRODBCLayer::GetFeatureCount(bForce);
     378             :     }
     379             : 
     380           0 :     return CPLAtoGIntBig(oStmt.GetColData(0));
     381             : }
     382             : 
     383             : /************************************************************************/
     384             : /*                           GetSpatialRef()                            */
     385             : /*                                                                      */
     386             : /*      We override this to try and fetch the table SRID from the       */
     387             : /*      geometry_columns table if the srsid is -2 (meaning we           */
     388             : /*      haven't yet even looked for it).                                */
     389             : /************************************************************************/
     390             : 
     391           0 : OGRSpatialReference *OGRODBCTableLayer::GetSpatialRef()
     392             : 
     393             : {
     394             : #ifdef notdef
     395             :     if (nSRSId == -2)
     396             :     {
     397             :         PGconn *hPGConn = poDS->GetPGConn();
     398             : 
     399             :         nSRSId = -1;
     400             : 
     401             :         poDS->SoftStartTransaction();
     402             : 
     403             :         char szCommand[1024] = {};
     404             :         sprintf(szCommand,
     405             :                 "SELECT srid FROM geometry_columns "
     406             :                 "WHERE f_table_name = '%s'",
     407             :                 poFeatureDefn->GetName());
     408             :         PGresult *hResult = PQexec(hPGConn, szCommand);
     409             : 
     410             :         if (hResult && PQresultStatus(hResult) == PGRES_TUPLES_OK &&
     411             :             PQntuples(hResult) == 1)
     412             :         {
     413             :             nSRSId = atoi(PQgetvalue(hResult, 0, 0));
     414             :         }
     415             : 
     416             :         poDS->SoftCommit();
     417             :     }
     418             : #endif
     419             : 
     420           0 :     return OGRODBCLayer::GetSpatialRef();
     421             : }

Generated by: LCOV version 1.14