Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: SAP HANA Spatial Driver
4 : * Purpose: OGRHanaLayer 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 "ogrhanafeaturewriter.h"
31 : #include "ogrhanautils.h"
32 :
33 : #include <algorithm>
34 : #include <limits>
35 : #include <sstream>
36 : #include <memory>
37 :
38 : #include "odbc/Exception.h"
39 : #include "odbc/ResultSet.h"
40 : #include "odbc/Statement.h"
41 : #include "odbc/Types.h"
42 :
43 : namespace OGRHANA
44 : {
45 : namespace
46 : {
47 : /************************************************************************/
48 : /* Helper methods */
49 : /************************************************************************/
50 :
51 11 : CPLString BuildQuery(const char *source, const char *columns, const char *where,
52 : const char *orderBy, int limit)
53 : {
54 11 : std::ostringstream os;
55 11 : os << "SELECT " << columns << " FROM (" << source << ")";
56 11 : if (where != nullptr && strlen(where) > 0)
57 0 : os << " WHERE " << where;
58 11 : if (orderBy != nullptr && strlen(orderBy) > 0)
59 0 : os << " ORDER BY " << orderBy;
60 11 : if (limit >= 0)
61 0 : os << " LIMIT " << std::to_string(limit);
62 33 : return os.str();
63 : }
64 :
65 11 : CPLString BuildQuery(const char *source, const char *columns)
66 : {
67 11 : return BuildQuery(source, columns, nullptr, nullptr, -1);
68 : }
69 :
70 24 : CPLString BuildSpatialFilter(int dbVersion, const OGRGeometry &geom,
71 : const CPLString &clmName, int srid)
72 : {
73 24 : OGREnvelope env;
74 24 : geom.getEnvelope(&env);
75 :
76 24 : if ((CPLIsInf(env.MinX) || CPLIsInf(env.MinY) || CPLIsInf(env.MaxX) ||
77 22 : CPLIsInf(env.MaxY)))
78 2 : return "";
79 :
80 88 : auto clampValue = [](double v)
81 : {
82 88 : constexpr double MAX_VALUE = 1e+150;
83 88 : if (v < -MAX_VALUE)
84 4 : return -MAX_VALUE;
85 84 : else if (v > MAX_VALUE)
86 4 : return MAX_VALUE;
87 80 : return v;
88 : };
89 :
90 22 : double minX = clampValue(env.MinX);
91 22 : double minY = clampValue(env.MinY);
92 22 : double maxX = clampValue(env.MaxX);
93 22 : double maxY = clampValue(env.MaxY);
94 :
95 : // TODO: add support for non-rectangular filter, see m_bFilterIsEnvelope
96 : // flag.
97 22 : if (dbVersion == 1)
98 0 : return CPLString().Printf(
99 : "\"%s\".ST_IntersectsRect(ST_GeomFromText('POINT(%.18g %.18g)', "
100 : "%d), ST_GeomFromText('POINT(%.18g %.18g)', %d)) = 1",
101 0 : clmName.c_str(), minX, minY, srid, maxX, maxY, srid);
102 : else
103 44 : return CPLString().Printf(
104 : "\"%s\".ST_IntersectsRectPlanar(ST_GeomFromText('POINT(%.18g "
105 : "%.18g)', %d), ST_GeomFromText('POINT(%.18g %.18g)', %d)) = 1",
106 22 : clmName.c_str(), minX, minY, srid, maxX, maxY, srid);
107 : }
108 :
109 : std::unique_ptr<OGRFieldDefn>
110 156 : CreateFieldDefn(const AttributeColumnDescription &columnDesc)
111 : {
112 156 : bool setFieldSize = false;
113 156 : bool setFieldPrecision = false;
114 :
115 156 : OGRFieldType ogrFieldType = OFTString;
116 156 : OGRFieldSubType ogrFieldSubType = OGRFieldSubType::OFSTNone;
117 :
118 156 : switch (columnDesc.type)
119 : {
120 2 : case odbc::SQLDataTypes::Bit:
121 : case odbc::SQLDataTypes::Boolean:
122 2 : ogrFieldType = columnDesc.isArray ? OFTIntegerList : OFTInteger;
123 2 : ogrFieldSubType = OGRFieldSubType::OFSTBoolean;
124 2 : break;
125 3 : case odbc::SQLDataTypes::TinyInt:
126 : case odbc::SQLDataTypes::SmallInt:
127 3 : ogrFieldType = columnDesc.isArray ? OFTIntegerList : OFTInteger;
128 3 : ogrFieldSubType = OGRFieldSubType::OFSTInt16;
129 3 : break;
130 51 : case odbc::SQLDataTypes::Integer:
131 51 : ogrFieldType = columnDesc.isArray ? OFTIntegerList : OFTInteger;
132 51 : break;
133 26 : case odbc::SQLDataTypes::BigInt:
134 26 : ogrFieldType = columnDesc.isArray ? OFTInteger64List : OFTInteger64;
135 26 : break;
136 23 : case odbc::SQLDataTypes::Double:
137 : case odbc::SQLDataTypes::Real:
138 : case odbc::SQLDataTypes::Float:
139 23 : ogrFieldType = columnDesc.isArray ? OFTRealList : OFTReal;
140 23 : if (columnDesc.type != odbc::SQLDataTypes::Double)
141 1 : ogrFieldSubType = OGRFieldSubType::OFSTFloat32;
142 23 : break;
143 3 : case odbc::SQLDataTypes::Decimal:
144 : case odbc::SQLDataTypes::Numeric:
145 3 : ogrFieldType = columnDesc.isArray ? OFTRealList : OFTReal;
146 3 : setFieldPrecision = true;
147 3 : break;
148 43 : case odbc::SQLDataTypes::Char:
149 : case odbc::SQLDataTypes::VarChar:
150 : case odbc::SQLDataTypes::LongVarChar:
151 : case odbc::SQLDataTypes::WChar:
152 : case odbc::SQLDataTypes::WVarChar:
153 : case odbc::SQLDataTypes::WLongVarChar:
154 : // Note: OFTWideString is deprecated
155 43 : ogrFieldType = columnDesc.isArray ? OFTStringList : OFTString;
156 43 : setFieldSize = true;
157 43 : break;
158 1 : case odbc::SQLDataTypes::Date:
159 : case odbc::SQLDataTypes::TypeDate:
160 1 : ogrFieldType = OFTDate;
161 1 : break;
162 1 : case odbc::SQLDataTypes::Time:
163 : case odbc::SQLDataTypes::TypeTime:
164 1 : ogrFieldType = OFTTime;
165 1 : break;
166 2 : case odbc::SQLDataTypes::Timestamp:
167 : case odbc::SQLDataTypes::TypeTimestamp:
168 2 : ogrFieldType = OFTDateTime;
169 2 : break;
170 1 : case odbc::SQLDataTypes::Binary:
171 : case odbc::SQLDataTypes::VarBinary:
172 : case odbc::SQLDataTypes::LongVarBinary:
173 1 : ogrFieldType = OFTBinary;
174 1 : setFieldSize = true;
175 1 : break;
176 0 : default:
177 0 : break;
178 : }
179 :
180 156 : if (columnDesc.isArray && !IsArrayField(ogrFieldType))
181 0 : CPLError(CE_Failure, CPLE_AppDefined,
182 : "Array of type %s in column %s is not supported",
183 : columnDesc.typeName.c_str(), columnDesc.name.c_str());
184 :
185 : auto field =
186 156 : std::make_unique<OGRFieldDefn>(columnDesc.name.c_str(), ogrFieldType);
187 156 : field->SetSubType(ogrFieldSubType);
188 156 : field->SetNullable(columnDesc.isNullable);
189 156 : if (!columnDesc.isArray)
190 : {
191 145 : if (setFieldSize)
192 41 : field->SetWidth(columnDesc.length);
193 145 : if (setFieldPrecision)
194 : {
195 3 : field->SetWidth(columnDesc.precision);
196 3 : field->SetPrecision(columnDesc.scale);
197 : }
198 : }
199 156 : if (columnDesc.defaultValue.empty())
200 144 : field->SetDefault(nullptr);
201 : else
202 12 : field->SetDefault(columnDesc.defaultValue.c_str());
203 312 : return field;
204 : }
205 :
206 513 : OGRGeometry *CreateGeometryFromWkb(const void *data, std::size_t size)
207 : {
208 513 : if (size > static_cast<std::size_t>(std::numeric_limits<int>::max()))
209 0 : CPLError(CE_Failure, CPLE_AppDefined, "createFromWkb(): %s",
210 : "Geometry size is larger than maximum integer value");
211 :
212 513 : int len = static_cast<int>(size);
213 :
214 513 : OGRGeometry *geom = nullptr;
215 513 : OGRErr err = OGRGeometryFactory::createFromWkb(data, nullptr, &geom, len);
216 :
217 513 : if (OGRERR_NONE == err)
218 513 : return geom;
219 :
220 0 : auto cplError = [](const char *message)
221 0 : { CPLError(CE_Failure, CPLE_AppDefined, "ReadFeature(): %s", message); };
222 :
223 0 : switch (err)
224 : {
225 0 : case OGRERR_NOT_ENOUGH_DATA:
226 0 : cplError("Not enough data to deserialize");
227 0 : return nullptr;
228 0 : case OGRERR_UNSUPPORTED_GEOMETRY_TYPE:
229 0 : cplError("Unsupported geometry type");
230 0 : return nullptr;
231 0 : case OGRERR_CORRUPT_DATA:
232 0 : cplError("Corrupt data");
233 0 : return nullptr;
234 0 : default:
235 0 : cplError("Unrecognized error");
236 0 : return nullptr;
237 : }
238 : }
239 :
240 : } // anonymous namespace
241 :
242 : /************************************************************************/
243 : /* OGRHanaLayer() */
244 : /************************************************************************/
245 :
246 421 : OGRHanaLayer::OGRHanaLayer(OGRHanaDataSource *datasource)
247 : : dataSource_(datasource), rawQuery_(""), queryStatement_(""),
248 421 : whereClause_("")
249 : {
250 421 : }
251 :
252 : /************************************************************************/
253 : /* ~OGRHanaLayer() */
254 : /************************************************************************/
255 :
256 418 : OGRHanaLayer::~OGRHanaLayer()
257 : {
258 418 : if (featureDefn_)
259 48 : featureDefn_->Release();
260 418 : }
261 :
262 1556 : void OGRHanaLayer::EnsureInitialized()
263 : {
264 1556 : if (initialized_)
265 1505 : return;
266 :
267 51 : OGRErr err = Initialize();
268 51 : if (OGRERR_NONE != err)
269 : {
270 0 : CPLError(CE_Failure, CPLE_AppDefined, "Failed to initialize layer: %s",
271 0 : GetName());
272 : }
273 51 : initialized_ = (OGRERR_NONE == err);
274 : }
275 :
276 : /************************************************************************/
277 : /* ClearQueryStatement() */
278 : /************************************************************************/
279 :
280 186 : void OGRHanaLayer::ClearQueryStatement()
281 : {
282 186 : queryStatement_.clear();
283 186 : }
284 :
285 : /************************************************************************/
286 : /* GetQueryStatement() */
287 : /************************************************************************/
288 :
289 168 : const CPLString &OGRHanaLayer::GetQueryStatement()
290 : {
291 168 : if (!queryStatement_.empty())
292 57 : return queryStatement_;
293 :
294 111 : EnsureInitialized();
295 :
296 111 : if (!geomColumns_.empty())
297 : {
298 99 : std::vector<CPLString> columns;
299 198 : for (const GeometryColumnDescription &geometryColumnDesc : geomColumns_)
300 297 : columns.push_back(QuotedIdentifier(geometryColumnDesc.name) +
301 198 : ".ST_AsBinary() AS " +
302 198 : QuotedIdentifier(geometryColumnDesc.name));
303 :
304 505 : for (const AttributeColumnDescription &attributeColumnDesc :
305 604 : attrColumns_)
306 505 : columns.push_back(QuotedIdentifier(attributeColumnDesc.name));
307 :
308 198 : queryStatement_ = CPLString().Printf(
309 198 : "SELECT %s FROM (%s) %s", JoinStrings(columns, ", ").c_str(),
310 198 : rawQuery_.c_str(), whereClause_.c_str());
311 : }
312 : else
313 : {
314 12 : if (whereClause_.empty())
315 12 : queryStatement_ = rawQuery_;
316 : else
317 : queryStatement_ =
318 0 : CPLString().Printf("SELECT * FROM (%s) %s", rawQuery_.c_str(),
319 0 : whereClause_.c_str());
320 : }
321 :
322 111 : return queryStatement_;
323 : }
324 :
325 : /************************************************************************/
326 : /* BuildWhereClause() */
327 : /************************************************************************/
328 :
329 121 : void OGRHanaLayer::BuildWhereClause()
330 : {
331 121 : whereClause_ = "";
332 :
333 242 : CPLString spatialFilter;
334 121 : if (m_poFilterGeom != nullptr)
335 : {
336 24 : EnsureInitialized();
337 :
338 24 : OGRGeomFieldDefn *geomFieldDefn = nullptr;
339 24 : if (featureDefn_->GetGeomFieldCount() != 0)
340 24 : geomFieldDefn = featureDefn_->GetGeomFieldDefn(m_iGeomFieldFilter);
341 :
342 24 : if (geomFieldDefn != nullptr)
343 : {
344 : const GeometryColumnDescription &geomClmDesc =
345 24 : geomColumns_[static_cast<std::size_t>(m_iGeomFieldFilter)];
346 48 : spatialFilter = BuildSpatialFilter(
347 24 : dataSource_->GetMajorVersion(), *m_poFilterGeom,
348 48 : geomClmDesc.name, geomClmDesc.srid);
349 : }
350 : }
351 :
352 121 : if (!attrFilter_.empty())
353 : {
354 32 : whereClause_ = " WHERE " + attrFilter_;
355 32 : if (!spatialFilter.empty())
356 4 : whereClause_ += " AND " + spatialFilter;
357 : }
358 89 : else if (!spatialFilter.empty())
359 18 : whereClause_ = " WHERE " + spatialFilter;
360 121 : }
361 :
362 : /************************************************************************/
363 : /* EnsureBufferCapacity() */
364 : /************************************************************************/
365 :
366 1155 : void OGRHanaLayer::EnsureBufferCapacity(std::size_t size)
367 : {
368 1155 : if (size > dataBuffer_.size())
369 65 : dataBuffer_.resize(size);
370 1155 : }
371 :
372 : /************************************************************************/
373 : /* GetNextFeatureInternal() */
374 : /************************************************************************/
375 :
376 597 : OGRFeature *OGRHanaLayer::GetNextFeatureInternal()
377 : {
378 597 : if (resultSet_.isNull())
379 : {
380 115 : const CPLString &queryStatement = GetQueryStatement();
381 115 : CPLAssert(!queryStatement.empty());
382 :
383 : try
384 : {
385 115 : odbc::StatementRef stmt = dataSource_->CreateStatement();
386 115 : resultSet_ = stmt->executeQuery(queryStatement.c_str());
387 : }
388 0 : catch (const odbc::Exception &ex)
389 : {
390 0 : CPLError(CE_Failure, CPLE_AppDefined,
391 0 : "Failed to execute query : %s", ex.what());
392 0 : return nullptr;
393 : }
394 : }
395 :
396 597 : return ReadFeature();
397 : }
398 :
399 : /************************************************************************/
400 : /* GetGeometryColumnSrid() */
401 : /************************************************************************/
402 :
403 11 : int OGRHanaLayer::GetGeometryColumnSrid(int columnIndex) const
404 : {
405 22 : if (columnIndex < 0 ||
406 11 : static_cast<std::size_t>(columnIndex) >= geomColumns_.size())
407 0 : return -1;
408 11 : return geomColumns_[static_cast<std::size_t>(columnIndex)].srid;
409 : }
410 :
411 : /************************************************************************/
412 : /* ReadFeature() */
413 : /************************************************************************/
414 :
415 597 : OGRFeature *OGRHanaLayer::ReadFeature()
416 : {
417 597 : if (!resultSet_->next())
418 54 : return nullptr;
419 :
420 1086 : auto feature = std::make_unique<OGRFeature>(featureDefn_);
421 543 : feature->SetFID(nextFeatureId_++);
422 :
423 543 : unsigned short paramIndex = 0;
424 :
425 : // Read geometries
426 1061 : for (std::size_t i = 0; i < geomColumns_.size(); ++i)
427 : {
428 518 : ++paramIndex;
429 518 : int geomIndex = static_cast<int>(i);
430 :
431 : OGRGeomFieldDefn *geomFieldDef =
432 518 : featureDefn_->GetGeomFieldDefn(geomIndex);
433 :
434 518 : if (geomFieldDef->IsIgnored())
435 0 : continue;
436 :
437 518 : std::size_t bufLength = resultSet_->getBinaryLength(paramIndex);
438 518 : if (bufLength == 0 || bufLength == odbc::ResultSet::NULL_DATA)
439 : {
440 5 : feature->SetGeomFieldDirectly(geomIndex, nullptr);
441 5 : continue;
442 : }
443 :
444 513 : OGRGeometry *geom = nullptr;
445 513 : if (bufLength != odbc::ResultSet::UNKNOWN_LENGTH)
446 : {
447 513 : EnsureBufferCapacity(bufLength);
448 513 : resultSet_->getBinaryData(paramIndex, dataBuffer_.data(),
449 : bufLength);
450 : geom =
451 513 : CreateGeometryFromWkb(dataBuffer_.data(), dataBuffer_.size());
452 : }
453 : else
454 : {
455 0 : odbc::Binary wkb = resultSet_->getBinary(paramIndex);
456 0 : if (!wkb.isNull() && wkb->size() > 0)
457 0 : geom = CreateGeometryFromWkb(
458 0 : static_cast<const void *>(wkb->data()), wkb->size());
459 : }
460 :
461 513 : if (geom != nullptr)
462 513 : geom->assignSpatialReference(geomFieldDef->GetSpatialRef());
463 513 : feature->SetGeomFieldDirectly(geomIndex, geom);
464 : }
465 :
466 : // Read feature attributes
467 543 : OGRHanaFeatureWriter featWriter(*feature);
468 543 : int fieldIndex = -1;
469 3182 : for (const AttributeColumnDescription &clmDesc : attrColumns_)
470 : {
471 2639 : ++paramIndex;
472 :
473 2639 : if (clmDesc.isFeatureID)
474 : {
475 528 : if (clmDesc.type == odbc::SQLDataTypes::Integer)
476 : {
477 528 : odbc::Int val = resultSet_->getInt(paramIndex);
478 528 : if (!val.isNull())
479 528 : feature->SetFID(static_cast<GIntBig>(*val));
480 : }
481 0 : else if (clmDesc.type == odbc::SQLDataTypes::BigInt)
482 : {
483 0 : odbc::Long val = resultSet_->getLong(paramIndex);
484 0 : if (!val.isNull())
485 0 : feature->SetFID(static_cast<GIntBig>(*val));
486 : }
487 528 : continue;
488 : }
489 :
490 2111 : ++fieldIndex;
491 :
492 2111 : OGRFieldDefn *fieldDefn = featureDefn_->GetFieldDefn(fieldIndex);
493 2111 : if (fieldDefn->IsIgnored())
494 0 : continue;
495 :
496 2111 : if (clmDesc.isArray)
497 : {
498 22 : odbc::Binary val = resultSet_->getBinary(paramIndex);
499 11 : if (val.isNull())
500 : {
501 0 : feature->SetFieldNull(fieldIndex);
502 0 : continue;
503 : }
504 :
505 11 : switch (clmDesc.type)
506 : {
507 1 : case odbc::SQLDataTypes::Boolean:
508 1 : featWriter.SetFieldValueAsArray<uint8_t, int32_t>(
509 : fieldIndex, val);
510 1 : break;
511 0 : case odbc::SQLDataTypes::TinyInt:
512 0 : featWriter.SetFieldValueAsArray<uint8_t, int32_t>(
513 : fieldIndex, val);
514 0 : break;
515 1 : case odbc::SQLDataTypes::SmallInt:
516 1 : featWriter.SetFieldValueAsArray<int16_t, int32_t>(
517 : fieldIndex, val);
518 1 : break;
519 2 : case odbc::SQLDataTypes::Integer:
520 2 : featWriter.SetFieldValueAsArray<int32_t, int32_t>(
521 : fieldIndex, val);
522 2 : break;
523 2 : case odbc::SQLDataTypes::BigInt:
524 2 : featWriter.SetFieldValueAsArray<GIntBig, GIntBig>(
525 : fieldIndex, val);
526 2 : break;
527 0 : case odbc::SQLDataTypes::Float:
528 : case odbc::SQLDataTypes::Real:
529 0 : featWriter.SetFieldValueAsArray<float, double>(fieldIndex,
530 : val);
531 0 : break;
532 2 : case odbc::SQLDataTypes::Double:
533 2 : featWriter.SetFieldValueAsArray<double, double>(fieldIndex,
534 : val);
535 2 : break;
536 3 : case odbc::SQLDataTypes::Char:
537 : case odbc::SQLDataTypes::VarChar:
538 : case odbc::SQLDataTypes::LongVarChar:
539 : case odbc::SQLDataTypes::WChar:
540 : case odbc::SQLDataTypes::WVarChar:
541 : case odbc::SQLDataTypes::WLongVarChar:
542 3 : featWriter.SetFieldValueAsStringArray(fieldIndex, val);
543 3 : break;
544 : }
545 :
546 11 : continue;
547 : }
548 :
549 2100 : switch (clmDesc.type)
550 : {
551 1 : case odbc::SQLDataTypes::Bit:
552 : case odbc::SQLDataTypes::Boolean:
553 : {
554 1 : odbc::Boolean val = resultSet_->getBoolean(paramIndex);
555 1 : featWriter.SetFieldValue(fieldIndex, val);
556 : }
557 1 : break;
558 0 : case odbc::SQLDataTypes::TinyInt:
559 : {
560 0 : odbc::Byte val = resultSet_->getByte(paramIndex);
561 0 : featWriter.SetFieldValue(fieldIndex, val);
562 : }
563 0 : break;
564 1 : case odbc::SQLDataTypes::SmallInt:
565 : {
566 1 : odbc::Short val = resultSet_->getShort(paramIndex);
567 1 : featWriter.SetFieldValue(fieldIndex, val);
568 : }
569 1 : break;
570 2 : case odbc::SQLDataTypes::Integer:
571 : {
572 2 : odbc::Int val = resultSet_->getInt(paramIndex);
573 2 : featWriter.SetFieldValue(fieldIndex, val);
574 : }
575 2 : break;
576 533 : case odbc::SQLDataTypes::BigInt:
577 : {
578 533 : odbc::Long val = resultSet_->getLong(paramIndex);
579 533 : featWriter.SetFieldValue(fieldIndex, val);
580 : }
581 533 : break;
582 1 : case odbc::SQLDataTypes::Real:
583 : case odbc::SQLDataTypes::Float:
584 : {
585 1 : odbc::Float val = resultSet_->getFloat(paramIndex);
586 1 : featWriter.SetFieldValue(fieldIndex, val);
587 : }
588 1 : break;
589 518 : case odbc::SQLDataTypes::Double:
590 : {
591 518 : odbc::Double val = resultSet_->getDouble(paramIndex);
592 518 : featWriter.SetFieldValue(fieldIndex, val);
593 : }
594 518 : break;
595 1 : case odbc::SQLDataTypes::Decimal:
596 : case odbc::SQLDataTypes::Numeric:
597 : {
598 2 : odbc::Decimal val = resultSet_->getDecimal(paramIndex);
599 1 : featWriter.SetFieldValue(fieldIndex, val);
600 : }
601 1 : break;
602 1036 : case odbc::SQLDataTypes::Char:
603 : case odbc::SQLDataTypes::VarChar:
604 : case odbc::SQLDataTypes::LongVarChar:
605 : // Note: NVARCHAR data type is converted to UTF-8 on the HANA side
606 : // when using a connection setting CHAR_AS_UTF8=1.
607 : case odbc::SQLDataTypes::WChar:
608 : case odbc::SQLDataTypes::WVarChar:
609 : case odbc::SQLDataTypes::WLongVarChar:
610 : {
611 1036 : std::size_t len = resultSet_->getStringLength(paramIndex);
612 1036 : if (len == odbc::ResultSet::NULL_DATA)
613 515 : feature->SetFieldNull(fieldIndex);
614 521 : else if (len == 0)
615 0 : feature->SetField(fieldIndex, "");
616 521 : else if (len != odbc::ResultSet::UNKNOWN_LENGTH)
617 : {
618 521 : EnsureBufferCapacity(len + 1);
619 521 : resultSet_->getStringData(paramIndex, dataBuffer_.data(),
620 : len + 1);
621 521 : featWriter.SetFieldValue(fieldIndex, dataBuffer_.data());
622 : }
623 : else
624 : {
625 0 : odbc::String data = resultSet_->getString(paramIndex);
626 0 : featWriter.SetFieldValue(fieldIndex, data);
627 : }
628 : }
629 1036 : break;
630 1 : case odbc::SQLDataTypes::Binary:
631 : case odbc::SQLDataTypes::VarBinary:
632 : case odbc::SQLDataTypes::LongVarBinary:
633 : {
634 1 : std::size_t len = resultSet_->getBinaryLength(paramIndex);
635 1 : if (len == 0)
636 0 : feature->SetField(fieldIndex, 0,
637 : static_cast<GByte *>(nullptr));
638 1 : else if (len == odbc::ResultSet::NULL_DATA)
639 0 : feature->SetFieldNull(fieldIndex);
640 1 : else if (len != odbc::ResultSet::UNKNOWN_LENGTH)
641 : {
642 1 : EnsureBufferCapacity(len);
643 1 : resultSet_->getBinaryData(paramIndex, dataBuffer_.data(),
644 : len);
645 1 : featWriter.SetFieldValue(fieldIndex, dataBuffer_.data(),
646 : len);
647 : }
648 : else
649 : {
650 0 : odbc::Binary binData = resultSet_->getBinary(paramIndex);
651 0 : featWriter.SetFieldValue(fieldIndex, binData);
652 : }
653 : }
654 1 : break;
655 1 : case odbc::SQLDataTypes::Date:
656 : case odbc::SQLDataTypes::TypeDate:
657 : {
658 1 : odbc::Date date = resultSet_->getDate(paramIndex);
659 1 : featWriter.SetFieldValue(fieldIndex, date);
660 : }
661 1 : break;
662 1 : case odbc::SQLDataTypes::Time:
663 : case odbc::SQLDataTypes::TypeTime:
664 : {
665 1 : odbc::Time time = resultSet_->getTime(paramIndex);
666 1 : featWriter.SetFieldValue(fieldIndex, time);
667 : }
668 1 : break;
669 4 : case odbc::SQLDataTypes::Timestamp:
670 : case odbc::SQLDataTypes::TypeTimestamp:
671 : {
672 : odbc::Timestamp timestamp =
673 4 : resultSet_->getTimestamp(paramIndex);
674 4 : featWriter.SetFieldValue(fieldIndex, timestamp);
675 : }
676 4 : break;
677 0 : default:
678 0 : break;
679 : }
680 : }
681 :
682 543 : return feature.release();
683 : }
684 :
685 : /************************************************************************/
686 : /* InitFeatureDefinition() */
687 : /************************************************************************/
688 :
689 51 : OGRErr OGRHanaLayer::InitFeatureDefinition(const CPLString &schemaName,
690 : const CPLString &tableName,
691 : const CPLString &query,
692 : const CPLString &featureDefName)
693 : {
694 51 : attrColumns_.clear();
695 51 : geomColumns_.clear();
696 51 : fidFieldIndex_ = OGRNullFID;
697 51 : fidFieldName_.clear();
698 51 : featureDefn_ = new OGRFeatureDefn(featureDefName.c_str());
699 51 : featureDefn_->Reference();
700 :
701 102 : std::vector<ColumnDescription> columnDescriptions;
702 : OGRErr err =
703 51 : dataSource_->GetQueryColumns(schemaName, query, columnDescriptions);
704 51 : if (err != OGRERR_NONE)
705 0 : return err;
706 :
707 : std::vector<CPLString> primKeys =
708 51 : dataSource_->GetTablePrimaryKeys(schemaName, tableName);
709 :
710 51 : if (featureDefn_->GetGeomFieldCount() == 1)
711 51 : featureDefn_->DeleteGeomFieldDefn(0);
712 :
713 239 : for (const ColumnDescription &clmDesc : columnDescriptions)
714 : {
715 188 : if (clmDesc.isGeometry)
716 : {
717 32 : const GeometryColumnDescription &geometryColumnDesc =
718 : clmDesc.geometryDescription;
719 :
720 : auto geomFieldDefn = std::make_unique<OGRGeomFieldDefn>(
721 64 : geometryColumnDesc.name.c_str(), geometryColumnDesc.type);
722 32 : geomFieldDefn->SetNullable(geometryColumnDesc.isNullable);
723 :
724 32 : if (geometryColumnDesc.srid >= 0)
725 : {
726 : OGRSpatialReference *srs =
727 29 : dataSource_->GetSrsById(geometryColumnDesc.srid);
728 29 : geomFieldDefn->SetSpatialRef(srs);
729 29 : srs->Release();
730 : }
731 32 : geomColumns_.push_back(geometryColumnDesc);
732 32 : featureDefn_->AddGeomFieldDefn(std::move(geomFieldDefn));
733 32 : continue;
734 : }
735 :
736 : AttributeColumnDescription attributeColumnDesc =
737 312 : clmDesc.attributeDescription;
738 312 : auto field = CreateFieldDefn(attributeColumnDesc);
739 :
740 260 : if ((field->GetType() == OFTInteger ||
741 312 : field->GetType() == OFTInteger64) &&
742 76 : (fidFieldIndex_ == OGRNullFID && primKeys.size() > 0))
743 : {
744 410 : for (const CPLString &key : primKeys)
745 : {
746 407 : if (key.compare(attributeColumnDesc.name) == 0)
747 : {
748 44 : fidFieldIndex_ = static_cast<int>(attrColumns_.size());
749 44 : fidFieldName_ = field->GetNameRef();
750 44 : attributeColumnDesc.isFeatureID = true;
751 44 : break;
752 : }
753 : }
754 : }
755 :
756 156 : if (!attributeColumnDesc.isFeatureID)
757 112 : featureDefn_->AddFieldDefn(field.get());
758 156 : attrColumns_.push_back(attributeColumnDesc);
759 : }
760 :
761 51 : return OGRERR_NONE;
762 : }
763 :
764 : /************************************************************************/
765 : /* ReadGeometryExtent() */
766 : /************************************************************************/
767 :
768 11 : void OGRHanaLayer::ReadGeometryExtent(int geomField, OGREnvelope *extent)
769 : {
770 11 : EnsureInitialized();
771 :
772 11 : OGRGeomFieldDefn *geomFieldDef = featureDefn_->GetGeomFieldDefn(geomField);
773 11 : const char *clmName = geomFieldDef->GetNameRef();
774 11 : int srid = GetGeometryColumnSrid(geomField);
775 22 : CPLString sql;
776 11 : if (dataSource_->IsSrsRoundEarth(srid))
777 : {
778 2 : CPLString quotedClmName = QuotedIdentifier(clmName);
779 1 : bool hasSrsPlanarEquivalent = dataSource_->HasSrsPlanarEquivalent(srid);
780 : CPLString geomColumn =
781 1 : !hasSrsPlanarEquivalent
782 : ? quotedClmName
783 2 : : CPLString().Printf("%s.ST_SRID(%d)", quotedClmName.c_str(),
784 3 : ToPlanarSRID(srid));
785 1 : CPLString columns = CPLString().Printf(
786 : "MIN(%s.ST_XMin()), MIN(%s.ST_YMin()), MAX(%s.ST_XMax()), "
787 : "MAX(%s.ST_YMax())",
788 : geomColumn.c_str(), geomColumn.c_str(), geomColumn.c_str(),
789 1 : geomColumn.c_str());
790 1 : sql = BuildQuery(rawQuery_.c_str(), columns.c_str());
791 : }
792 : else
793 : {
794 10 : CPLString columns = CPLString().Printf(
795 30 : "ST_EnvelopeAggr(%s) AS ext", QuotedIdentifier(clmName).c_str());
796 10 : CPLString subQuery = BuildQuery(rawQuery_.c_str(), columns);
797 20 : sql = CPLString().Printf(
798 : "SELECT ext.ST_XMin(),ext.ST_YMin(),ext.ST_XMax(),ext.ST_YMax() "
799 : "FROM (%s)",
800 10 : subQuery.c_str());
801 : }
802 :
803 11 : extent->MinX = 0.0;
804 11 : extent->MaxX = 0.0;
805 11 : extent->MinY = 0.0;
806 11 : extent->MaxY = 0.0;
807 :
808 22 : odbc::StatementRef stmt = dataSource_->CreateStatement();
809 22 : odbc::ResultSetRef rsExtent = stmt->executeQuery(sql.c_str());
810 11 : if (rsExtent->next())
811 : {
812 11 : odbc::Double val = rsExtent->getDouble(1);
813 11 : if (!val.isNull())
814 : {
815 11 : extent->MinX = *val;
816 11 : extent->MinY = *rsExtent->getDouble(2);
817 11 : extent->MaxX = *rsExtent->getDouble(3);
818 11 : extent->MaxY = *rsExtent->getDouble(4);
819 : }
820 : }
821 11 : rsExtent->close();
822 11 : }
823 :
824 : /************************************************************************/
825 : /* ResetReading() */
826 : /************************************************************************/
827 :
828 279 : void OGRHanaLayer::ResetReading()
829 : {
830 279 : nextFeatureId_ = 0;
831 279 : resultSet_.reset();
832 279 : }
833 :
834 : /************************************************************************/
835 : /* GetExtent() */
836 : /************************************************************************/
837 :
838 15 : OGRErr OGRHanaLayer::GetExtent(int iGeomField, OGREnvelope *extent, int force)
839 : {
840 26 : if (iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount() ||
841 11 : GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetType() == wkbNone)
842 : {
843 4 : extent->MinX = 0.0;
844 4 : extent->MaxX = 0.0;
845 4 : extent->MinY = 0.0;
846 4 : extent->MaxY = 0.0;
847 :
848 4 : if (iGeomField != 0)
849 : {
850 4 : CPLError(CE_Failure, CPLE_AppDefined,
851 : "Invalid geometry field index : %d", iGeomField);
852 : }
853 4 : return OGRERR_FAILURE;
854 : }
855 :
856 : try
857 : {
858 11 : ReadGeometryExtent(iGeomField, extent);
859 11 : return OGRERR_NONE;
860 : }
861 0 : catch (const std::exception &ex)
862 : {
863 : CPLString clmName =
864 0 : (iGeomField < static_cast<int>(geomColumns_.size()))
865 0 : ? geomColumns_[static_cast<std::size_t>(geomColumns_.size())]
866 0 : .name
867 0 : : "unknown column";
868 0 : CPLError(CE_Failure, CPLE_AppDefined,
869 : "Unable to query extent of '%s' using fast method: %s",
870 0 : clmName.c_str(), ex.what());
871 : }
872 :
873 0 : if (iGeomField == 0)
874 0 : return OGRLayer::GetExtent(extent, force);
875 : else
876 0 : return OGRLayer::GetExtent(iGeomField, extent, force);
877 : }
878 :
879 : /************************************************************************/
880 : /* GetFeatureCount() */
881 : /************************************************************************/
882 :
883 53 : GIntBig OGRHanaLayer::GetFeatureCount(CPL_UNUSED int force)
884 : {
885 53 : EnsureInitialized();
886 :
887 53 : GIntBig ret = 0;
888 53 : CPLString sql = CPLString().Printf("SELECT COUNT(*) FROM (%s) AS tmp",
889 106 : GetQueryStatement().c_str());
890 106 : odbc::StatementRef stmt = dataSource_->CreateStatement();
891 53 : odbc::ResultSetRef rs = stmt->executeQuery(sql.c_str());
892 53 : if (rs->next())
893 53 : ret = *rs->getLong(1);
894 53 : rs->close();
895 106 : return ret;
896 : }
897 :
898 : /************************************************************************/
899 : /* GetLayerDefn() */
900 : /************************************************************************/
901 :
902 417 : OGRFeatureDefn *OGRHanaLayer::GetLayerDefn()
903 : {
904 417 : EnsureInitialized();
905 417 : return featureDefn_;
906 : }
907 :
908 : /************************************************************************/
909 : /* GetName() */
910 : /************************************************************************/
911 :
912 2 : const char *OGRHanaLayer::GetName()
913 : {
914 2 : return GetDescription();
915 : }
916 :
917 : /************************************************************************/
918 : /* GetNextFeature() */
919 : /************************************************************************/
920 :
921 597 : OGRFeature *OGRHanaLayer::GetNextFeature()
922 : {
923 597 : EnsureInitialized();
924 :
925 : while (true)
926 : {
927 597 : OGRFeature *feature = GetNextFeatureInternal();
928 597 : if (feature == nullptr)
929 54 : return nullptr;
930 :
931 1179 : if ((m_poFilterGeom == nullptr ||
932 1086 : FilterGeometry(feature->GetGeometryRef())) &&
933 543 : (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(feature)))
934 543 : return feature;
935 :
936 0 : delete feature;
937 0 : }
938 : }
939 :
940 : /************************************************************************/
941 : /* GetFIDColumn() */
942 : /************************************************************************/
943 :
944 95 : const char *OGRHanaLayer::GetFIDColumn()
945 : {
946 95 : EnsureInitialized();
947 95 : return fidFieldName_.c_str();
948 : }
949 :
950 : /************************************************************************/
951 : /* SetAttributeFilter() */
952 : /************************************************************************/
953 :
954 101 : OGRErr OGRHanaLayer::SetAttributeFilter(const char *pszQuery)
955 : {
956 101 : CPLFree(m_pszAttrQueryString);
957 101 : m_pszAttrQueryString = pszQuery ? CPLStrdup(pszQuery) : nullptr;
958 :
959 101 : if (pszQuery == nullptr || strlen(pszQuery) == 0)
960 69 : attrFilter_ = "";
961 : else
962 32 : attrFilter_.assign(pszQuery, strlen(pszQuery));
963 :
964 101 : ClearQueryStatement();
965 101 : BuildWhereClause();
966 101 : ResetReading();
967 :
968 101 : return OGRERR_NONE;
969 : }
970 :
971 : /************************************************************************/
972 : /* SetSpatialFilter() */
973 : /************************************************************************/
974 :
975 78 : void OGRHanaLayer::SetSpatialFilter(int iGeomField, OGRGeometry *poGeom)
976 : {
977 78 : m_iGeomFieldFilter = 0;
978 :
979 78 : if (iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount())
980 : {
981 4 : CPLError(CE_Failure, CPLE_AppDefined,
982 : "Invalid geometry field index : %d", iGeomField);
983 4 : return;
984 : }
985 74 : m_iGeomFieldFilter = iGeomField;
986 :
987 74 : if (!InstallFilter(poGeom))
988 54 : return;
989 :
990 20 : ClearQueryStatement();
991 20 : BuildWhereClause();
992 20 : ResetReading();
993 : }
994 :
995 : } // namespace OGRHANA
|