1 : /******************************************************************************
2 : * $Id: ogrpgdumplayer.cpp 19705 2010-05-14 19:42:02Z rouault $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Purpose: Implements OGRPGDumpLayer class
6 : * Author: Even Rouault, <even dot rouault at mines dash paris dot org>
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2010, Even Rouault
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "ogr_pgdump.h"
31 : #include "cpl_conv.h"
32 : #include "cpl_string.h"
33 :
34 : CPL_CVSID("$Id: ogrpgdumplayer.cpp 19705 2010-05-14 19:42:02Z rouault $");
35 :
36 : #define USE_COPY_UNSET -1
37 :
38 : /* Flags for creating WKB format for PostGIS */
39 : #define WKBZOFFSET 0x80000000
40 : #define WKBMOFFSET 0x40000000
41 : #define WKBSRIDFLAG 0x20000000
42 : #define WKBBBOXFLAG 0x10000000
43 :
44 : static CPLString OGRPGDumpEscapeStringList(
45 : char** papszItems, int bForInsertOrUpdate);
46 :
47 : /************************************************************************/
48 : /* OGRPGDumpLayer() */
49 : /************************************************************************/
50 :
51 : OGRPGDumpLayer::OGRPGDumpLayer(OGRPGDumpDataSource* poDS,
52 : const char* pszSchemaName,
53 : const char* pszLayerName,
54 : const char* pszGeomColumn,
55 : const char *pszFIDColumn,
56 : int nCoordDimension,
57 : int nSRSId,
58 : int bWriteAsHexIn,
59 3 : int bCreateTable)
60 : {
61 3 : this->poDS = poDS;
62 3 : poFeatureDefn = new OGRFeatureDefn( pszLayerName );
63 3 : poFeatureDefn->Reference();
64 3 : nFeatures = 0;
65 3 : pszSqlTableName = CPLStrdup(CPLSPrintf("\"%s\".\"%s\"", pszSchemaName, pszLayerName));
66 3 : this->pszGeomColumn = (pszGeomColumn) ? CPLStrdup(pszGeomColumn) : NULL;
67 3 : this->pszFIDColumn = CPLStrdup(pszFIDColumn);
68 3 : this->nCoordDimension = nCoordDimension;
69 3 : this->nSRSId = nSRSId;
70 3 : this->bCreateTable = bCreateTable;
71 3 : bLaunderColumnNames = TRUE;
72 3 : bPreservePrecision = TRUE;
73 3 : bUseCopy = USE_COPY_UNSET;
74 3 : bWriteAsHex = bWriteAsHexIn;
75 3 : bCopyActive = FALSE;
76 3 : }
77 :
78 : /************************************************************************/
79 : /* ~OGRPGDumpLayer() */
80 : /************************************************************************/
81 :
82 3 : OGRPGDumpLayer::~OGRPGDumpLayer()
83 : {
84 3 : EndCopy();
85 :
86 3 : poFeatureDefn->Release();
87 3 : CPLFree(pszSqlTableName);
88 3 : CPLFree(pszGeomColumn);
89 3 : CPLFree(pszFIDColumn);
90 3 : }
91 :
92 : /************************************************************************/
93 : /* GetNextFeature() */
94 : /************************************************************************/
95 :
96 0 : OGRFeature *OGRPGDumpLayer::GetNextFeature()
97 : {
98 0 : CPLError(CE_Failure, CPLE_NotSupported, "PGDump driver is write only");
99 0 : return NULL;
100 : }
101 :
102 : /************************************************************************/
103 : /* GetNextFeature() */
104 : /************************************************************************/
105 :
106 0 : int OGRPGDumpLayer::TestCapability( const char * pszCap )
107 : {
108 0 : if( EQUAL(pszCap,OLCSequentialWrite) ||
109 : EQUAL(pszCap,OLCCreateField) )
110 0 : return TRUE;
111 : else
112 0 : return FALSE;
113 : }
114 :
115 : /************************************************************************/
116 : /* GeometryToHex() */
117 : /************************************************************************/
118 :
119 20 : char *OGRPGDumpLayer::GeometryToHex( OGRGeometry * poGeometry, int nSRSId )
120 : {
121 : GByte *pabyWKB;
122 : char *pszTextBuf;
123 : char *pszTextBufCurrent;
124 : char *pszHex;
125 :
126 20 : int nWkbSize = poGeometry->WkbSize();
127 20 : pabyWKB = (GByte *) CPLMalloc(nWkbSize);
128 :
129 20 : if( poGeometry->exportToWkb( wkbNDR, pabyWKB ) != OGRERR_NONE )
130 : {
131 0 : CPLFree( pabyWKB );
132 0 : return CPLStrdup("");
133 : }
134 :
135 : /* When converting to hex, each byte takes 2 hex characters. In addition
136 : we add in 8 characters to represent the SRID integer in hex, and
137 : one for a null terminator */
138 :
139 20 : int pszSize = nWkbSize*2 + 8 + 1;
140 20 : pszTextBuf = (char *) CPLMalloc(pszSize);
141 20 : pszTextBufCurrent = pszTextBuf;
142 :
143 : /* Convert the 1st byte, which is the endianess flag, to hex. */
144 20 : pszHex = CPLBinaryToHex( 1, pabyWKB );
145 20 : strcpy(pszTextBufCurrent, pszHex );
146 20 : CPLFree ( pszHex );
147 20 : pszTextBufCurrent += 2;
148 :
149 : /* Next, get the geom type which is bytes 2 through 5 */
150 : GUInt32 geomType;
151 20 : memcpy( &geomType, pabyWKB+1, 4 );
152 :
153 : /* Now add the SRID flag if an SRID is provided */
154 20 : if (nSRSId != -1)
155 : {
156 : /* Change the flag to wkbNDR (little) endianess */
157 10 : GUInt32 nGSrsFlag = CPL_LSBWORD32( WKBSRIDFLAG );
158 : /* Apply the flag */
159 10 : geomType = geomType | nGSrsFlag;
160 : }
161 :
162 : /* Now write the geom type which is 4 bytes */
163 20 : pszHex = CPLBinaryToHex( 4, (GByte*) &geomType );
164 20 : strcpy(pszTextBufCurrent, pszHex );
165 20 : CPLFree ( pszHex );
166 20 : pszTextBufCurrent += 8;
167 :
168 : /* Now include SRID if provided */
169 20 : if (nSRSId != -1)
170 : {
171 : /* Force the srsid to wkbNDR (little) endianess */
172 10 : GUInt32 nGSRSId = CPL_LSBWORD32( nSRSId );
173 10 : pszHex = CPLBinaryToHex( sizeof(nGSRSId),(GByte*) &nGSRSId );
174 10 : strcpy(pszTextBufCurrent, pszHex );
175 10 : CPLFree ( pszHex );
176 10 : pszTextBufCurrent += 8;
177 : }
178 :
179 : /* Copy the rest of the data over - subtract
180 : 5 since we already copied 5 bytes above */
181 20 : pszHex = CPLBinaryToHex( nWkbSize - 5, pabyWKB + 5 );
182 20 : strcpy(pszTextBufCurrent, pszHex );
183 20 : CPLFree ( pszHex );
184 :
185 20 : CPLFree( pabyWKB );
186 :
187 20 : return pszTextBuf;
188 : }
189 :
190 : /************************************************************************/
191 : /* GetNextFeature() */
192 : /************************************************************************/
193 :
194 30 : OGRErr OGRPGDumpLayer::CreateFeature( OGRFeature *poFeature )
195 : {
196 30 : if( NULL == poFeature )
197 : {
198 : CPLError( CE_Failure, CPLE_AppDefined,
199 0 : "NULL pointer to OGRFeature passed to CreateFeature()." );
200 0 : return OGRERR_FAILURE;
201 : }
202 :
203 30 : nFeatures ++;
204 :
205 : // We avoid testing the config option too often.
206 30 : if( bUseCopy == USE_COPY_UNSET )
207 3 : bUseCopy = CSLTestBoolean( CPLGetConfigOption( "PG_USE_COPY", "NO") );
208 :
209 30 : if( !bUseCopy )
210 : {
211 10 : return CreateFeatureViaInsert( poFeature );
212 : }
213 : else
214 : {
215 20 : if ( !bCopyActive )
216 2 : StartCopy();
217 :
218 20 : return CreateFeatureViaCopy( poFeature );
219 : }
220 : }
221 :
222 : /************************************************************************/
223 : /* CreateFeatureViaInsert() */
224 : /************************************************************************/
225 :
226 10 : OGRErr OGRPGDumpLayer::CreateFeatureViaInsert( OGRFeature *poFeature )
227 :
228 : {
229 10 : CPLString osCommand;
230 10 : int i = 0;
231 10 : int bNeedComma = FALSE;
232 10 : OGRErr eErr = OGRERR_FAILURE;
233 :
234 10 : if( NULL == poFeature )
235 : {
236 : CPLError( CE_Failure, CPLE_AppDefined,
237 0 : "NULL pointer to OGRFeature passed to CreateFeatureViaInsert()." );
238 0 : return eErr;
239 : }
240 :
241 : /* -------------------------------------------------------------------- */
242 : /* Form the INSERT command. */
243 : /* -------------------------------------------------------------------- */
244 10 : osCommand.Printf( "INSERT INTO %s (", pszSqlTableName );
245 :
246 10 : if( poFeature->GetGeometryRef() != NULL )
247 : {
248 10 : osCommand = osCommand + "\"" + pszGeomColumn + "\" ";
249 10 : bNeedComma = TRUE;
250 : }
251 :
252 10 : if( poFeature->GetFID() != OGRNullFID && pszFIDColumn != NULL )
253 : {
254 0 : if( bNeedComma )
255 0 : osCommand += ", ";
256 :
257 0 : osCommand = osCommand + "\"" + pszFIDColumn + "\" ";
258 0 : bNeedComma = TRUE;
259 : }
260 :
261 50 : for( i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
262 : {
263 40 : if( !poFeature->IsFieldSet( i ) )
264 10 : continue;
265 :
266 30 : if( !bNeedComma )
267 0 : bNeedComma = TRUE;
268 : else
269 30 : osCommand += ", ";
270 :
271 : osCommand = osCommand
272 30 : + "\"" + poFeatureDefn->GetFieldDefn(i)->GetNameRef() + "\"";
273 : }
274 :
275 10 : osCommand += ") VALUES (";
276 :
277 : /* Set the geometry */
278 10 : OGRGeometry *poGeom = poFeature->GetGeometryRef();
279 10 : bNeedComma = poGeom != NULL;
280 10 : if( poGeom != NULL)
281 : {
282 10 : char *pszWKT = NULL;
283 :
284 10 : poGeom->closeRings();
285 10 : poGeom->setCoordinateDimension( nCoordDimension );
286 :
287 10 : if( bWriteAsHex )
288 : {
289 10 : char* pszHex = GeometryToHex( poGeom, nSRSId );
290 10 : osCommand += "'";
291 10 : if (pszHex)
292 10 : osCommand += pszHex;
293 10 : osCommand += "'";
294 10 : CPLFree(pszHex);
295 : }
296 : else
297 : {
298 0 : poGeom->exportToWkt( &pszWKT );
299 :
300 0 : if( pszWKT != NULL )
301 : {
302 : osCommand +=
303 : CPLString().Printf(
304 0 : "GeomFromEWKT('SRID=%d;%s'::TEXT) ", nSRSId, pszWKT );
305 0 : OGRFree( pszWKT );
306 : }
307 : else
308 0 : osCommand += "''";
309 : }
310 : }
311 :
312 : /* Set the FID */
313 10 : if( poFeature->GetFID() != OGRNullFID && pszFIDColumn != NULL )
314 : {
315 0 : if( bNeedComma )
316 0 : osCommand += ", ";
317 0 : osCommand += CPLString().Printf( "%ld ", poFeature->GetFID() );
318 0 : bNeedComma = TRUE;
319 : }
320 :
321 :
322 50 : for( i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
323 : {
324 40 : if( !poFeature->IsFieldSet( i ) )
325 10 : continue;
326 :
327 30 : if( bNeedComma )
328 30 : osCommand += ", ";
329 : else
330 0 : bNeedComma = TRUE;
331 :
332 30 : AppendFieldValue(osCommand, poFeature, i);
333 : }
334 :
335 10 : osCommand += ")";
336 :
337 : /* -------------------------------------------------------------------- */
338 : /* Execute the insert. */
339 : /* -------------------------------------------------------------------- */
340 10 : poDS->Log(osCommand);
341 :
342 10 : return OGRERR_NONE;
343 : }
344 :
345 :
346 : /************************************************************************/
347 : /* CreateFeatureViaCopy() */
348 : /************************************************************************/
349 :
350 20 : OGRErr OGRPGDumpLayer::CreateFeatureViaCopy( OGRFeature *poFeature )
351 : {
352 20 : CPLString osCommand;
353 :
354 : /* First process geometry */
355 20 : OGRGeometry *poGeometry = (OGRGeometry *) poFeature->GetGeometryRef();
356 :
357 20 : if (pszGeomColumn)
358 : {
359 10 : char *pszGeom = NULL;
360 10 : if ( NULL != poGeometry /* && (bHasWkb || bHasPostGISGeometry || bHasPostGISGeography) */)
361 : {
362 10 : poGeometry->closeRings();
363 10 : poGeometry->setCoordinateDimension( nCoordDimension );
364 :
365 : //CheckGeomTypeCompatibility(poGeometry);
366 :
367 : /*if (bHasWkb)
368 : pszGeom = GeometryToBYTEA( poGeometry );
369 : else*/
370 10 : pszGeom = GeometryToHex( poGeometry, nSRSId );
371 : }
372 :
373 10 : if ( pszGeom )
374 : {
375 : osCommand += pszGeom,
376 10 : CPLFree( pszGeom );
377 : }
378 : else
379 : {
380 0 : osCommand = "\\N";
381 : }
382 : }
383 :
384 : /* Next process the field id column */
385 20 : if( /*bHasFid &&*/ poFeatureDefn->GetFieldIndex( pszFIDColumn ) != -1 )
386 : {
387 0 : if (osCommand.size() > 0)
388 0 : osCommand += "\t";
389 :
390 : /* Set the FID */
391 0 : if( poFeature->GetFID() != OGRNullFID )
392 : {
393 0 : osCommand += CPLString().Printf("%ld ", poFeature->GetFID());
394 : }
395 : else
396 : {
397 0 : osCommand += "\\N" ;
398 : }
399 : }
400 :
401 :
402 : /* Now process the remaining fields */
403 :
404 20 : int nFieldCount = poFeatureDefn->GetFieldCount();
405 100 : for( int i = 0; i < nFieldCount; i++ )
406 : {
407 80 : const char *pszStrValue = poFeature->GetFieldAsString(i);
408 80 : char *pszNeedToFree = NULL;
409 :
410 80 : if (osCommand.size() > 0)
411 70 : osCommand += "\t";
412 :
413 80 : if( !poFeature->IsFieldSet( i ) )
414 : {
415 20 : osCommand += "\\N" ;
416 :
417 20 : continue;
418 : }
419 :
420 60 : int nOGRFieldType = poFeatureDefn->GetFieldDefn(i)->GetType();
421 :
422 : // We need special formatting for integer list values.
423 60 : if( nOGRFieldType == OFTIntegerList )
424 : {
425 0 : int nCount, nOff = 0, j;
426 0 : const int *panItems = poFeature->GetFieldAsIntegerList(i,&nCount);
427 :
428 0 : pszNeedToFree = (char *) CPLMalloc(nCount * 13 + 10);
429 0 : strcpy( pszNeedToFree, "{" );
430 0 : for( j = 0; j < nCount; j++ )
431 : {
432 0 : if( j != 0 )
433 0 : strcat( pszNeedToFree+nOff, "," );
434 :
435 0 : nOff += strlen(pszNeedToFree+nOff);
436 0 : sprintf( pszNeedToFree+nOff, "%d", panItems[j] );
437 : }
438 0 : strcat( pszNeedToFree+nOff, "}" );
439 0 : pszStrValue = pszNeedToFree;
440 : }
441 :
442 : // We need special formatting for real list values.
443 60 : else if( nOGRFieldType == OFTRealList )
444 : {
445 0 : int nCount, nOff = 0, j;
446 0 : const double *padfItems =poFeature->GetFieldAsDoubleList(i,&nCount);
447 :
448 0 : pszNeedToFree = (char *) CPLMalloc(nCount * 40 + 10);
449 0 : strcpy( pszNeedToFree, "{" );
450 0 : for( j = 0; j < nCount; j++ )
451 : {
452 0 : if( j != 0 )
453 0 : strcat( pszNeedToFree+nOff, "," );
454 :
455 0 : nOff += strlen(pszNeedToFree+nOff);
456 0 : sprintf( pszNeedToFree+nOff, "%.16g", padfItems[j] );
457 : }
458 0 : strcat( pszNeedToFree+nOff, "}" );
459 0 : pszStrValue = pszNeedToFree;
460 : }
461 :
462 :
463 : // We need special formatting for string list values.
464 60 : else if( nOGRFieldType == OFTStringList )
465 : {
466 0 : CPLString osStr;
467 0 : char **papszItems = poFeature->GetFieldAsStringList(i);
468 :
469 0 : pszStrValue = pszNeedToFree = CPLStrdup(OGRPGDumpEscapeStringList(papszItems, FALSE));
470 : }
471 :
472 : // Binary formatting
473 60 : else if( nOGRFieldType == OFTBinary )
474 : {
475 0 : int nLen = 0;
476 0 : GByte* pabyData = poFeature->GetFieldAsBinary( i, &nLen );
477 0 : char* pszBytea = GByteArrayToBYTEA( pabyData, nLen);
478 :
479 0 : pszStrValue = pszNeedToFree = pszBytea;
480 : }
481 :
482 80 : if( nOGRFieldType != OFTIntegerList &&
483 : nOGRFieldType != OFTRealList &&
484 : nOGRFieldType != OFTInteger &&
485 : nOGRFieldType != OFTReal &&
486 : nOGRFieldType != OFTBinary )
487 : {
488 : int iChar;
489 :
490 180 : for( iChar = 0; pszStrValue[iChar] != '\0'; iChar++ )
491 : {
492 160 : if( poFeatureDefn->GetFieldDefn(i)->GetWidth() > 0
493 : && iChar == poFeatureDefn->GetFieldDefn(i)->GetWidth() )
494 : {
495 : CPLDebug( "PG",
496 : "Truncated %s field value, it was too long.",
497 0 : poFeatureDefn->GetFieldDefn(i)->GetNameRef() );
498 0 : break;
499 : }
500 :
501 : /* Escape embedded \, \t, \n, \r since they will cause COPY
502 : to misinterpret a line of text and thus abort */
503 160 : if( pszStrValue[iChar] == '\\' ||
504 : pszStrValue[iChar] == '\t' ||
505 : pszStrValue[iChar] == '\r' ||
506 : pszStrValue[iChar] == '\n' )
507 : {
508 0 : osCommand += '\\';
509 : }
510 :
511 160 : osCommand += pszStrValue[iChar];
512 : }
513 : }
514 : else
515 : {
516 40 : osCommand += pszStrValue;
517 : }
518 :
519 60 : if( pszNeedToFree )
520 0 : CPLFree( pszNeedToFree );
521 : }
522 :
523 : /* Add end of line marker */
524 : //osCommand += "\n";
525 :
526 :
527 : /* ------------------------------------------------------------ */
528 : /* Execute the copy. */
529 : /* ------------------------------------------------------------ */
530 :
531 20 : OGRErr result = OGRERR_NONE;
532 :
533 20 : poDS->Log(osCommand, FALSE);
534 :
535 20 : return result;
536 : }
537 :
538 : /************************************************************************/
539 : /* StartCopy() */
540 : /************************************************************************/
541 :
542 2 : OGRErr OGRPGDumpLayer::StartCopy()
543 :
544 : {
545 : /* Tell the datasource we are now planning to copy data */
546 2 : poDS->StartCopy( this );
547 :
548 2 : CPLString osFields = BuildCopyFields();
549 :
550 2 : int size = strlen(osFields) + strlen(pszSqlTableName) + 100;
551 2 : char *pszCommand = (char *) CPLMalloc(size);
552 :
553 : sprintf( pszCommand,
554 : "COPY %s (%s) FROM STDIN",
555 2 : pszSqlTableName, osFields.c_str() );
556 :
557 2 : poDS->Log(pszCommand);
558 2 : bCopyActive = TRUE;
559 :
560 2 : CPLFree( pszCommand );
561 :
562 2 : return OGRERR_NONE;
563 : }
564 :
565 : /************************************************************************/
566 : /* EndCopy() */
567 : /************************************************************************/
568 :
569 5 : OGRErr OGRPGDumpLayer::EndCopy()
570 :
571 : {
572 5 : if( !bCopyActive )
573 3 : return OGRERR_NONE;
574 :
575 2 : bCopyActive = FALSE;
576 :
577 2 : poDS->Log("\\.", FALSE);
578 2 : poDS->Log("END");
579 :
580 2 : bUseCopy = USE_COPY_UNSET;
581 :
582 2 : return OGRERR_NONE;
583 : }
584 :
585 : /************************************************************************/
586 : /* BuildCopyFields() */
587 : /************************************************************************/
588 :
589 2 : CPLString OGRPGDumpLayer::BuildCopyFields()
590 : {
591 2 : int i = 0;
592 2 : CPLString osFieldList;
593 :
594 2 : if( /*bHasFid &&*/ poFeatureDefn->GetFieldIndex( pszFIDColumn ) != -1 )
595 : {
596 0 : osFieldList += "\"";
597 0 : osFieldList += pszFIDColumn;
598 0 : osFieldList += "\"";
599 : }
600 :
601 2 : if( pszGeomColumn )
602 : {
603 1 : if( strlen(osFieldList) > 0 )
604 0 : osFieldList += ", ";
605 :
606 1 : osFieldList += "\"";
607 1 : osFieldList += pszGeomColumn;
608 1 : osFieldList += "\"";
609 : }
610 :
611 10 : for( i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
612 : {
613 8 : const char *pszName = poFeatureDefn->GetFieldDefn(i)->GetNameRef();
614 :
615 8 : if( strlen(osFieldList) > 0 )
616 7 : osFieldList += ", ";
617 :
618 8 : osFieldList += "\"";
619 8 : osFieldList += pszName;
620 8 : osFieldList += "\"" ;
621 : }
622 :
623 0 : return osFieldList;
624 : }
625 :
626 : /************************************************************************/
627 : /* EscapeString( ) */
628 : /************************************************************************/
629 :
630 : static CPLString OGRPGDumpEscapeString(
631 : const char* pszStrValue, int nMaxLength,
632 10 : const char* pszFieldName)
633 : {
634 10 : CPLString osCommand;
635 :
636 : /* We need to quote and escape string fields. */
637 10 : osCommand += "'";
638 :
639 10 : int nSrcLen = strlen(pszStrValue);
640 10 : if (nMaxLength > 0 && nSrcLen > nMaxLength)
641 : {
642 : CPLDebug( "PG",
643 : "Truncated %s field value, it was too long.",
644 0 : pszFieldName );
645 0 : nSrcLen = nMaxLength;
646 :
647 0 : while( nSrcLen > 0 && ((unsigned char *) pszStrValue)[nSrcLen-1] > 127 )
648 : {
649 0 : CPLDebug( "PG", "Backup to start of multi-byte character." );
650 0 : nSrcLen--;
651 : }
652 : }
653 :
654 10 : char* pszDestStr = (char*)CPLMalloc(2 * nSrcLen + 1);
655 :
656 : /* -------------------------------------------------------------------- */
657 : /* PQescapeStringConn was introduced in PostgreSQL security releases */
658 : /* 8.1.4, 8.0.8, 7.4.13, 7.3.15 */
659 : /* PG_HAS_PQESCAPESTRINGCONN is added by a test in 'configure' */
660 : /* so it is not set by default when building OGR for Win32 */
661 : /* -------------------------------------------------------------------- */
662 : #if defined(PG_HAS_PQESCAPESTRINGCONN)
663 : int nError;
664 : PQescapeStringConn (hPGConn, pszDestStr, pszStrValue, nSrcLen, &nError);
665 : if (nError == 0)
666 : osCommand += pszDestStr;
667 : else
668 : CPLError(CE_Warning, CPLE_AppDefined,
669 : "PQescapeString(): %s\n"
670 : " input: '%s'\n"
671 : " got: '%s'\n",
672 : PQerrorMessage( hPGConn ),
673 : pszStrValue, pszDestStr );
674 : #else
675 : //PQescapeString(pszDestStr, pszStrValue, nSrcLen);
676 :
677 : int i, j;
678 90 : for(i=0,j=0; i < nSrcLen; i++)
679 : {
680 80 : if (pszStrValue[i] == '\'')
681 : {
682 0 : pszDestStr[j++] = '\'';
683 0 : pszDestStr[j++] = '\'';
684 : }
685 80 : else if (pszStrValue[i] == '\\')
686 : {
687 0 : pszDestStr[j++] = '\\';
688 0 : pszDestStr[j++] = '\\';
689 : }
690 : else
691 80 : pszDestStr[j++] = pszStrValue[i];
692 : }
693 10 : pszDestStr[j] = 0;
694 :
695 10 : osCommand += pszDestStr;
696 : #endif
697 10 : CPLFree(pszDestStr);
698 :
699 10 : osCommand += "'";
700 :
701 0 : return osCommand;
702 : }
703 :
704 :
705 : /************************************************************************/
706 : /* OGRPGDumpEscapeStringList( ) */
707 : /************************************************************************/
708 :
709 : static CPLString OGRPGDumpEscapeStringList(
710 0 : char** papszItems, int bForInsertOrUpdate)
711 : {
712 0 : int bFirstItem = TRUE;
713 0 : CPLString osStr;
714 0 : if (bForInsertOrUpdate)
715 0 : osStr += "ARRAY[";
716 : else
717 0 : osStr += "{";
718 0 : while(*papszItems)
719 : {
720 0 : if (!bFirstItem)
721 : {
722 0 : osStr += ',';
723 : }
724 :
725 0 : char* pszStr = *papszItems;
726 0 : if (*pszStr != '\0')
727 : {
728 0 : if (bForInsertOrUpdate)
729 0 : osStr += OGRPGDumpEscapeString(pszStr, -1, "");
730 : else
731 : {
732 0 : osStr += '"';
733 :
734 0 : while(*pszStr)
735 : {
736 0 : if (*pszStr == '"' )
737 0 : osStr += "\\";
738 0 : osStr += *pszStr;
739 0 : pszStr++;
740 : }
741 :
742 0 : osStr += '"';
743 : }
744 : }
745 : else
746 0 : osStr += "NULL";
747 :
748 0 : bFirstItem = FALSE;
749 :
750 0 : papszItems++;
751 : }
752 0 : if (bForInsertOrUpdate)
753 0 : osStr += "]";
754 : else
755 0 : osStr += "}";
756 0 : return osStr;
757 : }
758 :
759 : /************************************************************************/
760 : /* AppendFieldValue() */
761 : /* */
762 : /* Used by CreateFeatureViaInsert() and SetFeature() to format a */
763 : /* non-empty field value */
764 : /************************************************************************/
765 :
766 : void OGRPGDumpLayer::AppendFieldValue(CPLString& osCommand,
767 30 : OGRFeature* poFeature, int i)
768 : {
769 30 : int nOGRFieldType = poFeatureDefn->GetFieldDefn(i)->GetType();
770 :
771 : // We need special formatting for integer list values.
772 30 : if( nOGRFieldType == OFTIntegerList )
773 : {
774 0 : int nCount, nOff = 0, j;
775 0 : const int *panItems = poFeature->GetFieldAsIntegerList(i,&nCount);
776 0 : char *pszNeedToFree = NULL;
777 :
778 0 : pszNeedToFree = (char *) CPLMalloc(nCount * 13 + 10);
779 0 : strcpy( pszNeedToFree, "'{" );
780 0 : for( j = 0; j < nCount; j++ )
781 : {
782 0 : if( j != 0 )
783 0 : strcat( pszNeedToFree+nOff, "," );
784 :
785 0 : nOff += strlen(pszNeedToFree+nOff);
786 0 : sprintf( pszNeedToFree+nOff, "%d", panItems[j] );
787 : }
788 0 : strcat( pszNeedToFree+nOff, "}'" );
789 :
790 0 : osCommand += pszNeedToFree;
791 0 : CPLFree(pszNeedToFree);
792 :
793 0 : return;
794 : }
795 :
796 : // We need special formatting for real list values.
797 30 : else if( nOGRFieldType == OFTRealList )
798 : {
799 0 : int nCount, nOff = 0, j;
800 0 : const double *padfItems =poFeature->GetFieldAsDoubleList(i,&nCount);
801 0 : char *pszNeedToFree = NULL;
802 :
803 0 : pszNeedToFree = (char *) CPLMalloc(nCount * 40 + 10);
804 0 : strcpy( pszNeedToFree, "'{" );
805 0 : for( j = 0; j < nCount; j++ )
806 : {
807 0 : if( j != 0 )
808 0 : strcat( pszNeedToFree+nOff, "," );
809 :
810 0 : nOff += strlen(pszNeedToFree+nOff);
811 0 : sprintf( pszNeedToFree+nOff, "%.16g", padfItems[j] );
812 : }
813 0 : strcat( pszNeedToFree+nOff, "}'" );
814 :
815 0 : osCommand += pszNeedToFree;
816 0 : CPLFree(pszNeedToFree);
817 :
818 0 : return;
819 : }
820 :
821 : // We need special formatting for string list values.
822 30 : else if( nOGRFieldType == OFTStringList )
823 : {
824 0 : char **papszItems = poFeature->GetFieldAsStringList(i);
825 :
826 0 : osCommand += OGRPGDumpEscapeStringList(papszItems, TRUE);
827 :
828 0 : return;
829 : }
830 :
831 : // Binary formatting
832 30 : else if( nOGRFieldType == OFTBinary )
833 : {
834 0 : osCommand += "'";
835 :
836 0 : int nLen = 0;
837 0 : GByte* pabyData = poFeature->GetFieldAsBinary( i, &nLen );
838 0 : char* pszBytea = GByteArrayToBYTEA( pabyData, nLen);
839 :
840 0 : osCommand += pszBytea;
841 :
842 0 : CPLFree(pszBytea);
843 0 : osCommand += "'";
844 :
845 0 : return;
846 : }
847 :
848 : // Flag indicating NULL or not-a-date date value
849 : // e.g. 0000-00-00 - there is no year 0
850 30 : OGRBoolean bIsDateNull = FALSE;
851 :
852 30 : const char *pszStrValue = poFeature->GetFieldAsString(i);
853 :
854 : // Check if date is NULL: 0000-00-00
855 30 : if( nOGRFieldType == OFTDate )
856 : {
857 0 : if( EQUALN( pszStrValue, "0000", 4 ) )
858 : {
859 0 : pszStrValue = "NULL";
860 0 : bIsDateNull = TRUE;
861 : }
862 : }
863 :
864 40 : if( nOGRFieldType != OFTInteger && nOGRFieldType != OFTReal
865 : && !bIsDateNull )
866 : {
867 : osCommand += OGRPGDumpEscapeString( pszStrValue,
868 : poFeatureDefn->GetFieldDefn(i)->GetWidth(),
869 10 : poFeatureDefn->GetFieldDefn(i)->GetNameRef() );
870 : }
871 : else
872 : {
873 20 : osCommand += pszStrValue;
874 : }
875 : }
876 :
877 :
878 : /************************************************************************/
879 : /* GByteArrayToBYTEA() */
880 : /************************************************************************/
881 :
882 0 : char* OGRPGDumpLayer::GByteArrayToBYTEA( const GByte* pabyData, int nLen)
883 : {
884 : char* pszTextBuf;
885 :
886 0 : pszTextBuf = (char *) CPLMalloc(nLen*5+1);
887 :
888 0 : int iSrc, iDst=0;
889 :
890 0 : for( iSrc = 0; iSrc < nLen; iSrc++ )
891 : {
892 0 : if( pabyData[iSrc] < 40 || pabyData[iSrc] > 126
893 : || pabyData[iSrc] == '\\' )
894 : {
895 0 : sprintf( pszTextBuf+iDst, "\\\\%03o", pabyData[iSrc] );
896 0 : iDst += 5;
897 : }
898 : else
899 0 : pszTextBuf[iDst++] = pabyData[iSrc];
900 : }
901 0 : pszTextBuf[iDst] = '\0';
902 :
903 0 : return pszTextBuf;
904 : }
905 :
906 : /************************************************************************/
907 : /* GetNextFeature() */
908 : /************************************************************************/
909 :
910 : OGRErr OGRPGDumpLayer::CreateField( OGRFieldDefn *poFieldIn,
911 12 : int bApproxOK )
912 : {
913 12 : if (nFeatures != 0)
914 : {
915 : CPLError(CE_Failure, CPLE_NotSupported,
916 0 : "Cannot create field after first feature has been written");
917 0 : return OGRERR_FAILURE;
918 : }
919 :
920 12 : CPLString osCommand;
921 : char szFieldType[256];
922 12 : OGRFieldDefn oField( poFieldIn );
923 :
924 : /* -------------------------------------------------------------------- */
925 : /* Do we want to "launder" the column names into Postgres */
926 : /* friendly format? */
927 : /* -------------------------------------------------------------------- */
928 12 : if( bLaunderColumnNames )
929 : {
930 12 : char *pszSafeName = poDS->LaunderName( oField.GetNameRef() );
931 :
932 12 : oField.SetName( pszSafeName );
933 12 : CPLFree( pszSafeName );
934 :
935 12 : if( EQUAL(oField.GetNameRef(),"oid") )
936 : {
937 : CPLError( CE_Warning, CPLE_AppDefined,
938 0 : "Renaming field 'oid' to 'oid_' to avoid conflict with internal oid field." );
939 0 : oField.SetName( "oid_" );
940 : }
941 : }
942 :
943 : /* -------------------------------------------------------------------- */
944 : /* Work out the PostgreSQL type. */
945 : /* -------------------------------------------------------------------- */
946 12 : if( oField.GetType() == OFTInteger )
947 : {
948 3 : if( oField.GetWidth() > 0 && bPreservePrecision )
949 0 : sprintf( szFieldType, "NUMERIC(%d,0)", oField.GetWidth() );
950 : else
951 3 : strcpy( szFieldType, "INTEGER" );
952 : }
953 9 : else if( oField.GetType() == OFTReal )
954 : {
955 3 : if( oField.GetWidth() > 0 && oField.GetPrecision() > 0
956 : && bPreservePrecision )
957 : sprintf( szFieldType, "NUMERIC(%d,%d)",
958 0 : oField.GetWidth(), oField.GetPrecision() );
959 : else
960 3 : strcpy( szFieldType, "FLOAT8" );
961 : }
962 6 : else if( oField.GetType() == OFTString )
963 : {
964 6 : if( oField.GetWidth() == 0 || !bPreservePrecision )
965 3 : strcpy( szFieldType, "VARCHAR" );
966 : else
967 3 : sprintf( szFieldType, "CHAR(%d)", oField.GetWidth() );
968 : }
969 0 : else if( oField.GetType() == OFTIntegerList )
970 : {
971 0 : strcpy( szFieldType, "INTEGER[]" );
972 : }
973 0 : else if( oField.GetType() == OFTRealList )
974 : {
975 0 : strcpy( szFieldType, "FLOAT8[]" );
976 : }
977 0 : else if( oField.GetType() == OFTStringList )
978 : {
979 0 : strcpy( szFieldType, "varchar[]" );
980 : }
981 0 : else if( oField.GetType() == OFTDate )
982 : {
983 0 : strcpy( szFieldType, "date" );
984 : }
985 0 : else if( oField.GetType() == OFTTime )
986 : {
987 0 : strcpy( szFieldType, "time" );
988 : }
989 0 : else if( oField.GetType() == OFTDateTime )
990 : {
991 0 : strcpy( szFieldType, "timestamp with time zone" );
992 : }
993 0 : else if( oField.GetType() == OFTBinary )
994 : {
995 0 : strcpy( szFieldType, "bytea" );
996 : }
997 0 : else if( bApproxOK )
998 : {
999 : CPLError( CE_Warning, CPLE_NotSupported,
1000 : "Can't create field %s with type %s on PostgreSQL layers. Creating as VARCHAR.",
1001 : oField.GetNameRef(),
1002 0 : OGRFieldDefn::GetFieldTypeName(oField.GetType()) );
1003 0 : strcpy( szFieldType, "VARCHAR" );
1004 : }
1005 : else
1006 : {
1007 : CPLError( CE_Failure, CPLE_NotSupported,
1008 : "Can't create field %s with type %s on PostgreSQL layers.",
1009 : oField.GetNameRef(),
1010 0 : OGRFieldDefn::GetFieldTypeName(oField.GetType()) );
1011 :
1012 12 : return OGRERR_FAILURE;
1013 : }
1014 :
1015 : /* -------------------------------------------------------------------- */
1016 : /* Create the new field. */
1017 : /* -------------------------------------------------------------------- */
1018 : osCommand.Printf( "ALTER TABLE %s ADD COLUMN \"%s\" %s",
1019 12 : pszSqlTableName, oField.GetNameRef(), szFieldType );
1020 12 : if (bCreateTable)
1021 12 : poDS->Log(osCommand);
1022 :
1023 12 : poFeatureDefn->AddFieldDefn( &oField );
1024 :
1025 12 : return OGRERR_NONE;
1026 : }
|