1
/******************************************************************************
2
* $Id: ogrpgdumpdatasource.cpp 22821 2011-07-28 17:54:47Z rouault $
4
* Project: OpenGIS Simple Features Reference Implementation
5
* Purpose: Implements OGRPGDumpDataSource class.
6
* Author: Even Rouault, <even dot rouault at mines dash paris dot org>
8
******************************************************************************
9
* Copyright (c) 2010, Even Rouault
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:
18
* The above copyright notice and this permission notice shall be included
19
* in all copies or substantial portions of the Software.
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
****************************************************************************/
31
#include "ogr_pgdump.h"
33
#include "cpl_string.h"
35
CPL_CVSID("$Id: ogrpgdumpdatasource.cpp 22821 2011-07-28 17:54:47Z rouault $");
37
/************************************************************************/
38
/* OGRPGDumpDataSource() */
39
/************************************************************************/
41
OGRPGDumpDataSource::OGRPGDumpDataSource(const char* pszName,
47
this->pszName = CPLStrdup(pszName);
50
bInTransaction = FALSE;
51
poLayerInCopyMode = NULL;
53
const char *pszCRLFFormat = CSLFetchNameValue( papszOptions, "LINEFORMAT");
56
if( pszCRLFFormat == NULL )
64
else if( EQUAL(pszCRLFFormat,"CRLF") )
66
else if( EQUAL(pszCRLFFormat,"LF") )
70
CPLError( CE_Warning, CPLE_AppDefined,
71
"LINEFORMAT=%s not understood, use one of CRLF or LF.",
79
pszEOL = (bUseCRLF) ? "\r\n" : "\n";
82
/************************************************************************/
83
/* ~OGRPGDumpDataSource() */
84
/************************************************************************/
86
OGRPGDumpDataSource::~OGRPGDumpDataSource()
98
for(i=0;i<nLayers;i++)
104
/************************************************************************/
105
/* StartTransaction() */
106
/************************************************************************/
108
void OGRPGDumpDataSource::StartTransaction()
112
bInTransaction = TRUE;
116
/************************************************************************/
118
/************************************************************************/
120
void OGRPGDumpDataSource::Commit()
126
bInTransaction = FALSE;
130
/************************************************************************/
132
/************************************************************************/
134
char *OGRPGDumpDataSource::LaunderName( const char *pszSrcName )
137
char *pszSafeName = CPLStrdup( pszSrcName );
139
for( int i = 0; pszSafeName[i] != '\0'; i++ )
141
pszSafeName[i] = (char) tolower( pszSafeName[i] );
142
if( pszSafeName[i] == '\'' || pszSafeName[i] == '-' || pszSafeName[i] == '#' )
143
pszSafeName[i] = '_';
146
if( strcmp(pszSrcName,pszSafeName) != 0 )
147
CPLDebug("PG","LaunderName('%s') -> '%s'",
148
pszSrcName, pszSafeName);
153
/************************************************************************/
155
/************************************************************************/
158
OGRPGDumpDataSource::CreateLayer( const char * pszLayerName,
159
OGRSpatialReference *poSRS,
160
OGRwkbGeometryType eType,
161
char ** papszOptions )
165
const char *pszGeomType = NULL;
166
char *pszTableName = NULL;
167
char *pszSchemaName = NULL;
169
int bHavePostGIS = TRUE;
171
const char* pszFIDColumnName = CSLFetchNameValue(papszOptions, "FID");
172
CPLString osFIDColumnName;
173
if (pszFIDColumnName == NULL)
174
osFIDColumnName = "OGC_FID";
177
if( CSLFetchBoolean(papszOptions,"LAUNDER", TRUE) )
179
char* pszLaunderedFid = LaunderName(pszFIDColumnName);
180
osFIDColumnName += OGRPGDumpEscapeColumnName(pszLaunderedFid);
181
CPLFree(pszLaunderedFid);
184
osFIDColumnName += OGRPGDumpEscapeColumnName(pszFIDColumnName);
186
pszFIDColumnName = osFIDColumnName.c_str();
188
if (strncmp(pszLayerName, "pg", 2) == 0)
190
CPLError(CE_Warning, CPLE_AppDefined,
191
"The layer name should not begin by 'pg' as it is a reserved prefix");
194
//bHavePostGIS = CSLFetchBoolean(papszOptions,"POSTGIS", TRUE);
196
int bCreateTable = CSLFetchBoolean(papszOptions,"CREATE_TABLE", TRUE);
197
int bCreateSchema = CSLFetchBoolean(papszOptions,"CREATE_SCHEMA", TRUE);
198
const char* pszDropTable = CSLFetchNameValueDef(papszOptions,"DROP_TABLE", "YES");
200
if( wkbFlatten(eType) == eType )
203
if( CSLFetchNameValue( papszOptions, "DIM") != NULL )
204
nDimension = atoi(CSLFetchNameValue( papszOptions, "DIM"));
206
/* Should we turn layers with None geometry type as Unknown/GEOMETRY */
207
/* so they are still recorded in geometry_columns table ? (#4012) */
208
int bNoneAsUnknown = CSLTestBoolean(CSLFetchNameValueDef(
209
papszOptions, "NONE_AS_UNKNOWN", "NO"));
210
if (bNoneAsUnknown && eType == wkbNone)
212
else if (eType == wkbNone)
213
bHavePostGIS = FALSE;
215
int bExtractSchemaFromLayerName = CSLTestBoolean(CSLFetchNameValueDef(
216
papszOptions, "EXTRACT_SCHEMA_FROM_LAYER_NAME", "YES"));
218
/* Postgres Schema handling:
219
Extract schema name from input layer name or passed with -lco SCHEMA.
220
Set layer name to "schema.table" or to "table" if schema == current_schema()
221
Usage without schema name is backwards compatible
223
const char* pszDotPos = strstr(pszLayerName,".");
224
if ( pszDotPos != NULL && bExtractSchemaFromLayerName )
226
int length = pszDotPos - pszLayerName;
227
pszSchemaName = (char*)CPLMalloc(length+1);
228
strncpy(pszSchemaName, pszLayerName, length);
229
pszSchemaName[length] = '\0';
231
if( CSLFetchBoolean(papszOptions,"LAUNDER", TRUE) )
232
pszTableName = LaunderName( pszDotPos + 1 ); //skip "."
234
pszTableName = CPLStrdup( pszDotPos + 1 ); //skip "."
238
pszSchemaName = NULL;
239
if( CSLFetchBoolean(papszOptions,"LAUNDER", TRUE) )
240
pszTableName = LaunderName( pszLayerName ); //skip "."
242
pszTableName = CPLStrdup( pszLayerName ); //skip "."
247
/* -------------------------------------------------------------------- */
248
/* Set the default schema for the layers. */
249
/* -------------------------------------------------------------------- */
250
if( CSLFetchNameValue( papszOptions, "SCHEMA" ) != NULL )
252
CPLFree(pszSchemaName);
253
pszSchemaName = CPLStrdup(CSLFetchNameValue( papszOptions, "SCHEMA" ));
256
osCommand.Printf("CREATE SCHEMA \"%s\"", pszSchemaName);
261
if ( pszSchemaName == NULL)
263
pszSchemaName = CPLStrdup("public");
266
/* -------------------------------------------------------------------- */
267
/* Do we already have this layer? */
268
/* -------------------------------------------------------------------- */
271
for( iLayer = 0; iLayer < nLayers; iLayer++ )
273
if( EQUAL(pszLayerName,papoLayers[iLayer]->GetLayerDefn()->GetName()) )
275
CPLError( CE_Failure, CPLE_AppDefined,
276
"Layer %s already exists, CreateLayer failed.\n",
278
CPLFree( pszTableName );
279
CPLFree( pszSchemaName );
285
if (bCreateTable && (EQUAL(pszDropTable, "YES") ||
286
EQUAL(pszDropTable, "ON") ||
287
EQUAL(pszDropTable, "TRUE") ||
288
EQUAL(pszDropTable, "IF_EXISTS")))
290
if (EQUAL(pszDropTable, "IF_EXISTS"))
291
osCommand.Printf("DROP TABLE IF EXISTS \"%s\".\"%s\" CASCADE", pszSchemaName, pszTableName );
293
osCommand.Printf("DROP TABLE \"%s\".\"%s\" CASCADE", pszSchemaName, pszTableName );
297
/* -------------------------------------------------------------------- */
298
/* Handle the GEOM_TYPE option. */
299
/* -------------------------------------------------------------------- */
300
pszGeomType = CSLFetchNameValue( papszOptions, "GEOM_TYPE" );
301
if( pszGeomType == NULL )
303
pszGeomType = "geometry";
306
if( !EQUAL(pszGeomType,"geometry") && !EQUAL(pszGeomType, "geography"))
308
CPLError( CE_Failure, CPLE_AppDefined,
309
"GEOM_TYPE in PostGIS enabled databases must be 'geometry' or 'geography'.\n"
310
"Creation of layer %s with GEOM_TYPE %s has failed.",
311
pszLayerName, pszGeomType );
312
CPLFree( pszTableName );
313
CPLFree( pszSchemaName );
317
/* -------------------------------------------------------------------- */
318
/* Try to get the SRS Id of this spatial reference system, */
319
/* adding tot the srs table if needed. */
320
/* -------------------------------------------------------------------- */
323
if( CSLFetchNameValue( papszOptions, "SRID") != NULL )
324
nSRSId = atoi(CSLFetchNameValue( papszOptions, "SRID"));
329
const char* pszAuthorityName = poSRS->GetAuthorityName(NULL);
330
if( pszAuthorityName != NULL && EQUAL( pszAuthorityName, "EPSG" ) )
332
/* Assume the EPSG Id is the SRS ID. Might be a wrong guess ! */
333
nSRSId = atoi( poSRS->GetAuthorityCode(NULL) );
337
const char* pszGeogCSName = poSRS->GetAttrValue("GEOGCS");
338
if (pszGeogCSName != NULL && EQUAL(pszGeogCSName, "GCS_WGS_1984"))
344
CPLString osEscapedTableNameSingleQuote = OGRPGDumpEscapeString(pszTableName, -1, "");
345
const char* pszEscapedTableNameSingleQuote = osEscapedTableNameSingleQuote.c_str();
347
const char *pszGeometryType = OGRToOGCGeomType(eType);
349
const char *pszGFldName = NULL;
350
if( bHavePostGIS && !EQUAL(pszGeomType, "geography"))
352
if( CSLFetchNameValue( papszOptions, "GEOMETRY_NAME") != NULL )
353
pszGFldName = CSLFetchNameValue( papszOptions, "GEOMETRY_NAME");
355
pszGFldName = "wkb_geometry";
357
/* Sometimes there is an old cruft entry in the geometry_columns
358
* table if things were not properly cleaned up before. We make
359
* an effort to clean out such cruft.
362
"DELETE FROM geometry_columns WHERE f_table_name = %s AND f_table_schema = '%s'",
363
pszEscapedTableNameSingleQuote, pszSchemaName );
371
/* -------------------------------------------------------------------- */
372
/* Create a basic table with the FID. Also include the */
373
/* geometry if this is not a PostGIS enabled table. */
374
/* -------------------------------------------------------------------- */
376
CPLString osCreateTable;
377
int bTemporary = CSLFetchNameValue( papszOptions, "TEMPORARY" ) != NULL &&
378
CSLTestBoolean(CSLFetchNameValue( papszOptions, "TEMPORARY" ));
381
CPLFree(pszSchemaName);
382
pszSchemaName = CPLStrdup("pg_temp_1");
383
osCreateTable.Printf("CREATE TEMPORARY TABLE \"%s\"", pszTableName);
386
osCreateTable.Printf("CREATE TABLE \"%s\".\"%s\"", pszSchemaName, pszTableName);
390
if (eType == wkbNone)
394
" CONSTRAINT \"%s_pk\" PRIMARY KEY (%s) )",
395
osCreateTable.c_str(), pszFIDColumnName, pszTableName, pszFIDColumnName );
401
" CONSTRAINT \"%s_pk\" PRIMARY KEY (%s) )",
402
osCreateTable.c_str(), pszFIDColumnName, pszGeomType, pszTableName, pszFIDColumnName );
404
else if ( EQUAL(pszGeomType, "geography") )
406
if( CSLFetchNameValue( papszOptions, "GEOMETRY_NAME") != NULL )
407
pszGFldName = CSLFetchNameValue( papszOptions, "GEOMETRY_NAME");
409
pszGFldName = "the_geog";
413
"%s ( %s SERIAL, \"%s\" geography(%s%s,%d), CONSTRAINT \"%s_pk\" PRIMARY KEY (%s) )",
414
osCreateTable.c_str(), pszFIDColumnName, pszGFldName, pszGeometryType, nDimension == 2 ? "" : "Z", nSRSId, pszTableName, pszFIDColumnName );
417
"%s ( %s SERIAL, \"%s\" geography(%s%s), CONSTRAINT \"%s_pk\" PRIMARY KEY (%s) )",
418
osCreateTable.c_str(), pszFIDColumnName, pszGFldName, pszGeometryType, nDimension == 2 ? "" : "Z", pszTableName, pszFIDColumnName );
423
"%s ( %s SERIAL, CONSTRAINT \"%s_pk\" PRIMARY KEY (%s) )",
424
osCreateTable.c_str(), pszFIDColumnName, pszTableName, pszFIDColumnName );
430
/* -------------------------------------------------------------------- */
431
/* Eventually we should be adding this table to a table of */
432
/* "geometric layers", capturing the WKT projection, and */
433
/* perhaps some other housekeeping. */
434
/* -------------------------------------------------------------------- */
435
if( bCreateTable && bHavePostGIS && !EQUAL(pszGeomType, "geography"))
438
"SELECT AddGeometryColumn('%s',%s,'%s',%d,'%s',%d)",
439
pszSchemaName, pszEscapedTableNameSingleQuote, pszGFldName,
440
nSRSId, pszGeometryType, nDimension );
444
if( bCreateTable && bHavePostGIS )
446
/* -------------------------------------------------------------------- */
447
/* Create the spatial index. */
449
/* We're doing this before we add geometry and record to the table */
450
/* so this may not be exactly the best way to do it. */
451
/* -------------------------------------------------------------------- */
452
const char *pszSI = CSLFetchNameValue( papszOptions, "SPATIAL_INDEX" );
453
if( pszSI == NULL || CSLTestBoolean(pszSI) )
455
osCommand.Printf("CREATE INDEX \"%s_geom_idx\" "
457
"USING GIST (\"%s\")",
458
pszTableName, pszSchemaName, pszTableName, pszGFldName);
464
/* -------------------------------------------------------------------- */
465
/* Create the layer object. */
466
/* -------------------------------------------------------------------- */
467
OGRPGDumpLayer *poLayer;
469
int bWriteAsHex = !CSLFetchBoolean(papszOptions,"WRITE_EWKT_GEOM",FALSE);
471
poLayer = new OGRPGDumpLayer( this, pszSchemaName, pszTableName, pszGFldName,
472
pszFIDColumnName, nDimension, nSRSId, bWriteAsHex, bCreateTable );
473
poLayer->SetLaunderFlag( CSLFetchBoolean(papszOptions,"LAUNDER",TRUE) );
474
poLayer->SetPrecisionFlag( CSLFetchBoolean(papszOptions,"PRECISION",TRUE));
476
/* -------------------------------------------------------------------- */
477
/* Add layer to data source layer list. */
478
/* -------------------------------------------------------------------- */
479
papoLayers = (OGRPGDumpLayer **)
480
CPLRealloc( papoLayers, sizeof(OGRPGDumpLayer *) * (nLayers+1) );
482
papoLayers[nLayers++] = poLayer;
484
CPLFree( pszTableName );
485
CPLFree( pszSchemaName );
490
/************************************************************************/
491
/* TestCapability() */
492
/************************************************************************/
494
int OGRPGDumpDataSource::TestCapability( const char * pszCap )
497
if( EQUAL(pszCap,ODsCCreateLayer) )
503
/************************************************************************/
505
/************************************************************************/
507
OGRLayer *OGRPGDumpDataSource::GetLayer( int iLayer )
510
if( iLayer < 0 || iLayer >= nLayers )
513
return papoLayers[iLayer];
516
/************************************************************************/
518
/************************************************************************/
520
void OGRPGDumpDataSource::Log(const char* pszStr, int bAddSemiColumn)
527
fp = VSIFOpenL(pszName, "wb");
530
CPLError(CE_Failure, CPLE_FileIO, "Cannot create %s", pszName);
536
VSIFPrintfL(fp, "%s;%s", pszStr, pszEOL);
538
VSIFPrintfL(fp, "%s%s", pszStr, pszEOL);
541
/************************************************************************/
543
/************************************************************************/
544
void OGRPGDumpDataSource::StartCopy( OGRPGDumpLayer *poPGLayer )
547
poLayerInCopyMode = poPGLayer;
550
/************************************************************************/
552
/************************************************************************/
553
OGRErr OGRPGDumpDataSource::EndCopy( )
555
if( poLayerInCopyMode != NULL )
557
OGRErr result = poLayerInCopyMode->EndCopy();
558
poLayerInCopyMode = NULL;