/src/gdal/ogr/ogrsf_frmts/carto/ogrcartotablelayer.cpp
Line | Count | Source |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: Carto Translator |
4 | | * Purpose: Implements OGRCARTOTableLayer class. |
5 | | * Author: Even Rouault, <even dot rouault at spatialys.com> |
6 | | * |
7 | | ****************************************************************************** |
8 | | * Copyright (c) 2013, Even Rouault <even dot rouault at spatialys.com> |
9 | | * |
10 | | * SPDX-License-Identifier: MIT |
11 | | ****************************************************************************/ |
12 | | |
13 | | #include "ogr_carto.h" |
14 | | #include "ogr_p.h" |
15 | | #include "ogr_pgdump.h" |
16 | | #include "ogrlibjsonutils.h" |
17 | | |
18 | | /************************************************************************/ |
19 | | /* OGRCARTOEscapeIdentifier( ) */ |
20 | | /************************************************************************/ |
21 | | |
22 | | CPLString OGRCARTOEscapeIdentifier(const char *pszStr) |
23 | 0 | { |
24 | 0 | CPLString osStr; |
25 | |
|
26 | 0 | osStr += "\""; |
27 | |
|
28 | 0 | char ch = '\0'; |
29 | 0 | for (int i = 0; (ch = pszStr[i]) != '\0'; i++) |
30 | 0 | { |
31 | 0 | if (ch == '"') |
32 | 0 | osStr.append(1, ch); |
33 | 0 | osStr.append(1, ch); |
34 | 0 | } |
35 | |
|
36 | 0 | osStr += "\""; |
37 | |
|
38 | 0 | return osStr; |
39 | 0 | } |
40 | | |
41 | | /************************************************************************/ |
42 | | /* OGRCARTOEscapeLiteralCopy( ) */ |
43 | | /************************************************************************/ |
44 | | |
45 | | CPLString OGRCARTOEscapeLiteralCopy(const char *pszStr) |
46 | 0 | { |
47 | 0 | CPLString osStr; |
48 | | |
49 | | /* convert special characters in COPY text format */ |
50 | | /* into their escaped forms, and double up the escape */ |
51 | | /* character */ |
52 | 0 | char ch = '\0'; |
53 | 0 | for (int i = 0; (ch = pszStr[i]) != '\0'; i++) |
54 | 0 | { |
55 | 0 | if (ch == '\t') // tab |
56 | 0 | osStr += "\\t"; |
57 | 0 | else if (ch == '\n') // new line |
58 | 0 | osStr += "\\n"; |
59 | 0 | else if (ch == '\r') // carriage return |
60 | 0 | osStr += "\\r"; |
61 | 0 | else if (ch == '\\') // escape character |
62 | 0 | osStr += "\\\\"; |
63 | 0 | else |
64 | 0 | osStr.append(1, ch); |
65 | 0 | } |
66 | |
|
67 | 0 | return osStr; |
68 | 0 | } |
69 | | |
70 | | /************************************************************************/ |
71 | | /* OGRCARTOEscapeLiteral( ) */ |
72 | | /************************************************************************/ |
73 | | |
74 | | CPLString OGRCARTOEscapeLiteral(const char *pszStr) |
75 | 0 | { |
76 | 0 | CPLString osStr; |
77 | |
|
78 | 0 | char ch = '\0'; |
79 | 0 | for (int i = 0; (ch = pszStr[i]) != '\0'; i++) |
80 | 0 | { |
81 | 0 | if (ch == '\'') |
82 | 0 | osStr.append(1, ch); |
83 | 0 | osStr.append(1, ch); |
84 | 0 | } |
85 | |
|
86 | 0 | return osStr; |
87 | 0 | } |
88 | | |
89 | | /************************************************************************/ |
90 | | /* OGRCARTOEscapeLiteral( ) */ |
91 | | /************************************************************************/ |
92 | | |
93 | | char *OGRCARTOTableLayer::OGRCARTOGetHexGeometry(OGRGeometry *poGeom, int i) |
94 | 0 | { |
95 | 0 | OGRCartoGeomFieldDefn *poGeomFieldDefn = |
96 | 0 | cpl::down_cast<OGRCartoGeomFieldDefn *>( |
97 | 0 | poFeatureDefn->GetGeomFieldDefn(i)); |
98 | 0 | int nSRID = poGeomFieldDefn->nSRID; |
99 | 0 | if (nSRID == 0) |
100 | 0 | nSRID = 4326; |
101 | 0 | char *pszEWKB; |
102 | 0 | if (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon && |
103 | 0 | wkbFlatten(GetGeomType()) == wkbMultiPolygon) |
104 | 0 | { |
105 | 0 | OGRMultiPolygon *poNewGeom = new OGRMultiPolygon(); |
106 | 0 | poNewGeom->addGeometry(poGeom); |
107 | 0 | pszEWKB = OGRGeometryToHexEWKB( |
108 | 0 | poNewGeom, nSRID, poDS->GetPostGISMajor(), poDS->GetPostGISMinor()); |
109 | 0 | delete poNewGeom; |
110 | 0 | } |
111 | 0 | else |
112 | 0 | pszEWKB = OGRGeometryToHexEWKB(poGeom, nSRID, poDS->GetPostGISMajor(), |
113 | 0 | poDS->GetPostGISMinor()); |
114 | 0 | return pszEWKB; |
115 | 0 | } |
116 | | |
117 | | /************************************************************************/ |
118 | | /* OGRCARTOTableLayer() */ |
119 | | /************************************************************************/ |
120 | | |
121 | | OGRCARTOTableLayer::OGRCARTOTableLayer(OGRCARTODataSource *poDSIn, |
122 | | const char *pszName) |
123 | 0 | : OGRCARTOLayer(poDSIn), osName(pszName) |
124 | 0 | { |
125 | 0 | SetDescription(osName); |
126 | 0 | bLaunderColumnNames = true; |
127 | 0 | bInDeferredInsert = poDS->DoBatchInsert(); |
128 | 0 | bCopyMode = poDS->DoCopyMode(); |
129 | 0 | eDeferredInsertState = INSERT_UNINIT; |
130 | 0 | m_nNextFIDWrite = -1; |
131 | 0 | bDeferredCreation = false; |
132 | 0 | bCartodbfy = false; |
133 | 0 | nMaxChunkSize = atoi(CPLGetConfigOption( |
134 | 0 | "CARTO_MAX_CHUNK_SIZE", |
135 | 0 | CPLGetConfigOption("CARTODB_MAX_CHUNK_SIZE", "15"))) * |
136 | 0 | 1024 * 1024; |
137 | 0 | bDropOnCreation = false; |
138 | 0 | } |
139 | | |
140 | | /************************************************************************/ |
141 | | /* ~OGRCARTOTableLayer() */ |
142 | | /************************************************************************/ |
143 | | |
144 | | OGRCARTOTableLayer::~OGRCARTOTableLayer() |
145 | | |
146 | 0 | { |
147 | 0 | if (bDeferredCreation) |
148 | 0 | RunDeferredCreationIfNecessary(); |
149 | 0 | CPL_IGNORE_RET_VAL(FlushDeferredBuffer()); |
150 | 0 | RunDeferredCartofy(); |
151 | 0 | } |
152 | | |
153 | | /************************************************************************/ |
154 | | /* GetLayerDefnInternal() */ |
155 | | /************************************************************************/ |
156 | | |
157 | | OGRFeatureDefn * |
158 | | OGRCARTOTableLayer::GetLayerDefnInternal(CPL_UNUSED json_object *poObjIn) |
159 | 0 | { |
160 | 0 | if (poFeatureDefn != nullptr) |
161 | 0 | return poFeatureDefn; |
162 | | |
163 | 0 | CPLString osCommand; |
164 | 0 | if (poDS->IsAuthenticatedConnection()) |
165 | 0 | { |
166 | | // Get everything ! |
167 | 0 | osCommand.Printf( |
168 | 0 | "SELECT a.attname, t.typname, a.attlen, " |
169 | 0 | "format_type(a.atttypid,a.atttypmod), " |
170 | 0 | "a.attnum, " |
171 | 0 | "a.attnotnull, " |
172 | 0 | "i.indisprimary, " |
173 | 0 | "pg_get_expr(def.adbin, c.oid) AS defaultexpr, " |
174 | 0 | "postgis_typmod_dims(a.atttypmod) dim, " |
175 | 0 | "postgis_typmod_srid(a.atttypmod) srid, " |
176 | 0 | "postgis_typmod_type(a.atttypmod)::text geomtyp, " |
177 | 0 | "srtext " |
178 | 0 | "FROM pg_class c " |
179 | 0 | "JOIN pg_attribute a ON a.attnum > 0 AND " |
180 | 0 | "a.attrelid = c.oid AND c.relname = '%s' " |
181 | 0 | "JOIN pg_type t ON a.atttypid = t.oid " |
182 | 0 | "JOIN pg_namespace n ON c.relnamespace=n.oid AND n.nspname= '%s' " |
183 | 0 | "LEFT JOIN pg_index i ON c.oid = i.indrelid AND " |
184 | 0 | "i.indisprimary = 't' AND a.attnum = ANY(i.indkey) " |
185 | 0 | "LEFT JOIN pg_attrdef def ON def.adrelid = c.oid AND " |
186 | 0 | "def.adnum = a.attnum " |
187 | 0 | "LEFT JOIN spatial_ref_sys srs ON srs.srid = " |
188 | 0 | "postgis_typmod_srid(a.atttypmod) " |
189 | 0 | "ORDER BY a.attnum", |
190 | 0 | OGRCARTOEscapeLiteral(osName).c_str(), |
191 | 0 | OGRCARTOEscapeLiteral(poDS->GetCurrentSchema()).c_str()); |
192 | 0 | } |
193 | 0 | else if (poDS->HasOGRMetadataFunction() != FALSE) |
194 | 0 | { |
195 | 0 | osCommand.Printf( |
196 | 0 | "SELECT * FROM ogr_table_metadata('%s', '%s')", |
197 | 0 | OGRCARTOEscapeLiteral(poDS->GetCurrentSchema()).c_str(), |
198 | 0 | OGRCARTOEscapeLiteral(osName).c_str()); |
199 | 0 | } |
200 | |
|
201 | 0 | if (!osCommand.empty()) |
202 | 0 | { |
203 | 0 | if (!poDS->IsAuthenticatedConnection() && |
204 | 0 | poDS->HasOGRMetadataFunction() < 0) |
205 | 0 | CPLPushErrorHandler(CPLQuietErrorHandler); |
206 | 0 | OGRLayer *poLyr = poDS->ExecuteSQLInternal(osCommand); |
207 | 0 | if (!poDS->IsAuthenticatedConnection() && |
208 | 0 | poDS->HasOGRMetadataFunction() < 0) |
209 | 0 | { |
210 | 0 | CPLPopErrorHandler(); |
211 | 0 | if (poLyr == nullptr) |
212 | 0 | { |
213 | 0 | CPLDebug("CARTO", |
214 | 0 | "ogr_table_metadata(text, text) not available"); |
215 | 0 | CPLErrorReset(); |
216 | 0 | } |
217 | 0 | else if (poLyr->GetLayerDefn()->GetFieldCount() != 12) |
218 | 0 | { |
219 | 0 | CPLDebug("CARTO", "ogr_table_metadata(text, text) has " |
220 | 0 | "unexpected column count"); |
221 | 0 | poDS->ReleaseResultSet(poLyr); |
222 | 0 | poLyr = nullptr; |
223 | 0 | } |
224 | 0 | poDS->SetOGRMetadataFunction(poLyr != nullptr); |
225 | 0 | } |
226 | 0 | if (poLyr) |
227 | 0 | { |
228 | 0 | OGRFeature *poFeat; |
229 | 0 | while ((poFeat = poLyr->GetNextFeature()) != nullptr) |
230 | 0 | { |
231 | 0 | if (poFeatureDefn == nullptr) |
232 | 0 | { |
233 | | // We could do that outside of the while() loop, but |
234 | | // by doing that here, we are somewhat robust to |
235 | | // ogr_table_metadata() returning suddenly an empty result |
236 | | // set for example if CDB_UserTables() no longer works |
237 | 0 | poFeatureDefn = new OGRFeatureDefn(osName); |
238 | 0 | poFeatureDefn->Reference(); |
239 | 0 | poFeatureDefn->SetGeomType(wkbNone); |
240 | 0 | } |
241 | |
|
242 | 0 | const char *pszAttname = poFeat->GetFieldAsString("attname"); |
243 | 0 | const char *pszType = poFeat->GetFieldAsString("typname"); |
244 | 0 | int nWidth = poFeat->GetFieldAsInteger("attlen"); |
245 | 0 | const char *pszFormatType = |
246 | 0 | poFeat->GetFieldAsString("format_type"); |
247 | 0 | int bNotNull = poFeat->GetFieldAsInteger("attnotnull"); |
248 | 0 | int bIsPrimary = poFeat->GetFieldAsInteger("indisprimary"); |
249 | 0 | int iDefaultExpr = |
250 | 0 | poLyr->GetLayerDefn()->GetFieldIndex("defaultexpr"); |
251 | 0 | const char *pszDefault = |
252 | 0 | (iDefaultExpr >= 0 && |
253 | 0 | poFeat->IsFieldSetAndNotNull(iDefaultExpr)) |
254 | 0 | ? poFeat->GetFieldAsString(iDefaultExpr) |
255 | 0 | : nullptr; |
256 | |
|
257 | 0 | if (bIsPrimary && |
258 | 0 | (EQUAL(pszType, "int2") || EQUAL(pszType, "int4") || |
259 | 0 | EQUAL(pszType, "int8") || EQUAL(pszType, "serial") || |
260 | 0 | EQUAL(pszType, "bigserial"))) |
261 | 0 | { |
262 | 0 | osFIDColName = pszAttname; |
263 | 0 | } |
264 | 0 | else if (strcmp(pszAttname, "created_at") == 0 || |
265 | 0 | strcmp(pszAttname, "updated_at") == 0 || |
266 | 0 | strcmp(pszAttname, "the_geom_webmercator") == 0) |
267 | 0 | { |
268 | | /* ignored */ |
269 | 0 | } |
270 | 0 | else |
271 | 0 | { |
272 | 0 | if (EQUAL(pszType, "geometry")) |
273 | 0 | { |
274 | 0 | int nDim = poFeat->GetFieldAsInteger("dim"); |
275 | 0 | int nSRID = poFeat->GetFieldAsInteger("srid"); |
276 | 0 | const char *pszGeomType = |
277 | 0 | poFeat->GetFieldAsString("geomtyp"); |
278 | 0 | const char *pszSRText = |
279 | 0 | (poFeat->IsFieldSetAndNotNull( |
280 | 0 | poLyr->GetLayerDefn()->GetFieldIndex("srtext"))) |
281 | 0 | ? poFeat->GetFieldAsString("srtext") |
282 | 0 | : nullptr; |
283 | 0 | OGRwkbGeometryType eType = |
284 | 0 | OGRFromOGCGeomType(pszGeomType); |
285 | 0 | if (nDim == 3) |
286 | 0 | eType = wkbSetZ(eType); |
287 | 0 | auto poFieldDefn = |
288 | 0 | std::make_unique<OGRCartoGeomFieldDefn>(pszAttname, |
289 | 0 | eType); |
290 | 0 | if (bNotNull) |
291 | 0 | poFieldDefn->SetNullable(FALSE); |
292 | 0 | if (pszSRText != nullptr) |
293 | 0 | { |
294 | 0 | auto l_poSRS = new OGRSpatialReference(); |
295 | 0 | l_poSRS->SetAxisMappingStrategy( |
296 | 0 | OAMS_TRADITIONAL_GIS_ORDER); |
297 | |
|
298 | 0 | if (l_poSRS->importFromWkt(pszSRText) != |
299 | 0 | OGRERR_NONE) |
300 | 0 | { |
301 | 0 | delete l_poSRS; |
302 | 0 | l_poSRS = nullptr; |
303 | 0 | } |
304 | 0 | if (l_poSRS != nullptr) |
305 | 0 | { |
306 | 0 | poFieldDefn->SetSpatialRef(l_poSRS); |
307 | 0 | l_poSRS->Release(); |
308 | 0 | } |
309 | 0 | } |
310 | 0 | poFieldDefn->nSRID = nSRID; |
311 | 0 | poFeatureDefn->AddGeomFieldDefn(std::move(poFieldDefn)); |
312 | 0 | } |
313 | 0 | else |
314 | 0 | { |
315 | 0 | OGRFieldDefn oField(pszAttname, OFTString); |
316 | 0 | if (bNotNull) |
317 | 0 | oField.SetNullable(FALSE); |
318 | 0 | OGRPGCommonLayerSetType(oField, pszType, pszFormatType, |
319 | 0 | nWidth); |
320 | 0 | if (pszDefault) |
321 | 0 | OGRPGCommonLayerNormalizeDefault(&oField, |
322 | 0 | pszDefault); |
323 | |
|
324 | 0 | poFeatureDefn->AddFieldDefn(&oField); |
325 | 0 | } |
326 | 0 | } |
327 | 0 | delete poFeat; |
328 | 0 | } |
329 | |
|
330 | 0 | poDS->ReleaseResultSet(poLyr); |
331 | 0 | } |
332 | 0 | } |
333 | |
|
334 | 0 | if (poFeatureDefn == nullptr) |
335 | 0 | { |
336 | 0 | osBaseSQL.Printf("SELECT * FROM %s", |
337 | 0 | OGRCARTOEscapeIdentifier(osName).c_str()); |
338 | 0 | EstablishLayerDefn(osName, nullptr); |
339 | 0 | osBaseSQL = ""; |
340 | 0 | } |
341 | |
|
342 | 0 | if (!osFIDColName.empty()) |
343 | 0 | { |
344 | 0 | osBaseSQL = "SELECT "; |
345 | 0 | osBaseSQL += OGRCARTOEscapeIdentifier(osFIDColName); |
346 | 0 | } |
347 | 0 | for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++) |
348 | 0 | { |
349 | 0 | if (osBaseSQL.empty()) |
350 | 0 | osBaseSQL = "SELECT "; |
351 | 0 | else |
352 | 0 | osBaseSQL += ", "; |
353 | 0 | osBaseSQL += OGRCARTOEscapeIdentifier( |
354 | 0 | poFeatureDefn->GetGeomFieldDefn(i)->GetNameRef()); |
355 | 0 | } |
356 | 0 | for (int i = 0; i < poFeatureDefn->GetFieldCount(); i++) |
357 | 0 | { |
358 | 0 | if (osBaseSQL.empty()) |
359 | 0 | osBaseSQL = "SELECT "; |
360 | 0 | else |
361 | 0 | osBaseSQL += ", "; |
362 | 0 | osBaseSQL += OGRCARTOEscapeIdentifier( |
363 | 0 | poFeatureDefn->GetFieldDefn(i)->GetNameRef()); |
364 | 0 | } |
365 | 0 | if (osBaseSQL.empty()) |
366 | 0 | osBaseSQL = "SELECT *"; |
367 | 0 | osBaseSQL += " FROM "; |
368 | 0 | osBaseSQL += OGRCARTOEscapeIdentifier(osName); |
369 | |
|
370 | 0 | osSELECTWithoutWHERE = osBaseSQL; |
371 | |
|
372 | 0 | return poFeatureDefn; |
373 | 0 | } |
374 | | |
375 | | /************************************************************************/ |
376 | | /* FetchNewFeatures() */ |
377 | | /************************************************************************/ |
378 | | |
379 | | json_object *OGRCARTOTableLayer::FetchNewFeatures() |
380 | 0 | { |
381 | 0 | if (!osFIDColName.empty()) |
382 | 0 | { |
383 | 0 | CPLString osSQL; |
384 | 0 | osSQL.Printf( |
385 | 0 | "%s WHERE %s%s >= " CPL_FRMT_GIB " ORDER BY %s ASC LIMIT %d", |
386 | 0 | osSELECTWithoutWHERE.c_str(), |
387 | 0 | (osWHERE.size()) ? CPLSPrintf("%s AND ", osWHERE.c_str()) : "", |
388 | 0 | OGRCARTOEscapeIdentifier(osFIDColName).c_str(), m_nNextFID, |
389 | 0 | OGRCARTOEscapeIdentifier(osFIDColName).c_str(), |
390 | 0 | GetFeaturesToFetch()); |
391 | 0 | return poDS->RunSQL(osSQL); |
392 | 0 | } |
393 | 0 | else |
394 | 0 | return OGRCARTOLayer::FetchNewFeatures(); |
395 | 0 | } |
396 | | |
397 | | /************************************************************************/ |
398 | | /* GetNextRawFeature() */ |
399 | | /************************************************************************/ |
400 | | |
401 | | OGRFeature *OGRCARTOTableLayer::GetNextRawFeature() |
402 | 0 | { |
403 | 0 | if (bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE) |
404 | 0 | return nullptr; |
405 | 0 | if (FlushDeferredBuffer() != OGRERR_NONE) |
406 | 0 | return nullptr; |
407 | 0 | return OGRCARTOLayer::GetNextRawFeature(); |
408 | 0 | } |
409 | | |
410 | | /************************************************************************/ |
411 | | /* SetAttributeFilter() */ |
412 | | /************************************************************************/ |
413 | | |
414 | | OGRErr OGRCARTOTableLayer::SetAttributeFilter(const char *pszQuery) |
415 | | |
416 | 0 | { |
417 | 0 | GetLayerDefn(); |
418 | |
|
419 | 0 | if (pszQuery == nullptr) |
420 | 0 | osQuery = ""; |
421 | 0 | else |
422 | 0 | { |
423 | 0 | osQuery = "("; |
424 | 0 | osQuery += pszQuery; |
425 | 0 | osQuery += ")"; |
426 | 0 | } |
427 | |
|
428 | 0 | BuildWhere(); |
429 | |
|
430 | 0 | ResetReading(); |
431 | |
|
432 | 0 | return OGRERR_NONE; |
433 | 0 | } |
434 | | |
435 | | /************************************************************************/ |
436 | | /* ISetSpatialFilter() */ |
437 | | /************************************************************************/ |
438 | | |
439 | | OGRErr OGRCARTOTableLayer::ISetSpatialFilter(int iGeomField, |
440 | | const OGRGeometry *poGeomIn) |
441 | | |
442 | 0 | { |
443 | 0 | m_iGeomFieldFilter = iGeomField; |
444 | |
|
445 | 0 | if (InstallFilter(poGeomIn)) |
446 | 0 | { |
447 | 0 | BuildWhere(); |
448 | |
|
449 | 0 | ResetReading(); |
450 | 0 | } |
451 | |
|
452 | 0 | return OGRERR_NONE; |
453 | 0 | } |
454 | | |
455 | | /************************************************************************/ |
456 | | /* RunDeferredCartofy() */ |
457 | | /************************************************************************/ |
458 | | |
459 | | void OGRCARTOTableLayer::RunDeferredCartofy() |
460 | | |
461 | 0 | { |
462 | 0 | if (bCartodbfy) |
463 | 0 | { |
464 | 0 | bCartodbfy = false; |
465 | |
|
466 | 0 | CPLString osSQL; |
467 | 0 | if (poDS->GetCurrentSchema() == "public") |
468 | 0 | osSQL.Printf("SELECT cdb_cartodbfytable('%s')", |
469 | 0 | OGRCARTOEscapeLiteral(osName).c_str()); |
470 | 0 | else |
471 | 0 | osSQL.Printf( |
472 | 0 | "SELECT cdb_cartodbfytable('%s', '%s')", |
473 | 0 | OGRCARTOEscapeLiteral(poDS->GetCurrentSchema()).c_str(), |
474 | 0 | OGRCARTOEscapeLiteral(osName).c_str()); |
475 | |
|
476 | 0 | json_object *poObj = poDS->RunSQL(osSQL); |
477 | 0 | if (poObj != nullptr) |
478 | 0 | json_object_put(poObj); |
479 | 0 | } |
480 | 0 | } |
481 | | |
482 | | /************************************************************************/ |
483 | | /* CARTOGeometryType() */ |
484 | | /************************************************************************/ |
485 | | |
486 | | static CPLString OGRCARTOGeometryType(OGRCartoGeomFieldDefn *poGeomField) |
487 | 0 | { |
488 | 0 | OGRwkbGeometryType eType = poGeomField->GetType(); |
489 | 0 | const char *pszGeometryType = OGRToOGCGeomType(eType); |
490 | 0 | const char *suffix = ""; |
491 | |
|
492 | 0 | if (OGR_GT_HasM(eType) && OGR_GT_HasZ(eType)) |
493 | 0 | { |
494 | 0 | suffix = "ZM"; |
495 | 0 | } |
496 | 0 | else if (OGR_GT_HasM(eType)) |
497 | 0 | { |
498 | 0 | suffix = "M"; |
499 | 0 | } |
500 | 0 | else if (OGR_GT_HasZ(eType)) |
501 | 0 | { |
502 | 0 | suffix = "Z"; |
503 | 0 | } |
504 | |
|
505 | 0 | CPLString osSQL; |
506 | 0 | osSQL.Printf("Geometry(%s%s,%d)", pszGeometryType, suffix, |
507 | 0 | poGeomField->nSRID); |
508 | |
|
509 | 0 | return osSQL; |
510 | 0 | } |
511 | | |
512 | | /************************************************************************/ |
513 | | /* FlushDeferredBuffer() */ |
514 | | /************************************************************************/ |
515 | | |
516 | | OGRErr OGRCARTOTableLayer::FlushDeferredBuffer(bool bReset) |
517 | 0 | { |
518 | 0 | if (bCopyMode) |
519 | 0 | return FlushDeferredCopy(bReset); |
520 | 0 | else |
521 | 0 | return FlushDeferredInsert(bReset); |
522 | 0 | } |
523 | | |
524 | | /************************************************************************/ |
525 | | /* FlushDeferredInsert() */ |
526 | | /************************************************************************/ |
527 | | |
528 | | OGRErr OGRCARTOTableLayer::FlushDeferredInsert(bool bReset) |
529 | 0 | { |
530 | 0 | OGRErr eErr = OGRERR_NONE; |
531 | 0 | if (bInDeferredInsert && !osDeferredBuffer.empty()) |
532 | 0 | { |
533 | 0 | osDeferredBuffer = "BEGIN;" + osDeferredBuffer; |
534 | 0 | if (eDeferredInsertState == INSERT_MULTIPLE_FEATURE) |
535 | 0 | { |
536 | 0 | osDeferredBuffer += ";"; |
537 | 0 | eDeferredInsertState = INSERT_UNINIT; |
538 | 0 | } |
539 | 0 | osDeferredBuffer += "COMMIT;"; |
540 | |
|
541 | 0 | json_object *poObj = poDS->RunSQL(osDeferredBuffer); |
542 | 0 | if (poObj != nullptr) |
543 | 0 | { |
544 | 0 | json_object_put(poObj); |
545 | 0 | } |
546 | 0 | else |
547 | 0 | { |
548 | 0 | bInDeferredInsert = false; |
549 | 0 | eErr = OGRERR_FAILURE; |
550 | 0 | } |
551 | 0 | } |
552 | |
|
553 | 0 | osDeferredBuffer = ""; |
554 | 0 | if (bReset) |
555 | 0 | { |
556 | 0 | bInDeferredInsert = false; |
557 | 0 | m_nNextFIDWrite = -1; |
558 | 0 | } |
559 | 0 | return eErr; |
560 | 0 | } |
561 | | |
562 | | /************************************************************************/ |
563 | | /* FlushDeferredCopy() */ |
564 | | /************************************************************************/ |
565 | | |
566 | | OGRErr OGRCARTOTableLayer::FlushDeferredCopy(bool bReset) |
567 | 0 | { |
568 | 0 | OGRErr eErr = OGRERR_NONE; |
569 | 0 | if (!osDeferredBuffer.empty()) |
570 | 0 | { |
571 | | /* And end-of-file marker to data buffer */ |
572 | 0 | osDeferredBuffer += "\\.\n"; |
573 | |
|
574 | 0 | json_object *poObj = poDS->RunCopyFrom(osCopySQL, osDeferredBuffer); |
575 | 0 | if (poObj != nullptr) |
576 | 0 | { |
577 | 0 | json_object_put(poObj); |
578 | 0 | } |
579 | 0 | else |
580 | 0 | { |
581 | 0 | bInDeferredInsert = false; |
582 | 0 | eErr = OGRERR_FAILURE; |
583 | 0 | } |
584 | 0 | } |
585 | |
|
586 | 0 | osDeferredBuffer.clear(); |
587 | 0 | if (bReset) |
588 | 0 | { |
589 | 0 | bInDeferredInsert = false; |
590 | 0 | m_nNextFIDWrite = -1; |
591 | 0 | } |
592 | 0 | return eErr; |
593 | 0 | } |
594 | | |
595 | | /************************************************************************/ |
596 | | /* CreateGeomField() */ |
597 | | /************************************************************************/ |
598 | | |
599 | | OGRErr |
600 | | OGRCARTOTableLayer::CreateGeomField(const OGRGeomFieldDefn *poGeomFieldIn, |
601 | | CPL_UNUSED int bApproxOK) |
602 | 0 | { |
603 | 0 | if (!poDS->IsReadWrite()) |
604 | 0 | { |
605 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
606 | 0 | "Operation not available in read-only mode"); |
607 | 0 | return OGRERR_FAILURE; |
608 | 0 | } |
609 | | |
610 | 0 | OGRwkbGeometryType eType = poGeomFieldIn->GetType(); |
611 | 0 | if (eType == wkbNone) |
612 | 0 | { |
613 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
614 | 0 | "Cannot create geometry field of type wkbNone"); |
615 | 0 | return OGRERR_FAILURE; |
616 | 0 | } |
617 | | |
618 | 0 | const char *pszNameIn = poGeomFieldIn->GetNameRef(); |
619 | 0 | if (pszNameIn == nullptr || EQUAL(pszNameIn, "")) |
620 | 0 | { |
621 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
622 | 0 | "Cannot add un-named geometry field"); |
623 | 0 | return OGRERR_FAILURE; |
624 | 0 | } |
625 | | |
626 | | /* Flush the write buffer before trying this. */ |
627 | 0 | if (eDeferredInsertState == INSERT_MULTIPLE_FEATURE) |
628 | 0 | { |
629 | 0 | if (FlushDeferredBuffer() != OGRERR_NONE) |
630 | 0 | return OGRERR_FAILURE; |
631 | 0 | } |
632 | | |
633 | 0 | auto poGeomField = |
634 | 0 | std::make_unique<OGRCartoGeomFieldDefn>(pszNameIn, eType); |
635 | 0 | if (EQUAL(poGeomField->GetNameRef(), "")) |
636 | 0 | { |
637 | 0 | if (poFeatureDefn->GetGeomFieldCount() == 0) |
638 | 0 | poGeomField->SetName("the_geom"); |
639 | 0 | } |
640 | 0 | const auto poSRSIn = poGeomFieldIn->GetSpatialRef(); |
641 | 0 | if (poSRSIn) |
642 | 0 | { |
643 | 0 | auto l_poSRS = poSRSIn->Clone(); |
644 | 0 | l_poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); |
645 | 0 | poGeomField->SetSpatialRef(l_poSRS); |
646 | 0 | l_poSRS->Release(); |
647 | 0 | } |
648 | |
|
649 | 0 | if (bLaunderColumnNames) |
650 | 0 | { |
651 | 0 | char *pszSafeName = |
652 | 0 | OGRPGCommonLaunderName(poGeomField->GetNameRef(), "CARTO", false); |
653 | 0 | poGeomField->SetName(pszSafeName); |
654 | 0 | CPLFree(pszSafeName); |
655 | 0 | } |
656 | |
|
657 | 0 | const OGRSpatialReference *poSRS = poGeomField->GetSpatialRef(); |
658 | 0 | int nSRID = 0; |
659 | 0 | if (poSRS != nullptr) |
660 | 0 | nSRID = poDS->FetchSRSId(poSRS); |
661 | |
|
662 | 0 | poGeomField->SetType(eType); |
663 | 0 | poGeomField->SetNullable(poGeomFieldIn->IsNullable()); |
664 | 0 | poGeomField->nSRID = nSRID; |
665 | | |
666 | | /* -------------------------------------------------------------------- */ |
667 | | /* Create the new field. */ |
668 | | /* -------------------------------------------------------------------- */ |
669 | |
|
670 | 0 | if (!bDeferredCreation) |
671 | 0 | { |
672 | 0 | CPLString osSQL; |
673 | 0 | osSQL.Printf( |
674 | 0 | "ALTER TABLE %s ADD COLUMN %s %s", |
675 | 0 | OGRCARTOEscapeIdentifier(osName).c_str(), |
676 | 0 | OGRCARTOEscapeIdentifier(poGeomField->GetNameRef()).c_str(), |
677 | 0 | OGRCARTOGeometryType(poGeomField.get()).c_str()); |
678 | 0 | if (!poGeomField->IsNullable()) |
679 | 0 | osSQL += " NOT NULL"; |
680 | |
|
681 | 0 | json_object *poObj = poDS->RunSQL(osSQL); |
682 | 0 | if (poObj == nullptr) |
683 | 0 | return OGRERR_FAILURE; |
684 | 0 | json_object_put(poObj); |
685 | 0 | } |
686 | | |
687 | 0 | poFeatureDefn->AddGeomFieldDefn(std::move(poGeomField)); |
688 | 0 | return OGRERR_NONE; |
689 | 0 | } |
690 | | |
691 | | /************************************************************************/ |
692 | | /* CreateField() */ |
693 | | /************************************************************************/ |
694 | | |
695 | | OGRErr OGRCARTOTableLayer::CreateField(const OGRFieldDefn *poFieldIn, |
696 | | CPL_UNUSED int bApproxOK) |
697 | 0 | { |
698 | 0 | GetLayerDefn(); |
699 | |
|
700 | 0 | if (!poDS->IsReadWrite()) |
701 | 0 | { |
702 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
703 | 0 | "Operation not available in read-only mode"); |
704 | 0 | return OGRERR_FAILURE; |
705 | 0 | } |
706 | | |
707 | 0 | if (eDeferredInsertState == INSERT_MULTIPLE_FEATURE) |
708 | 0 | { |
709 | 0 | if (FlushDeferredBuffer() != OGRERR_NONE) |
710 | 0 | return OGRERR_FAILURE; |
711 | 0 | } |
712 | | |
713 | 0 | OGRFieldDefn oField(poFieldIn); |
714 | 0 | if (bLaunderColumnNames) |
715 | 0 | { |
716 | 0 | char *pszName = |
717 | 0 | OGRPGCommonLaunderName(oField.GetNameRef(), "CARTO", false); |
718 | 0 | oField.SetName(pszName); |
719 | 0 | CPLFree(pszName); |
720 | 0 | } |
721 | | |
722 | | /* -------------------------------------------------------------------- */ |
723 | | /* Create the new field. */ |
724 | | /* -------------------------------------------------------------------- */ |
725 | |
|
726 | 0 | if (!bDeferredCreation) |
727 | 0 | { |
728 | 0 | CPLString osSQL; |
729 | 0 | osSQL.Printf("ALTER TABLE %s ADD COLUMN %s %s", |
730 | 0 | OGRCARTOEscapeIdentifier(osName).c_str(), |
731 | 0 | OGRCARTOEscapeIdentifier(oField.GetNameRef()).c_str(), |
732 | 0 | OGRPGCommonLayerGetType(oField, false, true).c_str()); |
733 | 0 | if (!oField.IsNullable()) |
734 | 0 | osSQL += " NOT NULL"; |
735 | 0 | if (oField.GetDefault() != nullptr && !oField.IsDefaultDriverSpecific()) |
736 | 0 | { |
737 | 0 | osSQL += " DEFAULT "; |
738 | 0 | osSQL += OGRPGCommonLayerGetPGDefault(&oField); |
739 | 0 | } |
740 | |
|
741 | 0 | json_object *poObj = poDS->RunSQL(osSQL); |
742 | 0 | if (poObj == nullptr) |
743 | 0 | return OGRERR_FAILURE; |
744 | 0 | json_object_put(poObj); |
745 | 0 | } |
746 | | |
747 | 0 | poFeatureDefn->AddFieldDefn(&oField); |
748 | |
|
749 | 0 | return OGRERR_NONE; |
750 | 0 | } |
751 | | |
752 | | /************************************************************************/ |
753 | | /* DeleteField() */ |
754 | | /************************************************************************/ |
755 | | |
756 | | OGRErr OGRCARTOTableLayer::DeleteField(int iField) |
757 | 0 | { |
758 | 0 | CPLString osSQL; |
759 | |
|
760 | 0 | if (!poDS->IsReadWrite()) |
761 | 0 | { |
762 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
763 | 0 | "Operation not available in read-only mode"); |
764 | 0 | return OGRERR_FAILURE; |
765 | 0 | } |
766 | | |
767 | 0 | if (iField < 0 || iField >= poFeatureDefn->GetFieldCount()) |
768 | 0 | { |
769 | 0 | CPLError(CE_Failure, CPLE_NotSupported, "Invalid field index"); |
770 | 0 | return OGRERR_FAILURE; |
771 | 0 | } |
772 | | |
773 | 0 | if (eDeferredInsertState == INSERT_MULTIPLE_FEATURE) |
774 | 0 | { |
775 | 0 | if (FlushDeferredBuffer() != OGRERR_NONE) |
776 | 0 | return OGRERR_FAILURE; |
777 | 0 | } |
778 | | |
779 | | /* -------------------------------------------------------------------- */ |
780 | | /* Drop the field. */ |
781 | | /* -------------------------------------------------------------------- */ |
782 | | |
783 | 0 | osSQL.Printf("ALTER TABLE %s DROP COLUMN %s", |
784 | 0 | OGRCARTOEscapeIdentifier(osName).c_str(), |
785 | 0 | OGRCARTOEscapeIdentifier( |
786 | 0 | poFeatureDefn->GetFieldDefn(iField)->GetNameRef()) |
787 | 0 | .c_str()); |
788 | |
|
789 | 0 | json_object *poObj = poDS->RunSQL(osSQL); |
790 | 0 | if (poObj == nullptr) |
791 | 0 | return OGRERR_FAILURE; |
792 | 0 | json_object_put(poObj); |
793 | |
|
794 | 0 | return poFeatureDefn->DeleteFieldDefn(iField); |
795 | 0 | } |
796 | | |
797 | | /************************************************************************/ |
798 | | /* ICreateFeature() */ |
799 | | /************************************************************************/ |
800 | | |
801 | | OGRErr OGRCARTOTableLayer::ICreateFeature(OGRFeature *poFeature) |
802 | | |
803 | 0 | { |
804 | 0 | if (bDeferredCreation) |
805 | 0 | { |
806 | 0 | if (RunDeferredCreationIfNecessary() != OGRERR_NONE) |
807 | 0 | return OGRERR_FAILURE; |
808 | 0 | } |
809 | | |
810 | 0 | GetLayerDefn(); |
811 | 0 | bool bHasUserFieldMatchingFID = false; |
812 | 0 | if (!osFIDColName.empty()) |
813 | 0 | bHasUserFieldMatchingFID = |
814 | 0 | poFeatureDefn->GetFieldIndex(osFIDColName) >= 0; |
815 | |
|
816 | 0 | if (!poDS->IsReadWrite()) |
817 | 0 | { |
818 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
819 | 0 | "Operation not available in read-only mode"); |
820 | 0 | return OGRERR_FAILURE; |
821 | 0 | } |
822 | | |
823 | 0 | CPLString osSQL; |
824 | |
|
825 | 0 | bool bHasJustGotNextFID = false; |
826 | 0 | if (!bHasUserFieldMatchingFID && bInDeferredInsert && m_nNextFIDWrite < 0 && |
827 | 0 | !osFIDColName.empty()) |
828 | 0 | { |
829 | 0 | CPLString osSeqName; |
830 | 0 | osSQL.Printf( |
831 | 0 | "SELECT pg_catalog.pg_get_serial_sequence('%s', '%s') AS seq_name", |
832 | 0 | OGRCARTOEscapeLiteral(osName).c_str(), |
833 | 0 | OGRCARTOEscapeLiteral(osFIDColName).c_str()); |
834 | 0 | json_object *poObj = poDS->RunSQL(osSQL); |
835 | 0 | json_object *poRowObj = OGRCARTOGetSingleRow(poObj); |
836 | 0 | if (poRowObj != nullptr) |
837 | 0 | { |
838 | 0 | json_object *poSeqName = |
839 | 0 | CPL_json_object_object_get(poRowObj, "seq_name"); |
840 | 0 | if (poSeqName != nullptr && |
841 | 0 | json_object_get_type(poSeqName) == json_type_string) |
842 | 0 | { |
843 | 0 | osSeqName = json_object_get_string(poSeqName); |
844 | 0 | } |
845 | 0 | } |
846 | |
|
847 | 0 | if (poObj != nullptr) |
848 | 0 | json_object_put(poObj); |
849 | |
|
850 | 0 | if (!osSeqName.empty()) |
851 | 0 | { |
852 | 0 | osSQL.Printf("SELECT nextval('%s') AS nextid", |
853 | 0 | OGRCARTOEscapeLiteral(osSeqName).c_str()); |
854 | |
|
855 | 0 | poObj = poDS->RunSQL(osSQL); |
856 | 0 | poRowObj = OGRCARTOGetSingleRow(poObj); |
857 | 0 | if (poRowObj != nullptr) |
858 | 0 | { |
859 | 0 | json_object *poID = |
860 | 0 | CPL_json_object_object_get(poRowObj, "nextid"); |
861 | 0 | if (poID != nullptr && |
862 | 0 | json_object_get_type(poID) == json_type_int) |
863 | 0 | { |
864 | 0 | m_nNextFIDWrite = json_object_get_int64(poID); |
865 | 0 | bHasJustGotNextFID = true; |
866 | 0 | } |
867 | 0 | } |
868 | |
|
869 | 0 | if (poObj != nullptr) |
870 | 0 | json_object_put(poObj); |
871 | 0 | } |
872 | 0 | } |
873 | |
|
874 | 0 | if (bCopyMode) |
875 | 0 | return ICreateFeatureCopy(poFeature, bHasUserFieldMatchingFID, |
876 | 0 | bHasJustGotNextFID); |
877 | 0 | else |
878 | 0 | return ICreateFeatureInsert(poFeature, bHasUserFieldMatchingFID, |
879 | 0 | bHasJustGotNextFID); |
880 | 0 | } |
881 | | |
882 | | /************************************************************************/ |
883 | | /* ICreateFeatureCopy() */ |
884 | | /************************************************************************/ |
885 | | |
886 | | OGRErr OGRCARTOTableLayer::ICreateFeatureCopy(OGRFeature *poFeature, |
887 | | bool bHasUserFieldMatchingFID, |
888 | | bool bHasJustGotNextFID) |
889 | 0 | { |
890 | 0 | CPLString osCopyFile; |
891 | 0 | GetLayerDefn(); |
892 | |
|
893 | 0 | if (eDeferredInsertState == INSERT_MULTIPLE_FEATURE) |
894 | 0 | { |
895 | 0 | bool bReset = false; |
896 | 0 | if (m_abFieldSetForInsert.size() != |
897 | 0 | static_cast<size_t>(poFeatureDefn->GetFieldCount())) |
898 | 0 | { |
899 | 0 | bReset = true; |
900 | 0 | } |
901 | 0 | else |
902 | 0 | { |
903 | 0 | for (int i = 0; i < poFeatureDefn->GetFieldCount(); i++) |
904 | 0 | { |
905 | 0 | if (m_abFieldSetForInsert[i] != |
906 | 0 | CPL_TO_BOOL(poFeature->IsFieldSet(i))) |
907 | 0 | { |
908 | 0 | bReset = true; |
909 | 0 | break; |
910 | 0 | } |
911 | 0 | } |
912 | 0 | } |
913 | 0 | if (bReset) |
914 | 0 | { |
915 | 0 | if (FlushDeferredBuffer(false) != OGRERR_NONE) |
916 | 0 | { |
917 | 0 | return OGRERR_FAILURE; |
918 | 0 | } |
919 | 0 | eDeferredInsertState = INSERT_UNINIT; |
920 | 0 | } |
921 | 0 | } |
922 | | |
923 | | /* We are doing a new COPY for each full buffer, so we will */ |
924 | | /* construct a new COPY statement here, even though we could */ |
925 | | /* reuse the same one over and over if we cached it (hmm) */ |
926 | 0 | if (eDeferredInsertState == INSERT_UNINIT) |
927 | 0 | { |
928 | 0 | osCopySQL.clear(); |
929 | 0 | osCopySQL.Printf("COPY %s ", OGRCARTOEscapeIdentifier(osName).c_str()); |
930 | 0 | bool bMustComma = false; |
931 | | /* Non-spatial column names */ |
932 | 0 | m_abFieldSetForInsert.resize(poFeatureDefn->GetFieldCount()); |
933 | 0 | for (int i = 0; i < poFeatureDefn->GetFieldCount(); i++) |
934 | 0 | { |
935 | | /* We base the columns we attempt to COPY based on */ |
936 | | /* the set pattern of the first feature we see. */ |
937 | 0 | m_abFieldSetForInsert[i] = CPL_TO_BOOL(poFeature->IsFieldSet(i)); |
938 | 0 | if (!poFeature->IsFieldSet(i)) |
939 | 0 | continue; |
940 | | |
941 | 0 | if (bMustComma) |
942 | 0 | osCopySQL += ","; |
943 | 0 | else |
944 | 0 | { |
945 | 0 | osCopySQL += "("; |
946 | 0 | bMustComma = true; |
947 | 0 | } |
948 | |
|
949 | 0 | osCopySQL += OGRCARTOEscapeIdentifier( |
950 | 0 | poFeatureDefn->GetFieldDefn(i)->GetNameRef()); |
951 | 0 | } |
952 | | /* Geometry column names */ |
953 | 0 | for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++) |
954 | 0 | { |
955 | 0 | if (bMustComma) |
956 | 0 | osCopySQL += ","; |
957 | 0 | else |
958 | 0 | bMustComma = true; |
959 | |
|
960 | 0 | osCopySQL += OGRCARTOEscapeIdentifier( |
961 | 0 | poFeatureDefn->GetGeomFieldDefn(i)->GetNameRef()); |
962 | 0 | } |
963 | | /* FID column */ |
964 | 0 | if (!bHasUserFieldMatchingFID && !osFIDColName.empty() && |
965 | 0 | (poFeature->GetFID() != OGRNullFID || |
966 | 0 | (m_nNextFIDWrite >= 0 && bHasJustGotNextFID))) |
967 | 0 | { |
968 | 0 | if (bMustComma) |
969 | 0 | osCopySQL += ","; |
970 | 0 | else |
971 | 0 | { |
972 | 0 | osCopySQL += "("; |
973 | 0 | bMustComma = true; |
974 | 0 | } |
975 | |
|
976 | 0 | osCopySQL += OGRCARTOEscapeIdentifier(osFIDColName); |
977 | 0 | } |
978 | | /* No columns at all? Return an error! */ |
979 | 0 | if (!bMustComma) |
980 | 0 | return OGRERR_FAILURE; |
981 | 0 | else |
982 | 0 | osCopySQL += ")"; |
983 | | |
984 | 0 | osCopySQL += " FROM STDIN WITH (FORMAT text, ENCODING UTF8)"; |
985 | 0 | CPLDebug("CARTO", "ICreateFeatureCopy(%s)", osCopySQL.c_str()); |
986 | |
|
987 | 0 | eDeferredInsertState = INSERT_MULTIPLE_FEATURE; |
988 | 0 | } |
989 | | |
990 | | /* Now write the data line into the copy file */ |
991 | 0 | bool bMustTab = false; |
992 | 0 | for (int i = 0; i < poFeatureDefn->GetFieldCount(); i++) |
993 | 0 | { |
994 | | /* Unset fields get skipped (assuming same field set |
995 | | pattern as first input feature) */ |
996 | 0 | if (!poFeature->IsFieldSet(i)) |
997 | 0 | continue; |
998 | | |
999 | | /* Tab separator for 'text' format as necessary */ |
1000 | 0 | if (bMustTab) |
1001 | 0 | osCopyFile += "\t"; |
1002 | 0 | else |
1003 | 0 | bMustTab = true; |
1004 | |
|
1005 | 0 | OGRFieldType eType = poFeatureDefn->GetFieldDefn(i)->GetType(); |
1006 | | /* Null fields get a NULL marker */ |
1007 | 0 | if (poFeature->IsFieldNull(i)) |
1008 | 0 | { |
1009 | 0 | osCopyFile += "\\N"; |
1010 | 0 | } |
1011 | 0 | else if (eType == OFTString || eType == OFTDateTime || |
1012 | 0 | eType == OFTDate || eType == OFTTime) |
1013 | 0 | { |
1014 | | /* Strip out tab and newline characters */ |
1015 | 0 | osCopyFile += |
1016 | 0 | OGRCARTOEscapeLiteralCopy(poFeature->GetFieldAsString(i)); |
1017 | 0 | } |
1018 | 0 | else if ((eType == OFTInteger || eType == OFTInteger64) && |
1019 | 0 | poFeatureDefn->GetFieldDefn(i)->GetSubType() == OFSTBoolean) |
1020 | 0 | { |
1021 | 0 | osCopyFile += poFeature->GetFieldAsInteger(i) ? "t" : "f"; |
1022 | 0 | } |
1023 | 0 | else |
1024 | 0 | osCopyFile += poFeature->GetFieldAsString(i); |
1025 | 0 | } |
1026 | |
|
1027 | 0 | for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++) |
1028 | 0 | { |
1029 | 0 | if (bMustTab) |
1030 | 0 | osCopyFile += "\t"; |
1031 | 0 | else |
1032 | 0 | bMustTab = true; |
1033 | |
|
1034 | 0 | OGRGeometry *poGeom = poFeature->GetGeomFieldRef(i); |
1035 | 0 | if (poGeom == nullptr) |
1036 | 0 | { |
1037 | 0 | osCopyFile += "\\N"; |
1038 | 0 | continue; |
1039 | 0 | } |
1040 | | |
1041 | 0 | char *pszEWKB = OGRCARTOGetHexGeometry(poGeom, i); |
1042 | 0 | osCopyFile += pszEWKB; |
1043 | 0 | CPLFree(pszEWKB); |
1044 | 0 | } |
1045 | |
|
1046 | 0 | if (!bHasUserFieldMatchingFID && !osFIDColName.empty()) |
1047 | 0 | { |
1048 | 0 | if (poFeature->GetFID() != OGRNullFID) |
1049 | 0 | { |
1050 | 0 | if (bMustTab) |
1051 | 0 | osCopyFile += "\t"; |
1052 | |
|
1053 | 0 | osCopyFile += CPLSPrintf(CPL_FRMT_GIB, poFeature->GetFID()); |
1054 | 0 | } |
1055 | 0 | else if (m_nNextFIDWrite >= 0 && bHasJustGotNextFID) |
1056 | 0 | { |
1057 | 0 | if (bMustTab) |
1058 | 0 | osCopyFile += "\t"; |
1059 | |
|
1060 | 0 | osCopyFile += CPLSPrintf(CPL_FRMT_GIB, m_nNextFIDWrite); |
1061 | 0 | } |
1062 | 0 | } |
1063 | | |
1064 | | /* If we do have access to the FID (because we're incrementing it */ |
1065 | | /* ourselves) set it onto the incoming feature so it knows what */ |
1066 | | /* FID was supplied by the back-end. */ |
1067 | 0 | if (!bHasUserFieldMatchingFID && !osFIDColName.empty() && |
1068 | 0 | m_nNextFIDWrite >= 0 && poFeature->GetFID() == OGRNullFID) |
1069 | 0 | { |
1070 | 0 | poFeature->SetFID(m_nNextFIDWrite); |
1071 | 0 | m_nNextFIDWrite++; |
1072 | 0 | } |
1073 | |
|
1074 | 0 | OGRErr eRet = OGRERR_NONE; |
1075 | | /* Add current record to buffer */ |
1076 | 0 | osDeferredBuffer += osCopyFile; |
1077 | 0 | osDeferredBuffer += "\n"; |
1078 | 0 | if ((int)osDeferredBuffer.size() > nMaxChunkSize) |
1079 | 0 | { |
1080 | 0 | eRet = FlushDeferredBuffer(false); |
1081 | 0 | eDeferredInsertState = INSERT_UNINIT; |
1082 | 0 | } |
1083 | |
|
1084 | 0 | return eRet; |
1085 | 0 | } |
1086 | | |
1087 | | /************************************************************************/ |
1088 | | /* ICreateFeatureInsert() */ |
1089 | | /************************************************************************/ |
1090 | | |
1091 | | OGRErr OGRCARTOTableLayer::ICreateFeatureInsert(OGRFeature *poFeature, |
1092 | | bool bHasUserFieldMatchingFID, |
1093 | | bool bHasJustGotNextFID) |
1094 | 0 | { |
1095 | 0 | CPLString osSQL; |
1096 | 0 | GetLayerDefn(); |
1097 | | |
1098 | | // Check if we can go on with multiple insertion mode |
1099 | 0 | if (eDeferredInsertState == INSERT_MULTIPLE_FEATURE) |
1100 | 0 | { |
1101 | 0 | if (!bHasUserFieldMatchingFID && !osFIDColName.empty() && |
1102 | 0 | (poFeature->GetFID() != OGRNullFID || |
1103 | 0 | (m_nNextFIDWrite >= 0 && bHasJustGotNextFID))) |
1104 | 0 | { |
1105 | 0 | if (FlushDeferredBuffer(false) != OGRERR_NONE) |
1106 | 0 | return OGRERR_FAILURE; |
1107 | 0 | } |
1108 | 0 | } |
1109 | | |
1110 | 0 | bool bWriteInsertInto = (eDeferredInsertState != INSERT_MULTIPLE_FEATURE); |
1111 | 0 | bool bResetToUninitInsertStateAfterwards = false; |
1112 | 0 | if (eDeferredInsertState == INSERT_UNINIT) |
1113 | 0 | { |
1114 | 0 | if (!bInDeferredInsert) |
1115 | 0 | { |
1116 | 0 | eDeferredInsertState = INSERT_SINGLE_FEATURE; |
1117 | 0 | } |
1118 | 0 | else if (!bHasUserFieldMatchingFID && !osFIDColName.empty() && |
1119 | 0 | (poFeature->GetFID() != OGRNullFID || |
1120 | 0 | (m_nNextFIDWrite >= 0 && bHasJustGotNextFID))) |
1121 | 0 | { |
1122 | 0 | eDeferredInsertState = INSERT_SINGLE_FEATURE; |
1123 | 0 | bResetToUninitInsertStateAfterwards = true; |
1124 | 0 | } |
1125 | 0 | else |
1126 | 0 | { |
1127 | 0 | eDeferredInsertState = INSERT_MULTIPLE_FEATURE; |
1128 | 0 | for (int i = 0; i < poFeatureDefn->GetFieldCount(); i++) |
1129 | 0 | { |
1130 | 0 | if (poFeatureDefn->GetFieldDefn(i)->GetDefault() != nullptr) |
1131 | 0 | eDeferredInsertState = INSERT_SINGLE_FEATURE; |
1132 | 0 | } |
1133 | 0 | } |
1134 | 0 | } |
1135 | |
|
1136 | 0 | bool bMustComma = false; |
1137 | 0 | if (bWriteInsertInto) |
1138 | 0 | { |
1139 | 0 | osSQL.Printf("INSERT INTO %s ", |
1140 | 0 | OGRCARTOEscapeIdentifier(osName).c_str()); |
1141 | 0 | for (int i = 0; i < poFeatureDefn->GetFieldCount(); i++) |
1142 | 0 | { |
1143 | 0 | if (eDeferredInsertState != INSERT_MULTIPLE_FEATURE && |
1144 | 0 | !poFeature->IsFieldSet(i)) |
1145 | 0 | continue; |
1146 | | |
1147 | 0 | if (bMustComma) |
1148 | 0 | osSQL += ", "; |
1149 | 0 | else |
1150 | 0 | { |
1151 | 0 | osSQL += "("; |
1152 | 0 | bMustComma = true; |
1153 | 0 | } |
1154 | |
|
1155 | 0 | osSQL += OGRCARTOEscapeIdentifier( |
1156 | 0 | poFeatureDefn->GetFieldDefn(i)->GetNameRef()); |
1157 | 0 | } |
1158 | |
|
1159 | 0 | for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++) |
1160 | 0 | { |
1161 | 0 | if (eDeferredInsertState != INSERT_MULTIPLE_FEATURE && |
1162 | 0 | poFeature->GetGeomFieldRef(i) == nullptr) |
1163 | 0 | continue; |
1164 | | |
1165 | 0 | if (bMustComma) |
1166 | 0 | osSQL += ", "; |
1167 | 0 | else |
1168 | 0 | { |
1169 | 0 | osSQL += "("; |
1170 | 0 | bMustComma = true; |
1171 | 0 | } |
1172 | |
|
1173 | 0 | osSQL += OGRCARTOEscapeIdentifier( |
1174 | 0 | poFeatureDefn->GetGeomFieldDefn(i)->GetNameRef()); |
1175 | 0 | } |
1176 | |
|
1177 | 0 | if (!bHasUserFieldMatchingFID && !osFIDColName.empty() && |
1178 | 0 | (poFeature->GetFID() != OGRNullFID || |
1179 | 0 | (m_nNextFIDWrite >= 0 && bHasJustGotNextFID))) |
1180 | 0 | { |
1181 | 0 | if (bMustComma) |
1182 | 0 | osSQL += ", "; |
1183 | 0 | else |
1184 | 0 | { |
1185 | 0 | osSQL += "("; |
1186 | 0 | bMustComma = true; |
1187 | 0 | } |
1188 | |
|
1189 | 0 | osSQL += OGRCARTOEscapeIdentifier(osFIDColName); |
1190 | 0 | } |
1191 | |
|
1192 | 0 | if (!bMustComma && eDeferredInsertState == INSERT_MULTIPLE_FEATURE) |
1193 | 0 | eDeferredInsertState = INSERT_SINGLE_FEATURE; |
1194 | 0 | } |
1195 | |
|
1196 | 0 | if (!bMustComma && eDeferredInsertState == INSERT_SINGLE_FEATURE) |
1197 | 0 | osSQL += "DEFAULT VALUES"; |
1198 | 0 | else |
1199 | 0 | { |
1200 | 0 | if (!bWriteInsertInto && |
1201 | 0 | eDeferredInsertState == INSERT_MULTIPLE_FEATURE) |
1202 | 0 | osSQL += ", ("; |
1203 | 0 | else |
1204 | 0 | osSQL += ") VALUES ("; |
1205 | |
|
1206 | 0 | bMustComma = false; |
1207 | 0 | for (int i = 0; i < poFeatureDefn->GetFieldCount(); i++) |
1208 | 0 | { |
1209 | 0 | if (!poFeature->IsFieldSet(i)) |
1210 | 0 | { |
1211 | 0 | if (eDeferredInsertState == INSERT_MULTIPLE_FEATURE) |
1212 | 0 | { |
1213 | 0 | if (bMustComma) |
1214 | 0 | osSQL += ", "; |
1215 | 0 | else |
1216 | 0 | bMustComma = true; |
1217 | 0 | osSQL += "NULL"; |
1218 | 0 | } |
1219 | 0 | continue; |
1220 | 0 | } |
1221 | | |
1222 | 0 | if (bMustComma) |
1223 | 0 | osSQL += ", "; |
1224 | 0 | else |
1225 | 0 | bMustComma = true; |
1226 | |
|
1227 | 0 | OGRFieldType eType = poFeatureDefn->GetFieldDefn(i)->GetType(); |
1228 | 0 | if (poFeature->IsFieldNull(i)) |
1229 | 0 | { |
1230 | 0 | osSQL += "NULL"; |
1231 | 0 | } |
1232 | 0 | else if (eType == OFTString || eType == OFTDateTime || |
1233 | 0 | eType == OFTDate || eType == OFTTime) |
1234 | 0 | { |
1235 | 0 | osSQL += "'"; |
1236 | 0 | osSQL += OGRCARTOEscapeLiteral(poFeature->GetFieldAsString(i)); |
1237 | 0 | osSQL += "'"; |
1238 | 0 | } |
1239 | 0 | else if ((eType == OFTInteger || eType == OFTInteger64) && |
1240 | 0 | poFeatureDefn->GetFieldDefn(i)->GetSubType() == |
1241 | 0 | OFSTBoolean) |
1242 | 0 | { |
1243 | 0 | osSQL += poFeature->GetFieldAsInteger(i) ? "'t'" : "'f'"; |
1244 | 0 | } |
1245 | 0 | else |
1246 | 0 | osSQL += poFeature->GetFieldAsString(i); |
1247 | 0 | } |
1248 | |
|
1249 | 0 | for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++) |
1250 | 0 | { |
1251 | 0 | OGRGeometry *poGeom = poFeature->GetGeomFieldRef(i); |
1252 | 0 | if (poGeom == nullptr) |
1253 | 0 | { |
1254 | 0 | if (eDeferredInsertState == INSERT_MULTIPLE_FEATURE) |
1255 | 0 | { |
1256 | 0 | if (bMustComma) |
1257 | 0 | osSQL += ", "; |
1258 | 0 | else |
1259 | 0 | bMustComma = true; |
1260 | 0 | osSQL += "NULL"; |
1261 | 0 | } |
1262 | 0 | continue; |
1263 | 0 | } |
1264 | | |
1265 | 0 | if (bMustComma) |
1266 | 0 | osSQL += ", "; |
1267 | 0 | else |
1268 | 0 | bMustComma = true; |
1269 | |
|
1270 | 0 | char *pszEWKB = OGRCARTOGetHexGeometry(poGeom, i); |
1271 | |
|
1272 | 0 | osSQL += "'"; |
1273 | 0 | osSQL += pszEWKB; |
1274 | 0 | osSQL += "'"; |
1275 | 0 | CPLFree(pszEWKB); |
1276 | 0 | } |
1277 | |
|
1278 | 0 | if (bWriteInsertInto && !bHasUserFieldMatchingFID && |
1279 | 0 | !osFIDColName.empty()) |
1280 | 0 | { |
1281 | 0 | if (poFeature->GetFID() != OGRNullFID) |
1282 | 0 | { |
1283 | 0 | if (bMustComma) |
1284 | 0 | osSQL += ", "; |
1285 | | // No need to set bMustComma to true in else case |
1286 | | // Not in a loop. |
1287 | |
|
1288 | 0 | osSQL += CPLSPrintf(CPL_FRMT_GIB, poFeature->GetFID()); |
1289 | 0 | } |
1290 | 0 | else if (m_nNextFIDWrite >= 0 && bHasJustGotNextFID) |
1291 | 0 | { |
1292 | 0 | if (bMustComma) |
1293 | 0 | osSQL += ", "; |
1294 | | // No need to set bMustComma to true in else case. |
1295 | | // Not in a loop. |
1296 | 0 | osSQL += CPLSPrintf(CPL_FRMT_GIB, m_nNextFIDWrite); |
1297 | 0 | } |
1298 | 0 | } |
1299 | |
|
1300 | 0 | osSQL += ")"; |
1301 | 0 | } |
1302 | |
|
1303 | 0 | if (!bHasUserFieldMatchingFID && !osFIDColName.empty() && |
1304 | 0 | m_nNextFIDWrite >= 0 && poFeature->GetFID() == OGRNullFID) |
1305 | 0 | { |
1306 | 0 | poFeature->SetFID(m_nNextFIDWrite); |
1307 | 0 | m_nNextFIDWrite++; |
1308 | 0 | } |
1309 | |
|
1310 | 0 | if (bInDeferredInsert) |
1311 | 0 | { |
1312 | 0 | OGRErr eRet = OGRERR_NONE; |
1313 | | // In multiple mode, this would require rebuilding the osSQL |
1314 | | // buffer. Annoying. |
1315 | 0 | if (eDeferredInsertState == INSERT_SINGLE_FEATURE && |
1316 | 0 | !osDeferredBuffer.empty() && |
1317 | 0 | (int)osDeferredBuffer.size() + (int)osSQL.size() > nMaxChunkSize) |
1318 | 0 | { |
1319 | 0 | eRet = FlushDeferredBuffer(false); |
1320 | 0 | } |
1321 | |
|
1322 | 0 | osDeferredBuffer += osSQL; |
1323 | 0 | if (eDeferredInsertState == INSERT_SINGLE_FEATURE) |
1324 | 0 | osDeferredBuffer += ";"; |
1325 | |
|
1326 | 0 | if ((int)osDeferredBuffer.size() > nMaxChunkSize) |
1327 | 0 | { |
1328 | 0 | eRet = FlushDeferredBuffer(false); |
1329 | 0 | } |
1330 | |
|
1331 | 0 | if (bResetToUninitInsertStateAfterwards) |
1332 | 0 | eDeferredInsertState = INSERT_UNINIT; |
1333 | |
|
1334 | 0 | return eRet; |
1335 | 0 | } |
1336 | | |
1337 | 0 | if (!osFIDColName.empty()) |
1338 | 0 | { |
1339 | 0 | osSQL += " RETURNING "; |
1340 | 0 | osSQL += OGRCARTOEscapeIdentifier(osFIDColName); |
1341 | |
|
1342 | 0 | json_object *poObj = poDS->RunSQL(osSQL); |
1343 | 0 | json_object *poRowObj = OGRCARTOGetSingleRow(poObj); |
1344 | 0 | if (poRowObj == nullptr) |
1345 | 0 | { |
1346 | 0 | if (poObj != nullptr) |
1347 | 0 | json_object_put(poObj); |
1348 | 0 | return OGRERR_FAILURE; |
1349 | 0 | } |
1350 | | |
1351 | 0 | json_object *poID = CPL_json_object_object_get(poRowObj, osFIDColName); |
1352 | 0 | if (poID != nullptr && json_object_get_type(poID) == json_type_int) |
1353 | 0 | { |
1354 | 0 | poFeature->SetFID(json_object_get_int64(poID)); |
1355 | 0 | } |
1356 | |
|
1357 | 0 | if (poObj != nullptr) |
1358 | 0 | json_object_put(poObj); |
1359 | |
|
1360 | 0 | return OGRERR_NONE; |
1361 | 0 | } |
1362 | 0 | else |
1363 | 0 | { |
1364 | 0 | OGRErr eRet = OGRERR_FAILURE; |
1365 | 0 | json_object *poObj = poDS->RunSQL(osSQL); |
1366 | 0 | if (poObj != nullptr) |
1367 | 0 | { |
1368 | 0 | json_object *poTotalRows = |
1369 | 0 | CPL_json_object_object_get(poObj, "total_rows"); |
1370 | 0 | if (poTotalRows != nullptr && |
1371 | 0 | json_object_get_type(poTotalRows) == json_type_int) |
1372 | 0 | { |
1373 | 0 | int nTotalRows = json_object_get_int(poTotalRows); |
1374 | 0 | if (nTotalRows == 1) |
1375 | 0 | { |
1376 | 0 | eRet = OGRERR_NONE; |
1377 | 0 | } |
1378 | 0 | } |
1379 | 0 | json_object_put(poObj); |
1380 | 0 | } |
1381 | |
|
1382 | 0 | return eRet; |
1383 | 0 | } |
1384 | 0 | } |
1385 | | |
1386 | | /************************************************************************/ |
1387 | | /* ISetFeature() */ |
1388 | | /************************************************************************/ |
1389 | | |
1390 | | OGRErr OGRCARTOTableLayer::ISetFeature(OGRFeature *poFeature) |
1391 | | |
1392 | 0 | { |
1393 | 0 | if (bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE) |
1394 | 0 | return OGRERR_FAILURE; |
1395 | 0 | if (FlushDeferredBuffer() != OGRERR_NONE) |
1396 | 0 | return OGRERR_FAILURE; |
1397 | | |
1398 | 0 | GetLayerDefn(); |
1399 | |
|
1400 | 0 | if (!poDS->IsReadWrite()) |
1401 | 0 | { |
1402 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
1403 | 0 | "Operation not available in read-only mode"); |
1404 | 0 | return OGRERR_FAILURE; |
1405 | 0 | } |
1406 | | |
1407 | 0 | if (poFeature->GetFID() == OGRNullFID) |
1408 | 0 | { |
1409 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
1410 | 0 | "FID required on features given to SetFeature()."); |
1411 | 0 | return OGRERR_FAILURE; |
1412 | 0 | } |
1413 | | |
1414 | 0 | CPLString osSQL; |
1415 | 0 | osSQL.Printf("UPDATE %s SET ", OGRCARTOEscapeIdentifier(osName).c_str()); |
1416 | 0 | bool bMustComma = false; |
1417 | 0 | for (int i = 0; i < poFeatureDefn->GetFieldCount(); i++) |
1418 | 0 | { |
1419 | 0 | if (!poFeature->IsFieldSet(i)) |
1420 | 0 | continue; |
1421 | | |
1422 | 0 | if (bMustComma) |
1423 | 0 | osSQL += ", "; |
1424 | 0 | else |
1425 | 0 | bMustComma = true; |
1426 | |
|
1427 | 0 | osSQL += OGRCARTOEscapeIdentifier( |
1428 | 0 | poFeatureDefn->GetFieldDefn(i)->GetNameRef()); |
1429 | 0 | osSQL += " = "; |
1430 | |
|
1431 | 0 | if (poFeature->IsFieldNull(i)) |
1432 | 0 | { |
1433 | 0 | osSQL += "NULL"; |
1434 | 0 | } |
1435 | 0 | else |
1436 | 0 | { |
1437 | 0 | OGRFieldType eType = poFeatureDefn->GetFieldDefn(i)->GetType(); |
1438 | 0 | if (eType == OFTString || eType == OFTDateTime || |
1439 | 0 | eType == OFTDate || eType == OFTTime) |
1440 | 0 | { |
1441 | 0 | osSQL += "'"; |
1442 | 0 | osSQL += OGRCARTOEscapeLiteral(poFeature->GetFieldAsString(i)); |
1443 | 0 | osSQL += "'"; |
1444 | 0 | } |
1445 | 0 | else if ((eType == OFTInteger || eType == OFTInteger64) && |
1446 | 0 | poFeatureDefn->GetFieldDefn(i)->GetSubType() == |
1447 | 0 | OFSTBoolean) |
1448 | 0 | { |
1449 | 0 | osSQL += poFeature->GetFieldAsInteger(i) ? "'t'" : "'f'"; |
1450 | 0 | } |
1451 | 0 | else |
1452 | 0 | osSQL += poFeature->GetFieldAsString(i); |
1453 | 0 | } |
1454 | 0 | } |
1455 | |
|
1456 | 0 | for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++) |
1457 | 0 | { |
1458 | 0 | if (bMustComma) |
1459 | 0 | osSQL += ", "; |
1460 | 0 | else |
1461 | 0 | bMustComma = true; |
1462 | |
|
1463 | 0 | osSQL += OGRCARTOEscapeIdentifier( |
1464 | 0 | poFeatureDefn->GetGeomFieldDefn(i)->GetNameRef()); |
1465 | 0 | osSQL += " = "; |
1466 | |
|
1467 | 0 | OGRGeometry *poGeom = poFeature->GetGeomFieldRef(i); |
1468 | 0 | if (poGeom == nullptr) |
1469 | 0 | { |
1470 | 0 | osSQL += "NULL"; |
1471 | 0 | } |
1472 | 0 | else |
1473 | 0 | { |
1474 | 0 | OGRCartoGeomFieldDefn *poGeomFieldDefn = |
1475 | 0 | cpl::down_cast<OGRCartoGeomFieldDefn *>( |
1476 | 0 | poFeatureDefn->GetGeomFieldDefn(i)); |
1477 | 0 | int nSRID = poGeomFieldDefn->nSRID; |
1478 | 0 | if (nSRID == 0) |
1479 | 0 | nSRID = 4326; |
1480 | 0 | char *pszEWKB = |
1481 | 0 | OGRGeometryToHexEWKB(poGeom, nSRID, poDS->GetPostGISMajor(), |
1482 | 0 | poDS->GetPostGISMinor()); |
1483 | 0 | osSQL += "'"; |
1484 | 0 | osSQL += pszEWKB; |
1485 | 0 | osSQL += "'"; |
1486 | 0 | CPLFree(pszEWKB); |
1487 | 0 | } |
1488 | 0 | } |
1489 | |
|
1490 | 0 | if (!bMustComma) // nothing to do |
1491 | 0 | return OGRERR_NONE; |
1492 | | |
1493 | 0 | osSQL += CPLSPrintf(" WHERE %s = " CPL_FRMT_GIB, |
1494 | 0 | OGRCARTOEscapeIdentifier(osFIDColName).c_str(), |
1495 | 0 | poFeature->GetFID()); |
1496 | |
|
1497 | 0 | OGRErr eRet = OGRERR_FAILURE; |
1498 | 0 | json_object *poObj = poDS->RunSQL(osSQL); |
1499 | 0 | if (poObj != nullptr) |
1500 | 0 | { |
1501 | 0 | json_object *poTotalRows = |
1502 | 0 | CPL_json_object_object_get(poObj, "total_rows"); |
1503 | 0 | if (poTotalRows != nullptr && |
1504 | 0 | json_object_get_type(poTotalRows) == json_type_int) |
1505 | 0 | { |
1506 | 0 | int nTotalRows = json_object_get_int(poTotalRows); |
1507 | 0 | if (nTotalRows > 0) |
1508 | 0 | { |
1509 | 0 | eRet = OGRERR_NONE; |
1510 | 0 | } |
1511 | 0 | else |
1512 | 0 | eRet = OGRERR_NON_EXISTING_FEATURE; |
1513 | 0 | } |
1514 | 0 | json_object_put(poObj); |
1515 | 0 | } |
1516 | |
|
1517 | 0 | return eRet; |
1518 | 0 | } |
1519 | | |
1520 | | /************************************************************************/ |
1521 | | /* DeleteFeature() */ |
1522 | | /************************************************************************/ |
1523 | | |
1524 | | OGRErr OGRCARTOTableLayer::DeleteFeature(GIntBig nFID) |
1525 | | |
1526 | 0 | { |
1527 | |
|
1528 | 0 | if (bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE) |
1529 | 0 | return OGRERR_FAILURE; |
1530 | 0 | if (FlushDeferredBuffer() != OGRERR_NONE) |
1531 | 0 | return OGRERR_FAILURE; |
1532 | | |
1533 | 0 | GetLayerDefn(); |
1534 | |
|
1535 | 0 | if (!poDS->IsReadWrite()) |
1536 | 0 | { |
1537 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
1538 | 0 | "Operation not available in read-only mode"); |
1539 | 0 | return OGRERR_FAILURE; |
1540 | 0 | } |
1541 | | |
1542 | 0 | if (osFIDColName.empty()) |
1543 | 0 | return OGRERR_FAILURE; |
1544 | | |
1545 | 0 | CPLString osSQL; |
1546 | 0 | osSQL.Printf("DELETE FROM %s WHERE %s = " CPL_FRMT_GIB, |
1547 | 0 | OGRCARTOEscapeIdentifier(osName).c_str(), |
1548 | 0 | OGRCARTOEscapeIdentifier(osFIDColName).c_str(), nFID); |
1549 | |
|
1550 | 0 | OGRErr eRet = OGRERR_FAILURE; |
1551 | 0 | json_object *poObj = poDS->RunSQL(osSQL); |
1552 | 0 | if (poObj != nullptr) |
1553 | 0 | { |
1554 | 0 | json_object *poTotalRows = |
1555 | 0 | CPL_json_object_object_get(poObj, "total_rows"); |
1556 | 0 | if (poTotalRows != nullptr && |
1557 | 0 | json_object_get_type(poTotalRows) == json_type_int) |
1558 | 0 | { |
1559 | 0 | int nTotalRows = json_object_get_int(poTotalRows); |
1560 | 0 | if (nTotalRows > 0) |
1561 | 0 | { |
1562 | 0 | eRet = OGRERR_NONE; |
1563 | 0 | } |
1564 | 0 | else |
1565 | 0 | eRet = OGRERR_NON_EXISTING_FEATURE; |
1566 | 0 | } |
1567 | 0 | json_object_put(poObj); |
1568 | 0 | } |
1569 | |
|
1570 | 0 | return eRet; |
1571 | 0 | } |
1572 | | |
1573 | | /************************************************************************/ |
1574 | | /* GetSRS_SQL() */ |
1575 | | /************************************************************************/ |
1576 | | |
1577 | | CPLString OGRCARTOTableLayer::GetSRS_SQL(const char *pszGeomCol) |
1578 | 0 | { |
1579 | 0 | CPLString osSQL; |
1580 | |
|
1581 | 0 | osSQL.Printf("SELECT srid, srtext FROM spatial_ref_sys WHERE srid IN " |
1582 | 0 | "(SELECT Find_SRID('%s', '%s', '%s'))", |
1583 | 0 | OGRCARTOEscapeLiteral(poDS->GetCurrentSchema()).c_str(), |
1584 | 0 | OGRCARTOEscapeLiteral(osName).c_str(), |
1585 | 0 | OGRCARTOEscapeLiteral(pszGeomCol).c_str()); |
1586 | |
|
1587 | 0 | return osSQL; |
1588 | 0 | } |
1589 | | |
1590 | | /************************************************************************/ |
1591 | | /* BuildWhere() */ |
1592 | | /* */ |
1593 | | /* Build the WHERE statement appropriate to the current set of */ |
1594 | | /* criteria (spatial and attribute queries). */ |
1595 | | /************************************************************************/ |
1596 | | |
1597 | | void OGRCARTOTableLayer::BuildWhere() |
1598 | | |
1599 | 0 | { |
1600 | 0 | osWHERE = ""; |
1601 | |
|
1602 | 0 | if (m_poFilterGeom != nullptr && m_iGeomFieldFilter >= 0 && |
1603 | 0 | m_iGeomFieldFilter < poFeatureDefn->GetGeomFieldCount()) |
1604 | 0 | { |
1605 | 0 | OGREnvelope sEnvelope; |
1606 | |
|
1607 | 0 | m_poFilterGeom->getEnvelope(&sEnvelope); |
1608 | |
|
1609 | 0 | CPLString osGeomColumn( |
1610 | 0 | poFeatureDefn->GetGeomFieldDefn(m_iGeomFieldFilter)->GetNameRef()); |
1611 | |
|
1612 | 0 | char szBox3D_1[128]; |
1613 | 0 | char szBox3D_2[128]; |
1614 | 0 | char *pszComma; |
1615 | |
|
1616 | 0 | CPLsnprintf(szBox3D_1, sizeof(szBox3D_1), "%.17g %.17g", sEnvelope.MinX, |
1617 | 0 | sEnvelope.MinY); |
1618 | 0 | while ((pszComma = strchr(szBox3D_1, ',')) != nullptr) |
1619 | 0 | *pszComma = '.'; |
1620 | 0 | CPLsnprintf(szBox3D_2, sizeof(szBox3D_2), "%.17g %.17g", sEnvelope.MaxX, |
1621 | 0 | sEnvelope.MaxY); |
1622 | 0 | while ((pszComma = strchr(szBox3D_2, ',')) != nullptr) |
1623 | 0 | *pszComma = '.'; |
1624 | 0 | osWHERE.Printf("(%s && 'BOX3D(%s, %s)'::box3d)", |
1625 | 0 | OGRCARTOEscapeIdentifier(osGeomColumn).c_str(), |
1626 | 0 | szBox3D_1, szBox3D_2); |
1627 | 0 | } |
1628 | |
|
1629 | 0 | if (!osQuery.empty()) |
1630 | 0 | { |
1631 | 0 | if (!osWHERE.empty()) |
1632 | 0 | osWHERE += " AND "; |
1633 | 0 | osWHERE += osQuery; |
1634 | 0 | } |
1635 | |
|
1636 | 0 | if (osFIDColName.empty()) |
1637 | 0 | { |
1638 | 0 | osBaseSQL = osSELECTWithoutWHERE; |
1639 | 0 | if (!osWHERE.empty()) |
1640 | 0 | { |
1641 | 0 | osBaseSQL += " WHERE "; |
1642 | 0 | osBaseSQL += osWHERE; |
1643 | 0 | } |
1644 | 0 | } |
1645 | 0 | } |
1646 | | |
1647 | | /************************************************************************/ |
1648 | | /* GetFeature() */ |
1649 | | /************************************************************************/ |
1650 | | |
1651 | | OGRFeature *OGRCARTOTableLayer::GetFeature(GIntBig nFeatureId) |
1652 | 0 | { |
1653 | |
|
1654 | 0 | if (bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE) |
1655 | 0 | return nullptr; |
1656 | 0 | if (FlushDeferredBuffer() != OGRERR_NONE) |
1657 | 0 | return nullptr; |
1658 | | |
1659 | 0 | GetLayerDefn(); |
1660 | |
|
1661 | 0 | if (osFIDColName.empty()) |
1662 | 0 | return OGRCARTOLayer::GetFeature(nFeatureId); |
1663 | | |
1664 | 0 | CPLString osSQL = osSELECTWithoutWHERE; |
1665 | 0 | osSQL += " WHERE "; |
1666 | 0 | osSQL += OGRCARTOEscapeIdentifier(osFIDColName).c_str(); |
1667 | 0 | osSQL += " = "; |
1668 | 0 | osSQL += CPLSPrintf(CPL_FRMT_GIB, nFeatureId); |
1669 | |
|
1670 | 0 | json_object *poObj = poDS->RunSQL(osSQL); |
1671 | 0 | json_object *poRowObj = OGRCARTOGetSingleRow(poObj); |
1672 | 0 | if (poRowObj == nullptr) |
1673 | 0 | { |
1674 | 0 | if (poObj != nullptr) |
1675 | 0 | json_object_put(poObj); |
1676 | 0 | return OGRCARTOLayer::GetFeature(nFeatureId); |
1677 | 0 | } |
1678 | | |
1679 | 0 | OGRFeature *poFeature = BuildFeature(poRowObj); |
1680 | 0 | json_object_put(poObj); |
1681 | |
|
1682 | 0 | return poFeature; |
1683 | 0 | } |
1684 | | |
1685 | | /************************************************************************/ |
1686 | | /* GetFeatureCount() */ |
1687 | | /************************************************************************/ |
1688 | | |
1689 | | GIntBig OGRCARTOTableLayer::GetFeatureCount(int bForce) |
1690 | 0 | { |
1691 | |
|
1692 | 0 | if (bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE) |
1693 | 0 | return 0; |
1694 | 0 | if (FlushDeferredBuffer() != OGRERR_NONE) |
1695 | 0 | return 0; |
1696 | | |
1697 | 0 | GetLayerDefn(); |
1698 | |
|
1699 | 0 | CPLString osSQL(CPLSPrintf("SELECT COUNT(*) FROM %s", |
1700 | 0 | OGRCARTOEscapeIdentifier(osName).c_str())); |
1701 | 0 | if (!osWHERE.empty()) |
1702 | 0 | { |
1703 | 0 | osSQL += " WHERE "; |
1704 | 0 | osSQL += osWHERE; |
1705 | 0 | } |
1706 | |
|
1707 | 0 | json_object *poObj = poDS->RunSQL(osSQL); |
1708 | 0 | json_object *poRowObj = OGRCARTOGetSingleRow(poObj); |
1709 | 0 | if (poRowObj == nullptr) |
1710 | 0 | { |
1711 | 0 | if (poObj != nullptr) |
1712 | 0 | json_object_put(poObj); |
1713 | 0 | return OGRCARTOLayer::GetFeatureCount(bForce); |
1714 | 0 | } |
1715 | | |
1716 | 0 | json_object *poCount = CPL_json_object_object_get(poRowObj, "count"); |
1717 | 0 | if (poCount == nullptr || json_object_get_type(poCount) != json_type_int) |
1718 | 0 | { |
1719 | 0 | json_object_put(poObj); |
1720 | 0 | return OGRCARTOLayer::GetFeatureCount(bForce); |
1721 | 0 | } |
1722 | | |
1723 | 0 | GIntBig nRet = (GIntBig)json_object_get_int64(poCount); |
1724 | |
|
1725 | 0 | json_object_put(poObj); |
1726 | |
|
1727 | 0 | return nRet; |
1728 | 0 | } |
1729 | | |
1730 | | /************************************************************************/ |
1731 | | /* IGetExtent() */ |
1732 | | /* */ |
1733 | | /* For PostGIS use internal Extend(geometry) function */ |
1734 | | /* in other cases we use standard OGRLayer::IGetExtent() */ |
1735 | | /************************************************************************/ |
1736 | | |
1737 | | OGRErr OGRCARTOTableLayer::IGetExtent(int iGeomField, OGREnvelope *psExtent, |
1738 | | bool bForce) |
1739 | 0 | { |
1740 | 0 | CPLString osSQL; |
1741 | |
|
1742 | 0 | if (bDeferredCreation && RunDeferredCreationIfNecessary() != OGRERR_NONE) |
1743 | 0 | return OGRERR_FAILURE; |
1744 | 0 | if (FlushDeferredBuffer() != OGRERR_NONE) |
1745 | 0 | return OGRERR_FAILURE; |
1746 | | |
1747 | 0 | OGRGeomFieldDefn *poGeomFieldDefn = |
1748 | 0 | poFeatureDefn->GetGeomFieldDefn(iGeomField); |
1749 | | |
1750 | | /* Do not take the spatial filter into account */ |
1751 | 0 | osSQL.Printf( |
1752 | 0 | "SELECT ST_Extent(%s) FROM %s", |
1753 | 0 | OGRCARTOEscapeIdentifier(poGeomFieldDefn->GetNameRef()).c_str(), |
1754 | 0 | OGRCARTOEscapeIdentifier(osName).c_str()); |
1755 | |
|
1756 | 0 | json_object *poObj = poDS->RunSQL(osSQL); |
1757 | 0 | json_object *poRowObj = OGRCARTOGetSingleRow(poObj); |
1758 | 0 | if (poRowObj != nullptr) |
1759 | 0 | { |
1760 | 0 | json_object *poExtent = |
1761 | 0 | CPL_json_object_object_get(poRowObj, "st_extent"); |
1762 | 0 | if (poExtent != nullptr && |
1763 | 0 | json_object_get_type(poExtent) == json_type_string) |
1764 | 0 | { |
1765 | 0 | const char *pszBox = json_object_get_string(poExtent); |
1766 | 0 | const char *ptr, *ptrEndParenthesis; |
1767 | 0 | char szVals[64 * 6 + 6]; |
1768 | |
|
1769 | 0 | ptr = strchr(pszBox, '('); |
1770 | 0 | if (ptr) |
1771 | 0 | ptr++; |
1772 | 0 | if (ptr == nullptr || |
1773 | 0 | (ptrEndParenthesis = strchr(ptr, ')')) == nullptr || |
1774 | 0 | ptrEndParenthesis - ptr > (int)(sizeof(szVals) - 1)) |
1775 | 0 | { |
1776 | 0 | CPLError(CE_Failure, CPLE_IllegalArg, |
1777 | 0 | "Bad extent representation: '%s'", pszBox); |
1778 | |
|
1779 | 0 | json_object_put(poObj); |
1780 | 0 | return OGRERR_FAILURE; |
1781 | 0 | } |
1782 | | |
1783 | 0 | strncpy(szVals, ptr, ptrEndParenthesis - ptr); |
1784 | 0 | szVals[ptrEndParenthesis - ptr] = '\0'; |
1785 | |
|
1786 | 0 | char **papszTokens = |
1787 | 0 | CSLTokenizeString2(szVals, " ,", CSLT_HONOURSTRINGS); |
1788 | 0 | int nTokenCnt = 4; |
1789 | |
|
1790 | 0 | if (CSLCount(papszTokens) != nTokenCnt) |
1791 | 0 | { |
1792 | 0 | CPLError(CE_Failure, CPLE_IllegalArg, |
1793 | 0 | "Bad extent representation: '%s'", pszBox); |
1794 | 0 | CSLDestroy(papszTokens); |
1795 | |
|
1796 | 0 | json_object_put(poObj); |
1797 | 0 | return OGRERR_FAILURE; |
1798 | 0 | } |
1799 | | |
1800 | | // Take X,Y coords |
1801 | | // For PostGIS ver >= 1.0.0 -> Tokens: X1 Y1 X2 Y2 (nTokenCnt = 4) |
1802 | | // For PostGIS ver < 1.0.0 -> Tokens: X1 Y1 Z1 X2 Y2 Z2 (nTokenCnt = |
1803 | | // 6) |
1804 | | // => X2 index calculated as nTokenCnt/2 |
1805 | | // Y2 index calculated as nTokenCnt/2+1 |
1806 | | |
1807 | 0 | psExtent->MinX = CPLAtof(papszTokens[0]); |
1808 | 0 | psExtent->MinY = CPLAtof(papszTokens[1]); |
1809 | 0 | psExtent->MaxX = CPLAtof(papszTokens[nTokenCnt / 2]); |
1810 | 0 | psExtent->MaxY = CPLAtof(papszTokens[nTokenCnt / 2 + 1]); |
1811 | |
|
1812 | 0 | CSLDestroy(papszTokens); |
1813 | |
|
1814 | 0 | json_object_put(poObj); |
1815 | 0 | return OGRERR_NONE; |
1816 | 0 | } |
1817 | 0 | } |
1818 | | |
1819 | 0 | if (poObj != nullptr) |
1820 | 0 | json_object_put(poObj); |
1821 | |
|
1822 | 0 | return OGRLayer::IGetExtent(iGeomField, psExtent, bForce); |
1823 | 0 | } |
1824 | | |
1825 | | /************************************************************************/ |
1826 | | /* TestCapability() */ |
1827 | | /************************************************************************/ |
1828 | | |
1829 | | int OGRCARTOTableLayer::TestCapability(const char *pszCap) const |
1830 | | |
1831 | 0 | { |
1832 | 0 | if (EQUAL(pszCap, OLCFastFeatureCount)) |
1833 | 0 | return TRUE; |
1834 | 0 | if (EQUAL(pszCap, OLCFastGetExtent)) |
1835 | 0 | return TRUE; |
1836 | 0 | if (EQUAL(pszCap, OLCRandomRead)) |
1837 | 0 | { |
1838 | 0 | GetLayerDefn(); |
1839 | 0 | return !osFIDColName.empty(); |
1840 | 0 | } |
1841 | | |
1842 | 0 | if (EQUAL(pszCap, OLCSequentialWrite) || EQUAL(pszCap, OLCRandomWrite) || |
1843 | 0 | EQUAL(pszCap, OLCDeleteFeature) || EQUAL(pszCap, OLCCreateField) || |
1844 | 0 | EQUAL(pszCap, OLCDeleteField) || EQUAL(pszCap, OLCCreateGeomField)) |
1845 | 0 | { |
1846 | 0 | return poDS->IsReadWrite(); |
1847 | 0 | } |
1848 | | |
1849 | 0 | return OGRCARTOLayer::TestCapability(pszCap); |
1850 | 0 | } |
1851 | | |
1852 | | /************************************************************************/ |
1853 | | /* SetDeferredCreation() */ |
1854 | | /************************************************************************/ |
1855 | | |
1856 | | void OGRCARTOTableLayer::SetDeferredCreation(OGRwkbGeometryType eGType, |
1857 | | OGRSpatialReference *poSRSIn, |
1858 | | bool bGeomNullable, |
1859 | | bool bCartodbfyIn) |
1860 | 0 | { |
1861 | 0 | bDeferredCreation = true; |
1862 | 0 | m_nNextFIDWrite = 1; |
1863 | 0 | CPLAssert(poFeatureDefn == nullptr); |
1864 | 0 | bCartodbfy = bCartodbfyIn; |
1865 | 0 | poFeatureDefn = new OGRFeatureDefn(osName); |
1866 | 0 | poFeatureDefn->Reference(); |
1867 | 0 | poFeatureDefn->SetGeomType(wkbNone); |
1868 | 0 | if (eGType == wkbPolygon) |
1869 | 0 | eGType = wkbMultiPolygon; |
1870 | 0 | else if (eGType == wkbPolygon25D) |
1871 | 0 | eGType = wkbMultiPolygon25D; |
1872 | 0 | if (eGType != wkbNone) |
1873 | 0 | { |
1874 | 0 | auto poFieldDefn = |
1875 | 0 | std::make_unique<OGRCartoGeomFieldDefn>("the_geom", eGType); |
1876 | 0 | poFieldDefn->SetNullable(bGeomNullable); |
1877 | 0 | if (poSRSIn != nullptr) |
1878 | 0 | { |
1879 | 0 | poFieldDefn->nSRID = poDS->FetchSRSId(poSRSIn); |
1880 | 0 | poFieldDefn->SetSpatialRef(poSRSIn); |
1881 | 0 | } |
1882 | 0 | poFeatureDefn->AddGeomFieldDefn(std::move(poFieldDefn)); |
1883 | 0 | } |
1884 | 0 | osFIDColName = "cartodb_id"; |
1885 | 0 | osBaseSQL.Printf("SELECT * FROM %s", |
1886 | 0 | OGRCARTOEscapeIdentifier(osName).c_str()); |
1887 | 0 | osSELECTWithoutWHERE = osBaseSQL; |
1888 | 0 | } |
1889 | | |
1890 | | /************************************************************************/ |
1891 | | /* RunDeferredCreationIfNecessary() */ |
1892 | | /************************************************************************/ |
1893 | | |
1894 | | OGRErr OGRCARTOTableLayer::RunDeferredCreationIfNecessary() |
1895 | 0 | { |
1896 | 0 | if (!bDeferredCreation) |
1897 | 0 | return OGRERR_NONE; |
1898 | 0 | bDeferredCreation = false; |
1899 | |
|
1900 | 0 | CPLString osSQL; |
1901 | 0 | CPLDebug("CARTO", "Overwrite on creation (%d)", bDropOnCreation); |
1902 | 0 | if (bDropOnCreation) |
1903 | 0 | osSQL.Printf("BEGIN; DROP TABLE IF EXISTS %s;", |
1904 | 0 | OGRCARTOEscapeIdentifier(osName).c_str()); |
1905 | |
|
1906 | 0 | osSQL += CPLSPrintf("CREATE TABLE %s ( %s SERIAL,", |
1907 | 0 | OGRCARTOEscapeIdentifier(osName).c_str(), |
1908 | 0 | osFIDColName.c_str()); |
1909 | |
|
1910 | 0 | for (int i = 0; i < poFeatureDefn->GetGeomFieldCount(); i++) |
1911 | 0 | { |
1912 | 0 | OGRCartoGeomFieldDefn *poFieldDefn = |
1913 | 0 | cpl::down_cast<OGRCartoGeomFieldDefn *>( |
1914 | 0 | poFeatureDefn->GetGeomFieldDefn(i)); |
1915 | 0 | OGRwkbGeometryType eGType = poFieldDefn->GetType(); |
1916 | 0 | if (eGType == wkbNone) |
1917 | 0 | continue; |
1918 | | |
1919 | 0 | const char *pszFieldName = "the_geom"; |
1920 | |
|
1921 | 0 | if (i > 0) |
1922 | 0 | pszFieldName = poFieldDefn->GetNameRef(); |
1923 | |
|
1924 | 0 | if (pszFieldName == nullptr || strlen(pszFieldName) == 0) |
1925 | 0 | return OGRERR_FAILURE; |
1926 | | |
1927 | 0 | osSQL += CPLSPrintf("%s %s%s,", pszFieldName, |
1928 | 0 | OGRCARTOGeometryType(poFieldDefn).c_str(), |
1929 | 0 | (!poFieldDefn->IsNullable()) ? " NOT NULL" : ""); |
1930 | 0 | } |
1931 | | |
1932 | 0 | for (int i = 0; i < poFeatureDefn->GetFieldCount(); i++) |
1933 | 0 | { |
1934 | 0 | OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn(i); |
1935 | 0 | if (strcmp(poFieldDefn->GetNameRef(), osFIDColName) != 0) |
1936 | 0 | { |
1937 | 0 | osSQL += OGRCARTOEscapeIdentifier(poFieldDefn->GetNameRef()); |
1938 | 0 | osSQL += " "; |
1939 | 0 | osSQL += OGRPGCommonLayerGetType(*poFieldDefn, false, true); |
1940 | 0 | if (!poFieldDefn->IsNullable()) |
1941 | 0 | osSQL += " NOT NULL"; |
1942 | 0 | if (poFieldDefn->GetDefault() != nullptr && |
1943 | 0 | !poFieldDefn->IsDefaultDriverSpecific()) |
1944 | 0 | { |
1945 | 0 | osSQL += " DEFAULT "; |
1946 | 0 | osSQL += poFieldDefn->GetDefault(); |
1947 | 0 | } |
1948 | 0 | osSQL += ","; |
1949 | 0 | } |
1950 | 0 | } |
1951 | |
|
1952 | 0 | osSQL += CPLSPrintf("PRIMARY KEY (%s) )", osFIDColName.c_str()); |
1953 | |
|
1954 | 0 | CPLString osSeqName(OGRCARTOEscapeIdentifier( |
1955 | 0 | CPLSPrintf("%s_%s_seq", osName.c_str(), osFIDColName.c_str()))); |
1956 | |
|
1957 | 0 | osSQL += ";"; |
1958 | 0 | osSQL += |
1959 | 0 | CPLSPrintf("DROP SEQUENCE IF EXISTS %s CASCADE", osSeqName.c_str()); |
1960 | 0 | osSQL += ";"; |
1961 | 0 | osSQL += CPLSPrintf("CREATE SEQUENCE %s START 1", osSeqName.c_str()); |
1962 | 0 | osSQL += ";"; |
1963 | 0 | osSQL += CPLSPrintf("ALTER SEQUENCE %s OWNED BY %s.%s", osSeqName.c_str(), |
1964 | 0 | OGRCARTOEscapeIdentifier(osName).c_str(), |
1965 | 0 | osFIDColName.c_str()); |
1966 | 0 | osSQL += ";"; |
1967 | 0 | osSQL += |
1968 | 0 | CPLSPrintf("ALTER TABLE %s ALTER COLUMN %s SET DEFAULT nextval('%s')", |
1969 | 0 | OGRCARTOEscapeIdentifier(osName).c_str(), |
1970 | 0 | osFIDColName.c_str(), osSeqName.c_str()); |
1971 | |
|
1972 | 0 | if (bDropOnCreation) |
1973 | 0 | osSQL += "; COMMIT;"; |
1974 | |
|
1975 | 0 | bDropOnCreation = false; |
1976 | |
|
1977 | 0 | json_object *poObj = poDS->RunSQL(osSQL); |
1978 | 0 | if (poObj == nullptr) |
1979 | 0 | return OGRERR_FAILURE; |
1980 | 0 | json_object_put(poObj); |
1981 | |
|
1982 | 0 | return OGRERR_NONE; |
1983 | 0 | } |