Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: SAP HANA Spatial Driver
4 : * Purpose: OGRHanaTableLayer class implementation
5 : * Author: Maxim Rylov
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2020, SAP SE
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_hana.h"
30 : #include "ogrhanafeaturereader.h"
31 : #include "ogrhanautils.h"
32 :
33 : #include <algorithm>
34 : #include <cmath>
35 : #include <cstdio>
36 : #include <cstring>
37 : #include <limits>
38 : #include <sstream>
39 :
40 : #include "odbc/Exception.h"
41 : #include "odbc/PreparedStatement.h"
42 : #include "odbc/ResultSet.h"
43 : #include "odbc/Statement.h"
44 : #include "odbc/Types.h"
45 :
46 : namespace OGRHANA
47 : {
48 : namespace
49 : {
50 :
51 : constexpr const char *UNSUPPORTED_OP_READ_ONLY =
52 : "%s : unsupported operation on a read-only datasource.";
53 :
54 12 : const char *GetColumnDefaultValue(const OGRFieldDefn &field)
55 : {
56 12 : const char *defaultValue = field.GetDefault();
57 12 : if (field.GetType() == OFTInteger && field.GetSubType() == OFSTBoolean)
58 0 : return (EQUAL(defaultValue, "1") || EQUAL(defaultValue, "'t'"))
59 1 : ? "TRUE"
60 1 : : "FALSE";
61 11 : return defaultValue;
62 : }
63 :
64 1 : CPLString FindGeomFieldName(const OGRFeatureDefn &featureDefn)
65 : {
66 1 : if (featureDefn.GetGeomFieldCount() == 0)
67 0 : return "OGR_GEOMETRY";
68 :
69 1 : int numGeomFields = featureDefn.GetGeomFieldCount();
70 1 : for (int i = 1; i <= 2 * numGeomFields; ++i)
71 : {
72 1 : CPLString name = CPLSPrintf("OGR_GEOMETRY_%d", i);
73 1 : if (featureDefn.GetGeomFieldIndex(name) < 0)
74 1 : return name;
75 : }
76 :
77 0 : return "OGR_GEOMETRY";
78 : }
79 :
80 93 : CPLString GetParameterValue(short type, const CPLString &typeName, bool isArray)
81 : {
82 93 : if (isArray)
83 : {
84 4 : CPLString arrayType = "STRING";
85 4 : switch (type)
86 : {
87 0 : case odbc::SQLDataTypes::TinyInt:
88 0 : arrayType = "TINYINT";
89 0 : break;
90 0 : case odbc::SQLDataTypes::SmallInt:
91 0 : arrayType = "SMALLINT";
92 0 : break;
93 1 : case odbc::SQLDataTypes::Integer:
94 1 : arrayType = "INT";
95 1 : break;
96 1 : case odbc::SQLDataTypes::BigInt:
97 1 : arrayType = "BIGINT";
98 1 : break;
99 0 : case odbc::SQLDataTypes::Float:
100 : case odbc::SQLDataTypes::Real:
101 0 : arrayType = "REAL";
102 0 : break;
103 1 : case odbc::SQLDataTypes::Double:
104 1 : arrayType = "DOUBLE";
105 1 : break;
106 1 : case odbc::SQLDataTypes::WVarChar:
107 1 : arrayType = "STRING";
108 1 : break;
109 : }
110 8 : return "ARRAY(SELECT * FROM OGR_PARSE_" + arrayType + "_ARRAY(?, '" +
111 8 : ARRAY_VALUES_DELIMITER + "'))";
112 : }
113 89 : else if (typeName.compare("NCLOB") == 0)
114 0 : return "TO_NCLOB(?)";
115 89 : else if (typeName.compare("CLOB") == 0)
116 0 : return "TO_CLOB(?)";
117 89 : else if (typeName.compare("BLOB") == 0)
118 0 : return "TO_BLOB(?)";
119 : else
120 89 : return "?";
121 : }
122 :
123 2 : std::vector<int> ParseIntValues(const std::string &str)
124 : {
125 2 : std::vector<int> values;
126 : try
127 : {
128 4 : std::stringstream stream(str);
129 6 : while (stream.good())
130 : {
131 4 : std::string value;
132 4 : std::getline(stream, value, ',');
133 4 : values.push_back(std::stoi(value.c_str()));
134 : }
135 : }
136 0 : catch (...)
137 : {
138 0 : values.clear();
139 : }
140 2 : return values;
141 : }
142 :
143 3 : ColumnTypeInfo ParseColumnTypeInfo(const CPLString &typeDef)
144 : {
145 0 : auto incorrectFormatErr = [&]()
146 : {
147 0 : CPLError(CE_Failure, CPLE_NotSupported,
148 0 : "Column type '%s' has incorrect format.", typeDef.c_str());
149 3 : };
150 :
151 6 : CPLString typeName;
152 6 : std::vector<int> typeSize;
153 :
154 3 : const size_t posStart = typeDef.find("(");
155 3 : if (posStart == std::string::npos)
156 : {
157 1 : typeName = typeDef;
158 : }
159 : else
160 : {
161 2 : const size_t posEnd = typeDef.rfind(")");
162 2 : if (posEnd != std::string::npos && posEnd > posStart)
163 : {
164 2 : const size_t posLast = typeDef.find_last_not_of(" \n\r\t");
165 2 : if (posLast == posEnd)
166 : {
167 2 : typeName = typeDef.substr(0, posStart);
168 : const std::string values =
169 2 : typeDef.substr(posStart + 1, posEnd - posStart - 1);
170 2 : typeSize = ParseIntValues(values);
171 : }
172 : }
173 :
174 2 : if (typeSize.empty() || typeSize.size() > 2)
175 : {
176 0 : incorrectFormatErr();
177 0 : return {"", odbc::SQLDataTypes::Unknown, 0, 0};
178 : }
179 : }
180 :
181 3 : typeName.Trim();
182 :
183 3 : if (EQUAL(typeName.c_str(), "BOOLEAN"))
184 0 : return {typeName, odbc::SQLDataTypes::Boolean, 0, 0};
185 3 : else if (EQUAL(typeName.c_str(), "TINYINT"))
186 0 : return {typeName, odbc::SQLDataTypes::TinyInt, 0, 0};
187 3 : else if (EQUAL(typeName.c_str(), "SMALLINT"))
188 1 : return {typeName, odbc::SQLDataTypes::SmallInt, 0, 0};
189 2 : else if (EQUAL(typeName.c_str(), "INTEGER"))
190 0 : return {typeName, odbc::SQLDataTypes::Integer, 0, 0};
191 2 : else if (EQUAL(typeName.c_str(), "DECIMAL"))
192 : {
193 2 : switch (typeSize.size())
194 : {
195 0 : case 0:
196 0 : return {typeName, odbc::SQLDataTypes::Decimal, 0, 0};
197 0 : case 1:
198 0 : return {typeName, odbc::SQLDataTypes::Decimal, typeSize[0], 0};
199 2 : case 2:
200 2 : return {typeName, odbc::SQLDataTypes::Decimal, typeSize[0],
201 2 : typeSize[1]};
202 : }
203 : }
204 0 : else if (EQUAL(typeName.c_str(), "FLOAT"))
205 : {
206 0 : switch (typeSize.size())
207 : {
208 0 : case 0:
209 0 : return {typeName, odbc::SQLDataTypes::Float, 10, 0};
210 0 : case 1:
211 0 : return {typeName, odbc::SQLDataTypes::Float, typeSize[0], 0};
212 0 : default:
213 0 : incorrectFormatErr();
214 0 : return {"", odbc::SQLDataTypes::Unknown, 0, 0};
215 : }
216 : }
217 0 : else if (EQUAL(typeName.c_str(), "REAL"))
218 0 : return {typeName, odbc::SQLDataTypes::Real, 0, 0};
219 0 : else if (EQUAL(typeName.c_str(), "DOUBLE"))
220 0 : return {typeName, odbc::SQLDataTypes::Double, 0, 0};
221 0 : else if (EQUAL(typeName.c_str(), "VARCHAR"))
222 : {
223 0 : switch (typeSize.size())
224 : {
225 0 : case 0:
226 0 : return {typeName, odbc::SQLDataTypes::VarChar, 1, 0};
227 0 : case 1:
228 0 : return {typeName, odbc::SQLDataTypes::VarChar, typeSize[0], 0};
229 0 : default:
230 0 : incorrectFormatErr();
231 0 : return {"", odbc::SQLDataTypes::Unknown, 0, 0};
232 : }
233 : }
234 0 : else if (EQUAL(typeName.c_str(), "NVARCHAR"))
235 : {
236 0 : switch (typeSize.size())
237 : {
238 0 : case 0:
239 0 : return {typeName, odbc::SQLDataTypes::WVarChar, 1, 0};
240 0 : case 1:
241 0 : return {typeName, odbc::SQLDataTypes::WVarChar, typeSize[0], 0};
242 0 : case 2:
243 0 : incorrectFormatErr();
244 0 : return {"", odbc::SQLDataTypes::Unknown, 0, 0};
245 : }
246 : }
247 0 : else if (EQUAL(typeName.c_str(), "NCLOB"))
248 0 : return {typeName, odbc::SQLDataTypes::WLongVarChar, 0, 0};
249 0 : else if (EQUAL(typeName.c_str(), "DATE"))
250 0 : return {typeName, odbc::SQLDataTypes::Date, 0, 0};
251 0 : else if (EQUAL(typeName.c_str(), "TIME"))
252 0 : return {typeName, odbc::SQLDataTypes::Time, 0, 0};
253 0 : else if (EQUAL(typeName.c_str(), "TIMESTAMP"))
254 0 : return {typeName, odbc::SQLDataTypes::Timestamp, 0, 0};
255 0 : else if (EQUAL(typeName.c_str(), "VARBINARY"))
256 : {
257 0 : switch (typeSize.size())
258 : {
259 0 : case 0:
260 0 : return {typeName, odbc::SQLDataTypes::VarBinary, 1, 0};
261 0 : case 1:
262 0 : return {typeName, odbc::SQLDataTypes::VarBinary, typeSize[0],
263 0 : 0};
264 0 : case 2:
265 0 : incorrectFormatErr();
266 0 : return {"", odbc::SQLDataTypes::Unknown, 0, 0};
267 : }
268 : }
269 0 : else if (EQUAL(typeName.c_str(), "BLOB"))
270 0 : return {typeName, odbc::SQLDataTypes::LongVarBinary, 0, 0};
271 :
272 0 : CPLError(CE_Failure, CPLE_NotSupported, "Unknown column type '%s'.",
273 : typeName.c_str());
274 0 : return {std::move(typeName), odbc::SQLDataTypes::Unknown, 0, 0};
275 : }
276 :
277 65 : CPLString GetColumnDefinition(const ColumnTypeInfo &typeInfo)
278 : {
279 65 : bool isArray = std::strstr(typeInfo.name, "ARRAY") != nullptr;
280 :
281 65 : if (isArray)
282 : {
283 4 : switch (typeInfo.type)
284 : {
285 0 : case odbc::SQLDataTypes::SmallInt:
286 0 : return "SMALLINT ARRAY";
287 1 : case odbc::SQLDataTypes::Integer:
288 1 : return "INTEGER ARRAY";
289 1 : case odbc::SQLDataTypes::BigInt:
290 1 : return "BIGINT ARRAY";
291 0 : case odbc::SQLDataTypes::Real:
292 0 : return "REAL ARRAY";
293 1 : case odbc::SQLDataTypes::Double:
294 1 : return "DOUBLE ARRAY";
295 1 : case odbc::SQLDataTypes::WVarChar:
296 1 : return "NVARCHAR(512) ARRAY";
297 0 : default:
298 0 : return "UNKNOWN";
299 : }
300 : }
301 :
302 61 : switch (typeInfo.type)
303 : {
304 34 : case odbc::SQLDataTypes::Boolean:
305 : case odbc::SQLDataTypes::TinyInt:
306 : case odbc::SQLDataTypes::SmallInt:
307 : case odbc::SQLDataTypes::Integer:
308 : case odbc::SQLDataTypes::BigInt:
309 : case odbc::SQLDataTypes::Float:
310 : case odbc::SQLDataTypes::Real:
311 : case odbc::SQLDataTypes::Double:
312 : case odbc::SQLDataTypes::Date:
313 : case odbc::SQLDataTypes::TypeDate:
314 : case odbc::SQLDataTypes::Time:
315 : case odbc::SQLDataTypes::TypeTime:
316 : case odbc::SQLDataTypes::Timestamp:
317 : case odbc::SQLDataTypes::TypeTimestamp:
318 : case odbc::SQLDataTypes::Char:
319 : case odbc::SQLDataTypes::WChar:
320 : case odbc::SQLDataTypes::LongVarChar:
321 : case odbc::SQLDataTypes::LongVarBinary:
322 34 : return typeInfo.name;
323 3 : case odbc::SQLDataTypes::Decimal:
324 : case odbc::SQLDataTypes::Numeric:
325 6 : return CPLString().Printf("DECIMAL(%d,%d)", typeInfo.width,
326 3 : typeInfo.precision);
327 24 : case odbc::SQLDataTypes::VarChar:
328 : case odbc::SQLDataTypes::WVarChar:
329 : case odbc::SQLDataTypes::Binary:
330 : case odbc::SQLDataTypes::VarBinary:
331 : case odbc::SQLDataTypes::WLongVarChar:
332 24 : return (typeInfo.width == 0)
333 : ? typeInfo.name
334 48 : : CPLString().Printf("%s(%d)", typeInfo.name.c_str(),
335 48 : typeInfo.width);
336 0 : default:
337 0 : return "UNKNOWN";
338 : }
339 : }
340 :
341 64 : void SetFieldDefn(OGRFieldDefn &field, const ColumnTypeInfo &typeInfo)
342 : {
343 58 : auto isArray = [&typeInfo]()
344 58 : { return std::strstr(typeInfo.name, "ARRAY") != nullptr; };
345 :
346 64 : switch (typeInfo.type)
347 : {
348 1 : case odbc::SQLDataTypes::Bit:
349 : case odbc::SQLDataTypes::Boolean:
350 1 : field.SetType(OFTInteger);
351 1 : field.SetSubType(OFSTBoolean);
352 1 : break;
353 2 : case odbc::SQLDataTypes::TinyInt:
354 : case odbc::SQLDataTypes::SmallInt:
355 2 : field.SetType(isArray() ? OFTIntegerList : OFTInteger);
356 2 : field.SetSubType(OFSTInt16);
357 2 : break;
358 4 : case odbc::SQLDataTypes::Integer:
359 4 : field.SetType(isArray() ? OFTIntegerList : OFTInteger);
360 4 : break;
361 12 : case odbc::SQLDataTypes::BigInt:
362 12 : field.SetType(isArray() ? OFTInteger64List : OFTInteger64);
363 12 : break;
364 13 : case odbc::SQLDataTypes::Double:
365 : case odbc::SQLDataTypes::Real:
366 : case odbc::SQLDataTypes::Float:
367 13 : field.SetType(isArray() ? OFTRealList : OFTReal);
368 13 : if (typeInfo.type != odbc::SQLDataTypes::Double)
369 1 : field.SetSubType(OFSTFloat32);
370 13 : break;
371 3 : case odbc::SQLDataTypes::Decimal:
372 : case odbc::SQLDataTypes::Numeric:
373 3 : field.SetType(isArray() ? OFTRealList : OFTReal);
374 3 : break;
375 0 : case odbc::SQLDataTypes::Char:
376 : case odbc::SQLDataTypes::VarChar:
377 : case odbc::SQLDataTypes::LongVarChar:
378 0 : field.SetType(isArray() ? OFTStringList : OFTString);
379 0 : break;
380 24 : case odbc::SQLDataTypes::WChar:
381 : case odbc::SQLDataTypes::WVarChar:
382 : case odbc::SQLDataTypes::WLongVarChar:
383 24 : field.SetType(isArray() ? OFTStringList : OFTString);
384 24 : break;
385 1 : case odbc::SQLDataTypes::Date:
386 : case odbc::SQLDataTypes::TypeDate:
387 1 : field.SetType(OFTDate);
388 1 : break;
389 1 : case odbc::SQLDataTypes::Time:
390 : case odbc::SQLDataTypes::TypeTime:
391 1 : field.SetType(OFTTime);
392 1 : break;
393 2 : case odbc::SQLDataTypes::Timestamp:
394 : case odbc::SQLDataTypes::TypeTimestamp:
395 2 : field.SetType(OFTDateTime);
396 2 : break;
397 1 : case odbc::SQLDataTypes::Binary:
398 : case odbc::SQLDataTypes::VarBinary:
399 : case odbc::SQLDataTypes::LongVarBinary:
400 1 : field.SetType(OFTBinary);
401 1 : break;
402 0 : default:
403 0 : break;
404 : }
405 :
406 64 : field.SetWidth(typeInfo.width);
407 64 : field.SetPrecision(typeInfo.precision);
408 64 : }
409 :
410 : } // anonymous namespace
411 :
412 : /************************************************************************/
413 : /* OGRHanaTableLayer() */
414 : /************************************************************************/
415 :
416 408 : OGRHanaTableLayer::OGRHanaTableLayer(OGRHanaDataSource *datasource,
417 : const char *schemaName,
418 408 : const char *tableName, int update)
419 : : OGRHanaLayer(datasource), schemaName_(schemaName), tableName_(tableName),
420 408 : updateMode_(update)
421 : {
422 : rawQuery_ =
423 408 : "SELECT * FROM " + GetFullTableNameQuoted(schemaName_, tableName_);
424 408 : SetDescription(tableName_.c_str());
425 408 : }
426 :
427 : /************************************************************************/
428 : /* ~OGRHanaTableLayer() */
429 : /************************************************************************/
430 :
431 816 : OGRHanaTableLayer::~OGRHanaTableLayer()
432 : {
433 408 : FlushPendingBatches(true);
434 816 : }
435 :
436 : /* -------------------------------------------------------------------- */
437 : /* Initialize() */
438 : /* -------------------------------------------------------------------- */
439 :
440 38 : OGRErr OGRHanaTableLayer::Initialize()
441 : {
442 38 : if (initialized_)
443 0 : return OGRERR_NONE;
444 :
445 : OGRErr err =
446 38 : InitFeatureDefinition(schemaName_, tableName_, rawQuery_, tableName_);
447 38 : if (err != OGRERR_NONE)
448 0 : return err;
449 :
450 38 : if (fidFieldIndex_ != OGRNullFID)
451 : {
452 35 : CPLDebug("HANA", "table %s has FID column %s.", tableName_.c_str(),
453 : fidFieldName_.c_str());
454 :
455 35 : CPLString sql = CPLString().Printf(
456 : "SELECT COUNT(*) FROM %s",
457 105 : GetFullTableNameQuoted(schemaName_, tableName_).c_str());
458 70 : odbc::StatementRef stmt = dataSource_->CreateStatement();
459 70 : odbc::ResultSetRef rs = stmt->executeQuery(sql.c_str());
460 35 : allowAutoFIDOnCreateFeature_ =
461 35 : rs->next() ? (*rs->getLong(1) == 0) : false;
462 35 : rs->close();
463 : }
464 : else
465 : {
466 3 : CPLDebug("HANA",
467 : "table %s has no FID column, FIDs will not be reliable!",
468 : tableName_.c_str());
469 :
470 3 : allowAutoFIDOnCreateFeature_ = true;
471 : }
472 :
473 38 : return OGRERR_NONE;
474 : }
475 :
476 : /* -------------------------------------------------------------------- */
477 : /* ExecuteUpdate() */
478 : /* -------------------------------------------------------------------- */
479 :
480 : std::pair<OGRErr, std::size_t>
481 141 : OGRHanaTableLayer::ExecuteUpdate(odbc::PreparedStatement &statement,
482 : bool withBatch, const char *functionName)
483 : {
484 141 : std::size_t ret = 0;
485 :
486 : try
487 : {
488 141 : if (withBatch)
489 : {
490 8 : if (statement.getBatchDataSize() >= batchSize_)
491 0 : statement.executeBatch();
492 8 : ret = 1;
493 : }
494 : else
495 : {
496 133 : ret = statement.executeUpdate();
497 : }
498 :
499 141 : if (!dataSource_->IsTransactionStarted())
500 131 : dataSource_->Commit();
501 : }
502 0 : catch (odbc::Exception &ex)
503 : {
504 0 : CPLError(CE_Failure, CPLE_AppDefined, "Failed to execute %s: %s",
505 0 : functionName, ex.what());
506 0 : return {OGRERR_FAILURE, 0};
507 : }
508 :
509 141 : return {OGRERR_NONE, ret};
510 : }
511 :
512 : /* -------------------------------------------------------------------- */
513 : /* CreateDeleteFeatureStatement() */
514 : /* -------------------------------------------------------------------- */
515 :
516 3 : odbc::PreparedStatementRef OGRHanaTableLayer::CreateDeleteFeatureStatement()
517 : {
518 3 : CPLString sql = CPLString().Printf(
519 : "DELETE FROM %s WHERE %s = ?",
520 6 : GetFullTableNameQuoted(schemaName_, tableName_).c_str(),
521 12 : QuotedIdentifier(GetFIDColumn()).c_str());
522 6 : return dataSource_->PrepareStatement(sql.c_str());
523 : }
524 :
525 : /* -------------------------------------------------------------------- */
526 : /* CreateInsertFeatureStatement() */
527 : /* -------------------------------------------------------------------- */
528 :
529 : odbc::PreparedStatementRef
530 16 : OGRHanaTableLayer::CreateInsertFeatureStatement(bool withFID)
531 : {
532 32 : std::vector<CPLString> columns;
533 32 : std::vector<CPLString> values;
534 16 : bool hasArray = false;
535 103 : for (const AttributeColumnDescription &clmDesc : attrColumns_)
536 : {
537 87 : if (clmDesc.isFeatureID && !withFID)
538 : {
539 2 : if (clmDesc.isAutoIncrement)
540 2 : continue;
541 : }
542 :
543 85 : columns.push_back(QuotedIdentifier(clmDesc.name));
544 85 : values.push_back(
545 170 : GetParameterValue(clmDesc.type, clmDesc.typeName, clmDesc.isArray));
546 85 : if (clmDesc.isArray)
547 4 : hasArray = true;
548 : }
549 :
550 31 : for (const GeometryColumnDescription &geomClmDesc : geomColumns_)
551 : {
552 15 : columns.push_back(QuotedIdentifier(geomClmDesc.name));
553 30 : values.push_back("ST_GeomFromWKB(? , " +
554 45 : std::to_string(geomClmDesc.srid) + ")");
555 : }
556 :
557 16 : if (hasArray && !parseFunctionsChecked_)
558 : {
559 : // Create helper functions if needed.
560 1 : if (!dataSource_->ParseArrayFunctionsExist(schemaName_.c_str()))
561 1 : dataSource_->CreateParseArrayFunctions(schemaName_.c_str());
562 1 : parseFunctionsChecked_ = true;
563 : }
564 :
565 16 : const CPLString sql = CPLString().Printf(
566 : "INSERT INTO %s (%s) VALUES(%s)",
567 32 : GetFullTableNameQuoted(schemaName_, tableName_).c_str(),
568 64 : JoinStrings(columns, ", ").c_str(), JoinStrings(values, ", ").c_str());
569 :
570 32 : return dataSource_->PrepareStatement(sql.c_str());
571 : }
572 :
573 : /* -------------------------------------------------------------------- */
574 : /* CreateUpdateFeatureStatement() */
575 : /* -------------------------------------------------------------------- */
576 :
577 3 : odbc::PreparedStatementRef OGRHanaTableLayer::CreateUpdateFeatureStatement()
578 : {
579 6 : std::vector<CPLString> values;
580 3 : values.reserve(attrColumns_.size());
581 3 : bool hasArray = false;
582 :
583 14 : for (const AttributeColumnDescription &clmDesc : attrColumns_)
584 : {
585 11 : if (clmDesc.isFeatureID)
586 : {
587 3 : if (clmDesc.isAutoIncrement)
588 3 : continue;
589 : }
590 8 : values.push_back(
591 16 : QuotedIdentifier(clmDesc.name) + " = " +
592 16 : GetParameterValue(clmDesc.type, clmDesc.typeName, clmDesc.isArray));
593 8 : if (clmDesc.isArray)
594 0 : hasArray = true;
595 : }
596 :
597 6 : for (const GeometryColumnDescription &geomClmDesc : geomColumns_)
598 : {
599 9 : values.push_back(QuotedIdentifier(geomClmDesc.name) + " = " +
600 6 : "ST_GeomFromWKB(?, " +
601 12 : std::to_string(geomClmDesc.srid) + ")");
602 : }
603 :
604 3 : if (hasArray && !parseFunctionsChecked_)
605 : {
606 : // Create helper functions if needed.
607 0 : if (!dataSource_->ParseArrayFunctionsExist(schemaName_.c_str()))
608 0 : dataSource_->CreateParseArrayFunctions(schemaName_.c_str());
609 0 : parseFunctionsChecked_ = true;
610 : }
611 :
612 3 : const CPLString sql = CPLString().Printf(
613 : "UPDATE %s SET %s WHERE %s = ?",
614 6 : GetFullTableNameQuoted(schemaName_, tableName_).c_str(),
615 6 : JoinStrings(values, ", ").c_str(),
616 15 : QuotedIdentifier(GetFIDColumn()).c_str());
617 :
618 6 : return dataSource_->PrepareStatement(sql.c_str());
619 : }
620 :
621 : /* -------------------------------------------------------------------- */
622 : /* ResetPreparedStatements() */
623 : /* -------------------------------------------------------------------- */
624 :
625 65 : void OGRHanaTableLayer::ResetPreparedStatements()
626 : {
627 65 : if (!currentIdentityValueStmt_.isNull())
628 0 : currentIdentityValueStmt_ = nullptr;
629 65 : if (!insertFeatureStmtWithFID_.isNull())
630 1 : insertFeatureStmtWithFID_ = nullptr;
631 65 : if (!insertFeatureStmtWithoutFID_.isNull())
632 0 : insertFeatureStmtWithoutFID_ = nullptr;
633 65 : if (!deleteFeatureStmt_.isNull())
634 0 : deleteFeatureStmt_ = nullptr;
635 65 : if (!updateFeatureStmt_.isNull())
636 0 : updateFeatureStmt_ = nullptr;
637 65 : }
638 :
639 : /************************************************************************/
640 : /* SetStatementParameters() */
641 : /************************************************************************/
642 :
643 133 : OGRErr OGRHanaTableLayer::SetStatementParameters(
644 : odbc::PreparedStatement &statement, OGRFeature *feature, bool newFeature,
645 : bool withFID, const char *functionName)
646 : {
647 133 : OGRHanaFeatureReader featReader(*feature);
648 :
649 133 : unsigned short paramIndex = 0;
650 133 : int fieldIndex = -1;
651 783 : for (const AttributeColumnDescription &clmDesc : attrColumns_)
652 : {
653 650 : if (clmDesc.isFeatureID)
654 : {
655 133 : if (!withFID && clmDesc.isAutoIncrement)
656 18 : continue;
657 :
658 115 : ++paramIndex;
659 :
660 115 : switch (clmDesc.type)
661 : {
662 115 : case odbc::SQLDataTypes::Integer:
663 115 : if (feature->GetFID() == OGRNullFID)
664 0 : statement.setInt(paramIndex, odbc::Int());
665 : else
666 : {
667 115 : if (std::numeric_limits<std::int32_t>::min() >
668 230 : feature->GetFID() ||
669 115 : std::numeric_limits<std::int32_t>::max() <
670 115 : feature->GetFID())
671 : {
672 0 : CPLError(CE_Failure, CPLE_AppDefined,
673 : "%s: Feature id with value %s cannot "
674 : "be stored in a column of type INTEGER",
675 : functionName,
676 0 : std::to_string(feature->GetFID()).c_str());
677 0 : return OGRERR_FAILURE;
678 : }
679 :
680 115 : statement.setInt(paramIndex,
681 230 : odbc::Int(static_cast<std::int32_t>(
682 115 : feature->GetFID())));
683 : }
684 115 : break;
685 0 : case odbc::SQLDataTypes::BigInt:
686 0 : if (feature->GetFID() == OGRNullFID)
687 0 : statement.setLong(paramIndex, odbc::Long());
688 : else
689 0 : statement.setLong(paramIndex,
690 0 : odbc::Long(static_cast<std::int64_t>(
691 0 : feature->GetFID())));
692 0 : break;
693 0 : default:
694 0 : CPLError(CE_Failure, CPLE_AppDefined,
695 : "%s: Unexpected type ('%s') in the field "
696 : "'%s'",
697 0 : functionName, std::to_string(clmDesc.type).c_str(),
698 : clmDesc.name.c_str());
699 0 : return OGRERR_FAILURE;
700 : }
701 115 : continue;
702 : }
703 : else
704 517 : ++paramIndex;
705 :
706 517 : ++fieldIndex;
707 :
708 517 : switch (clmDesc.type)
709 : {
710 1 : case odbc::SQLDataTypes::Bit:
711 : case odbc::SQLDataTypes::Boolean:
712 1 : statement.setBoolean(paramIndex,
713 1 : featReader.GetFieldAsBoolean(fieldIndex));
714 1 : break;
715 0 : case odbc::SQLDataTypes::TinyInt:
716 0 : if (clmDesc.isArray)
717 0 : statement.setString(
718 0 : paramIndex, featReader.GetFieldAsIntArray(fieldIndex));
719 : else
720 0 : statement.setByte(paramIndex,
721 0 : featReader.GetFieldAsByte(fieldIndex));
722 0 : break;
723 1 : case odbc::SQLDataTypes::SmallInt:
724 1 : if (clmDesc.isArray)
725 0 : statement.setString(
726 0 : paramIndex, featReader.GetFieldAsIntArray(fieldIndex));
727 : else
728 1 : statement.setShort(paramIndex,
729 2 : featReader.GetFieldAsShort(fieldIndex));
730 1 : break;
731 3 : case odbc::SQLDataTypes::Integer:
732 3 : if (clmDesc.isArray)
733 1 : statement.setString(
734 2 : paramIndex, featReader.GetFieldAsIntArray(fieldIndex));
735 : else
736 2 : statement.setInt(paramIndex,
737 4 : featReader.GetFieldAsInt(fieldIndex));
738 3 : break;
739 126 : case odbc::SQLDataTypes::BigInt:
740 126 : if (clmDesc.isArray)
741 1 : statement.setString(
742 : paramIndex,
743 2 : featReader.GetFieldAsBigIntArray(fieldIndex));
744 : else
745 125 : statement.setLong(paramIndex,
746 250 : featReader.GetFieldAsLong(fieldIndex));
747 126 : break;
748 1 : case odbc::SQLDataTypes::Float:
749 : case odbc::SQLDataTypes::Real:
750 1 : if (clmDesc.isArray)
751 0 : statement.setString(
752 0 : paramIndex, featReader.GetFieldAsRealArray(fieldIndex));
753 : else
754 1 : statement.setFloat(paramIndex,
755 2 : featReader.GetFieldAsFloat(fieldIndex));
756 1 : break;
757 126 : case odbc::SQLDataTypes::Double:
758 126 : if (clmDesc.isArray)
759 1 : statement.setString(
760 : paramIndex,
761 2 : featReader.GetFieldAsDoubleArray(fieldIndex));
762 : else
763 125 : statement.setDouble(
764 250 : paramIndex, featReader.GetFieldAsDouble(fieldIndex));
765 126 : break;
766 1 : case odbc::SQLDataTypes::Decimal:
767 : case odbc::SQLDataTypes::Numeric:
768 1 : if ((!feature->IsFieldSet(fieldIndex) ||
769 2 : feature->IsFieldNull(fieldIndex)) &&
770 1 : feature->GetFieldDefnRef(fieldIndex)->GetDefault() ==
771 : nullptr)
772 0 : statement.setDecimal(paramIndex, odbc::Decimal());
773 : else
774 1 : statement.setDouble(
775 2 : paramIndex, featReader.GetFieldAsDouble(fieldIndex));
776 1 : break;
777 0 : case odbc::SQLDataTypes::Char:
778 : case odbc::SQLDataTypes::VarChar:
779 : case odbc::SQLDataTypes::LongVarChar:
780 0 : if (clmDesc.isArray)
781 0 : statement.setString(
782 : paramIndex,
783 0 : featReader.GetFieldAsStringArray(fieldIndex));
784 : else
785 0 : statement.setString(paramIndex,
786 0 : featReader.GetFieldAsString(
787 0 : fieldIndex, clmDesc.length));
788 0 : break;
789 251 : case odbc::SQLDataTypes::WChar:
790 : case odbc::SQLDataTypes::WVarChar:
791 : case odbc::SQLDataTypes::WLongVarChar:
792 251 : if (clmDesc.isArray)
793 1 : statement.setString(
794 : paramIndex,
795 2 : featReader.GetFieldAsStringArray(fieldIndex));
796 : else
797 250 : statement.setString(paramIndex,
798 250 : featReader.GetFieldAsNString(
799 250 : fieldIndex, clmDesc.length));
800 251 : break;
801 1 : case odbc::SQLDataTypes::Binary:
802 : case odbc::SQLDataTypes::VarBinary:
803 : case odbc::SQLDataTypes::LongVarBinary:
804 : {
805 1 : Binary bin = featReader.GetFieldAsBinary(fieldIndex);
806 1 : statement.setBytes(paramIndex, bin.data, bin.size);
807 : }
808 1 : break;
809 1 : case odbc::SQLDataTypes::DateTime:
810 : case odbc::SQLDataTypes::TypeDate:
811 1 : statement.setDate(paramIndex,
812 1 : featReader.GetFieldAsDate(fieldIndex));
813 1 : break;
814 1 : case odbc::SQLDataTypes::Time:
815 : case odbc::SQLDataTypes::TypeTime:
816 1 : statement.setTime(paramIndex,
817 1 : featReader.GetFieldAsTime(fieldIndex));
818 1 : break;
819 4 : case odbc::SQLDataTypes::Timestamp:
820 : case odbc::SQLDataTypes::TypeTimestamp:
821 4 : statement.setTimestamp(
822 4 : paramIndex, featReader.GetFieldAsTimestamp(fieldIndex));
823 4 : break;
824 : }
825 : }
826 :
827 263 : for (std::size_t i = 0; i < geomColumns_.size(); ++i)
828 : {
829 130 : ++paramIndex;
830 130 : Binary wkb{nullptr, 0};
831 130 : OGRErr err = GetGeometryWkb(feature, static_cast<int>(i), wkb);
832 130 : if (OGRERR_NONE != err)
833 0 : return err;
834 130 : statement.setBytes(paramIndex, wkb.data, wkb.size);
835 : }
836 :
837 133 : if (!newFeature)
838 : {
839 10 : ++paramIndex;
840 :
841 10 : statement.setLong(paramIndex, odbc::Long(static_cast<std::int64_t>(
842 10 : feature->GetFID())));
843 : }
844 :
845 133 : return OGRERR_NONE;
846 : }
847 :
848 : /* -------------------------------------------------------------------- */
849 : /* DropTable() */
850 : /* -------------------------------------------------------------------- */
851 :
852 0 : OGRErr OGRHanaTableLayer::DropTable()
853 : {
854 : CPLString sql =
855 0 : "DROP TABLE " + GetFullTableNameQuoted(schemaName_, tableName_);
856 : try
857 : {
858 0 : dataSource_->ExecuteSQL(sql.c_str());
859 0 : CPLDebug("HANA", "Dropped table %s.", GetName());
860 : }
861 0 : catch (const odbc::Exception &ex)
862 : {
863 0 : CPLError(CE_Failure, CPLE_AppDefined, "Unable to delete layer '%s': %s",
864 0 : tableName_.c_str(), ex.what());
865 0 : return OGRERR_FAILURE;
866 : }
867 :
868 0 : return OGRERR_NONE;
869 : }
870 :
871 : /* -------------------------------------------------------------------- */
872 : /* ExecutePendingBatches() */
873 : /* -------------------------------------------------------------------- */
874 :
875 145 : OGRErr OGRHanaTableLayer::ExecutePendingBatches(BatchOperation op)
876 : {
877 8 : auto hasFlag = [op](BatchOperation flag) { return (op & flag) == flag; };
878 :
879 : try
880 : {
881 145 : if (!deleteFeatureStmt_.isNull() &&
882 147 : deleteFeatureStmt_->getBatchDataSize() > 0 &&
883 2 : hasFlag(BatchOperation::DELETE))
884 2 : deleteFeatureStmt_->executeBatch();
885 145 : if (!insertFeatureStmtWithFID_.isNull() &&
886 150 : insertFeatureStmtWithFID_->getBatchDataSize() > 0 &&
887 5 : hasFlag(BatchOperation::INSERT))
888 3 : insertFeatureStmtWithFID_->executeBatch();
889 145 : if (!insertFeatureStmtWithoutFID_.isNull() &&
890 145 : insertFeatureStmtWithoutFID_->getBatchDataSize() > 0 &&
891 0 : hasFlag(BatchOperation::INSERT))
892 0 : insertFeatureStmtWithoutFID_->executeBatch();
893 145 : if (!updateFeatureStmt_.isNull() &&
894 146 : updateFeatureStmt_->getBatchDataSize() > 0 &&
895 1 : hasFlag(BatchOperation::UPDATE))
896 1 : updateFeatureStmt_->executeBatch();
897 :
898 145 : return OGRERR_NONE;
899 : }
900 0 : catch (const odbc::Exception &ex)
901 : {
902 0 : ClearBatches();
903 :
904 0 : CPLError(CE_Failure, CPLE_AppDefined,
905 0 : "Failed to execute batch commands: %s", ex.what());
906 0 : return OGRERR_FAILURE;
907 : }
908 : }
909 :
910 : /* -------------------------------------------------------------------- */
911 : /* FlushPendingBatches() */
912 : /* -------------------------------------------------------------------- */
913 :
914 834 : void OGRHanaTableLayer::FlushPendingBatches(bool commit)
915 : {
916 834 : if (!HasPendingBatches())
917 830 : return;
918 :
919 4 : OGRErr err = ExecutePendingBatches(BatchOperation::ALL);
920 4 : if (OGRERR_NONE == err && commit && !dataSource_->IsTransactionStarted())
921 0 : dataSource_->Commit();
922 : }
923 :
924 : /* -------------------------------------------------------------------- */
925 : /* HasPendingBatches() */
926 : /* -------------------------------------------------------------------- */
927 :
928 841 : bool OGRHanaTableLayer::HasPendingBatches() const
929 : {
930 841 : return (!deleteFeatureStmt_.isNull() &&
931 45 : deleteFeatureStmt_->getBatchDataSize() > 0) ||
932 840 : (!insertFeatureStmtWithFID_.isNull() &&
933 95 : insertFeatureStmtWithFID_->getBatchDataSize() > 0) ||
934 838 : (!insertFeatureStmtWithoutFID_.isNull() &&
935 1709 : insertFeatureStmtWithoutFID_->getBatchDataSize() > 0) ||
936 838 : (!updateFeatureStmt_.isNull() &&
937 883 : updateFeatureStmt_->getBatchDataSize() > 0);
938 : }
939 :
940 : /* -------------------------------------------------------------------- */
941 : /* GetColumnTypeInfo() */
942 : /* -------------------------------------------------------------------- */
943 :
944 : ColumnTypeInfo
945 65 : OGRHanaTableLayer::GetColumnTypeInfo(const OGRFieldDefn &field) const
946 : {
947 68 : for (const auto &clmType : customColumnDefs_)
948 : {
949 6 : if (EQUAL(clmType.name.c_str(), field.GetNameRef()))
950 3 : return ParseColumnTypeInfo(clmType.typeDef);
951 : }
952 :
953 62 : switch (field.GetType())
954 : {
955 6 : case OFTInteger:
956 6 : if (preservePrecision_ && field.GetWidth() > 10)
957 : {
958 : return {"DECIMAL", odbc::SQLDataTypes::Decimal,
959 0 : field.GetWidth(), 0};
960 : }
961 : else
962 : {
963 6 : if (field.GetSubType() == OFSTBoolean)
964 : return {"BOOLEAN", odbc::SQLDataTypes::Boolean,
965 1 : field.GetWidth(), 0};
966 5 : else if (field.GetSubType() == OFSTInt16)
967 : return {"SMALLINT", odbc::SQLDataTypes::SmallInt,
968 1 : field.GetWidth(), 0};
969 : else
970 : return {"INTEGER", odbc::SQLDataTypes::Integer,
971 4 : field.GetWidth(), 0};
972 : }
973 : break;
974 11 : case OFTInteger64:
975 11 : if (preservePrecision_ && field.GetWidth() > 20)
976 : {
977 : return {"DECIMAL", odbc::SQLDataTypes::Decimal,
978 0 : field.GetWidth(), 0};
979 : }
980 : else
981 11 : return {"BIGINT", odbc::SQLDataTypes::BigInt, field.GetWidth(),
982 11 : 0};
983 : break;
984 13 : case OFTReal:
985 13 : if (preservePrecision_ && field.GetWidth() != 0)
986 : {
987 : return {"DECIMAL", odbc::SQLDataTypes::Decimal,
988 1 : field.GetWidth(), field.GetPrecision()};
989 : }
990 : else
991 : {
992 12 : if (field.GetSubType() == OFSTFloat32)
993 1 : return {"REAL", odbc::SQLDataTypes::Real, field.GetWidth(),
994 1 : field.GetPrecision()};
995 : else
996 : return {"DOUBLE", odbc::SQLDataTypes::Double,
997 11 : field.GetWidth(), field.GetPrecision()};
998 : }
999 23 : case OFTString:
1000 23 : if (field.GetWidth() == 0 || !preservePrecision_)
1001 : {
1002 13 : int width = static_cast<int>(defaultStringSize_);
1003 13 : return {"NVARCHAR", odbc::SQLDataTypes::WLongVarChar, width, 0};
1004 : }
1005 : else
1006 : {
1007 10 : if (field.GetWidth() <= 5000)
1008 : return {"NVARCHAR", odbc::SQLDataTypes::WLongVarChar,
1009 10 : field.GetWidth(), 0};
1010 : else
1011 0 : return {"NCLOB", odbc::SQLDataTypes::WLongVarChar, 0, 0};
1012 : }
1013 1 : case OFTBinary:
1014 1 : if (field.GetWidth() <= 5000)
1015 : return {"VARBINARY", odbc::SQLDataTypes::VarBinary,
1016 1 : field.GetWidth(), 0};
1017 : else
1018 : return {"BLOB", odbc::SQLDataTypes::LongVarBinary,
1019 0 : field.GetWidth(), 0};
1020 1 : case OFTDate:
1021 1 : return {"DATE", odbc::SQLDataTypes::TypeDate, field.GetWidth(), 0};
1022 1 : case OFTTime:
1023 1 : return {"TIME", odbc::SQLDataTypes::TypeTime, field.GetWidth(), 0};
1024 2 : case OFTDateTime:
1025 : return {"TIMESTAMP", odbc::SQLDataTypes::TypeTimestamp,
1026 2 : field.GetWidth(), 0};
1027 1 : case OFTIntegerList:
1028 1 : if (field.GetSubType() == OGRFieldSubType::OFSTInt16)
1029 0 : return {"ARRAY", odbc::SQLDataTypes::SmallInt, field.GetWidth(),
1030 0 : 0};
1031 : else
1032 1 : return {"ARRAY", odbc::SQLDataTypes::Integer, field.GetWidth(),
1033 1 : 0};
1034 1 : case OFTInteger64List:
1035 1 : return {"ARRAY", odbc::SQLDataTypes::BigInt, field.GetWidth(), 0};
1036 1 : case OFTRealList:
1037 1 : if (field.GetSubType() == OGRFieldSubType::OFSTFloat32)
1038 0 : return {"ARRAY", odbc::SQLDataTypes::Real, field.GetWidth(), 0};
1039 : else
1040 1 : return {"ARRAY", odbc::SQLDataTypes::Double, field.GetWidth(),
1041 1 : 0};
1042 : break;
1043 1 : case OFTStringList:
1044 1 : return {"ARRAY", odbc::SQLDataTypes::WVarChar, 512, 0};
1045 0 : default:
1046 0 : break;
1047 : }
1048 :
1049 0 : return {"", odbc::SQLDataTypes::Unknown, 0, 0};
1050 : }
1051 :
1052 : /* -------------------------------------------------------------------- */
1053 : /* GetGeometryWkb() */
1054 : /* -------------------------------------------------------------------- */
1055 130 : OGRErr OGRHanaTableLayer::GetGeometryWkb(OGRFeature *feature, int fieldIndex,
1056 : Binary &binary)
1057 : {
1058 130 : OGRGeometry *geom = feature->GetGeomFieldRef(fieldIndex);
1059 130 : if (geom == nullptr || !IsGeometryTypeSupported(geom->getIsoGeometryType()))
1060 10 : return OGRERR_NONE;
1061 :
1062 : // Rings must be closed, otherwise HANA throws an exception
1063 120 : geom->closeRings();
1064 120 : std::size_t size = static_cast<std::size_t>(geom->WkbSize());
1065 120 : EnsureBufferCapacity(size);
1066 120 : unsigned char *data = reinterpret_cast<unsigned char *>(dataBuffer_.data());
1067 120 : OGRErr err = geom->exportToWkb(OGRwkbByteOrder::wkbNDR, data,
1068 : OGRwkbVariant::wkbVariantIso);
1069 120 : if (OGRERR_NONE == err)
1070 : {
1071 120 : binary.data = data;
1072 120 : binary.size = size;
1073 : }
1074 120 : return err;
1075 : }
1076 :
1077 : /************************************************************************/
1078 : /* GetExtent() */
1079 : /************************************************************************/
1080 :
1081 8 : OGRErr OGRHanaTableLayer::GetExtent(int geomField, OGREnvelope *extent,
1082 : int force)
1083 : {
1084 8 : if (geomField >= 0 && geomField < GetLayerDefn()->GetGeomFieldCount())
1085 : {
1086 6 : FlushPendingBatches(false);
1087 : }
1088 :
1089 8 : return OGRHanaLayer::GetExtent(geomField, extent, force);
1090 : }
1091 :
1092 : /************************************************************************/
1093 : /* GetFeatureCount() */
1094 : /************************************************************************/
1095 :
1096 39 : GIntBig OGRHanaTableLayer::GetFeatureCount(int force)
1097 : {
1098 39 : FlushPendingBatches(false);
1099 :
1100 39 : return OGRHanaLayer::GetFeatureCount(force);
1101 : }
1102 :
1103 : /************************************************************************/
1104 : /* ResetReading() */
1105 : /************************************************************************/
1106 :
1107 195 : void OGRHanaTableLayer::ResetReading()
1108 : {
1109 195 : FlushPendingBatches(false);
1110 :
1111 195 : if (OGRNullFID != fidFieldIndex_ && nextFeatureId_ > 0)
1112 60 : allowAutoFIDOnCreateFeature_ = false;
1113 :
1114 195 : OGRHanaLayer::ResetReading();
1115 195 : }
1116 :
1117 : /************************************************************************/
1118 : /* TestCapability() */
1119 : /************************************************************************/
1120 :
1121 146 : int OGRHanaTableLayer::TestCapability(const char *capabilities)
1122 : {
1123 146 : if (EQUAL(capabilities, OLCRandomRead))
1124 : {
1125 2 : EnsureInitialized();
1126 2 : return fidFieldIndex_ != OGRNullFID;
1127 : }
1128 144 : if (EQUAL(capabilities, OLCFastFeatureCount))
1129 10 : return TRUE;
1130 134 : if (EQUAL(capabilities, OLCFastSpatialFilter))
1131 : {
1132 10 : EnsureInitialized();
1133 10 : return !geomColumns_.empty();
1134 : }
1135 124 : if (EQUAL(capabilities, OLCFastGetExtent))
1136 : {
1137 12 : EnsureInitialized();
1138 12 : return !geomColumns_.empty();
1139 : }
1140 112 : if (EQUAL(capabilities, OLCCreateField))
1141 12 : return updateMode_;
1142 100 : if (EQUAL(capabilities, OLCCreateGeomField) ||
1143 90 : EQUAL(capabilities, ODsCCreateGeomFieldAfterCreateLayer))
1144 10 : return updateMode_;
1145 90 : if (EQUAL(capabilities, OLCDeleteField))
1146 2 : return updateMode_;
1147 88 : if (EQUAL(capabilities, OLCDeleteFeature))
1148 : {
1149 12 : EnsureInitialized();
1150 12 : return updateMode_ && fidFieldIndex_ != OGRNullFID;
1151 : }
1152 76 : if (EQUAL(capabilities, OLCAlterFieldDefn))
1153 12 : return updateMode_;
1154 64 : if (EQUAL(capabilities, OLCRandomWrite))
1155 11 : return updateMode_;
1156 53 : if (EQUAL(capabilities, OLCMeasuredGeometries))
1157 17 : return TRUE;
1158 36 : if (EQUAL(capabilities, OLCSequentialWrite))
1159 1 : return updateMode_;
1160 35 : if (EQUAL(capabilities, OLCTransactions))
1161 11 : return updateMode_;
1162 24 : if (EQUAL(capabilities, OLCStringsAsUTF8))
1163 1 : return TRUE;
1164 :
1165 23 : return FALSE;
1166 : }
1167 :
1168 : /************************************************************************/
1169 : /* ICreateFeature() */
1170 : /************************************************************************/
1171 :
1172 123 : OGRErr OGRHanaTableLayer::ICreateFeature(OGRFeature *feature)
1173 : {
1174 123 : if (!updateMode_)
1175 : {
1176 0 : CPLError(CE_Failure, CPLE_NotSupported, UNSUPPORTED_OP_READ_ONLY,
1177 : "CreateFeature");
1178 0 : return OGRERR_FAILURE;
1179 : }
1180 :
1181 123 : if (nullptr == feature)
1182 : {
1183 0 : CPLError(CE_Failure, CPLE_AppDefined,
1184 : "NULL pointer to OGRFeature passed to CreateFeature().");
1185 0 : return OGRERR_FAILURE;
1186 : }
1187 :
1188 123 : EnsureInitialized();
1189 :
1190 : OGRErr err =
1191 123 : ExecutePendingBatches(BatchOperation::DELETE | BatchOperation::UPDATE);
1192 123 : if (OGRERR_NONE != err)
1193 0 : return err;
1194 :
1195 123 : bool hasFID = feature->GetFID() != OGRNullFID;
1196 123 : if (hasFID && OGRNullFID != fidFieldIndex_)
1197 7 : allowAutoFIDOnCreateFeature_ = false;
1198 :
1199 123 : if (!hasFID && allowAutoFIDOnCreateFeature_)
1200 : {
1201 108 : feature->SetFID(nextFeatureId_++);
1202 108 : hasFID = true;
1203 : }
1204 :
1205 123 : bool useBatch = hasFID && dataSource_->IsTransactionStarted();
1206 :
1207 : try
1208 : {
1209 123 : odbc::PreparedStatementRef &stmt =
1210 : hasFID ? insertFeatureStmtWithFID_ : insertFeatureStmtWithoutFID_;
1211 :
1212 123 : if (stmt.isNull())
1213 : {
1214 16 : stmt = CreateInsertFeatureStatement(hasFID);
1215 16 : if (stmt.isNull())
1216 0 : return OGRERR_FAILURE;
1217 : }
1218 :
1219 123 : err = SetStatementParameters(*stmt, feature, true, hasFID,
1220 : "CreateFeature");
1221 123 : if (OGRERR_NONE != err)
1222 0 : return err;
1223 :
1224 123 : if (useBatch)
1225 5 : stmt->addBatch();
1226 :
1227 123 : auto ret = ExecuteUpdate(*stmt, useBatch, "CreateFeature");
1228 :
1229 123 : err = ret.first;
1230 123 : if (OGRERR_NONE != err)
1231 0 : return err;
1232 :
1233 123 : if (!hasFID && OGRNullFID != fidFieldIndex_)
1234 : {
1235 8 : const CPLString sql = CPLString().Printf(
1236 : "SELECT CURRENT_IDENTITY_VALUE() \"current identity value\" "
1237 : "FROM %s",
1238 16 : GetFullTableNameQuoted(schemaName_, tableName_).c_str());
1239 :
1240 8 : if (currentIdentityValueStmt_.isNull())
1241 : {
1242 : currentIdentityValueStmt_ =
1243 2 : dataSource_->PrepareStatement(sql.c_str());
1244 2 : if (currentIdentityValueStmt_.isNull())
1245 0 : return OGRERR_FAILURE;
1246 : }
1247 :
1248 : odbc::ResultSetRef rsIdentity =
1249 16 : currentIdentityValueStmt_->executeQuery();
1250 8 : if (rsIdentity->next())
1251 : {
1252 8 : odbc::Long id = rsIdentity->getLong(1);
1253 8 : if (!id.isNull())
1254 8 : feature->SetFID(static_cast<GIntBig>(*id));
1255 : }
1256 8 : rsIdentity->close();
1257 : }
1258 :
1259 123 : return err;
1260 : }
1261 0 : catch (const std::exception &ex)
1262 : {
1263 0 : CPLError(CE_Failure, CPLE_NotSupported, "Unable to create feature: %s",
1264 0 : ex.what());
1265 0 : return OGRERR_FAILURE;
1266 : }
1267 : return OGRERR_NONE;
1268 : }
1269 :
1270 : /************************************************************************/
1271 : /* DeleteFeature() */
1272 : /************************************************************************/
1273 :
1274 8 : OGRErr OGRHanaTableLayer::DeleteFeature(GIntBig nFID)
1275 : {
1276 8 : if (!updateMode_)
1277 : {
1278 0 : CPLError(CE_Failure, CPLE_NotSupported, UNSUPPORTED_OP_READ_ONLY,
1279 : "DeleteFeature");
1280 0 : return OGRERR_FAILURE;
1281 : }
1282 :
1283 8 : if (nFID == OGRNullFID)
1284 : {
1285 0 : CPLError(CE_Failure, CPLE_AppDefined,
1286 : "DeleteFeature(" CPL_FRMT_GIB
1287 : ") failed. Unable to delete features "
1288 : "in tables without\n a recognised FID column.",
1289 : nFID);
1290 0 : return OGRERR_FAILURE;
1291 : }
1292 :
1293 8 : if (OGRNullFID == fidFieldIndex_)
1294 : {
1295 0 : CPLError(CE_Failure, CPLE_AppDefined,
1296 : "DeleteFeature(" CPL_FRMT_GIB
1297 : ") failed. Unable to delete features "
1298 : "in tables without\n a recognised FID column.",
1299 : nFID);
1300 0 : return OGRERR_FAILURE;
1301 : }
1302 :
1303 8 : EnsureInitialized();
1304 :
1305 8 : if (deleteFeatureStmt_.isNull())
1306 : {
1307 3 : deleteFeatureStmt_ = CreateDeleteFeatureStatement();
1308 3 : if (deleteFeatureStmt_.isNull())
1309 0 : return OGRERR_FAILURE;
1310 : }
1311 :
1312 : OGRErr err =
1313 8 : ExecutePendingBatches(BatchOperation::INSERT | BatchOperation::UPDATE);
1314 8 : if (OGRERR_NONE != err)
1315 0 : return err;
1316 :
1317 8 : deleteFeatureStmt_->setLong(1, odbc::Long(static_cast<std::int64_t>(nFID)));
1318 8 : bool withBatch = dataSource_->IsTransactionStarted();
1319 8 : if (withBatch)
1320 2 : deleteFeatureStmt_->addBatch();
1321 :
1322 8 : auto ret = ExecuteUpdate(*deleteFeatureStmt_, withBatch, "DeleteFeature");
1323 8 : return (OGRERR_NONE == ret.first && ret.second != 1)
1324 16 : ? OGRERR_NON_EXISTING_FEATURE
1325 8 : : ret.first;
1326 : }
1327 :
1328 : /************************************************************************/
1329 : /* ISetFeature() */
1330 : /************************************************************************/
1331 :
1332 10 : OGRErr OGRHanaTableLayer::ISetFeature(OGRFeature *feature)
1333 : {
1334 10 : if (!updateMode_)
1335 : {
1336 0 : CPLError(CE_Failure, CPLE_NotSupported, UNSUPPORTED_OP_READ_ONLY,
1337 : "SetFeature");
1338 0 : return OGRERR_FAILURE;
1339 : }
1340 :
1341 10 : if (nullptr == feature)
1342 : {
1343 0 : CPLError(CE_Failure, CPLE_AppDefined,
1344 : "NULL pointer to OGRFeature passed to SetFeature().");
1345 0 : return OGRERR_FAILURE;
1346 : }
1347 :
1348 10 : if (feature->GetFID() == OGRNullFID)
1349 : {
1350 0 : CPLError(CE_Failure, CPLE_AppDefined,
1351 : "FID required on features given to SetFeature().");
1352 0 : return OGRERR_FAILURE;
1353 : }
1354 :
1355 10 : if (OGRNullFID == fidFieldIndex_)
1356 : {
1357 0 : CPLError(CE_Failure, CPLE_AppDefined,
1358 : "Unable to update features in tables without\n"
1359 : "a recognised FID column.");
1360 0 : return OGRERR_FAILURE;
1361 : }
1362 :
1363 10 : EnsureInitialized();
1364 :
1365 10 : if (updateFeatureStmt_.isNull())
1366 : {
1367 3 : updateFeatureStmt_ = CreateUpdateFeatureStatement();
1368 3 : if (updateFeatureStmt_.isNull())
1369 0 : return OGRERR_FAILURE;
1370 : }
1371 :
1372 10 : if (OGRNullFID != fidFieldIndex_)
1373 10 : allowAutoFIDOnCreateFeature_ = false;
1374 :
1375 : OGRErr err =
1376 10 : ExecutePendingBatches(BatchOperation::DELETE | BatchOperation::INSERT);
1377 10 : if (OGRERR_NONE != err)
1378 0 : return err;
1379 :
1380 : try
1381 : {
1382 10 : err = SetStatementParameters(*updateFeatureStmt_, feature, false, false,
1383 : "SetFeature");
1384 :
1385 10 : if (OGRERR_NONE != err)
1386 0 : return err;
1387 :
1388 10 : bool withBatch = dataSource_->IsTransactionStarted();
1389 10 : if (withBatch)
1390 1 : updateFeatureStmt_->addBatch();
1391 :
1392 10 : auto ret = ExecuteUpdate(*updateFeatureStmt_, withBatch, "SetFeature");
1393 10 : return (OGRERR_NONE == ret.first && ret.second != 1)
1394 20 : ? OGRERR_NON_EXISTING_FEATURE
1395 10 : : ret.first;
1396 : }
1397 0 : catch (const std::exception &ex)
1398 : {
1399 0 : CPLError(CE_Failure, CPLE_NotSupported, "Unable to create feature: %s",
1400 0 : ex.what());
1401 0 : return OGRERR_FAILURE;
1402 : }
1403 : }
1404 :
1405 : /************************************************************************/
1406 : /* CreateField() */
1407 : /************************************************************************/
1408 :
1409 66 : OGRErr OGRHanaTableLayer::CreateField(const OGRFieldDefn *srsField,
1410 : int approxOK)
1411 : {
1412 66 : if (!updateMode_)
1413 : {
1414 0 : CPLError(CE_Failure, CPLE_NotSupported, UNSUPPORTED_OP_READ_ONLY,
1415 : "CreateField");
1416 0 : return OGRERR_FAILURE;
1417 : }
1418 :
1419 66 : if (srsField->GetNameRef() == nullptr)
1420 : {
1421 0 : CPLError(CE_Failure, CPLE_AppDefined, "Field name cannot be NULL");
1422 0 : return OGRERR_FAILURE;
1423 : }
1424 :
1425 66 : EnsureInitialized();
1426 :
1427 132 : OGRFieldDefn dstField(srsField);
1428 :
1429 66 : if (launderColumnNames_)
1430 : {
1431 63 : auto nameRes = dataSource_->LaunderName(dstField.GetNameRef());
1432 63 : if (nameRes.first != OGRERR_NONE)
1433 0 : return nameRes.first;
1434 63 : dstField.SetName(nameRes.second.c_str());
1435 : }
1436 :
1437 197 : if (fidFieldIndex_ != OGRNullFID &&
1438 67 : EQUAL(dstField.GetNameRef(), GetFIDColumn()) &&
1439 133 : dstField.GetType() != OFTInteger && dstField.GetType() != OFTInteger64)
1440 : {
1441 1 : CPLError(CE_Failure, CPLE_AppDefined, "Wrong field type for %s",
1442 : dstField.GetNameRef());
1443 1 : return OGRERR_FAILURE;
1444 : }
1445 :
1446 130 : ColumnTypeInfo columnTypeInfo = GetColumnTypeInfo(dstField);
1447 130 : CPLString columnDef = GetColumnDefinition(columnTypeInfo);
1448 :
1449 65 : if (columnTypeInfo.type == odbc::SQLDataTypes::Unknown)
1450 : {
1451 0 : if (columnTypeInfo.name.empty())
1452 0 : return OGRERR_FAILURE;
1453 :
1454 0 : if (approxOK)
1455 : {
1456 0 : dstField.SetDefault(nullptr);
1457 0 : CPLError(CE_Warning, CPLE_NotSupported,
1458 : "Unable to create field %s with type %s on HANA layers. "
1459 : "Creating as VARCHAR.",
1460 : dstField.GetNameRef(),
1461 : OGRFieldDefn::GetFieldTypeName(dstField.GetType()));
1462 0 : columnTypeInfo.name = "VARCHAR";
1463 0 : columnTypeInfo.width = static_cast<int>(defaultStringSize_);
1464 0 : columnDef = "VARCHAR(" + std::to_string(defaultStringSize_) + ")";
1465 : }
1466 : else
1467 : {
1468 0 : CPLError(CE_Failure, CPLE_NotSupported,
1469 : "Unable to create field %s with type %s on HANA layers.",
1470 : dstField.GetNameRef(),
1471 : OGRFieldDefn::GetFieldTypeName(dstField.GetType()));
1472 :
1473 0 : return OGRERR_FAILURE;
1474 : }
1475 : }
1476 :
1477 : CPLString clmClause =
1478 195 : QuotedIdentifier(dstField.GetNameRef()) + " " + columnDef;
1479 65 : if (!dstField.IsNullable())
1480 0 : clmClause += " NOT NULL";
1481 65 : if (dstField.GetDefault() != nullptr && !dstField.IsDefaultDriverSpecific())
1482 : {
1483 24 : if (IsArrayField(dstField.GetType()) ||
1484 12 : columnTypeInfo.type == odbc::SQLDataTypes::LongVarBinary)
1485 : {
1486 0 : CPLError(
1487 : CE_Failure, CPLE_NotSupported,
1488 : "Default value cannot be created on column of data type %s: "
1489 : "%s.",
1490 : columnTypeInfo.name.c_str(), dstField.GetNameRef());
1491 :
1492 0 : return OGRERR_FAILURE;
1493 : }
1494 :
1495 : clmClause +=
1496 12 : CPLString().Printf(" DEFAULT %s", GetColumnDefaultValue(dstField));
1497 : }
1498 :
1499 65 : FlushPendingBatches(false);
1500 :
1501 65 : const CPLString sql = CPLString().Printf(
1502 : "ALTER TABLE %s ADD(%s)",
1503 130 : GetFullTableNameQuoted(schemaName_, tableName_).c_str(),
1504 195 : clmClause.c_str());
1505 :
1506 : try
1507 : {
1508 66 : dataSource_->ExecuteSQL(sql.c_str());
1509 : }
1510 1 : catch (const odbc::Exception &ex)
1511 : {
1512 1 : CPLError(CE_Failure, CPLE_AppDefined,
1513 : "Failed to execute create attribute field %s: %s",
1514 1 : dstField.GetNameRef(), ex.what());
1515 1 : return OGRERR_FAILURE;
1516 : }
1517 :
1518 : // columnTypeInfo might contain a different definition due to custom column
1519 : // types
1520 64 : SetFieldDefn(dstField, columnTypeInfo);
1521 :
1522 64 : AttributeColumnDescription clmDesc;
1523 64 : clmDesc.name = dstField.GetNameRef();
1524 64 : clmDesc.type = columnTypeInfo.type;
1525 64 : clmDesc.typeName = columnTypeInfo.name;
1526 64 : clmDesc.isArray = IsArrayField(dstField.GetType());
1527 64 : clmDesc.length = columnTypeInfo.width;
1528 64 : clmDesc.isNullable = dstField.IsNullable();
1529 64 : clmDesc.isAutoIncrement = false; // TODO
1530 64 : clmDesc.scale = static_cast<unsigned short>(columnTypeInfo.precision);
1531 64 : clmDesc.precision = static_cast<unsigned short>(columnTypeInfo.width);
1532 64 : if (dstField.GetDefault() != nullptr)
1533 12 : clmDesc.defaultValue = dstField.GetDefault();
1534 :
1535 64 : attrColumns_.push_back(clmDesc);
1536 64 : featureDefn_->AddFieldDefn(&dstField);
1537 :
1538 64 : ColumnsChanged();
1539 :
1540 64 : return OGRERR_NONE;
1541 : }
1542 :
1543 : /************************************************************************/
1544 : /* CreateGeomField() */
1545 : /************************************************************************/
1546 :
1547 5 : OGRErr OGRHanaTableLayer::CreateGeomField(const OGRGeomFieldDefn *geomField,
1548 : int)
1549 : {
1550 5 : if (!updateMode_)
1551 : {
1552 1 : CPLError(CE_Failure, CPLE_AppDefined, UNSUPPORTED_OP_READ_ONLY,
1553 : "CreateGeomField");
1554 1 : return OGRERR_FAILURE;
1555 : }
1556 :
1557 4 : if (!IsGeometryTypeSupported(geomField->GetType()))
1558 : {
1559 1 : CPLError(CE_Failure, CPLE_NotSupported,
1560 : "Geometry field '%s' in layer '%s' has unsupported type %s",
1561 : geomField->GetNameRef(), tableName_.c_str(),
1562 : OGRGeometryTypeToName(geomField->GetType()));
1563 1 : return OGRERR_FAILURE;
1564 : }
1565 :
1566 3 : EnsureInitialized();
1567 :
1568 3 : if (featureDefn_->GetGeomFieldIndex(geomField->GetNameRef()) >= 0)
1569 : {
1570 1 : CPLError(
1571 : CE_Failure, CPLE_AppDefined,
1572 : "CreateGeomField() called with an already existing field name: %s",
1573 : geomField->GetNameRef());
1574 1 : return OGRERR_FAILURE;
1575 : }
1576 :
1577 2 : FlushPendingBatches(false);
1578 :
1579 2 : int srid = dataSource_->GetSrsId(geomField->GetSpatialRef());
1580 2 : if (srid == UNDETERMINED_SRID)
1581 : {
1582 1 : CPLError(CE_Failure, CPLE_AppDefined,
1583 : "Unable to determine the srs-id for field name: %s",
1584 : geomField->GetNameRef());
1585 1 : return OGRERR_FAILURE;
1586 : }
1587 :
1588 2 : CPLString clmName(geomField->GetNameRef());
1589 1 : if (launderColumnNames_)
1590 : {
1591 1 : auto nameRes = dataSource_->LaunderName(geomField->GetNameRef());
1592 1 : if (nameRes.first != OGRERR_NONE)
1593 0 : return nameRes.first;
1594 1 : clmName.swap(nameRes.second);
1595 : }
1596 :
1597 1 : if (clmName.empty())
1598 1 : clmName = FindGeomFieldName(*featureDefn_);
1599 :
1600 1 : CPLString sql = CPLString().Printf(
1601 : "ALTER TABLE %s ADD(%s ST_GEOMETRY(%d))",
1602 2 : GetFullTableNameQuoted(schemaName_, tableName_).c_str(),
1603 4 : QuotedIdentifier(clmName).c_str(), srid);
1604 :
1605 : try
1606 : {
1607 1 : dataSource_->ExecuteSQL(sql.c_str());
1608 : }
1609 0 : catch (const odbc::Exception &ex)
1610 : {
1611 0 : CPLError(CE_Failure, CPLE_AppDefined,
1612 : "Failed to execute CreateGeomField() with field name '%s': %s",
1613 0 : geomField->GetNameRef(), ex.what());
1614 0 : return OGRERR_FAILURE;
1615 : }
1616 :
1617 : auto newGeomField = std::make_unique<OGRGeomFieldDefn>(
1618 1 : clmName.c_str(), geomField->GetType());
1619 1 : newGeomField->SetNullable(geomField->IsNullable());
1620 1 : newGeomField->SetSpatialRef(geomField->GetSpatialRef());
1621 2 : geomColumns_.push_back({newGeomField->GetNameRef(), newGeomField->GetType(),
1622 1 : srid, newGeomField->IsNullable() == TRUE});
1623 1 : featureDefn_->AddGeomFieldDefn(std::move(newGeomField));
1624 :
1625 1 : ColumnsChanged();
1626 :
1627 1 : return OGRERR_NONE;
1628 : }
1629 :
1630 : /************************************************************************/
1631 : /* DeleteField() */
1632 : /************************************************************************/
1633 :
1634 0 : OGRErr OGRHanaTableLayer::DeleteField(int field)
1635 : {
1636 0 : if (!updateMode_)
1637 : {
1638 0 : CPLError(CE_Failure, CPLE_NotSupported, UNSUPPORTED_OP_READ_ONLY,
1639 : "DeleteField");
1640 0 : return OGRERR_FAILURE;
1641 : }
1642 :
1643 0 : if (field < 0 || field >= featureDefn_->GetFieldCount())
1644 : {
1645 0 : CPLError(CE_Failure, CPLE_NotSupported, "Field index is out of range");
1646 0 : return OGRERR_FAILURE;
1647 : }
1648 :
1649 0 : EnsureInitialized();
1650 :
1651 0 : FlushPendingBatches(false);
1652 :
1653 0 : CPLString clmName = featureDefn_->GetFieldDefn(field)->GetNameRef();
1654 0 : CPLString sql = CPLString().Printf(
1655 : "ALTER TABLE %s DROP (%s)",
1656 0 : GetFullTableNameQuoted(schemaName_, tableName_).c_str(),
1657 0 : QuotedIdentifier(clmName).c_str());
1658 :
1659 : try
1660 : {
1661 0 : dataSource_->ExecuteSQL(sql.c_str());
1662 : }
1663 0 : catch (const odbc::Exception &ex)
1664 : {
1665 0 : CPLError(CE_Failure, CPLE_AppDefined, "Failed to drop column %s: %s",
1666 0 : clmName.c_str(), ex.what());
1667 0 : return OGRERR_FAILURE;
1668 : }
1669 :
1670 : auto it = std::find_if(attrColumns_.begin(), attrColumns_.end(),
1671 0 : [&](const AttributeColumnDescription &cd)
1672 0 : { return cd.name == clmName; });
1673 0 : attrColumns_.erase(it);
1674 0 : OGRErr ret = featureDefn_->DeleteFieldDefn(field);
1675 :
1676 0 : ColumnsChanged();
1677 :
1678 0 : return ret;
1679 : }
1680 :
1681 : /************************************************************************/
1682 : /* AlterFieldDefn() */
1683 : /************************************************************************/
1684 :
1685 0 : OGRErr OGRHanaTableLayer::AlterFieldDefn(int field, OGRFieldDefn *newFieldDefn,
1686 : int flagsIn)
1687 : {
1688 0 : if (!updateMode_)
1689 : {
1690 0 : CPLError(CE_Failure, CPLE_NotSupported, UNSUPPORTED_OP_READ_ONLY,
1691 : "AlterFieldDefn");
1692 0 : return OGRERR_FAILURE;
1693 : }
1694 :
1695 0 : EnsureInitialized();
1696 :
1697 0 : if (field < 0 || field >= featureDefn_->GetFieldCount())
1698 : {
1699 0 : CPLError(CE_Failure, CPLE_NotSupported, "Field index is out of range");
1700 0 : return OGRERR_FAILURE;
1701 : }
1702 :
1703 0 : OGRFieldDefn *fieldDefn = featureDefn_->GetFieldDefn(field);
1704 :
1705 0 : int64_t columnDescIdx = -1;
1706 0 : for (size_t i = 0; i < attrColumns_.size(); ++i)
1707 : {
1708 0 : if (EQUAL(attrColumns_[i].name.c_str(), fieldDefn->GetNameRef()))
1709 : {
1710 0 : columnDescIdx = i;
1711 0 : break;
1712 : }
1713 : }
1714 :
1715 0 : if (columnDescIdx < 0)
1716 : {
1717 0 : CPLError(CE_Failure, CPLE_NotSupported,
1718 : "Column description cannot be found");
1719 0 : return OGRERR_FAILURE;
1720 : }
1721 :
1722 0 : CPLString clmName(newFieldDefn->GetNameRef());
1723 :
1724 0 : if (launderColumnNames_)
1725 : {
1726 0 : auto nameRes = dataSource_->LaunderName(newFieldDefn->GetNameRef());
1727 0 : if (nameRes.first != OGRERR_NONE)
1728 0 : return nameRes.first;
1729 0 : clmName.swap(nameRes.second);
1730 : }
1731 :
1732 0 : FlushPendingBatches(false);
1733 :
1734 0 : ColumnTypeInfo columnTypeInfo = GetColumnTypeInfo(*newFieldDefn);
1735 :
1736 : try
1737 : {
1738 0 : if ((flagsIn & ALTER_NAME_FLAG) &&
1739 0 : (strcmp(fieldDefn->GetNameRef(), newFieldDefn->GetNameRef()) != 0))
1740 : {
1741 0 : CPLString sql = CPLString().Printf(
1742 : "RENAME COLUMN %s TO %s",
1743 0 : GetFullColumnNameQuoted(schemaName_, tableName_,
1744 : fieldDefn->GetNameRef())
1745 : .c_str(),
1746 0 : QuotedIdentifier(clmName).c_str());
1747 0 : dataSource_->ExecuteSQL(sql.c_str());
1748 : }
1749 :
1750 0 : if ((flagsIn & ALTER_TYPE_FLAG) ||
1751 0 : (flagsIn & ALTER_WIDTH_PRECISION_FLAG) ||
1752 0 : (flagsIn & ALTER_NULLABLE_FLAG) || (flagsIn & ALTER_DEFAULT_FLAG))
1753 : {
1754 0 : CPLString fieldTypeDef = GetColumnDefinition(columnTypeInfo);
1755 0 : if ((flagsIn & ALTER_NULLABLE_FLAG) &&
1756 0 : fieldDefn->IsNullable() != newFieldDefn->IsNullable())
1757 : {
1758 0 : if (fieldDefn->IsNullable())
1759 0 : fieldTypeDef += " NULL";
1760 : else
1761 0 : fieldTypeDef += " NOT NULL";
1762 : }
1763 :
1764 0 : if ((flagsIn & ALTER_DEFAULT_FLAG) &&
1765 0 : ((fieldDefn->GetDefault() == nullptr &&
1766 0 : newFieldDefn->GetDefault() != nullptr) ||
1767 0 : (fieldDefn->GetDefault() != nullptr &&
1768 0 : newFieldDefn->GetDefault() == nullptr) ||
1769 0 : (fieldDefn->GetDefault() != nullptr &&
1770 0 : newFieldDefn->GetDefault() != nullptr &&
1771 0 : strcmp(fieldDefn->GetDefault(), newFieldDefn->GetDefault()) !=
1772 : 0)))
1773 : {
1774 : fieldTypeDef +=
1775 0 : " DEFAULT " + ((fieldDefn->GetType() == OFTString)
1776 0 : ? Literal(newFieldDefn->GetDefault())
1777 0 : : CPLString(newFieldDefn->GetDefault()));
1778 : }
1779 :
1780 0 : CPLString sql = CPLString().Printf(
1781 : "ALTER TABLE %s ALTER(%s %s)",
1782 0 : GetFullTableNameQuoted(schemaName_, tableName_).c_str(),
1783 0 : QuotedIdentifier(clmName).c_str(), fieldTypeDef.c_str());
1784 :
1785 0 : dataSource_->ExecuteSQL(sql.c_str());
1786 : }
1787 : }
1788 0 : catch (const odbc::Exception &ex)
1789 : {
1790 0 : CPLError(CE_Failure, CPLE_AppDefined, "Failed to alter field %s: %s",
1791 0 : fieldDefn->GetNameRef(), ex.what());
1792 0 : return OGRERR_FAILURE;
1793 : }
1794 :
1795 : // Update field definition and column description
1796 :
1797 0 : AttributeColumnDescription &attrClmDesc = attrColumns_[columnDescIdx];
1798 :
1799 0 : if (flagsIn & ALTER_NAME_FLAG)
1800 : {
1801 0 : fieldDefn->SetName(clmName.c_str());
1802 0 : attrClmDesc.name.assign(clmName.c_str());
1803 : }
1804 :
1805 0 : if (flagsIn & ALTER_TYPE_FLAG)
1806 : {
1807 0 : fieldDefn->SetSubType(OFSTNone);
1808 0 : fieldDefn->SetType(newFieldDefn->GetType());
1809 0 : fieldDefn->SetSubType(newFieldDefn->GetSubType());
1810 0 : attrClmDesc.isArray = IsArrayField(newFieldDefn->GetType());
1811 0 : attrClmDesc.type = columnTypeInfo.type;
1812 0 : attrClmDesc.typeName = columnTypeInfo.name;
1813 : }
1814 :
1815 0 : if (flagsIn & ALTER_WIDTH_PRECISION_FLAG)
1816 : {
1817 0 : fieldDefn->SetWidth(newFieldDefn->GetWidth());
1818 0 : fieldDefn->SetPrecision(newFieldDefn->GetPrecision());
1819 0 : attrClmDesc.length = newFieldDefn->GetWidth();
1820 0 : attrClmDesc.scale = newFieldDefn->GetWidth();
1821 0 : attrClmDesc.precision = newFieldDefn->GetPrecision();
1822 : }
1823 :
1824 0 : if (flagsIn & ALTER_NULLABLE_FLAG)
1825 : {
1826 0 : fieldDefn->SetNullable(newFieldDefn->IsNullable());
1827 0 : attrClmDesc.isNullable = newFieldDefn->IsNullable();
1828 : }
1829 :
1830 0 : if (flagsIn & ALTER_DEFAULT_FLAG)
1831 : {
1832 0 : fieldDefn->SetDefault(newFieldDefn->GetDefault());
1833 0 : attrClmDesc.name.assign(newFieldDefn->GetDefault());
1834 : }
1835 :
1836 0 : ColumnsChanged();
1837 :
1838 0 : return OGRERR_NONE;
1839 : }
1840 :
1841 : /************************************************************************/
1842 : /* ClearBatches() */
1843 : /************************************************************************/
1844 :
1845 4 : void OGRHanaTableLayer::ClearBatches()
1846 : {
1847 4 : if (!insertFeatureStmtWithFID_.isNull())
1848 4 : insertFeatureStmtWithFID_->clearBatch();
1849 4 : if (!insertFeatureStmtWithoutFID_.isNull())
1850 1 : insertFeatureStmtWithoutFID_->clearBatch();
1851 4 : if (!updateFeatureStmt_.isNull())
1852 2 : updateFeatureStmt_->clearBatch();
1853 4 : }
1854 :
1855 : /************************************************************************/
1856 : /* ColumnsChanged() */
1857 : /************************************************************************/
1858 :
1859 65 : void OGRHanaTableLayer::ColumnsChanged()
1860 : {
1861 65 : ClearQueryStatement();
1862 65 : ResetReading();
1863 65 : ResetPreparedStatements();
1864 65 : }
1865 :
1866 : /************************************************************************/
1867 : /* SetCustomColumnTypes() */
1868 : /************************************************************************/
1869 :
1870 18 : void OGRHanaTableLayer::SetCustomColumnTypes(const char *columnTypes)
1871 : {
1872 18 : if (columnTypes == nullptr)
1873 17 : return;
1874 :
1875 1 : const char *ptr = columnTypes;
1876 1 : const char *start = ptr;
1877 42 : while (*ptr != '\0')
1878 : {
1879 41 : if (*ptr == '(')
1880 : {
1881 : // Skip commas inside brackets, for example decimal(20,5)
1882 12 : while (*ptr != '\0' && *ptr != ')')
1883 : {
1884 10 : ++ptr;
1885 : }
1886 : }
1887 :
1888 41 : ++ptr;
1889 :
1890 41 : if (*ptr == ',' || *ptr == '\0')
1891 : {
1892 3 : std::size_t len = static_cast<std::size_t>(ptr - start);
1893 3 : const char *sep = std::find(start, start + len, '=');
1894 3 : if (sep != nullptr)
1895 : {
1896 3 : std::size_t pos = static_cast<std::size_t>(sep - start);
1897 6 : customColumnDefs_.push_back(
1898 : {CPLString(start, pos),
1899 3 : CPLString(start + pos + 1, len - pos - 1)});
1900 : }
1901 :
1902 3 : start = ptr + 1;
1903 : }
1904 : }
1905 : }
1906 :
1907 : /************************************************************************/
1908 : /* StartTransaction() */
1909 : /************************************************************************/
1910 :
1911 11 : OGRErr OGRHanaTableLayer::StartTransaction()
1912 : {
1913 11 : return dataSource_->StartTransaction();
1914 : }
1915 :
1916 : /************************************************************************/
1917 : /* CommitTransaction() */
1918 : /************************************************************************/
1919 :
1920 7 : OGRErr OGRHanaTableLayer::CommitTransaction()
1921 : {
1922 7 : if (HasPendingBatches())
1923 : {
1924 0 : OGRErr err = ExecutePendingBatches(BatchOperation::ALL);
1925 0 : if (OGRERR_NONE != err)
1926 0 : return err;
1927 : }
1928 :
1929 7 : return dataSource_->CommitTransaction();
1930 : }
1931 :
1932 : /************************************************************************/
1933 : /* RollbackTransaction() */
1934 : /************************************************************************/
1935 :
1936 4 : OGRErr OGRHanaTableLayer::RollbackTransaction()
1937 : {
1938 4 : ClearBatches();
1939 4 : return dataSource_->RollbackTransaction();
1940 : }
1941 :
1942 : } // namespace OGRHANA
|