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