Skip to content

Commit

Permalink
HANA: Add support for REAL_VECTOR type
Browse files Browse the repository at this point in the history
  • Loading branch information
mrylov committed Apr 22, 2024
1 parent 18f9ed2 commit d48e35f
Show file tree
Hide file tree
Showing 5 changed files with 448 additions and 303 deletions.
50 changes: 50 additions & 0 deletions autotest/ogr/ogr_hana.py
Original file line number Diff line number Diff line change
Expand Up @@ -1167,6 +1167,56 @@ def create_feature(fid, geom_wkt=None):
layer.CommitTransaction()


###############################################################################
# Test REAL_VECTOR type


def test_ogr_hana_38():
conn = create_connection()
layer_name = get_test_name()
table_name = f'"{gdaltest.hana_schema_name}"."{layer_name}"'
execute_sql(
conn,
f"CREATE COLUMN TABLE {table_name} (ID INT PRIMARY KEY, EMB1 REAL_VECTOR(3), EMB2 REAL_VECTOR)",
)
execute_sql(
conn,
f"INSERT INTO {table_name} VALUES (1, TO_REAL_VECTOR('[0.1,0.2,0.3]'), TO_REAL_VECTOR('[0.1,0.2,0.3]'))",
)

def check_value(expected):
ds = open_datasource(0)
layer = ds.GetLayerByName(layer_name)
layer_defn = layer.GetLayerDefn()
assert layer.GetLayerDefn().GetFieldCount() == 2
field_emb1 = layer_defn.GetFieldDefn(layer_defn.GetFieldIndex("EMB1"))
assert field_emb1.GetType() == ogr.OFTBinary
assert field_emb1.GetWidth() == 16
field_emb2 = layer_defn.GetFieldDefn(layer_defn.GetFieldIndex("EMB2"))
assert field_emb2.GetType() == ogr.OFTBinary
assert field_emb2.GetWidth() == 65000
check_feature_count(layer, 1)
feat = layer.GetNextFeature()
assert feat.GetFieldAsBinary("EMB1") == expected
assert feat.GetFieldAsBinary("EMB2") == expected

# '[0.1,0.2,0.3]'
vec0 = b"\x03\x00\x00\x00\xCD\xCC\xCC\x3D\xCD\xCC\x4C\x3E\x9A\x99\x99\x3E"
# '[0.1,0.2,0.1]'
vec1 = b"\x03\x00\x00\x00\xCD\xCC\xCC\x3D\xCD\xCC\x4C\x3E\xCD\xCC\xCC\x3D"

check_value(vec0)

ds = open_datasource(1)
layer = ds.GetLayerByName(layer_name)
feat = layer.GetNextFeature()
feat.SetField("EMB1", vec1)
feat.SetField("EMB2", vec1)
layer.SetFeature(feat)

check_value(vec1)


###############################################################################
# Create a table from data/poly.shp

Expand Down
70 changes: 69 additions & 1 deletion ogr/ogrsf_frmts/hana/ogr_hana.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include <vector>

#include "odbc/Forwards.h"
#include "odbc/Types.h"

class OGRHanaDataSource;

Expand All @@ -50,9 +51,76 @@ constexpr static int DEFAULT_STRING_SIZE = 256;
constexpr static int UNDETERMINED_SRID = -1;

/************************************************************************/
/* Internal struct definitions */
/* Internal enum and struct definitions */
/************************************************************************/

