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

Generated by: LCOV version 1.14