1 /******************************************************************************
2 *
3 * Project: OpenGIS Simple Features Reference Implementation
4 * Purpose: Implements OGRPGDumpLayer 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 "ogr_pgdump.h"
30 #include "cpl_conv.h"
31 #include "cpl_string.h"
32 #include "ogr_p.h"
33
34 CPL_CVSID("$Id: ogrpgdumplayer.cpp 379fc8667418dc54e864d828ea35be513e69abc9 2021-04-03 21:58:21 +0200 Even Rouault $")
35 //
36 static CPLString OGRPGDumpEscapeStringList(
37 char** papszItems, bool bForInsertOrUpdate,
38 OGRPGCommonEscapeStringCbk pfnEscapeString,
39 void* userdata );
40
OGRPGDumpEscapeStringWithUserData(CPL_UNUSED void * user_data,const char * pszStrValue,int nMaxLength,CPL_UNUSED const char * pszLayerName,const char * pszFieldName)41 static CPLString OGRPGDumpEscapeStringWithUserData(
42 CPL_UNUSED void* user_data,
43 const char* pszStrValue, int nMaxLength,
44 CPL_UNUSED const char* pszLayerName,
45 const char* pszFieldName )
46 {
47 return OGRPGDumpEscapeString(pszStrValue, nMaxLength, pszFieldName);
48 }
49
50 /************************************************************************/
51 /* OGRPGDumpLayer() */
52 /************************************************************************/
53
OGRPGDumpLayer(OGRPGDumpDataSource * poDSIn,const char * pszSchemaNameIn,const char * pszTableName,const char * pszFIDColumnIn,int bWriteAsHexIn,int bCreateTableIn)54 OGRPGDumpLayer::OGRPGDumpLayer( OGRPGDumpDataSource* poDSIn,
55 const char* pszSchemaNameIn,
56 const char* pszTableName,
57 const char *pszFIDColumnIn,
58 int bWriteAsHexIn,
59 int bCreateTableIn ) :
60 pszSchemaName(CPLStrdup(pszSchemaNameIn)),
61 pszSqlTableName(CPLStrdup(
62 CPLString().Printf("%s.%s",
63 OGRPGDumpEscapeColumnName(pszSchemaName).c_str(),
64 OGRPGDumpEscapeColumnName(pszTableName).c_str()))),
65 pszFIDColumn(CPLStrdup(pszFIDColumnIn)),
66 poFeatureDefn(new OGRFeatureDefn(pszTableName)),
67 poDS(poDSIn),
68 bWriteAsHex(CPL_TO_BOOL(bWriteAsHexIn)),
69 bCreateTable(bCreateTableIn)
70 {
71 SetDescription( poFeatureDefn->GetName() );
72 poFeatureDefn->SetGeomType(wkbNone);
73 poFeatureDefn->Reference();
74 }
75
76 /************************************************************************/
77 /* ~OGRPGDumpLayer() */
78 /************************************************************************/
79
~OGRPGDumpLayer()80 OGRPGDumpLayer::~OGRPGDumpLayer()
81 {
82 EndCopy();
83 UpdateSequenceIfNeeded();
84
85 poFeatureDefn->Release();
86 CPLFree(pszSchemaName);
87 CPLFree(pszSqlTableName);
88 CPLFree(pszFIDColumn);
89 CSLDestroy(papszOverrideColumnTypes);
90 }
91
92 /************************************************************************/
93 /* GetNextFeature() */
94 /************************************************************************/
95
GetNextFeature()96 OGRFeature *OGRPGDumpLayer::GetNextFeature()
97 {
98 CPLError(CE_Failure, CPLE_NotSupported, "PGDump driver is write only");
99 return nullptr;
100 }
101
102 /************************************************************************/
103 /* GetNextFeature() */
104 /************************************************************************/
105
TestCapability(const char * pszCap)106 int OGRPGDumpLayer::TestCapability( const char * pszCap )
107 {
108 if( EQUAL(pszCap,OLCSequentialWrite) ||
109 EQUAL(pszCap,OLCCreateField) ||
110 EQUAL(pszCap,OLCCreateGeomField) ||
111 EQUAL(pszCap,OLCCurveGeometries) ||
112 EQUAL(pszCap,OLCMeasuredGeometries) )
113 return TRUE;
114 else
115 return FALSE;
116 }
117
118 /************************************************************************/
119 /* GetNextFeature() */
120 /************************************************************************/
121
ICreateFeature(OGRFeature * poFeature)122 OGRErr OGRPGDumpLayer::ICreateFeature( OGRFeature *poFeature )
123 {
124 if( nullptr == poFeature )
125 {
126 CPLError( CE_Failure, CPLE_AppDefined,
127 "NULL pointer to OGRFeature passed to CreateFeature()." );
128 return OGRERR_FAILURE;
129 }
130
131 /* In case the FID column has also been created as a regular field */
132 if( iFIDAsRegularColumnIndex >= 0 )
133 {
134 if( poFeature->GetFID() == OGRNullFID )
135 {
136 if( poFeature->IsFieldSetAndNotNull( iFIDAsRegularColumnIndex ) )
137 {
138 poFeature->SetFID(
139 poFeature->GetFieldAsInteger64(iFIDAsRegularColumnIndex));
140 }
141 }
142 else
143 {
144 if( !poFeature->IsFieldSetAndNotNull( iFIDAsRegularColumnIndex ) ||
145 poFeature->GetFieldAsInteger64(iFIDAsRegularColumnIndex) != poFeature->GetFID() )
146 {
147 CPLError(CE_Failure, CPLE_AppDefined,
148 "Inconsistent values of FID and field of same name");
149 return OGRERR_FAILURE;
150 }
151 }
152 }
153
154 if( !poFeature->Validate((OGR_F_VAL_ALL & ~OGR_F_VAL_WIDTH) |
155 OGR_F_VAL_ALLOW_DIFFERENT_GEOM_DIM, TRUE ) )
156 return OGRERR_FAILURE;
157
158 // We avoid testing the config option too often.
159 if( bUseCopy == USE_COPY_UNSET )
160 bUseCopy = CPLTestBool( CPLGetConfigOption( "PG_USE_COPY", "NO") );
161
162 OGRErr eErr;
163 if( !bUseCopy )
164 {
165 eErr = CreateFeatureViaInsert( poFeature );
166 }
167 else
168 {
169 // If there's a unset field with a default value, then we must use a
170 // specific INSERT statement to avoid unset fields to be bound to NULL.
171 bool bHasDefaultValue = false;
172 const int nFieldCount = poFeatureDefn->GetFieldCount();
173 for( int iField = 0; iField < nFieldCount; iField++ )
174 {
175 if( !poFeature->IsFieldSetAndNotNull( iField ) &&
176 poFeature->GetFieldDefnRef(iField)->GetDefault() != nullptr )
177 {
178 bHasDefaultValue = true;
179 break;
180 }
181 }
182 if( bHasDefaultValue )
183 {
184 EndCopy();
185 eErr = CreateFeatureViaInsert( poFeature );
186 }
187 else
188 {
189 const bool bFIDSet = poFeature->GetFID() != OGRNullFID;
190 if( bCopyActive && bFIDSet != bCopyStatementWithFID )
191 {
192 EndCopy();
193 eErr = CreateFeatureViaInsert( poFeature );
194 }
195 else
196 {
197 if ( !bCopyActive )
198 {
199 // This is a heuristics. If the first feature to be copied
200 // has a FID set (and that a FID column has been
201 // identified), then we will try to copy FID values from
202 // features. Otherwise, we will not do and assume that the
203 // FID column is an autoincremented column.
204 StartCopy(bFIDSet);
205 bCopyStatementWithFID = bFIDSet;
206 bNeedToUpdateSequence = bFIDSet;
207 }
208
209 eErr = CreateFeatureViaCopy( poFeature );
210 if( bFIDSet )
211 bAutoFIDOnCreateViaCopy = false;
212 if( eErr == OGRERR_NONE && bAutoFIDOnCreateViaCopy )
213 {
214 poFeature->SetFID( ++iNextShapeId );
215 }
216 }
217 }
218 }
219
220 if( eErr == OGRERR_NONE && iFIDAsRegularColumnIndex >= 0 )
221 {
222 poFeature->SetField(iFIDAsRegularColumnIndex, poFeature->GetFID());
223 }
224 return eErr;
225 }
226
227 /************************************************************************/
228 /* CreateFeatureViaInsert() */
229 /************************************************************************/
230
CreateFeatureViaInsert(OGRFeature * poFeature)231 OGRErr OGRPGDumpLayer::CreateFeatureViaInsert( OGRFeature *poFeature )
232
233 {
234 OGRErr eErr = OGRERR_FAILURE;
235
236 if( nullptr == poFeature )
237 {
238 CPLError( CE_Failure, CPLE_AppDefined,
239 "NULL pointer to OGRFeature passed to CreateFeatureViaInsert()." );
240 return eErr;
241 }
242
243 /* -------------------------------------------------------------------- */
244 /* Form the INSERT command. */
245 /* -------------------------------------------------------------------- */
246 CPLString osCommand;
247 osCommand.Printf( "INSERT INTO %s (", pszSqlTableName );
248
249 bool bNeedComma = false;
250
251 for( int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++ )
252 {
253 OGRGeometry *poGeom = poFeature->GetGeomFieldRef(i);
254 if( poGeom != nullptr )
255 {
256 if( bNeedComma )
257 osCommand += ", ";
258
259 OGRGeomFieldDefn* poGFldDefn = poFeature->GetGeomFieldDefnRef(i);
260 osCommand = osCommand + OGRPGDumpEscapeColumnName(poGFldDefn->GetNameRef()) + " ";
261 bNeedComma = true;
262 }
263 }
264
265 if( poFeature->GetFID() != OGRNullFID && pszFIDColumn != nullptr )
266 {
267 bNeedToUpdateSequence = true;
268 if( bNeedComma )
269 osCommand += ", ";
270
271 osCommand = osCommand + OGRPGDumpEscapeColumnName(pszFIDColumn) + " ";
272 bNeedComma = true;
273 }
274 else
275 {
276 UpdateSequenceIfNeeded();
277 }
278
279 for( int i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
280 {
281 if( i == iFIDAsRegularColumnIndex )
282 continue;
283 if( !poFeature->IsFieldSet( i ) )
284 continue;
285
286 if( !bNeedComma )
287 bNeedComma = true;
288 else
289 osCommand += ", ";
290
291 osCommand = osCommand
292 + OGRPGDumpEscapeColumnName(poFeatureDefn->GetFieldDefn(i)->GetNameRef());
293 }
294
295 const bool bEmptyInsert = !bNeedComma;
296
297 osCommand += ") VALUES (";
298
299 /* Set the geometry */
300 bNeedComma = false;
301 for( int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++ )
302 {
303 OGRGeometry *poGeom = poFeature->GetGeomFieldRef(i);
304 if( poGeom != nullptr )
305 {
306 char *pszWKT = nullptr;
307
308 OGRPGDumpGeomFieldDefn* poGFldDefn =
309 (OGRPGDumpGeomFieldDefn*) poFeature->GetGeomFieldDefnRef(i);
310
311 poGeom->closeRings();
312 poGeom->set3D(poGFldDefn->GeometryTypeFlags & OGRGeometry::OGR_G_3D);
313 poGeom->setMeasured(poGFldDefn->GeometryTypeFlags & OGRGeometry::OGR_G_MEASURED);
314
315 if( bNeedComma )
316 osCommand += ", ";
317
318 if( bWriteAsHex )
319 {
320 char* pszHex = OGRGeometryToHexEWKB( poGeom, poGFldDefn->nSRSId,
321 nPostGISMajor,
322 nPostGISMinor );
323 osCommand += "'";
324 if (pszHex)
325 osCommand += pszHex;
326 osCommand += "'";
327 CPLFree(pszHex);
328 }
329 else
330 {
331 poGeom->exportToWkt( &pszWKT, wkbVariantIso );
332
333 if( pszWKT != nullptr )
334 {
335 osCommand +=
336 CPLString().Printf(
337 "GeomFromEWKT('SRID=%d;%s'::TEXT) ", poGFldDefn->nSRSId, pszWKT );
338 CPLFree( pszWKT );
339 }
340 else
341 osCommand += "''";
342 }
343
344 bNeedComma = true;
345 }
346 }
347
348 /* Set the FID */
349 if( poFeature->GetFID() != OGRNullFID && pszFIDColumn != nullptr )
350 {
351 if( bNeedComma )
352 osCommand += ", ";
353 osCommand += CPLString().Printf( CPL_FRMT_GIB, poFeature->GetFID() );
354 bNeedComma = true;
355 }
356
357 for( int i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
358 {
359 if( i == iFIDAsRegularColumnIndex )
360 continue;
361 if( !poFeature->IsFieldSet( i ) )
362 continue;
363
364 if( bNeedComma )
365 osCommand += ", ";
366 else
367 bNeedComma = true;
368
369 OGRPGCommonAppendFieldValue(osCommand, poFeature, i,
370 OGRPGDumpEscapeStringWithUserData, nullptr);
371 }
372
373 osCommand += ")";
374
375 if( bEmptyInsert )
376 osCommand.Printf( "INSERT INTO %s DEFAULT VALUES", pszSqlTableName );
377
378 /* -------------------------------------------------------------------- */
379 /* Execute the insert. */
380 /* -------------------------------------------------------------------- */
381 poDS->Log(osCommand);
382
383 if( poFeature->GetFID() == OGRNullFID )
384 poFeature->SetFID( ++iNextShapeId );
385
386 return OGRERR_NONE;
387 }
388
389 /************************************************************************/
390 /* CreateFeatureViaCopy() */
391 /************************************************************************/
392
CreateFeatureViaCopy(OGRFeature * poFeature)393 OGRErr OGRPGDumpLayer::CreateFeatureViaCopy( OGRFeature *poFeature )
394 {
395 CPLString osCommand;
396
397 /* First process geometry */
398 for( int i = 0; i < poFeature->GetGeomFieldCount(); i++ )
399 {
400 OGRGeometry *poGeometry = poFeature->GetGeomFieldRef(i);
401 char *pszGeom = nullptr;
402 if ( nullptr != poGeometry /* && (bHasWkb || bHasPostGISGeometry || bHasPostGISGeography) */)
403 {
404 OGRPGDumpGeomFieldDefn* poGFldDefn =
405 (OGRPGDumpGeomFieldDefn*) poFeature->GetGeomFieldDefnRef(i);
406
407 poGeometry->closeRings();
408 poGeometry->set3D(poGFldDefn->GeometryTypeFlags & OGRGeometry::OGR_G_3D);
409 poGeometry->setMeasured(poGFldDefn->GeometryTypeFlags & OGRGeometry::OGR_G_MEASURED);
410
411 //CheckGeomTypeCompatibility(poGeometry);
412
413 /*if (bHasWkb)
414 pszGeom = GeometryToBYTEA( poGeometry );
415 else*/
416 pszGeom = OGRGeometryToHexEWKB( poGeometry, poGFldDefn->nSRSId,
417 nPostGISMajor,
418 nPostGISMinor );
419 }
420
421 if (!osCommand.empty())
422 osCommand += "\t";
423 if ( pszGeom )
424 {
425 osCommand += pszGeom;
426 CPLFree( pszGeom );
427 }
428 else
429 {
430 osCommand += "\\N";
431 }
432 }
433
434 OGRPGCommonAppendCopyFieldsExceptGeom(osCommand,
435 poFeature,
436 pszFIDColumn,
437 bFIDColumnInCopyFields,
438 std::vector<bool>(poFeatureDefn->GetFieldCount(), true),
439 OGRPGDumpEscapeStringWithUserData,
440 nullptr);
441
442 /* Add end of line marker */
443 // osCommand += "\n";
444
445 /* ------------------------------------------------------------ */
446 /* Execute the copy. */
447 /* ------------------------------------------------------------ */
448
449 OGRErr result = OGRERR_NONE;
450
451 poDS->Log(osCommand, false);
452
453 return result;
454 }
455
456 /************************************************************************/
457 /* OGRPGCommonAppendCopyFieldsExceptGeom() */
458 /************************************************************************/
459
OGRPGCommonAppendCopyFieldsExceptGeom(CPLString & osCommand,OGRFeature * poFeature,const char * pszFIDColumn,bool bFIDColumnInCopyFields,const std::vector<bool> & abFieldsToInclude,OGRPGCommonEscapeStringCbk pfnEscapeString,void * userdata)460 void OGRPGCommonAppendCopyFieldsExceptGeom(
461 CPLString& osCommand,
462 OGRFeature* poFeature,
463 const char* pszFIDColumn,
464 bool bFIDColumnInCopyFields,
465 const std::vector<bool>& abFieldsToInclude,
466 OGRPGCommonEscapeStringCbk pfnEscapeString,
467 void* userdata )
468 {
469 OGRFeatureDefn* poFeatureDefn = poFeature->GetDefnRef();
470
471 /* Next process the field id column */
472 int nFIDIndex = -1;
473 if( bFIDColumnInCopyFields )
474 {
475 if (!osCommand.empty())
476 osCommand += "\t";
477
478 nFIDIndex = poFeatureDefn->GetFieldIndex( pszFIDColumn );
479
480 /* Set the FID */
481 if( poFeature->GetFID() != OGRNullFID )
482 {
483 osCommand += CPLString().Printf( CPL_FRMT_GIB, poFeature->GetFID());
484 }
485 else
486 {
487 osCommand += "\\N" ;
488 }
489 }
490
491 /* Now process the remaining fields */
492
493 int nFieldCount = poFeatureDefn->GetFieldCount();
494 bool bAddTab = !osCommand.empty();
495
496 CPLAssert( nFieldCount == static_cast<int>(abFieldsToInclude.size()) );
497
498 for( int i = 0; i < nFieldCount; i++ )
499 {
500 if (i == nFIDIndex)
501 continue;
502 if( !abFieldsToInclude[i] )
503 continue;
504
505 const char *pszStrValue = poFeature->GetFieldAsString(i);
506 char *pszNeedToFree = nullptr;
507
508 if( bAddTab )
509 osCommand += "\t";
510 bAddTab = true;
511
512 if( !poFeature->IsFieldSetAndNotNull( i ) )
513 {
514 osCommand += "\\N" ;
515
516 continue;
517 }
518
519 const int nOGRFieldType = poFeatureDefn->GetFieldDefn(i)->GetType();
520
521 // We need special formatting for integer list values.
522 if( nOGRFieldType == OFTIntegerList )
523 {
524 int nCount, nOff = 0;
525 const int *panItems = poFeature->GetFieldAsIntegerList(i,&nCount);
526
527 const size_t nLen = nCount * 13 + 10;
528 pszNeedToFree = (char *) CPLMalloc(nLen);
529 strcpy( pszNeedToFree, "{" );
530 for( int j = 0; j < nCount; j++ )
531 {
532 if( j != 0 )
533 strcat( pszNeedToFree+nOff, "," );
534
535 nOff += static_cast<int>(strlen(pszNeedToFree+nOff));
536 snprintf( pszNeedToFree+nOff, nLen-nOff, "%d", panItems[j] );
537 }
538 strcat( pszNeedToFree+nOff, "}" );
539 pszStrValue = pszNeedToFree;
540 }
541
542 else if( nOGRFieldType == OFTInteger64List )
543 {
544 int nCount, nOff = 0;
545 const GIntBig *panItems = poFeature->GetFieldAsInteger64List(i,&nCount);
546
547 const size_t nLen = nCount * 26 + 10;
548 pszNeedToFree = (char *) CPLMalloc(nLen);
549 strcpy( pszNeedToFree, "{" );
550 for( int j = 0; j < nCount; j++ )
551 {
552 if( j != 0 )
553 strcat( pszNeedToFree+nOff, "," );
554
555 nOff += static_cast<int>(strlen(pszNeedToFree+nOff));
556 snprintf( pszNeedToFree+nOff, nLen-nOff, CPL_FRMT_GIB, panItems[j] );
557 }
558 strcat( pszNeedToFree+nOff, "}" );
559 pszStrValue = pszNeedToFree;
560 }
561
562 // We need special formatting for real list values.
563 else if( nOGRFieldType == OFTRealList )
564 {
565 int nOff = 0;
566 int nCount = 0;
567 const double *padfItems =
568 poFeature->GetFieldAsDoubleList(i,&nCount);
569
570 const size_t nLen = nCount * 40 + 10;
571 pszNeedToFree = (char *) CPLMalloc(nLen);
572 strcpy( pszNeedToFree, "{" );
573 for( int j = 0; j < nCount; j++ )
574 {
575 if( j != 0 )
576 strcat( pszNeedToFree+nOff, "," );
577
578 nOff += static_cast<int>(strlen(pszNeedToFree+nOff));
579 //Check for special values. They need to be quoted.
580 if( CPLIsNan(padfItems[j]) )
581 snprintf( pszNeedToFree+nOff, nLen-nOff, "NaN" );
582 else if( CPLIsInf(padfItems[j]) )
583 snprintf( pszNeedToFree+nOff, nLen-nOff, (padfItems[j] > 0) ? "Infinity" : "-Infinity" );
584 else
585 CPLsnprintf( pszNeedToFree+nOff, nLen-nOff, "%.16g", padfItems[j] );
586 }
587 strcat( pszNeedToFree+nOff, "}" );
588 pszStrValue = pszNeedToFree;
589 }
590
591 // We need special formatting for string list values.
592 else if( nOGRFieldType == OFTStringList )
593 {
594 CPLString osStr;
595 char **papszItems = poFeature->GetFieldAsStringList(i);
596
597 pszStrValue = pszNeedToFree = CPLStrdup(
598 OGRPGDumpEscapeStringList(papszItems, false,
599 pfnEscapeString, userdata));
600 }
601
602 // Binary formatting
603 else if( nOGRFieldType == OFTBinary )
604 {
605 int nLen = 0;
606 GByte* pabyData = poFeature->GetFieldAsBinary( i, &nLen );
607 char* pszBytea = OGRPGDumpLayer::GByteArrayToBYTEA( pabyData, nLen);
608
609 pszStrValue = pszNeedToFree = pszBytea;
610 }
611
612 else if( nOGRFieldType == OFTReal )
613 {
614 //Check for special values. They need to be quoted.
615 double dfVal = poFeature->GetFieldAsDouble(i);
616 if( CPLIsNan(dfVal) )
617 pszStrValue = "NaN";
618 else if( CPLIsInf(dfVal) )
619 pszStrValue = (dfVal > 0) ? "Infinity" : "-Infinity";
620 }
621
622 if( nOGRFieldType != OFTIntegerList &&
623 nOGRFieldType != OFTInteger64List &&
624 nOGRFieldType != OFTRealList &&
625 nOGRFieldType != OFTInteger &&
626 nOGRFieldType != OFTInteger64 &&
627 nOGRFieldType != OFTReal &&
628 nOGRFieldType != OFTBinary )
629 {
630 int iUTFChar = 0;
631 const int nMaxWidth = poFeatureDefn->GetFieldDefn(i)->GetWidth();
632
633 for( int iChar = 0; pszStrValue[iChar] != '\0'; iChar++ )
634 {
635 //count of utf chars
636 if (nOGRFieldType != OFTStringList && (pszStrValue[iChar] & 0xc0) != 0x80)
637 {
638 if( nMaxWidth > 0 && iUTFChar == nMaxWidth )
639 {
640 CPLDebug( "PG",
641 "Truncated %s field value, it was too long.",
642 poFeatureDefn->GetFieldDefn(i)->GetNameRef() );
643 break;
644 }
645 iUTFChar++;
646 }
647
648 /* Escape embedded \, \t, \n, \r since they will cause COPY
649 to misinterpret a line of text and thus abort */
650 if( pszStrValue[iChar] == '\\' ||
651 pszStrValue[iChar] == '\t' ||
652 pszStrValue[iChar] == '\r' ||
653 pszStrValue[iChar] == '\n' )
654 {
655 osCommand += '\\';
656 }
657
658 osCommand += pszStrValue[iChar];
659 }
660 }
661 else
662 {
663 osCommand += pszStrValue;
664 }
665
666 if( pszNeedToFree )
667 CPLFree( pszNeedToFree );
668 }
669 }
670
671 /************************************************************************/
672 /* StartCopy() */
673 /************************************************************************/
674
StartCopy(int bSetFID)675 OGRErr OGRPGDumpLayer::StartCopy( int bSetFID )
676
677 {
678 /* Tell the datasource we are now planning to copy data */
679 poDS->StartCopy( this );
680
681 CPLString osFields = BuildCopyFields(bSetFID);
682
683 size_t size = osFields.size() + strlen(pszSqlTableName) + 100;
684 char *pszCommand = (char *) CPLMalloc(size);
685
686 snprintf( pszCommand, size,
687 "COPY %s (%s) FROM STDIN",
688 pszSqlTableName, osFields.c_str() );
689
690 poDS->Log(pszCommand);
691 bCopyActive = true;
692
693 CPLFree( pszCommand );
694
695 return OGRERR_NONE;
696 }
697
698 /************************************************************************/
699 /* EndCopy() */
700 /************************************************************************/
701
EndCopy()702 OGRErr OGRPGDumpLayer::EndCopy()
703
704 {
705 if( !bCopyActive )
706 return OGRERR_NONE;
707
708 bCopyActive = false;
709
710 poDS->Log("\\.", false);
711 poDS->Log("END");
712
713 bUseCopy = USE_COPY_UNSET;
714
715 UpdateSequenceIfNeeded();
716
717 return OGRERR_NONE;
718 }
719
720 /************************************************************************/
721 /* UpdateSequenceIfNeeded() */
722 /************************************************************************/
723
UpdateSequenceIfNeeded()724 void OGRPGDumpLayer::UpdateSequenceIfNeeded()
725 {
726 if( bNeedToUpdateSequence && pszFIDColumn != nullptr )
727 {
728 CPLString osCommand;
729 osCommand.Printf(
730 "SELECT setval(pg_get_serial_sequence(%s, %s), MAX(%s)) FROM %s",
731 OGRPGDumpEscapeString(pszSqlTableName).c_str(),
732 OGRPGDumpEscapeString(pszFIDColumn).c_str(),
733 OGRPGDumpEscapeColumnName(pszFIDColumn).c_str(),
734 pszSqlTableName);
735 poDS->Log(osCommand);
736 bNeedToUpdateSequence = false;
737 }
738 }
739
740 /************************************************************************/
741 /* BuildCopyFields() */
742 /************************************************************************/
743
BuildCopyFields(int bSetFID)744 CPLString OGRPGDumpLayer::BuildCopyFields( int bSetFID )
745 {
746 CPLString osFieldList;
747
748 for( int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++ )
749 {
750 if( !osFieldList.empty() )
751 osFieldList += ", ";
752
753 OGRGeomFieldDefn* poGFldDefn = poFeatureDefn->GetGeomFieldDefn(i);
754
755 osFieldList += OGRPGDumpEscapeColumnName(poGFldDefn->GetNameRef());
756 }
757
758 int nFIDIndex = -1;
759 bFIDColumnInCopyFields = pszFIDColumn != nullptr && bSetFID;
760 if( bFIDColumnInCopyFields )
761 {
762 if( !osFieldList.empty() )
763 osFieldList += ", ";
764
765 nFIDIndex = poFeatureDefn->GetFieldIndex( pszFIDColumn );
766
767 osFieldList += OGRPGDumpEscapeColumnName(pszFIDColumn);
768 }
769
770 for( int i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
771 {
772 if (i == nFIDIndex)
773 continue;
774
775 const char *pszName = poFeatureDefn->GetFieldDefn(i)->GetNameRef();
776
777 if( !osFieldList.empty() )
778 osFieldList += ", ";
779
780 osFieldList += OGRPGDumpEscapeColumnName(pszName);
781 }
782
783 return osFieldList;
784 }
785
786 /************************************************************************/
787 /* OGRPGDumpEscapeColumnName( ) */
788 /************************************************************************/
789
OGRPGDumpEscapeColumnName(const char * pszColumnName)790 CPLString OGRPGDumpEscapeColumnName(const char* pszColumnName)
791 {
792 CPLString osStr = "\"";
793
794 char ch = '\0';
795 for( int i = 0; (ch = pszColumnName[i]) != '\0'; i++ )
796 {
797 if (ch == '"')
798 osStr.append(1, ch);
799 osStr.append(1, ch);
800 }
801
802 osStr += "\"";
803
804 return osStr;
805 }
806
807 /************************************************************************/
808 /* EscapeString( ) */
809 /************************************************************************/
810
OGRPGDumpEscapeString(const char * pszStrValue,int nMaxLength,const char * pszFieldName)811 CPLString OGRPGDumpEscapeString( const char* pszStrValue, int nMaxLength,
812 const char* pszFieldName )
813 {
814 CPLString osCommand;
815
816 /* We need to quote and escape string fields. */
817 osCommand += "'";
818
819 int nSrcLen = static_cast<int>(strlen(pszStrValue));
820 const int nSrcLenUTF = CPLStrlenUTF8(pszStrValue);
821
822 if (nMaxLength > 0 && nSrcLenUTF > nMaxLength)
823 {
824 CPLDebug( "PG",
825 "Truncated %s field value, it was too long.",
826 pszFieldName );
827
828 int iUTF8Char = 0;
829 for(int iChar = 0; iChar < nSrcLen; iChar++ )
830 {
831 if( (((unsigned char *) pszStrValue)[iChar] & 0xc0) != 0x80 )
832 {
833 if( iUTF8Char == nMaxLength )
834 {
835 nSrcLen = iChar;
836 break;
837 }
838 iUTF8Char ++;
839 }
840 }
841 }
842
843 char* pszDestStr = (char*)CPLMalloc(2 * nSrcLen + 1);
844
845 /* -------------------------------------------------------------------- */
846 /* PQescapeStringConn was introduced in PostgreSQL security releases */
847 /* 8.1.4, 8.0.8, 7.4.13, 7.3.15 */
848 /* PG_HAS_PQESCAPESTRINGCONN is added by a test in 'configure' */
849 /* so it is not set by default when building OGR for Win32 */
850 /* -------------------------------------------------------------------- */
851 #if defined(PG_HAS_PQESCAPESTRINGCONN)
852 int nError = 0;
853 PQescapeStringConn (hPGConn, pszDestStr, pszStrValue, nSrcLen, &nError);
854 if (nError == 0)
855 osCommand += pszDestStr;
856 else
857 CPLError(CE_Warning, CPLE_AppDefined,
858 "PQescapeString(): %s\n"
859 " input: '%s'\n"
860 " got: '%s'\n",
861 PQerrorMessage( hPGConn ),
862 pszStrValue, pszDestStr );
863 #else
864 //PQescapeString(pszDestStr, pszStrValue, nSrcLen);
865
866 int j = 0; // Used after for.
867 for( int i = 0; i < nSrcLen; i++)
868 {
869 if (pszStrValue[i] == '\'')
870 {
871 pszDestStr[j++] = '\'';
872 pszDestStr[j++] = '\'';
873 }
874 // FIXME: at some point (when we drop PostgreSQL < 9.1 support, remove
875 // the escaping of backslash and remove
876 // 'SET standard_conforming_strings = OFF'
877 // in ICreateLayer().
878 else if (pszStrValue[i] == '\\')
879 {
880 pszDestStr[j++] = '\\';
881 pszDestStr[j++] = '\\';
882 }
883 else
884 {
885 pszDestStr[j++] = pszStrValue[i];
886 }
887 }
888 pszDestStr[j] = 0;
889
890 osCommand += pszDestStr;
891 #endif
892 CPLFree(pszDestStr);
893
894 osCommand += "'";
895
896 return osCommand;
897 }
898
899 /************************************************************************/
900 /* OGRPGDumpEscapeStringList( ) */
901 /************************************************************************/
902
OGRPGDumpEscapeStringList(char ** papszItems,bool bForInsertOrUpdate,OGRPGCommonEscapeStringCbk pfnEscapeString,void * userdata)903 static CPLString OGRPGDumpEscapeStringList(
904 char** papszItems, bool bForInsertOrUpdate,
905 OGRPGCommonEscapeStringCbk pfnEscapeString,
906 void* userdata)
907 {
908 bool bFirstItem = true;
909 CPLString osStr;
910 if (bForInsertOrUpdate)
911 osStr += "ARRAY[";
912 else
913 osStr += "{";
914 while(papszItems && *papszItems)
915 {
916 if( !bFirstItem )
917 {
918 osStr += ',';
919 }
920
921 char* pszStr = *papszItems;
922 if (*pszStr != '\0')
923 {
924 if (bForInsertOrUpdate)
925 osStr += pfnEscapeString(userdata, pszStr, 0, "", "");
926 else
927 {
928 osStr += '"';
929
930 while(*pszStr)
931 {
932 if (*pszStr == '"' )
933 osStr += "\\";
934 osStr += *pszStr;
935 pszStr++;
936 }
937
938 osStr += '"';
939 }
940 }
941 else
942 osStr += "NULL";
943
944 bFirstItem = false;
945
946 papszItems++;
947 }
948 if (bForInsertOrUpdate)
949 {
950 osStr += "]";
951 if( papszItems == nullptr )
952 osStr += "::varchar[]";
953 }
954 else
955 osStr += "}";
956 return osStr;
957 }
958
959 /************************************************************************/
960 /* AppendFieldValue() */
961 /* */
962 /* Used by CreateFeatureViaInsert() and SetFeature() to format a */
963 /* non-empty field value */
964 /************************************************************************/
965
OGRPGCommonAppendFieldValue(CPLString & osCommand,OGRFeature * poFeature,int i,OGRPGCommonEscapeStringCbk pfnEscapeString,void * userdata)966 void OGRPGCommonAppendFieldValue(CPLString& osCommand,
967 OGRFeature* poFeature, int i,
968 OGRPGCommonEscapeStringCbk pfnEscapeString,
969 void* userdata)
970 {
971 if( poFeature->IsFieldNull(i) )
972 {
973 osCommand += "NULL";
974 return;
975 }
976
977 OGRFeatureDefn* poFeatureDefn = poFeature->GetDefnRef();
978 OGRFieldType nOGRFieldType = poFeatureDefn->GetFieldDefn(i)->GetType();
979 OGRFieldSubType eSubType = poFeatureDefn->GetFieldDefn(i)->GetSubType();
980
981 // We need special formatting for integer list values.
982 if( nOGRFieldType == OFTIntegerList )
983 {
984 int nCount, nOff = 0, j;
985 const int *panItems = poFeature->GetFieldAsIntegerList(i,&nCount);
986
987 const size_t nLen = nCount * 13 + 10;
988 char *pszNeedToFree = (char *) CPLMalloc(nLen);
989 strcpy( pszNeedToFree, "'{" );
990 for( j = 0; j < nCount; j++ )
991 {
992 if( j != 0 )
993 strcat( pszNeedToFree+nOff, "," );
994
995 nOff += static_cast<int>(strlen(pszNeedToFree+nOff));
996 snprintf( pszNeedToFree+nOff, nLen-nOff, "%d", panItems[j] );
997 }
998 strcat( pszNeedToFree+nOff, "}'" );
999
1000 osCommand += pszNeedToFree;
1001 CPLFree(pszNeedToFree);
1002
1003 return;
1004 }
1005
1006 else if( nOGRFieldType == OFTInteger64List )
1007 {
1008 int nCount, nOff = 0, j;
1009 const GIntBig *panItems = poFeature->GetFieldAsInteger64List(i,&nCount);
1010
1011 const size_t nLen = nCount * 26 + 10;
1012 char *pszNeedToFree = (char *) CPLMalloc(nLen);
1013 strcpy( pszNeedToFree, "'{" );
1014 for( j = 0; j < nCount; j++ )
1015 {
1016 if( j != 0 )
1017 strcat( pszNeedToFree+nOff, "," );
1018
1019 nOff += static_cast<int>(strlen(pszNeedToFree+nOff));
1020 snprintf( pszNeedToFree+nOff, nLen-nOff, CPL_FRMT_GIB, panItems[j] );
1021 }
1022 strcat( pszNeedToFree+nOff, "}'" );
1023
1024 osCommand += pszNeedToFree;
1025 CPLFree(pszNeedToFree);
1026
1027 return;
1028 }
1029
1030 // We need special formatting for real list values.
1031 else if( nOGRFieldType == OFTRealList )
1032 {
1033 int nCount = 0;
1034 int nOff = 0;
1035 const double *padfItems = poFeature->GetFieldAsDoubleList(i,&nCount);
1036
1037 const size_t nLen = nCount * 40 + 10;
1038 char *pszNeedToFree = (char *) CPLMalloc(nLen);
1039 strcpy( pszNeedToFree, "'{" );
1040 for( int j = 0; j < nCount; j++ )
1041 {
1042 if( j != 0 )
1043 strcat( pszNeedToFree+nOff, "," );
1044
1045 nOff += static_cast<int>(strlen(pszNeedToFree+nOff));
1046 //Check for special values. They need to be quoted.
1047 if( CPLIsNan(padfItems[j]) )
1048 snprintf( pszNeedToFree+nOff, nLen-nOff, "NaN" );
1049 else if( CPLIsInf(padfItems[j]) )
1050 snprintf( pszNeedToFree+nOff, nLen-nOff, (padfItems[j] > 0) ? "Infinity" : "-Infinity" );
1051 else
1052 CPLsnprintf( pszNeedToFree+nOff, nLen-nOff, "%.16g", padfItems[j] );
1053 }
1054 strcat( pszNeedToFree+nOff, "}'" );
1055
1056 osCommand += pszNeedToFree;
1057 CPLFree(pszNeedToFree);
1058
1059 return;
1060 }
1061
1062 // We need special formatting for string list values.
1063 else if( nOGRFieldType == OFTStringList )
1064 {
1065 char **papszItems = poFeature->GetFieldAsStringList(i);
1066
1067 osCommand += OGRPGDumpEscapeStringList(papszItems, true,
1068 pfnEscapeString, userdata);
1069
1070 return;
1071 }
1072
1073 // Binary formatting
1074 else if( nOGRFieldType == OFTBinary )
1075 {
1076 osCommand += "E'";
1077
1078 int nLen = 0;
1079 GByte* pabyData = poFeature->GetFieldAsBinary( i, &nLen );
1080 char* pszBytea = OGRPGDumpLayer::GByteArrayToBYTEA( pabyData, nLen);
1081
1082 osCommand += pszBytea;
1083
1084 CPLFree(pszBytea);
1085 osCommand += "'";
1086
1087 return;
1088 }
1089
1090 // Flag indicating NULL or not-a-date date value
1091 // e.g. 0000-00-00 - there is no year 0
1092 bool bIsDateNull = false;
1093
1094 const char *pszStrValue = poFeature->GetFieldAsString(i);
1095
1096 // Check if date is NULL: 0000-00-00
1097 if( nOGRFieldType == OFTDate )
1098 {
1099 if( STARTS_WITH_CI(pszStrValue, "0000") )
1100 {
1101 pszStrValue = "NULL";
1102 bIsDateNull = true;
1103 }
1104 }
1105 else if ( nOGRFieldType == OFTReal )
1106 {
1107 //Check for special values. They need to be quoted.
1108 double dfVal = poFeature->GetFieldAsDouble(i);
1109 if( CPLIsNan(dfVal) )
1110 pszStrValue = "'NaN'";
1111 else if( CPLIsInf(dfVal) )
1112 pszStrValue = (dfVal > 0) ? "'Infinity'" : "'-Infinity'";
1113 }
1114 else if ( (nOGRFieldType == OFTInteger ||
1115 nOGRFieldType == OFTInteger64) && eSubType == OFSTBoolean )
1116 pszStrValue = poFeature->GetFieldAsInteger(i) ? "'t'" : "'f'";
1117
1118 if( nOGRFieldType != OFTInteger && nOGRFieldType != OFTInteger64 &&
1119 nOGRFieldType != OFTReal && nOGRFieldType != OFTStringList
1120 && !bIsDateNull )
1121 {
1122 osCommand += pfnEscapeString( userdata, pszStrValue,
1123 poFeatureDefn->GetFieldDefn(i)->GetWidth(),
1124 poFeatureDefn->GetName(),
1125 poFeatureDefn->GetFieldDefn(i)->GetNameRef() );
1126 }
1127 else
1128 {
1129 osCommand += pszStrValue;
1130 }
1131 }
1132
1133 /************************************************************************/
1134 /* GByteArrayToBYTEA() */
1135 /************************************************************************/
1136
GByteArrayToBYTEA(const GByte * pabyData,int nLen)1137 char* OGRPGDumpLayer::GByteArrayToBYTEA( const GByte* pabyData, int nLen)
1138 {
1139 const size_t nTextBufLen = nLen * 5 + 1;
1140 char* pszTextBuf;
1141 pszTextBuf = (char *) CPLMalloc(nTextBufLen);
1142
1143 int iDst = 0;
1144
1145 for( int iSrc = 0; iSrc < nLen; iSrc++ )
1146 {
1147 if( pabyData[iSrc] < 40 || pabyData[iSrc] > 126
1148 || pabyData[iSrc] == '\\' )
1149 {
1150 snprintf( pszTextBuf+iDst, nTextBufLen - iDst, "\\\\%03o", pabyData[iSrc] );
1151 iDst += 5;
1152 }
1153 else
1154 pszTextBuf[iDst++] = pabyData[iSrc];
1155 }
1156 pszTextBuf[iDst] = '\0';
1157
1158 return pszTextBuf;
1159 }
1160
1161 /************************************************************************/
1162 /* OGRPGCommonLayerGetType() */
1163 /************************************************************************/
1164
OGRPGCommonLayerGetType(OGRFieldDefn & oField,bool bPreservePrecision,bool bApproxOK)1165 CPLString OGRPGCommonLayerGetType( OGRFieldDefn& oField,
1166 bool bPreservePrecision,
1167 bool bApproxOK )
1168 {
1169 const char* pszFieldType = "";
1170
1171 /* -------------------------------------------------------------------- */
1172 /* Work out the PostgreSQL type. */
1173 /* -------------------------------------------------------------------- */
1174 if( oField.GetType() == OFTInteger )
1175 {
1176 if( oField.GetSubType() == OFSTBoolean )
1177 pszFieldType = "BOOLEAN";
1178 else if( oField.GetSubType() == OFSTInt16 )
1179 pszFieldType = "SMALLINT";
1180 else if( oField.GetWidth() > 0 && bPreservePrecision )
1181 pszFieldType = CPLSPrintf( "NUMERIC(%d,0)", oField.GetWidth() );
1182 else
1183 pszFieldType = "INTEGER";
1184 }
1185 else if( oField.GetType() == OFTInteger64 )
1186 {
1187 if( oField.GetWidth() > 0 && bPreservePrecision )
1188 pszFieldType = CPLSPrintf( "NUMERIC(%d,0)", oField.GetWidth() );
1189 else
1190 pszFieldType = "INT8";
1191 }
1192 else if( oField.GetType() == OFTReal )
1193 {
1194 if( oField.GetSubType() == OFSTFloat32 )
1195 pszFieldType = "REAL";
1196 else if( oField.GetWidth() > 0 &&
1197 oField.GetPrecision() > 0 &&
1198 bPreservePrecision )
1199 pszFieldType = CPLSPrintf( "NUMERIC(%d,%d)",
1200 oField.GetWidth(), oField.GetPrecision() );
1201 else
1202 pszFieldType = "FLOAT8";
1203 }
1204 else if( oField.GetType() == OFTString )
1205 {
1206 if (oField.GetSubType() == OFSTJSON )
1207 pszFieldType = CPLGetConfigOption("OGR_PG_JSON_TYPE", "JSON");
1208 else if (oField.GetSubType() == OFSTUUID )
1209 pszFieldType = CPLGetConfigOption("OGR_PG_UUID_TYPE", "UUID");
1210 else if (oField.GetWidth() > 0 && oField.GetWidth() < 10485760 && bPreservePrecision )
1211 pszFieldType = CPLSPrintf( "VARCHAR(%d)", oField.GetWidth() );
1212 else
1213 pszFieldType = CPLGetConfigOption("OGR_PG_STRING_TYPE", "VARCHAR");
1214 }
1215 else if( oField.GetType() == OFTIntegerList )
1216 {
1217 if( oField.GetSubType() == OFSTBoolean )
1218 pszFieldType = "BOOLEAN[]";
1219 else if( oField.GetSubType() == OFSTInt16 )
1220 pszFieldType = "INT2[]";
1221 else
1222 pszFieldType = "INTEGER[]";
1223 }
1224 else if( oField.GetType() == OFTInteger64List )
1225 {
1226 pszFieldType = "INT8[]";
1227 }
1228 else if( oField.GetType() == OFTRealList )
1229 {
1230 if( oField.GetSubType() == OFSTFloat32 )
1231 pszFieldType = "REAL[]";
1232 else
1233 pszFieldType = "FLOAT8[]";
1234 }
1235 else if( oField.GetType() == OFTStringList )
1236 {
1237 pszFieldType = "varchar[]";
1238 }
1239 else if( oField.GetType() == OFTDate )
1240 {
1241 pszFieldType = "date";
1242 }
1243 else if( oField.GetType() == OFTTime )
1244 {
1245 pszFieldType = "time";
1246 }
1247 else if( oField.GetType() == OFTDateTime )
1248 {
1249 pszFieldType = "timestamp with time zone";
1250 }
1251 else if( oField.GetType() == OFTBinary )
1252 {
1253 pszFieldType = "bytea";
1254 }
1255 else if( bApproxOK )
1256 {
1257 CPLError( CE_Warning, CPLE_NotSupported,
1258 "Can't create field %s with type %s on PostgreSQL layers. Creating as VARCHAR.",
1259 oField.GetNameRef(),
1260 OGRFieldDefn::GetFieldTypeName(oField.GetType()) );
1261 pszFieldType = "VARCHAR";
1262 }
1263 else
1264 {
1265 CPLError( CE_Failure, CPLE_NotSupported,
1266 "Can't create field %s with type %s on PostgreSQL layers.",
1267 oField.GetNameRef(),
1268 OGRFieldDefn::GetFieldTypeName(oField.GetType()) );
1269 }
1270
1271 return pszFieldType;
1272 }
1273
1274 /************************************************************************/
1275 /* OGRPGCommonLayerSetType() */
1276 /************************************************************************/
1277
OGRPGCommonLayerSetType(OGRFieldDefn & oField,const char * pszType,const char * pszFormatType,int nWidth)1278 bool OGRPGCommonLayerSetType( OGRFieldDefn& oField,
1279 const char* pszType,
1280 const char* pszFormatType,
1281 int nWidth )
1282 {
1283 if( EQUAL(pszType,"text") )
1284 {
1285 oField.SetType( OFTString );
1286 }
1287 else if( EQUAL(pszType,"_bpchar") ||
1288 EQUAL(pszType,"_varchar") ||
1289 EQUAL(pszType,"_text"))
1290 {
1291 oField.SetType( OFTStringList );
1292 }
1293 else if( EQUAL(pszType,"bpchar") || EQUAL(pszType,"varchar") )
1294 {
1295 if( nWidth == -1 )
1296 {
1297 if( STARTS_WITH_CI(pszFormatType, "character(") )
1298 nWidth = atoi(pszFormatType+10);
1299 else if( STARTS_WITH_CI(pszFormatType, "character varying(") )
1300 nWidth = atoi(pszFormatType+18);
1301 else
1302 nWidth = 0;
1303 }
1304 oField.SetType( OFTString );
1305 oField.SetWidth( nWidth );
1306 }
1307 else if( EQUAL(pszType,"bool") )
1308 {
1309 oField.SetType( OFTInteger );
1310 oField.SetSubType( OFSTBoolean );
1311 oField.SetWidth( 1 );
1312 }
1313 else if( EQUAL(pszType,"_numeric") )
1314 {
1315 if( EQUAL(pszFormatType, "numeric[]") )
1316 oField.SetType( OFTRealList );
1317 else
1318 {
1319 const char *pszPrecision = strstr(pszFormatType,",");
1320 int nPrecision = 0;
1321
1322 nWidth = atoi(pszFormatType + 8);
1323 if( pszPrecision != nullptr )
1324 nPrecision = atoi(pszPrecision+1);
1325
1326 if( nPrecision == 0 )
1327 {
1328 if( nWidth >= 10 )
1329 oField.SetType( OFTInteger64List );
1330 else
1331 oField.SetType( OFTIntegerList );
1332 }
1333 else
1334 oField.SetType( OFTRealList );
1335
1336 oField.SetWidth( nWidth );
1337 oField.SetPrecision( nPrecision );
1338 }
1339 }
1340 else if( EQUAL(pszType,"numeric") )
1341 {
1342 if( EQUAL(pszFormatType, "numeric") )
1343 oField.SetType( OFTReal );
1344 else
1345 {
1346 const char *pszPrecision = strstr(pszFormatType,",");
1347 int nPrecision = 0;
1348
1349 nWidth = atoi(pszFormatType + 8);
1350 if( pszPrecision != nullptr )
1351 nPrecision = atoi(pszPrecision+1);
1352
1353 if( nPrecision == 0 )
1354 {
1355 if( nWidth >= 10 )
1356 oField.SetType( OFTInteger64 );
1357 else
1358 oField.SetType( OFTInteger );
1359 }
1360 else
1361 oField.SetType( OFTReal );
1362
1363 oField.SetWidth( nWidth );
1364 oField.SetPrecision( nPrecision );
1365 }
1366 }
1367 else if( EQUAL(pszFormatType,"integer[]") )
1368 {
1369 oField.SetType( OFTIntegerList );
1370 }
1371 else if( EQUAL(pszFormatType,"smallint[]") )
1372 {
1373 oField.SetType( OFTIntegerList );
1374 oField.SetSubType( OFSTInt16 );
1375 }
1376 else if( EQUAL(pszFormatType,"boolean[]") )
1377 {
1378 oField.SetType( OFTIntegerList );
1379 oField.SetSubType( OFSTBoolean );
1380 }
1381 else if( EQUAL(pszFormatType, "float[]") ||
1382 EQUAL(pszFormatType, "real[]") )
1383 {
1384 oField.SetType( OFTRealList );
1385 oField.SetSubType( OFSTFloat32 );
1386 }
1387 else if( EQUAL(pszFormatType, "double precision[]") )
1388 {
1389 oField.SetType( OFTRealList );
1390 }
1391 else if( EQUAL(pszType,"int2") )
1392 {
1393 oField.SetType( OFTInteger );
1394 oField.SetSubType( OFSTInt16 );
1395 oField.SetWidth( 5 );
1396 }
1397 else if( EQUAL(pszType,"int8") )
1398 {
1399 oField.SetType( OFTInteger64 );
1400 }
1401 else if( EQUAL(pszFormatType,"bigint[]") )
1402 {
1403 oField.SetType( OFTInteger64List );
1404 }
1405 else if( STARTS_WITH_CI(pszType, "int") )
1406 {
1407 oField.SetType( OFTInteger );
1408 }
1409 else if( EQUAL(pszType,"float4") )
1410 {
1411 oField.SetType( OFTReal );
1412 oField.SetSubType( OFSTFloat32 );
1413 }
1414 else if( STARTS_WITH_CI(pszType, "float") ||
1415 STARTS_WITH_CI(pszType, "double") ||
1416 EQUAL(pszType,"real") )
1417 {
1418 oField.SetType( OFTReal );
1419 }
1420 else if( STARTS_WITH_CI(pszType, "timestamp") )
1421 {
1422 oField.SetType( OFTDateTime );
1423 }
1424 else if( STARTS_WITH_CI(pszType, "date") )
1425 {
1426 oField.SetType( OFTDate );
1427 }
1428 else if( STARTS_WITH_CI(pszType, "time") )
1429 {
1430 oField.SetType( OFTTime );
1431 }
1432 else if( EQUAL(pszType,"bytea") )
1433 {
1434 oField.SetType( OFTBinary );
1435 }
1436 else if( EQUAL(pszType,"json") || EQUAL(pszType, "jsonb") )
1437 {
1438 oField.SetType( OFTString );
1439 oField.SetSubType( OFSTJSON );
1440 }
1441 else if( EQUAL(pszType,"uuid") )
1442 {
1443 oField.SetType( OFTString );
1444 oField.SetSubType( OFSTUUID );
1445 }
1446 else
1447 {
1448 CPLDebug( "PGCommon", "Field %s is of unknown format type %s (type=%s).",
1449 oField.GetNameRef(), pszFormatType, pszType );
1450 return false;
1451 }
1452 return true;
1453 }
1454
1455 /************************************************************************/
1456 /* OGRPGCommonLayerNormalizeDefault() */
1457 /************************************************************************/
1458
OGRPGCommonLayerNormalizeDefault(OGRFieldDefn * poFieldDefn,const char * pszDefault)1459 void OGRPGCommonLayerNormalizeDefault(OGRFieldDefn* poFieldDefn,
1460 const char* pszDefault)
1461 {
1462 if(pszDefault==nullptr)
1463 return;
1464 CPLString osDefault(pszDefault);
1465 size_t nPos = osDefault.find("::character varying");
1466 if( nPos != std::string::npos &&
1467 nPos + strlen("::character varying") == osDefault.size() )
1468 {
1469 osDefault.resize(nPos);
1470 }
1471 else if( (nPos = osDefault.find("::text")) != std::string::npos &&
1472 nPos + strlen("::text") == osDefault.size() )
1473 {
1474 osDefault.resize(nPos);
1475 }
1476 else if( strcmp(osDefault, "now()") == 0 )
1477 osDefault = "CURRENT_TIMESTAMP";
1478 else if( strcmp(osDefault, "('now'::text)::date") == 0 )
1479 osDefault = "CURRENT_DATE";
1480 else if( strcmp(osDefault, "('now'::text)::time with time zone") == 0 )
1481 osDefault = "CURRENT_TIME";
1482 else
1483 {
1484 nPos = osDefault.find("::timestamp with time zone");
1485 if( poFieldDefn->GetType() == OFTDateTime && nPos != std::string::npos )
1486 {
1487 osDefault.resize(nPos);
1488 nPos = osDefault.find("'+");
1489 if( nPos != std::string::npos )
1490 {
1491 osDefault.resize(nPos);
1492 osDefault += "'";
1493 }
1494 int nYear = 0;
1495 int nMonth = 0;
1496 int nDay = 0;
1497 int nHour = 0;
1498 int nMinute = 0;
1499 float fSecond = 0.0f;
1500 if( sscanf(osDefault, "'%d-%d-%d %d:%d:%f'", &nYear, &nMonth, &nDay,
1501 &nHour, &nMinute, &fSecond) == 6 ||
1502 sscanf(osDefault, "'%d-%d-%d %d:%d:%f+00'", &nYear, &nMonth, &nDay,
1503 &nHour, &nMinute, &fSecond) == 6)
1504 {
1505 if( osDefault.find('.') == std::string::npos )
1506 osDefault = CPLSPrintf("'%04d/%02d/%02d %02d:%02d:%02d'",
1507 nYear, nMonth, nDay, nHour, nMinute, (int)(fSecond+0.5));
1508 else
1509 osDefault = CPLSPrintf("'%04d/%02d/%02d %02d:%02d:%06.3f'",
1510 nYear, nMonth, nDay, nHour, nMinute, fSecond);
1511 }
1512 }
1513 }
1514 poFieldDefn->SetDefault(osDefault);
1515 }
1516
1517 /************************************************************************/
1518 /* OGRPGCommonLayerGetPGDefault() */
1519 /************************************************************************/
1520
OGRPGCommonLayerGetPGDefault(OGRFieldDefn * poFieldDefn)1521 CPLString OGRPGCommonLayerGetPGDefault(OGRFieldDefn* poFieldDefn)
1522 {
1523 CPLString osRet = poFieldDefn->GetDefault();
1524 int nYear = 0;
1525 int nMonth = 0;
1526 int nDay = 0;
1527 int nHour = 0;
1528 int nMinute = 0;
1529 float fSecond = 0.0f;
1530 if( sscanf(osRet, "'%d/%d/%d %d:%d:%f'",
1531 &nYear, &nMonth, &nDay,
1532 &nHour, &nMinute, &fSecond) == 6 )
1533 {
1534 osRet.resize(osRet.size()-1);
1535 osRet += "+00'::timestamp with time zone";
1536 }
1537 return osRet;
1538 }
1539
1540 /************************************************************************/
1541 /* GetNextFeature() */
1542 /************************************************************************/
1543
CreateField(OGRFieldDefn * poFieldIn,int bApproxOK)1544 OGRErr OGRPGDumpLayer::CreateField( OGRFieldDefn *poFieldIn,
1545 int bApproxOK )
1546 {
1547 CPLString osFieldType;
1548 OGRFieldDefn oField( poFieldIn );
1549
1550 // Can be set to NO to test ogr2ogr default behavior
1551 const bool bAllowCreationOfFieldWithFIDName =
1552 CPLTestBool(CPLGetConfigOption(
1553 "PGDUMP_DEBUG_ALLOW_CREATION_FIELD_WITH_FID_NAME", "YES"));
1554
1555 if( bAllowCreationOfFieldWithFIDName && pszFIDColumn != nullptr &&
1556 EQUAL( oField.GetNameRef(), pszFIDColumn ) &&
1557 oField.GetType() != OFTInteger &&
1558 oField.GetType() != OFTInteger64 )
1559 {
1560 CPLError(CE_Failure, CPLE_AppDefined, "Wrong field type for %s",
1561 oField.GetNameRef());
1562 return OGRERR_FAILURE;
1563 }
1564
1565 /* -------------------------------------------------------------------- */
1566 /* Do we want to "launder" the column names into Postgres */
1567 /* friendly format? */
1568 /* -------------------------------------------------------------------- */
1569 if( bLaunderColumnNames )
1570 {
1571 char *pszSafeName =
1572 OGRPGCommonLaunderName( oField.GetNameRef(), "PGDump" );
1573
1574 oField.SetName( pszSafeName );
1575 CPLFree( pszSafeName );
1576
1577 if( EQUAL(oField.GetNameRef(),"oid") )
1578 {
1579 CPLError( CE_Warning, CPLE_AppDefined,
1580 "Renaming field 'oid' to 'oid_' to avoid conflict with "
1581 "internal oid field." );
1582 oField.SetName( "oid_" );
1583 }
1584 }
1585
1586 const char* pszOverrideType =
1587 CSLFetchNameValue(papszOverrideColumnTypes, oField.GetNameRef());
1588 if( pszOverrideType != nullptr )
1589 {
1590 osFieldType = pszOverrideType;
1591 }
1592 else
1593 {
1594 osFieldType =
1595 OGRPGCommonLayerGetType(oField, bPreservePrecision,
1596 CPL_TO_BOOL(bApproxOK));
1597 if (osFieldType.empty())
1598 return OGRERR_FAILURE;
1599 }
1600
1601 /* -------------------------------------------------------------------- */
1602 /* Create the new field. */
1603 /* -------------------------------------------------------------------- */
1604 CPLString osCommand;
1605 osCommand.Printf( "ALTER TABLE %s ADD COLUMN %s %s",
1606 pszSqlTableName,
1607 OGRPGDumpEscapeColumnName(oField.GetNameRef()).c_str(),
1608 osFieldType.c_str() );
1609 if( !oField.IsNullable() )
1610 osCommand += " NOT NULL";
1611 if( oField.IsUnique() )
1612 osCommand += " UNIQUE";
1613 if( oField.GetDefault() != nullptr && !oField.IsDefaultDriverSpecific() )
1614 {
1615 osCommand += " DEFAULT ";
1616 osCommand += OGRPGCommonLayerGetPGDefault(&oField);
1617 }
1618
1619 poFeatureDefn->AddFieldDefn( &oField );
1620
1621 if( bAllowCreationOfFieldWithFIDName && pszFIDColumn != nullptr &&
1622 EQUAL( oField.GetNameRef(), pszFIDColumn ) )
1623 {
1624 iFIDAsRegularColumnIndex = poFeatureDefn->GetFieldCount() - 1;
1625 }
1626 else
1627 {
1628 if( bCreateTable )
1629 poDS->Log(osCommand);
1630 }
1631
1632 return OGRERR_NONE;
1633 }
1634
1635 /************************************************************************/
1636 /* CreateGeomField() */
1637 /************************************************************************/
1638
CreateGeomField(OGRGeomFieldDefn * poGeomFieldIn,int)1639 OGRErr OGRPGDumpLayer::CreateGeomField( OGRGeomFieldDefn *poGeomFieldIn,
1640 int /* bApproxOK */ )
1641 {
1642 OGRwkbGeometryType eType = poGeomFieldIn->GetType();
1643 if( eType == wkbNone )
1644 {
1645 CPLError(CE_Failure, CPLE_AppDefined,
1646 "Cannot create geometry field of type wkbNone");
1647 return OGRERR_FAILURE;
1648 }
1649
1650 // Check if GEOMETRY_NAME layer creation option was set, but no initial
1651 // column was created in ICreateLayer()
1652 const CPLString osGeomFieldName =
1653 !m_osFirstGeometryFieldName.empty()
1654 ? m_osFirstGeometryFieldName
1655 : CPLString(poGeomFieldIn->GetNameRef());
1656
1657 m_osFirstGeometryFieldName = ""; // reset for potential next geom columns
1658
1659 OGRGeomFieldDefn oTmpGeomFieldDefn( poGeomFieldIn );
1660 oTmpGeomFieldDefn.SetName(osGeomFieldName);
1661
1662 CPLString osCommand;
1663 OGRPGDumpGeomFieldDefn *poGeomField =
1664 new OGRPGDumpGeomFieldDefn( &oTmpGeomFieldDefn );
1665
1666 /* -------------------------------------------------------------------- */
1667 /* Do we want to "launder" the column names into Postgres */
1668 /* friendly format? */
1669 /* -------------------------------------------------------------------- */
1670 if( bLaunderColumnNames )
1671 {
1672 char *pszSafeName =
1673 OGRPGCommonLaunderName( poGeomField->GetNameRef(), "PGDump" );
1674
1675 poGeomField->SetName( pszSafeName );
1676 CPLFree( pszSafeName );
1677 }
1678
1679 OGRSpatialReference* poSRS = poGeomField->GetSpatialRef();
1680 int nSRSId = nUnknownSRSId;
1681 if( nForcedSRSId != -2 )
1682 nSRSId = nForcedSRSId;
1683 else if( poSRS != nullptr )
1684 {
1685 const char* pszAuthorityName = poSRS->GetAuthorityName(nullptr);
1686 if( pszAuthorityName != nullptr && EQUAL( pszAuthorityName, "EPSG" ) )
1687 {
1688 /* Assume the EPSG Id is the SRS ID. Might be a wrong guess ! */
1689 nSRSId = atoi( poSRS->GetAuthorityCode(nullptr) );
1690 }
1691 else
1692 {
1693 const char* pszGeogCSName = poSRS->GetAttrValue("GEOGCS");
1694 if (pszGeogCSName != nullptr && EQUAL(pszGeogCSName, "GCS_WGS_1984"))
1695 nSRSId = 4326;
1696 }
1697 }
1698
1699 poGeomField->nSRSId = nSRSId;
1700
1701 int GeometryTypeFlags = 0;
1702 if( OGR_GT_HasZ((OGRwkbGeometryType)eType) )
1703 GeometryTypeFlags |= OGRGeometry::OGR_G_3D;
1704 if( OGR_GT_HasM((OGRwkbGeometryType)eType) )
1705 GeometryTypeFlags |= OGRGeometry::OGR_G_MEASURED;
1706 if( nForcedGeometryTypeFlags >= 0 )
1707 {
1708 GeometryTypeFlags = nForcedGeometryTypeFlags;
1709 eType = OGR_GT_SetModifier(eType,
1710 GeometryTypeFlags & OGRGeometry::OGR_G_3D,
1711 GeometryTypeFlags & OGRGeometry::OGR_G_MEASURED);
1712 }
1713 poGeomField->SetType(eType);
1714 poGeomField->GeometryTypeFlags = GeometryTypeFlags;
1715
1716 /* -------------------------------------------------------------------- */
1717 /* Create the new field. */
1718 /* -------------------------------------------------------------------- */
1719 if (bCreateTable)
1720 {
1721 const char *suffix = "";
1722 int dim = 2;
1723 if( (poGeomField->GeometryTypeFlags & OGRGeometry::OGR_G_3D) && (poGeomField->GeometryTypeFlags & OGRGeometry::OGR_G_MEASURED) )
1724 dim = 4;
1725 else if( poGeomField->GeometryTypeFlags & OGRGeometry::OGR_G_MEASURED )
1726 {
1727 if( wkbFlatten(poGeomField->GetType()) != wkbUnknown )
1728 suffix = "M";
1729 dim = 3;
1730 }
1731 else if( poGeomField->GeometryTypeFlags & OGRGeometry::OGR_G_3D )
1732 dim = 3;
1733
1734 const char *pszGeometryType = OGRToOGCGeomType(poGeomField->GetType());
1735 osCommand.Printf(
1736 "SELECT AddGeometryColumn(%s,%s,%s,%d,'%s%s',%d)",
1737 OGRPGDumpEscapeString(pszSchemaName).c_str(),
1738 OGRPGDumpEscapeString(poFeatureDefn->GetName()).c_str(),
1739 OGRPGDumpEscapeString(poGeomField->GetNameRef()).c_str(),
1740 nSRSId, pszGeometryType, suffix, dim );
1741
1742 poDS->Log(osCommand);
1743
1744 if( !poGeomField->IsNullable() )
1745 {
1746 osCommand.Printf( "ALTER TABLE %s ALTER COLUMN %s SET NOT NULL",
1747 OGRPGDumpEscapeColumnName(poFeatureDefn->GetName()).c_str(),
1748 OGRPGDumpEscapeColumnName(poGeomField->GetNameRef()).c_str() );
1749
1750 poDS->Log(osCommand);
1751 }
1752
1753 if( bCreateSpatialIndexFlag )
1754 {
1755 osCommand.Printf("CREATE INDEX %s ON %s USING %s (%s)",
1756 OGRPGDumpEscapeColumnName(
1757 CPLSPrintf("%s_%s_geom_idx", GetName(), poGeomField->GetNameRef())).c_str(),
1758 pszSqlTableName,
1759 osSpatialIndexType.c_str(),
1760 OGRPGDumpEscapeColumnName(poGeomField->GetNameRef()).c_str());
1761
1762 poDS->Log(osCommand);
1763 }
1764 }
1765
1766 poFeatureDefn->AddGeomFieldDefn( poGeomField, FALSE );
1767
1768 return OGRERR_NONE;
1769 }
1770
1771 /************************************************************************/
1772 /* SetOverrideColumnTypes() */
1773 /************************************************************************/
1774
SetOverrideColumnTypes(const char * pszOverrideColumnTypes)1775 void OGRPGDumpLayer::SetOverrideColumnTypes( const char* pszOverrideColumnTypes )
1776 {
1777 if( pszOverrideColumnTypes == nullptr )
1778 return;
1779
1780 const char* pszIter = pszOverrideColumnTypes;
1781 CPLString osCur;
1782 while(*pszIter != '\0')
1783 {
1784 if( *pszIter == '(' )
1785 {
1786 /* Ignore commas inside ( ) pair */
1787 while(*pszIter != '\0')
1788 {
1789 if( *pszIter == ')' )
1790 {
1791 osCur += *pszIter;
1792 pszIter ++;
1793 break;
1794 }
1795 osCur += *pszIter;
1796 pszIter ++;
1797 }
1798 if( *pszIter == '\0')
1799 break;
1800 }
1801
1802 if( *pszIter == ',' )
1803 {
1804 papszOverrideColumnTypes = CSLAddString(papszOverrideColumnTypes, osCur);
1805 osCur = "";
1806 }
1807 else
1808 osCur += *pszIter;
1809 pszIter ++;
1810 }
1811 if( !osCur.empty() )
1812 papszOverrideColumnTypes = CSLAddString(papszOverrideColumnTypes, osCur);
1813 }
1814
1815 /************************************************************************/
1816 /* SetMetadata() */
1817 /************************************************************************/
1818
SetMetadata(char ** papszMD,const char * pszDomain)1819 CPLErr OGRPGDumpLayer::SetMetadata(char** papszMD, const char* pszDomain)
1820 {
1821 OGRLayer::SetMetadata(papszMD, pszDomain);
1822 if( !osForcedDescription.empty() &&
1823 (pszDomain == nullptr || EQUAL(pszDomain, "")) )
1824 {
1825 OGRLayer::SetMetadataItem("DESCRIPTION", osForcedDescription);
1826 }
1827
1828 if( (pszDomain == nullptr || EQUAL(pszDomain, "")) &&
1829 osForcedDescription.empty() )
1830 {
1831 const char* l_pszDescription = OGRLayer::GetMetadataItem("DESCRIPTION");
1832 CPLString osCommand;
1833
1834 osCommand.Printf( "COMMENT ON TABLE %s IS %s",
1835 pszSqlTableName,
1836 l_pszDescription && l_pszDescription[0] != '\0' ?
1837 OGRPGDumpEscapeString(l_pszDescription).c_str() : "NULL" );
1838 poDS->Log( osCommand );
1839 }
1840
1841 return CE_None;
1842 }
1843
1844 /************************************************************************/
1845 /* SetMetadataItem() */
1846 /************************************************************************/
1847
SetMetadataItem(const char * pszName,const char * pszValue,const char * pszDomain)1848 CPLErr OGRPGDumpLayer::SetMetadataItem(const char* pszName, const char* pszValue,
1849 const char* pszDomain)
1850 {
1851 if( (pszDomain == nullptr || EQUAL(pszDomain, "")) && pszName != nullptr &&
1852 EQUAL(pszName, "DESCRIPTION") && !osForcedDescription.empty() )
1853 {
1854 return CE_None;
1855 }
1856 OGRLayer::SetMetadataItem(pszName, pszValue, pszDomain);
1857 if( (pszDomain == nullptr || EQUAL(pszDomain, "")) && pszName != nullptr &&
1858 EQUAL(pszName, "DESCRIPTION") )
1859 {
1860 SetMetadata( GetMetadata() );
1861 }
1862 return CE_None;
1863 }
1864
1865 /************************************************************************/
1866 /* SetForcedDescription() */
1867 /************************************************************************/
1868
SetForcedDescription(const char * pszDescriptionIn)1869 void OGRPGDumpLayer::SetForcedDescription( const char* pszDescriptionIn )
1870 {
1871 osForcedDescription = pszDescriptionIn;
1872 OGRLayer::SetMetadataItem("DESCRIPTION", osForcedDescription);
1873
1874 if( pszDescriptionIn[0] != '\0' )
1875 {
1876 CPLString osCommand;
1877 osCommand.Printf( "COMMENT ON TABLE %s IS %s",
1878 pszSqlTableName,
1879 OGRPGDumpEscapeString(pszDescriptionIn).c_str() );
1880 poDS->Log( osCommand );
1881 }
1882 }
1883