class QGRHanaDataTypes
{
QGRHanaDataTypes() = delete;

public:
/// Unknown data type.
static constexpr int Unknown = odbc::SQLDataTypes::Unknown;
/// 64-bit integer value.
static constexpr int BigInt = odbc::SQLDataTypes::BigInt;
/// Binary data of fixed length.
static constexpr int Binary = odbc::SQLDataTypes::Binary;
/// Single bit binary data.
static constexpr int Bit = odbc::SQLDataTypes::Bit;
/// Boolean value.
static constexpr int Boolean = odbc::SQLDataTypes::Boolean;
/// Character string of fixed string length.
static constexpr int Char = odbc::SQLDataTypes::Char;
/// Year, month, and day fields.
static constexpr int Date = odbc::SQLDataTypes::Date;
/// Year, month, and day fields.
static constexpr int DateTime = odbc::SQLDataTypes::DateTime;
/// Signed, exact, numeric value.
static constexpr int Decimal = odbc::SQLDataTypes::Decimal;
/// Double-precision floating point number.
static constexpr int Double = odbc::SQLDataTypes::Double;
/// Floating point number with driver-specific precision.
static constexpr int Float = odbc::SQLDataTypes::Float;
/// 32-bit integer value.
static constexpr int Integer = odbc::SQLDataTypes::Integer;
/// Variable length binary data.
static constexpr int LongVarBinary = odbc::SQLDataTypes::LongVarBinary;
/// Variable length character data.
static constexpr int LongVarChar = odbc::SQLDataTypes::LongVarChar;
/// Signed, exact, numeric value.
static constexpr int Numeric = odbc::SQLDataTypes::Numeric;
/// Single-precision floating point number.
static constexpr int Real = odbc::SQLDataTypes::Real;
/// 16-bit integer value.
static constexpr int SmallInt = odbc::SQLDataTypes::SmallInt;
/// Hour, minute, and second fields.
static constexpr int Time = odbc::SQLDataTypes::Time;
/// Year, month, day, hour, minute, and second fields.
static constexpr int Timestamp = odbc::SQLDataTypes::Timestamp;
/// 8-bit integer value.
static constexpr int TinyInt = odbc::SQLDataTypes::TinyInt;
/// Year, month, and day fields.
static constexpr int TypeDate = odbc::SQLDataTypes::TypeDate;
/// Hour, minute, and second fields.
static constexpr int TypeTime = odbc::SQLDataTypes::TypeTime;
/// Year, month, day, hour, minute, and second fields.
static constexpr int TypeTimestamp = odbc::SQLDataTypes::TypeTimestamp;
/// Variable length binary data.
static constexpr int VarBinary = odbc::SQLDataTypes::VarBinary;
/// Variable-length character string.
static constexpr int VarChar = odbc::SQLDataTypes::VarChar;
/// Unicode character string of fixed string length.
static constexpr int WChar = odbc::SQLDataTypes::WChar;
/// Unicode variable-length character data.
static constexpr int WLongVarChar = odbc::SQLDataTypes::WLongVarChar;
/// Unicode variable-length character string.
static constexpr int WVarChar = odbc::SQLDataTypes::WVarChar;
/// ST_GEOMETRY/ST_POINT value.
static constexpr int Geometry = 29812;
/// REAL_VECTOR value.
static constexpr int RealVector = 29814;
};

