LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/pgdump - ogrpgdumpdatasource.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 291 324 89.8 %
Date: 2024-05-04 12:52:34 Functions: 12 12 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Implements OGRPGDumpDataSource class.
       5             :  * Author:   Even Rouault, <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * Permission is hereby granted, free of charge, to any person obtaining a
      11             :  * copy of this software and associated documentation files (the "Software"),
      12             :  * to deal in the Software without restriction, including without limitation
      13             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      14             :  * and/or sell copies of the Software, and to permit persons to whom the
      15             :  * Software is furnished to do so, subject to the following conditions:
      16             :  *
      17             :  * The above copyright notice and this permission notice shall be included
      18             :  * in all copies or substantial portions of the Software.
      19             :  *
      20             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      21             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      22             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      23             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      24             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      25             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      26             :  * DEALINGS IN THE SOFTWARE.
      27             :  ****************************************************************************/
      28             : 
      29             : #include <algorithm>
      30             : #include <cstring>
      31             : #include "ogr_pgdump.h"
      32             : #include "cpl_conv.h"
      33             : #include "cpl_string.h"
      34             : 
      35             : /************************************************************************/
      36             : /*                      OGRPGDumpDataSource()                           */
      37             : /************************************************************************/
      38             : 
      39          96 : OGRPGDumpDataSource::OGRPGDumpDataSource(const char *pszNameIn,
      40          96 :                                          char **papszOptions)
      41             : {
      42          96 :     SetDescription(pszNameIn);
      43             : 
      44          96 :     const char *pszCRLFFormat = CSLFetchNameValue(papszOptions, "LINEFORMAT");
      45             : 
      46          96 :     bool bUseCRLF = false;
      47          96 :     if (pszCRLFFormat == nullptr)
      48             :     {
      49             : #ifdef _WIN32
      50             :         bUseCRLF = true;
      51             : #endif
      52             :     }
      53          52 :     else if (EQUAL(pszCRLFFormat, "CRLF"))
      54             :     {
      55           1 :         bUseCRLF = true;
      56             :     }
      57          51 :     else if (EQUAL(pszCRLFFormat, "LF"))
      58             :     {
      59          51 :         bUseCRLF = false;
      60             :     }
      61             :     else
      62             :     {
      63           0 :         CPLError(CE_Warning, CPLE_AppDefined,
      64             :                  "LINEFORMAT=%s not understood, use one of CRLF or LF.",
      65             :                  pszCRLFFormat);
      66             : #ifdef _WIN32
      67             :         bUseCRLF = true;
      68             : #endif
      69             :     }
      70             : 
      71          96 :     if (bUseCRLF)
      72           1 :         m_pszEOL = "\r\n";
      73             : 
      74          96 :     m_fp = VSIFOpenL(pszNameIn, "wb");
      75          96 :     if (m_fp == nullptr)
      76             :     {
      77           1 :         CPLError(CE_Failure, CPLE_FileIO, "Cannot create %s", pszNameIn);
      78           1 :         return;
      79             :     }
      80             : }
      81             : 
      82             : /************************************************************************/
      83             : /*                          ~OGRPGDumpDataSource()                          */
      84             : /************************************************************************/
      85             : 
      86         192 : OGRPGDumpDataSource::~OGRPGDumpDataSource()
      87             : 
      88             : {
      89          96 :     EndCopy();
      90          96 :     m_apoLayers.clear();
      91             : 
      92          96 :     if (m_fp)
      93             :     {
      94          95 :         LogCommit();
      95          95 :         VSIFCloseL(m_fp);
      96          95 :         m_fp = nullptr;
      97             :     }
      98         192 : }
      99             : 
     100             : /************************************************************************/
     101             : /*                         LogStartTransaction()                        */
     102             : /************************************************************************/
     103             : 
     104         111 : void OGRPGDumpDataSource::LogStartTransaction()
     105             : {
     106         111 :     if (m_bInTransaction)
     107           0 :         return;
     108         111 :     m_bInTransaction = true;
     109         111 :     Log("BEGIN");
     110             : }
     111             : 
     112             : /************************************************************************/
     113             : /*                             LogCommit()                              */
     114             : /************************************************************************/
     115             : 
     116         206 : void OGRPGDumpDataSource::LogCommit()
     117             : {
     118         206 :     EndCopy();
     119             : 
     120         206 :     if (!m_bInTransaction)
     121          95 :         return;
     122         111 :     m_bInTransaction = false;
     123         111 :     Log("COMMIT");
     124             : }
     125             : 
     126             : /************************************************************************/
     127             : /*                         OGRPGCommonLaunderName()                     */
     128             : /************************************************************************/
     129             : 
     130      198889 : char *OGRPGCommonLaunderName(const char *pszSrcName, const char *pszDebugPrefix,
     131             :                              bool bUTF8ToASCII)
     132             : 
     133             : {
     134      198889 :     char *pszSafeName = bUTF8ToASCII ? CPLUTF8ForceToASCII(pszSrcName, '_')
     135      198883 :                                      : CPLStrdup(pszSrcName);
     136             : 
     137      198889 :     int i = 0;  // needed after loop
     138     8514700 :     for (; i < OGR_PG_NAMEDATALEN - 1 && pszSafeName[i] != '\0'; i++)
     139             :     {
     140     8315810 :         if (static_cast<unsigned char>(pszSafeName[i]) <= 127)
     141             :         {
     142     8315800 :             pszSafeName[i] =
     143     8315800 :                 (char)CPLTolower(static_cast<unsigned char>(pszSafeName[i]));
     144     8315800 :             if (pszSafeName[i] == '\'' || pszSafeName[i] == '-' ||
     145     8315800 :                 pszSafeName[i] == '#')
     146             :             {
     147           6 :                 pszSafeName[i] = '_';
     148             :             }
     149             :         }
     150             :     }
     151      198889 :     pszSafeName[i] = '\0';
     152             : 
     153      198889 :     if (strcmp(pszSrcName, pszSafeName) != 0)
     154             :     {
     155      177367 :         if (CPLStrlenUTF8(pszSafeName) < CPLStrlenUTF8(pszSrcName))
     156             :         {
     157       55617 :             CPLError(CE_Warning, CPLE_AppDefined,
     158             :                      "%s identifier truncated to %s", pszSrcName, pszSafeName);
     159             :         }
     160             :         else
     161             :         {
     162      121750 :             CPLDebug(pszDebugPrefix, "LaunderName('%s') -> '%s'", pszSrcName,
     163             :                      pszSafeName);
     164             :         }
     165             :     }
     166             : 
     167      198889 :     return pszSafeName;
     168             : }
     169             : 
     170             : /************************************************************************/
     171             : /*                           ICreateLayer()                             */
     172             : /************************************************************************/
     173             : 
     174             : OGRLayer *
     175         111 : OGRPGDumpDataSource::ICreateLayer(const char *pszLayerName,
     176             :                                   const OGRGeomFieldDefn *poGeomFieldDefn,
     177             :                                   CSLConstList papszOptions)
     178             : 
     179             : {
     180         111 :     if (STARTS_WITH(pszLayerName, "pg"))
     181             :     {
     182           0 :         CPLError(CE_Warning, CPLE_AppDefined,
     183             :                  "The layer name should not begin by 'pg' as it is a reserved "
     184             :                  "prefix");
     185             :     }
     186             : 
     187         111 :     auto eType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone;
     188             :     const auto poSRS =
     189         111 :         poGeomFieldDefn ? poGeomFieldDefn->GetSpatialRef() : nullptr;
     190             : 
     191         111 :     const bool bCreateTable = CPLFetchBool(papszOptions, "CREATE_TABLE", true);
     192             :     const bool bCreateSchema =
     193         111 :         CPLFetchBool(papszOptions, "CREATE_SCHEMA", true);
     194             :     const char *pszDropTable =
     195         111 :         CSLFetchNameValueDef(papszOptions, "DROP_TABLE", "IF_EXISTS");
     196         111 :     int nGeometryTypeFlags = 0;
     197             : 
     198         111 :     if (OGR_GT_HasZ(eType))
     199          23 :         nGeometryTypeFlags |= OGRGeometry::OGR_G_3D;
     200         111 :     if (OGR_GT_HasM(eType))
     201           2 :         nGeometryTypeFlags |= OGRGeometry::OGR_G_MEASURED;
     202             : 
     203         111 :     int nForcedGeometryTypeFlags = -1;
     204         111 :     const char *pszDim = CSLFetchNameValue(papszOptions, "DIM");
     205         111 :     if (pszDim != nullptr)
     206             :     {
     207          19 :         if (EQUAL(pszDim, "XY") || EQUAL(pszDim, "2"))
     208             :         {
     209           0 :             nGeometryTypeFlags = 0;
     210           0 :             nForcedGeometryTypeFlags = nGeometryTypeFlags;
     211             :         }
     212          19 :         else if (EQUAL(pszDim, "XYZ") || EQUAL(pszDim, "3"))
     213             :         {
     214           7 :             nGeometryTypeFlags = OGRGeometry::OGR_G_3D;
     215           7 :             nForcedGeometryTypeFlags = nGeometryTypeFlags;
     216             :         }
     217          12 :         else if (EQUAL(pszDim, "XYM"))
     218             :         {
     219           6 :             nGeometryTypeFlags = OGRGeometry::OGR_G_MEASURED;
     220           6 :             nForcedGeometryTypeFlags = nGeometryTypeFlags;
     221             :         }
     222           6 :         else if (EQUAL(pszDim, "XYZM") || EQUAL(pszDim, "4"))
     223             :         {
     224           6 :             nGeometryTypeFlags =
     225             :                 OGRGeometry::OGR_G_3D | OGRGeometry::OGR_G_MEASURED;
     226           6 :             nForcedGeometryTypeFlags = nGeometryTypeFlags;
     227             :         }
     228             :         else
     229             :         {
     230           0 :             CPLError(CE_Failure, CPLE_AppDefined, "Invalid value for DIM");
     231             :         }
     232             :     }
     233             : 
     234         111 :     const int nDimension =
     235         111 :         2 + ((nGeometryTypeFlags & OGRGeometry::OGR_G_3D) ? 1 : 0) +
     236         111 :         ((nGeometryTypeFlags & OGRGeometry::OGR_G_MEASURED) ? 1 : 0);
     237             : 
     238             :     /* Should we turn layers with None geometry type as Unknown/GEOMETRY */
     239             :     /* so they are still recorded in geometry_columns table ? (#4012) */
     240         111 :     const bool bNoneAsUnknown = CPLTestBool(
     241             :         CSLFetchNameValueDef(papszOptions, "NONE_AS_UNKNOWN", "NO"));
     242             : 
     243         111 :     if (bNoneAsUnknown && eType == wkbNone)
     244           0 :         eType = wkbUnknown;
     245             : 
     246         111 :     const bool bExtractSchemaFromLayerName = CPLTestBool(CSLFetchNameValueDef(
     247             :         papszOptions, "EXTRACT_SCHEMA_FROM_LAYER_NAME", "YES"));
     248             : 
     249             :     // Postgres Schema handling:
     250             : 
     251             :     // Extract schema name from input layer name or passed with -lco SCHEMA.
     252             :     // Set layer name to "schema.table" or to "table" if schema ==
     253             :     // current_schema() Usage without schema name is backwards compatible
     254             : 
     255         111 :     const char *pszDotPos = strstr(pszLayerName, ".");
     256         222 :     std::string osTable;
     257         222 :     std::string osSchema;
     258             :     const bool bUTF8ToASCII =
     259         111 :         CPLFetchBool(papszOptions, "LAUNDER_ASCII", false);
     260             :     const bool bLaunder =
     261         111 :         bUTF8ToASCII || CPLFetchBool(papszOptions, "LAUNDER", true);
     262             : 
     263         111 :     if (pszDotPos != nullptr && bExtractSchemaFromLayerName)
     264             :     {
     265          48 :         const size_t length = static_cast<size_t>(pszDotPos - pszLayerName);
     266          48 :         osSchema = pszLayerName;
     267          48 :         osSchema.resize(length);
     268             : 
     269          48 :         if (bLaunder)
     270             :         {
     271          48 :             char *pszTmp = OGRPGCommonLaunderName(pszDotPos + 1, "PGDump",
     272             :                                                   bUTF8ToASCII);  // skip "."
     273          48 :             osTable = pszTmp;
     274          48 :             CPLFree(pszTmp);
     275             :         }
     276             :         else
     277          48 :             osTable = pszDotPos + 1;  // skip "."
     278             :     }
     279             :     else
     280             :     {
     281          63 :         if (bLaunder)
     282             :         {
     283             :             char *pszTmp =
     284          62 :                 OGRPGCommonLaunderName(pszLayerName, "PGDump", bUTF8ToASCII);
     285          62 :             osTable = pszTmp;
     286          62 :             CPLFree(pszTmp);
     287             :         }
     288             :         else
     289           1 :             osTable = pszLayerName;
     290             :     }
     291             : 
     292             :     const std::string osTableEscaped =
     293         222 :         OGRPGDumpEscapeColumnName(osTable.c_str());
     294         111 :     const char *pszTableEscaped = osTableEscaped.c_str();
     295             : 
     296         111 :     LogCommit();
     297             : 
     298             :     /* -------------------------------------------------------------------- */
     299             :     /*      Set the default schema for the layers.                          */
     300             :     /* -------------------------------------------------------------------- */
     301         222 :     CPLString osCommand;
     302             : 
     303         111 :     const char *pszSchemaOption = CSLFetchNameValue(papszOptions, "SCHEMA");
     304         111 :     if (pszSchemaOption)
     305             :     {
     306           2 :         osSchema = pszSchemaOption;
     307           2 :         if (bCreateSchema)
     308             :         {
     309             :             osCommand.Printf(
     310             :                 "CREATE SCHEMA %s",
     311           2 :                 OGRPGDumpEscapeColumnName(osSchema.c_str()).c_str());
     312           2 :             Log(osCommand);
     313             :         }
     314             :     }
     315             : 
     316         111 :     const bool bTemporary = CPLFetchBool(papszOptions, "TEMPORARY", false);
     317         111 :     if (bTemporary)
     318             :     {
     319           1 :         osSchema = "pg_temp";
     320             :     }
     321             : 
     322         111 :     if (osSchema.empty())
     323             :     {
     324          60 :         osSchema = "public";
     325             :     }
     326             :     const std::string osSchemaEscaped =
     327         222 :         OGRPGDumpEscapeColumnName(osSchema.c_str());
     328         111 :     const char *pszSchemaEscaped = osSchemaEscaped.c_str();
     329             : 
     330             :     /* -------------------------------------------------------------------- */
     331             :     /*      Do we already have this layer?                                  */
     332             :     /* -------------------------------------------------------------------- */
     333         127 :     for (const auto &poLayer : m_apoLayers)
     334             :     {
     335          16 :         if (EQUAL(pszLayerName, poLayer->GetDescription()))
     336             :         {
     337           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     338             :                      "Layer %s already exists, CreateLayer failed.\n",
     339             :                      pszLayerName);
     340           0 :             return nullptr;
     341             :         }
     342             :     }
     343             : 
     344         111 :     if (bCreateTable &&
     345         110 :         (EQUAL(pszDropTable, "YES") || EQUAL(pszDropTable, "ON") ||
     346         110 :          EQUAL(pszDropTable, "TRUE") || EQUAL(pszDropTable, "IF_EXISTS")))
     347             :     {
     348         110 :         if (EQUAL(pszDropTable, "IF_EXISTS"))
     349             :             osCommand.Printf("DROP TABLE IF EXISTS %s.%s CASCADE",
     350         110 :                              pszSchemaEscaped, pszTableEscaped);
     351             :         else
     352             :             osCommand.Printf("DROP TABLE %s.%s CASCADE", pszSchemaEscaped,
     353           0 :                              pszTableEscaped);
     354         110 :         Log(osCommand);
     355             :     }
     356             : 
     357             :     /* -------------------------------------------------------------------- */
     358             :     /*      Handle the GEOM_TYPE option.                                    */
     359             :     /* -------------------------------------------------------------------- */
     360         111 :     const char *pszGeomType = CSLFetchNameValue(papszOptions, "GEOM_TYPE");
     361         111 :     if (pszGeomType == nullptr)
     362             :     {
     363         104 :         pszGeomType = "geometry";
     364             :     }
     365             : 
     366         111 :     if (!EQUAL(pszGeomType, "geometry") && !EQUAL(pszGeomType, "geography"))
     367             :     {
     368           0 :         CPLError(
     369             :             CE_Failure, CPLE_AppDefined,
     370             :             "GEOM_TYPE in PostGIS enabled databases must be 'geometry' or "
     371             :             "'geography'.  Creation of layer %s with GEOM_TYPE %s has failed.",
     372             :             pszLayerName, pszGeomType);
     373           0 :         return nullptr;
     374             :     }
     375             : 
     376             :     /* -------------------------------------------------------------------- */
     377             :     /*      Try to get the SRS Id of this spatial reference system,         */
     378             :     /*      adding tot the srs table if needed.                             */
     379             :     /* -------------------------------------------------------------------- */
     380             :     const char *pszPostgisVersion =
     381         111 :         CSLFetchNameValueDef(papszOptions, "POSTGIS_VERSION", "2.2");
     382         111 :     const int nPostGISMajor = atoi(pszPostgisVersion);
     383         111 :     const char *pszPostgisVersionDot = strchr(pszPostgisVersion, '.');
     384         111 :     const int nPostGISMinor =
     385         111 :         pszPostgisVersionDot ? atoi(pszPostgisVersionDot + 1) : 0;
     386         111 :     const int nUnknownSRSId = nPostGISMajor >= 2 ? 0 : -1;
     387             : 
     388         111 :     int nSRSId = nUnknownSRSId;
     389         111 :     int nForcedSRSId = -2;
     390         111 :     const char *pszSRID = CSLFetchNameValue(papszOptions, "SRID");
     391         111 :     if (pszSRID)
     392             :     {
     393           1 :         nSRSId = atoi(pszSRID);
     394           1 :         nForcedSRSId = nSRSId;
     395             :     }
     396             :     else
     397             :     {
     398         110 :         if (poSRS)
     399             :         {
     400           0 :             const char *pszAuthorityName = poSRS->GetAuthorityName(nullptr);
     401           0 :             if (pszAuthorityName != nullptr && EQUAL(pszAuthorityName, "EPSG"))
     402             :             {
     403             :                 /* Assume the EPSG Id is the SRS ID. Might be a wrong guess ! */
     404           0 :                 nSRSId = atoi(poSRS->GetAuthorityCode(nullptr));
     405             :             }
     406             :             else
     407             :             {
     408           0 :                 const char *pszGeogCSName = poSRS->GetAttrValue("GEOGCS");
     409           0 :                 if (pszGeogCSName != nullptr &&
     410           0 :                     EQUAL(pszGeogCSName, "GCS_WGS_1984"))
     411             :                 {
     412           0 :                     nSRSId = 4326;
     413             :                 }
     414             :             }
     415             :         }
     416             :     }
     417             : 
     418             :     const std::string osEscapedTableNameSingleQuote =
     419         222 :         OGRPGDumpEscapeString(osTable.c_str());
     420             :     const char *pszEscapedTableNameSingleQuote =
     421         111 :         osEscapedTableNameSingleQuote.c_str();
     422             : 
     423         111 :     const char *pszGeometryType = OGRToOGCGeomType(eType);
     424             : 
     425         111 :     const char *pszGFldName = CSLFetchNameValue(papszOptions, "GEOMETRY_NAME");
     426         111 :     if (eType != wkbNone && !EQUAL(pszGeomType, "geography"))
     427             :     {
     428          74 :         if (pszGFldName == nullptr)
     429          73 :             pszGFldName = "wkb_geometry";
     430             : 
     431          74 :         if (nPostGISMajor < 2)
     432             :         {
     433             :             // Sometimes there is an old cruft entry in the geometry_columns
     434             :             // table if things were not properly cleaned up before.  We make
     435             :             // an effort to clean out such cruft.
     436             :             //
     437             :             // Note: PostGIS 2.0 defines geometry_columns as a view (no clean up
     438             :             // is needed).
     439             : 
     440             :             osCommand.Printf("DELETE FROM geometry_columns "
     441             :                              "WHERE f_table_name = %s AND f_table_schema = %s",
     442             :                              pszEscapedTableNameSingleQuote,
     443           1 :                              OGRPGDumpEscapeString(osSchema.c_str()).c_str());
     444           1 :             if (bCreateTable)
     445           1 :                 Log(osCommand);
     446             :         }
     447             :     }
     448             : 
     449         111 :     LogStartTransaction();
     450             : 
     451             :     /* -------------------------------------------------------------------- */
     452             :     /*      Create an empty table first.                                    */
     453             :     /* -------------------------------------------------------------------- */
     454         111 :     if (bCreateTable)
     455             :     {
     456         110 :         if (bTemporary)
     457             :         {
     458           1 :             osCommand.Printf("CREATE TEMPORARY TABLE %s()", pszTableEscaped);
     459             :         }
     460             :         else
     461             :         {
     462             :             osCommand.Printf("CREATE%s TABLE %s.%s()",
     463         109 :                              CPLFetchBool(papszOptions, "UNLOGGED", false)
     464             :                                  ? " UNLOGGED"
     465             :                                  : "",
     466         109 :                              pszSchemaEscaped, pszTableEscaped);
     467             :         }
     468         110 :         Log(osCommand);
     469             :     }
     470             : 
     471             :     /* -------------------------------------------------------------------- */
     472             :     /*      Add FID if needed.                                              */
     473             :     /* -------------------------------------------------------------------- */
     474         111 :     const char *pszFIDColumnNameIn = CSLFetchNameValue(papszOptions, "FID");
     475         222 :     CPLString osFIDColumnName;
     476         111 :     if (pszFIDColumnNameIn == nullptr)
     477         105 :         osFIDColumnName = "ogc_fid";
     478             :     else
     479             :     {
     480           6 :         if (bLaunder)
     481             :         {
     482           6 :             char *pszLaunderedFid = OGRPGCommonLaunderName(
     483             :                 pszFIDColumnNameIn, "PGDump", bUTF8ToASCII);
     484           6 :             osFIDColumnName = pszLaunderedFid;
     485           6 :             CPLFree(pszLaunderedFid);
     486             :         }
     487             :         else
     488             :         {
     489           0 :             osFIDColumnName = pszFIDColumnNameIn;
     490             :         }
     491             :     }
     492             :     const CPLString osFIDColumnNameEscaped =
     493         222 :         OGRPGDumpEscapeColumnName(osFIDColumnName);
     494             : 
     495         111 :     const bool bFID64 = CPLFetchBool(papszOptions, "FID64", false);
     496         111 :     const char *pszSerialType = bFID64 ? "BIGSERIAL" : "SERIAL";
     497             : 
     498         111 :     if (bCreateTable && !osFIDColumnName.empty())
     499             :     {
     500         216 :         std::string osConstraintName(osTable);
     501         108 :         if (bLaunder && osConstraintName.size() + strlen("_pk") >
     502             :                             static_cast<size_t>(OGR_PG_NAMEDATALEN - 1))
     503             :         {
     504           1 :             osConstraintName.resize(OGR_PG_NAMEDATALEN - 1 - strlen("_pk"));
     505             :         }
     506         108 :         osConstraintName += "_pk";
     507             :         osCommand.Printf(
     508             :             "ALTER TABLE %s.%s ADD COLUMN %s %s "
     509             :             "CONSTRAINT %s PRIMARY KEY",
     510             :             pszSchemaEscaped, pszTableEscaped, osFIDColumnNameEscaped.c_str(),
     511             :             pszSerialType,
     512         108 :             OGRPGDumpEscapeColumnName(osConstraintName.c_str()).c_str());
     513         108 :         Log(osCommand);
     514             :     }
     515             : 
     516             :     /* -------------------------------------------------------------------- */
     517             :     /*      Create geometry/geography column (actual creation possibly      */
     518             :     /*      deferred).                                                      */
     519             :     /* -------------------------------------------------------------------- */
     520         222 :     std::vector<std::string> aosGeomCommands;
     521         111 :     if (bCreateTable && eType != wkbNone && EQUAL(pszGeomType, "geography"))
     522             :     {
     523           7 :         if (CSLFetchNameValue(papszOptions, "GEOMETRY_NAME") != nullptr)
     524           0 :             pszGFldName = CSLFetchNameValue(papszOptions, "GEOMETRY_NAME");
     525             :         else
     526           7 :             pszGFldName = "the_geog";
     527             : 
     528           7 :         const char *suffix = "";
     529           7 :         if ((nGeometryTypeFlags & OGRGeometry::OGR_G_MEASURED) &&
     530           4 :             (nGeometryTypeFlags & OGRGeometry::OGR_G_3D))
     531             :         {
     532           2 :             suffix = "ZM";
     533             :         }
     534           5 :         else if ((nGeometryTypeFlags & OGRGeometry::OGR_G_MEASURED))
     535             :         {
     536           2 :             suffix = "M";
     537             :         }
     538           3 :         else if ((nGeometryTypeFlags & OGRGeometry::OGR_G_3D))
     539             :         {
     540           2 :             suffix = "Z";
     541             :         }
     542             : 
     543           7 :         if (nSRSId)
     544             :             osCommand.Printf("ALTER TABLE %s.%s "
     545             :                              "ADD COLUMN %s geography(%s%s,%d)",
     546             :                              pszSchemaEscaped, pszTableEscaped,
     547           0 :                              OGRPGDumpEscapeColumnName(pszGFldName).c_str(),
     548           0 :                              pszGeometryType, suffix, nSRSId);
     549             :         else
     550             :             osCommand.Printf("ALTER TABLE %s.%s "
     551             :                              "ADD COLUMN %s geography(%s%s)",
     552             :                              pszSchemaEscaped, pszTableEscaped,
     553          14 :                              OGRPGDumpEscapeColumnName(pszGFldName).c_str(),
     554           7 :                              pszGeometryType, suffix);
     555           7 :         aosGeomCommands.push_back(osCommand);
     556             :     }
     557         104 :     else if (bCreateTable && eType != wkbNone)
     558             :     {
     559          73 :         const char *suffix = "";
     560          73 :         if (nGeometryTypeFlags ==
     561          76 :                 static_cast<int>(OGRGeometry::OGR_G_MEASURED) &&
     562           3 :             wkbFlatten(eType) != wkbUnknown)
     563             :         {
     564           2 :             suffix = "M";
     565             :         }
     566             : 
     567             :         osCommand.Printf(
     568             :             "SELECT AddGeometryColumn(%s,%s,%s,%d,'%s%s',%d)",
     569         146 :             OGRPGDumpEscapeString(bTemporary ? "" : osSchema.c_str()).c_str(),
     570             :             pszEscapedTableNameSingleQuote,
     571         146 :             OGRPGDumpEscapeString(pszGFldName).c_str(), nSRSId, pszGeometryType,
     572         146 :             suffix, nDimension);
     573          73 :         aosGeomCommands.push_back(osCommand);
     574             :     }
     575             : 
     576             :     const char *pszSI =
     577         111 :         CSLFetchNameValueDef(papszOptions, "SPATIAL_INDEX", "GIST");
     578         111 :     const bool bCreateSpatialIndex =
     579           0 :         (EQUAL(pszSI, "GIST") || EQUAL(pszSI, "SPGIST") ||
     580         111 :          EQUAL(pszSI, "BRIN") || EQUAL(pszSI, "YES") || EQUAL(pszSI, "ON") ||
     581           0 :          EQUAL(pszSI, "TRUE"));
     582         111 :     if (!bCreateSpatialIndex && !EQUAL(pszSI, "NO") && !EQUAL(pszSI, "OFF") &&
     583           0 :         !EQUAL(pszSI, "FALSE") && !EQUAL(pszSI, "NONE"))
     584             :     {
     585           0 :         CPLError(CE_Warning, CPLE_NotSupported,
     586             :                  "SPATIAL_INDEX=%s not supported", pszSI);
     587             :     }
     588         222 :     const char *pszSpatialIndexType = EQUAL(pszSI, "SPGIST") ? "SPGIST"
     589         111 :                                       : EQUAL(pszSI, "BRIN") ? "BRIN"
     590             :                                                              : "GIST";
     591             : 
     592         222 :     std::vector<std::string> aosSpatialIndexCreationCommands;
     593         111 :     if (bCreateTable && bCreateSpatialIndex && pszGFldName && eType != wkbNone)
     594             :     {
     595         160 :         std::string osIndexName(osTable);
     596         160 :         std::string osSuffix("_");
     597          80 :         osSuffix += pszGFldName;
     598          80 :         osSuffix += "_geom_idx";
     599          80 :         if (bLaunder)
     600             :         {
     601          79 :             if (osSuffix.size() >= static_cast<size_t>(OGR_PG_NAMEDATALEN - 1))
     602             :             {
     603           0 :                 osSuffix = "_0_geom_idx";
     604             :             }
     605          79 :             if (osIndexName.size() + osSuffix.size() >
     606             :                 static_cast<size_t>(OGR_PG_NAMEDATALEN - 1))
     607           1 :                 osIndexName.resize(OGR_PG_NAMEDATALEN - 1 - osSuffix.size());
     608             :         }
     609          80 :         osIndexName += osSuffix;
     610             : 
     611             :         /* --------------------------------------------------------------- */
     612             :         /*      Create the spatial index.                                  */
     613             :         /* --------------------------------------------------------------- */
     614             :         osCommand.Printf("CREATE INDEX %s "
     615             :                          "ON %s.%s "
     616             :                          "USING %s (%s)",
     617         160 :                          OGRPGDumpEscapeColumnName(osIndexName.c_str()).c_str(),
     618             :                          pszSchemaEscaped, pszTableEscaped, pszSpatialIndexType,
     619         240 :                          OGRPGDumpEscapeColumnName(pszGFldName).c_str());
     620          80 :         aosSpatialIndexCreationCommands.push_back(osCommand);
     621             :     }
     622             : 
     623             :     /* -------------------------------------------------------------------- */
     624             :     /*      Create the layer object.                                        */
     625             :     /* -------------------------------------------------------------------- */
     626             :     const bool bWriteAsHex =
     627         111 :         !CPLFetchBool(papszOptions, "WRITE_EWKT_GEOM", false);
     628             : 
     629             :     auto poLayer = std::make_unique<OGRPGDumpLayer>(
     630         111 :         this, osSchema.c_str(), osTable.c_str(),
     631         111 :         !osFIDColumnName.empty() ? osFIDColumnName.c_str() : nullptr,
     632         222 :         bWriteAsHex, bCreateTable);
     633         111 :     poLayer->SetLaunderFlag(bLaunder);
     634         111 :     poLayer->SetUTF8ToASCIIFlag(bUTF8ToASCII);
     635         111 :     poLayer->SetPrecisionFlag(CPLFetchBool(papszOptions, "PRECISION", true));
     636             : 
     637             :     const char *pszOverrideColumnTypes =
     638         111 :         CSLFetchNameValue(papszOptions, "COLUMN_TYPES");
     639         111 :     poLayer->SetOverrideColumnTypes(pszOverrideColumnTypes);
     640         111 :     poLayer->SetUnknownSRSId(nUnknownSRSId);
     641         111 :     poLayer->SetForcedSRSId(nForcedSRSId);
     642         111 :     poLayer->SetCreateSpatialIndex(bCreateSpatialIndex, pszSpatialIndexType);
     643         111 :     poLayer->SetPostGISVersion(nPostGISMajor, nPostGISMinor);
     644         111 :     poLayer->SetForcedGeometryTypeFlags(nForcedGeometryTypeFlags);
     645             : 
     646             :     // Log geometry field creation immediately or defer it, according to
     647             :     // GEOM_COLUMN_POSITION
     648         111 :     const bool bGeomColumnPositionImmediate = EQUAL(
     649             :         CSLFetchNameValueDef(papszOptions, "GEOM_COLUMN_POSITION", "IMMEDIATE"),
     650             :         "IMMEDIATE");
     651         111 :     poLayer->SetGeomColumnPositionImmediate(bGeomColumnPositionImmediate);
     652         111 :     if (bGeomColumnPositionImmediate)
     653             :     {
     654         180 :         for (const auto &osSQL : aosGeomCommands)
     655          75 :             Log(osSQL.c_str());
     656             :     }
     657             :     else
     658             :     {
     659           6 :         poLayer->SetDeferredGeomFieldCreationCommands(aosGeomCommands);
     660             :     }
     661         111 :     poLayer->SetSpatialIndexCreationCommands(aosSpatialIndexCreationCommands);
     662             : 
     663         111 :     const char *pszDescription = CSLFetchNameValue(papszOptions, "DESCRIPTION");
     664         111 :     if (pszDescription != nullptr)
     665           1 :         poLayer->SetForcedDescription(pszDescription);
     666             : 
     667         111 :     if (eType != wkbNone)
     668             :     {
     669         162 :         OGRGeomFieldDefn oTmp(pszGFldName, eType);
     670          81 :         auto poGeomField = std::make_unique<OGRPGDumpGeomFieldDefn>(&oTmp);
     671          81 :         poGeomField->m_nSRSId = nSRSId;
     672          81 :         poGeomField->m_nGeometryTypeFlags = nGeometryTypeFlags;
     673          81 :         poLayer->GetLayerDefn()->AddGeomFieldDefn(std::move(poGeomField));
     674             :     }
     675          30 :     else if (pszGFldName)
     676           6 :         poLayer->SetGeometryFieldName(pszGFldName);
     677             : 
     678             :     /* -------------------------------------------------------------------- */
     679             :     /*      Add layer to data source layer list.                            */
     680             :     /* -------------------------------------------------------------------- */
     681         111 :     m_apoLayers.emplace_back(std::move(poLayer));
     682             : 
     683         111 :     return m_apoLayers.back().get();
     684             : }
     685             : 
     686             : /************************************************************************/
     687             : /*                           TestCapability()                           */
     688             : /************************************************************************/
     689             : 
     690          75 : int OGRPGDumpDataSource::TestCapability(const char *pszCap)
     691             : 
     692             : {
     693          75 :     if (EQUAL(pszCap, ODsCCreateLayer))
     694          39 :         return TRUE;
     695          36 :     else if (EQUAL(pszCap, ODsCCreateGeomFieldAfterCreateLayer))
     696          13 :         return TRUE;
     697          23 :     else if (EQUAL(pszCap, ODsCCurveGeometries))
     698           0 :         return TRUE;
     699          23 :     else if (EQUAL(pszCap, ODsCMeasuredGeometries))
     700           0 :         return TRUE;
     701          23 :     else if (EQUAL(pszCap, ODsCZGeometries))
     702           0 :         return TRUE;
     703          23 :     else if (EQUAL(pszCap, ODsCRandomLayerWrite))
     704           0 :         return TRUE;
     705             :     else
     706          23 :         return FALSE;
     707             : }
     708             : 
     709             : /************************************************************************/
     710             : /*                              GetLayer()                              */
     711             : /************************************************************************/
     712             : 
     713           7 : OGRLayer *OGRPGDumpDataSource::GetLayer(int iLayer)
     714             : 
     715             : {
     716           7 :     if (iLayer < 0 || iLayer >= static_cast<int>(m_apoLayers.size()))
     717           0 :         return nullptr;
     718             :     else
     719           7 :         return m_apoLayers[iLayer].get();
     720             : }
     721             : 
     722             : /************************************************************************/
     723             : /*                                  Log()                               */
     724             : /************************************************************************/
     725             : 
     726        1204 : bool OGRPGDumpDataSource::Log(const char *pszStr, bool bAddSemiColumn)
     727             : {
     728        1204 :     if (m_fp == nullptr)
     729             :     {
     730           1 :         return false;
     731             :     }
     732             : 
     733        1203 :     VSIFWriteL(pszStr, strlen(pszStr), 1, m_fp);
     734        1203 :     if (bAddSemiColumn)
     735             :     {
     736        1162 :         const char chSemiColumn = ';';
     737        1162 :         VSIFWriteL(&chSemiColumn, 1, 1, m_fp);
     738             :     }
     739        1203 :     VSIFWriteL(m_pszEOL, strlen(m_pszEOL), 1, m_fp);
     740        1203 :     return true;
     741             : }
     742             : 
     743             : /************************************************************************/
     744             : /*                             StartCopy()                              */
     745             : /************************************************************************/
     746          10 : void OGRPGDumpDataSource::StartCopy(OGRPGDumpLayer *poPGLayer)
     747             : {
     748          10 :     EndCopy();
     749          10 :     m_poLayerInCopyMode = poPGLayer;
     750          10 : }
     751             : 
     752             : /************************************************************************/
     753             : /*                              EndCopy()                               */
     754             : /************************************************************************/
     755         312 : OGRErr OGRPGDumpDataSource::EndCopy()
     756             : {
     757         312 :     if (m_poLayerInCopyMode != nullptr)
     758             :     {
     759          10 :         OGRErr result = m_poLayerInCopyMode->EndCopy();
     760          10 :         m_poLayerInCopyMode = nullptr;
     761             : 
     762          10 :         return result;
     763             :     }
     764             : 
     765         302 :     return OGRERR_NONE;
     766             : }

Generated by: LCOV version 1.14