struct ColumnDefinition
{
CPLString name;
Expand Down
155 changes: 78 additions & 77 deletions ogr/ogrsf_frmts/hana/ogrhanadatasource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -411,42 +411,43 @@ CPLString FormatDefaultValue(const char *value, short dataType)

switch (dataType)
{
case odbc::SQLDataTypes::Bit:
case odbc::SQLDataTypes::Boolean:
case QGRHanaDataTypes::Bit:
case QGRHanaDataTypes::Boolean:
return value;
case odbc::SQLDataTypes::TinyInt:
case odbc::SQLDataTypes::SmallInt:
case odbc::SQLDataTypes::Integer:
case odbc::SQLDataTypes::BigInt:
case odbc::SQLDataTypes::Real:
case odbc::SQLDataTypes::Float:
case odbc::SQLDataTypes::Double:
case odbc::SQLDataTypes::Decimal:
case odbc::SQLDataTypes::Numeric:
case QGRHanaDataTypes::TinyInt:
case QGRHanaDataTypes::SmallInt:
case QGRHanaDataTypes::Integer:
case QGRHanaDataTypes::BigInt:
case QGRHanaDataTypes::Real:
case QGRHanaDataTypes::Float:
case QGRHanaDataTypes::Double:
case QGRHanaDataTypes::Decimal:
case QGRHanaDataTypes::Numeric:
return value;
case odbc::SQLDataTypes::Char:
case odbc::SQLDataTypes::VarChar:
case odbc::SQLDataTypes::LongVarChar:
case odbc::SQLDataTypes::WChar:
case odbc::SQLDataTypes::WVarChar:
case odbc::SQLDataTypes::WLongVarChar:
case QGRHanaDataTypes::Char:
case QGRHanaDataTypes::VarChar:
case QGRHanaDataTypes::LongVarChar:
case QGRHanaDataTypes::WChar:
case QGRHanaDataTypes::WVarChar:
case QGRHanaDataTypes::WLongVarChar:
return Literal(value);
case odbc::SQLDataTypes::Binary:
case odbc::SQLDataTypes::VarBinary:
case odbc::SQLDataTypes::LongVarBinary:
case QGRHanaDataTypes::Binary:
case QGRHanaDataTypes::VarBinary:
case QGRHanaDataTypes::LongVarBinary:
case QGRHanaDataTypes::RealVector:
return value;
case odbc::SQLDataTypes::Date:
case odbc::SQLDataTypes::TypeDate:
case QGRHanaDataTypes::Date:
case QGRHanaDataTypes::TypeDate:
if (EQUAL(value, "CURRENT_DATE"))
return value;
return Literal(value);
case odbc::SQLDataTypes::Time:
case odbc::SQLDataTypes::TypeTime:
case QGRHanaDataTypes::Time:
case QGRHanaDataTypes::TypeTime:
if (EQUAL(value, "CURRENT_TIME"))
return value;
return Literal(value);
case odbc::SQLDataTypes::Timestamp:
case odbc::SQLDataTypes::TypeTimestamp:
case QGRHanaDataTypes::Timestamp:
case QGRHanaDataTypes::TypeTimestamp:
if (EQUAL(value, "CURRENT_TIMESTAMP"))
return value;
return Literal(value);
Expand All @@ -458,37 +459,37 @@ CPLString FormatDefaultValue(const char *value, short dataType)
short GetArrayDataType(const CPLString &typeName)
{
if (typeName == "BOOLEAN ARRAY")
return odbc::SQLDataTypes::Boolean;
return QGRHanaDataTypes::Boolean;
else if (typeName == "TINYINT ARRAY")
return odbc::SQLDataTypes::TinyInt;
return QGRHanaDataTypes::TinyInt;
else if (typeName == "SMALLINT ARRAY")
return odbc::SQLDataTypes::SmallInt;
return QGRHanaDataTypes::SmallInt;
else if (typeName == "INTEGER ARRAY")
return odbc::SQLDataTypes::Integer;
return QGRHanaDataTypes::Integer;
else if (typeName == "BIGINT ARRAY")
return odbc::SQLDataTypes::BigInt;
return QGRHanaDataTypes::BigInt;
else if (typeName == "DOUBLE ARRAY")
return odbc::SQLDataTypes::Double;
return QGRHanaDataTypes::Double;
else if (typeName == "REAL ARRAY")
return odbc::SQLDataTypes::Float;
return QGRHanaDataTypes::Float;
else if (typeName == "DECIMAL ARRAY" || typeName == "SMALLDECIMAL ARRAY")
return odbc::SQLDataTypes::Decimal;
return QGRHanaDataTypes::Decimal;
else if (typeName == "CHAR ARRAY")
return odbc::SQLDataTypes::Char;
return QGRHanaDataTypes::Char;
else if (typeName == "VARCHAR ARRAY")
return odbc::SQLDataTypes::VarChar;
return QGRHanaDataTypes::VarChar;
else if (typeName == "NCHAR ARRAY")
return odbc::SQLDataTypes::WChar;
return QGRHanaDataTypes::WChar;
else if (typeName == "NVARCHAR ARRAY")
return odbc::SQLDataTypes::WVarChar;
return QGRHanaDataTypes::WVarChar;
else if (typeName == "DATE ARRAY")
return odbc::SQLDataTypes::Date;
return QGRHanaDataTypes::Date;
else if (typeName == "TIME ARRAY")
return odbc::SQLDataTypes::Time;
return QGRHanaDataTypes::Time;
else if (typeName == "TIMESTAMP ARRAY" || typeName == "SECONDDATE ARRAY")
return odbc::SQLDataTypes::Timestamp;
return QGRHanaDataTypes::Timestamp;

return odbc::SQLDataTypes::Unknown;
return QGRHanaDataTypes::Unknown;
}

std::vector<CPLString> GetSupportedArrayTypes()
Expand All @@ -498,32 +499,34 @@ std::vector<CPLString> GetSupportedArrayTypes()

bool IsKnownDataType(short dataType)
{
return dataType == odbc::SQLDataTypes::Bit ||
dataType == odbc::SQLDataTypes::Boolean ||
dataType == odbc::SQLDataTypes::TinyInt ||
dataType == odbc::SQLDataTypes::SmallInt ||
dataType == odbc::SQLDataTypes::Integer ||
dataType == odbc::SQLDataTypes::BigInt ||
dataType == odbc::SQLDataTypes::Double ||
dataType == odbc::SQLDataTypes::Real ||
dataType == odbc::SQLDataTypes::Float ||
dataType == odbc::SQLDataTypes::Decimal ||
dataType == odbc::SQLDataTypes::Numeric ||
dataType == odbc::SQLDataTypes::Char ||
dataType == odbc::SQLDataTypes::VarChar ||
dataType == odbc::SQLDataTypes::LongVarChar ||
dataType == odbc::SQLDataTypes::WChar ||
dataType == odbc::SQLDataTypes::WVarChar ||
dataType == odbc::SQLDataTypes::WLongVarChar ||
dataType == odbc::SQLDataTypes::Date ||
dataType == odbc::SQLDataTypes::TypeDate ||
dataType == odbc::SQLDataTypes::Time ||
dataType == odbc::SQLDataTypes::TypeTime ||
dataType == odbc::SQLDataTypes::Timestamp ||
dataType == odbc::SQLDataTypes::TypeTimestamp ||
dataType == odbc::SQLDataTypes::Binary ||
dataType == odbc::SQLDataTypes::VarBinary ||
dataType == odbc::SQLDataTypes::LongVarBinary;
return dataType == QGRHanaDataTypes::Bit ||
dataType == QGRHanaDataTypes::Boolean ||
dataType == QGRHanaDataTypes::TinyInt ||
dataType == QGRHanaDataTypes::SmallInt ||
dataType == QGRHanaDataTypes::Integer ||
dataType == QGRHanaDataTypes::BigInt ||
dataType == QGRHanaDataTypes::Double ||
dataType == QGRHanaDataTypes::Real ||
dataType == QGRHanaDataTypes::Float ||
dataType == QGRHanaDataTypes::Decimal ||
dataType == QGRHanaDataTypes::Numeric ||
dataType == QGRHanaDataTypes::Char ||
dataType == QGRHanaDataTypes::VarChar ||
dataType == QGRHanaDataTypes::LongVarChar ||
dataType == QGRHanaDataTypes::WChar ||
dataType == QGRHanaDataTypes::WVarChar ||
dataType == QGRHanaDataTypes::WLongVarChar ||
dataType == QGRHanaDataTypes::Date ||
dataType == QGRHanaDataTypes::TypeDate ||
dataType == QGRHanaDataTypes::Time ||
dataType == QGRHanaDataTypes::TypeTime ||
dataType == QGRHanaDataTypes::Timestamp ||
dataType == QGRHanaDataTypes::TypeTimestamp ||
dataType == QGRHanaDataTypes::Binary ||
dataType == QGRHanaDataTypes::VarBinary ||
dataType == QGRHanaDataTypes::LongVarBinary ||
dataType == QGRHanaDataTypes::Geometry ||
dataType == QGRHanaDataTypes::RealVector;
}

} // anonymous namespace
Expand Down Expand Up @@ -1048,11 +1051,14 @@ OGRErr OGRHanaDataSource::GetQueryColumns(
continue;

bool isArray = false;
bool isGeometry = false;
CPLString tableName = rsmd->getTableName(clmIndex);
CPLString columnName = rsmd->getColumnName(clmIndex);
CPLString defaultValue;
short dataType = rsmd->getColumnType(clmIndex);
// TODO: remove when HANA Client is fixed.
if (dataType == QGRHanaDataTypes::VarBinary &&
typeName == "REAL_VECTOR")
dataType = QGRHanaDataTypes::RealVector;

if (!schemaName.empty() && !tableName.empty())
{
Expand Down Expand Up @@ -1080,7 +1086,7 @@ OGRErr OGRHanaDataSource::GetQueryColumns(
typeName = *rsArrayTypes->getString(1);
dataType = GetArrayDataType(typeName);

if (dataType == odbc::SQLDataTypes::Unknown)
if (dataType == QGRHanaDataTypes::Unknown)
{
CPLError(
CE_Failure, CPLE_AppDefined,
Expand All @@ -1105,18 +1111,13 @@ OGRErr OGRHanaDataSource::GetQueryColumns(
if (name->compare("SHORTTEXT") == 0 ||
name->compare("ALPHANUM") == 0)
{
dataType = odbc::SQLDataTypes::WVarChar;
}
else if (name->compare("ST_GEOMETRY") == 0 ||
name->compare("ST_POINT") == 0)
{
isGeometry = true;
dataType = QGRHanaDataTypes::WVarChar;
}
}
rsTypeInfo->close();
}

if (isGeometry)
if (dataType == QGRHanaDataTypes::Geometry)
{
GeometryColumnDescription geometryColumnDesc;
if (schemaName.empty() || tableName.empty())
Expand Down
Loading

0 comments on commit d48e35f

Please sign in to comment.