From ebfff70fad7542c58f48b8fa16241c37caba8484 Mon Sep 17 00:00:00 2001 From: ziyi chen Date: Wed, 21 Feb 2024 12:21:58 -0500 Subject: [PATCH] Fix python prepared statement uuid binding --- src/common/arrow/arrow_row_batch.cpp | 2 +- src/common/type_utils.cpp | 8 ++- src/common/types/uuid.cpp | 38 +++++++++++--- src/common/types/value/value.cpp | 8 +-- src/function/cast_from_string_functions.cpp | 12 ++--- src/function/vector_cast_functions.cpp | 7 +-- src/function/vector_uuid_functions.cpp | 2 +- src/include/common/type_utils.h | 6 +-- src/include/common/types/uuid.h | 50 ++++++------------- src/include/common/types/value/value.h | 3 +- .../functions/cast_from_string_functions.h | 2 +- .../function/uuid/functions/gen_random_uuid.h | 6 +-- tools/python_api/src_cpp/py_connection.cpp | 8 +++ tools/python_api/src_cpp/py_query_result.cpp | 2 +- .../test/test_prepared_statement.py | 8 ++- tools/rust_api/include/kuzu_rs.h | 2 +- 16 files changed, 90 insertions(+), 74 deletions(-) diff --git a/src/common/arrow/arrow_row_batch.cpp b/src/common/arrow/arrow_row_batch.cpp index fad9d4ea3fd..435f9b26462 100644 --- a/src/common/arrow/arrow_row_batch.cpp +++ b/src/common/arrow/arrow_row_batch.cpp @@ -255,7 +255,7 @@ template<> void ArrowRowBatch::templateCopyNonNullValue( ArrowVector* vector, const main::DataTypeInfo& /*typeInfo*/, Value* value, std::int64_t pos) { auto offsets = (std::uint32_t*)vector->data.data(); - auto str = uuid_t::toString(value->val.int128Val); + auto str = UUID::toString(value->val.int128Val); auto strLength = str.length(); offsets[pos + 1] = offsets[pos] + strLength; vector->overflow.resize(offsets[pos + 1]); diff --git a/src/common/type_utils.cpp b/src/common/type_utils.cpp index c0bb646b0c4..8a4035e5c10 100644 --- a/src/common/type_utils.cpp +++ b/src/common/type_utils.cpp @@ -1,7 +1,5 @@ #include "common/type_utils.h" -#include "common/types/blob.h" -#include "common/types/uuid.h" #include "common/vector/value_vector.h" namespace kuzu { @@ -64,7 +62,7 @@ static std::string entryToString( case LogicalTypeID::UNION: return TypeUtils::toString(*reinterpret_cast(value), valueVector); case LogicalTypeID::UUID: - return TypeUtils::toString(*reinterpret_cast(value)); + return TypeUtils::toString(*reinterpret_cast(value)); case LogicalTypeID::NODE: return TypeUtils::nodeToString( *reinterpret_cast(value), valueVector); @@ -160,8 +158,8 @@ std::string TypeUtils::toString(const blob_t& val, void* /*valueVector*/) { } template<> -std::string TypeUtils::toString(const uuid_t& val, void* /*valueVector*/) { - return val.toString(); +std::string TypeUtils::toString(const ku_uuid_t& val, void* /*valueVector*/) { + return UUID::toString(val); } template<> diff --git a/src/common/types/uuid.cpp b/src/common/types/uuid.cpp index a7aacaee993..eaad41fb329 100644 --- a/src/common/types/uuid.cpp +++ b/src/common/types/uuid.cpp @@ -5,12 +5,12 @@ namespace kuzu { namespace common { -void uuid_t::byteToHex(char byteVal, char* buf, uint64_t& pos) { +void UUID::byteToHex(char byteVal, char* buf, uint64_t& pos) { buf[pos++] = HEX_DIGITS[(byteVal >> 4) & 0xf]; buf[pos++] = HEX_DIGITS[byteVal & 0xf]; } -unsigned char uuid_t::hex2Char(char ch) { +unsigned char UUID::hex2Char(char ch) { if (ch >= '0' && ch <= '9') { return ch - '0'; } @@ -21,9 +21,13 @@ unsigned char uuid_t::hex2Char(char ch) { return 10 + ch - 'A'; } return 0; -}; +} + +bool UUID::isHex(char ch) { + return (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'); +} -bool uuid_t::fromString(std::string str, int128_t& result) { +bool UUID::fromString(std::string str, int128_t& result) { if (str.empty()) { return false; } @@ -59,7 +63,17 @@ bool uuid_t::fromString(std::string str, int128_t& result) { return count == 32; } -void uuid_t::toString(int128_t input, char* buf) { +int128_t UUID::fromString(std::string str) { + int128_t result; + fromString(str, result); + return result; +} + +int128_t UUID::fromCString(const char* str, uint64_t len) { + return fromString(std::string(str, len)); +} + +void UUID::toString(int128_t input, char* buf) { // Flip back before convert to string int64_t high = input.high ^ (int64_t(1) << 63); uint64_t pos = 0; @@ -85,7 +99,17 @@ void uuid_t::toString(int128_t input, char* buf) { byteToHex(input.low & 0xFF, buf, pos); } -uuid_t uuid_t::generateRandomUUID(RandomEngine* engine) { +std::string UUID::toString(int128_t input) { + char buff[UUID_STRING_LENGTH]; + toString(input, buff); + return std::string(buff, UUID_STRING_LENGTH); +} + +std::string UUID::toString(ku_uuid_t val) { + return toString(val.value); +} + +ku_uuid_t UUID::generateRandomUUID(RandomEngine* engine) { uint8_t bytes[16]; for (int i = 0; i < 16; i += 4) { *reinterpret_cast(bytes + i) = engine->nextRandomInteger(); @@ -116,7 +140,7 @@ uuid_t uuid_t::generateRandomUUID(RandomEngine* engine) { result.low |= ((uint64_t)bytes[13] << 16); result.low |= ((uint64_t)bytes[14] << 8); result.low |= bytes[15]; - return uuid_t{result}; + return ku_uuid_t{result}; } } // namespace common diff --git a/src/common/types/value/value.cpp b/src/common/types/value/value.cpp index 0596efb21b4..2b4a73912c1 100644 --- a/src/common/types/value/value.cpp +++ b/src/common/types/value/value.cpp @@ -181,7 +181,7 @@ Value::Value(int128_t val_) : isNull_{false} { val.int128Val = val_; } -Value::Value(uuid_t val_) : isNull_{false} { +Value::Value(ku_uuid_t val_) : isNull_{false} { dataType = LogicalType::UUID(); val.int128Val = val_.value; } @@ -323,8 +323,8 @@ void Value::copyValueFrom(const uint8_t* value) { strVal = ((blob_t*)value)->value.getAsString(); } break; case LogicalTypeID::UUID: { - val.int128Val = ((uuid_t*)value)->value; - strVal = uuid_t::toString(val.int128Val); + val.int128Val = ((ku_uuid_t*)value)->value; + strVal = UUID::toString(*((ku_uuid_t*)value)); } break; case LogicalTypeID::STRING: { strVal = ((ku_string_t*)value)->getAsString(); @@ -472,7 +472,7 @@ std::string Value::toString() const { case LogicalTypeID::BLOB: return Blob::toString(reinterpret_cast(strVal.c_str()), strVal.length()); case LogicalTypeID::UUID: - return uuid_t::toString(val.int128Val); + return UUID::toString(val.int128Val); case LogicalTypeID::STRING: return strVal; case LogicalTypeID::RDF_VARIANT: { diff --git a/src/function/cast_from_string_functions.cpp b/src/function/cast_from_string_functions.cpp index c27bd4ca29f..c7930d71392 100644 --- a/src/function/cast_from_string_functions.cpp +++ b/src/function/cast_from_string_functions.cpp @@ -161,16 +161,16 @@ void CastStringHelper::cast(const char* input, uint64_t len, blob_t& /*result*/, //---------------------- cast String to UUID ------------------------------ // template<> -void CastString::operation(const ku_string_t& input, uuid_t& result, ValueVector* /*result_vector*/, - uint64_t /*rowToAdd*/, const CSVOption* /*option*/) { - result.value = uuid_t::fromString(input.getAsString()); +void CastString::operation(const ku_string_t& input, ku_uuid_t& result, + ValueVector* /*result_vector*/, uint64_t /*rowToAdd*/, const CSVOption* /*option*/) { + result.value = UUID::fromString(input.getAsString()); } // LCOV_EXCL_START template<> -void CastStringHelper::cast(const char* input, uint64_t len, uuid_t& result, +void CastStringHelper::cast(const char* input, uint64_t len, ku_uuid_t& result, ValueVector* /*vector*/, uint64_t /*rowToAdd*/, const CSVOption* /*option*/) { - result.value = uuid_t::fromCString(input, len); + result.value = UUID::fromCString(input, len); } // LCOV_EXCL_STOP @@ -886,7 +886,7 @@ void CastString::copyStringToVector( CastStringHelper::cast(strVal.data(), strVal.length(), val, vector, rowToAdd, option); } break; case LogicalTypeID::UUID: { - uuid_t val; + ku_uuid_t val; CastStringHelper::cast(strVal.data(), strVal.length(), val); vector->setValue(rowToAdd, val.value); } break; diff --git a/src/function/vector_cast_functions.cpp b/src/function/vector_cast_functions.cpp index ebfcbba068a..02376b6f454 100644 --- a/src/function/vector_cast_functions.cpp +++ b/src/function/vector_cast_functions.cpp @@ -208,8 +208,8 @@ static std::unique_ptr bindCastFromStringFunction( ScalarFunction::UnaryCastStringExecFunction; } break; case LogicalTypeID::UUID: { - execFunc = - ScalarFunction::UnaryCastStringExecFunction; + execFunc = ScalarFunction::UnaryCastStringExecFunction; } break; case LogicalTypeID::STRING: { execFunc = @@ -456,7 +456,8 @@ static std::unique_ptr bindCastToStringFunction( func = ScalarFunction::UnaryCastExecFunction; } break; case LogicalTypeID::UUID: { - func = ScalarFunction::UnaryCastExecFunction; + func = + ScalarFunction::UnaryCastExecFunction; } break; case LogicalTypeID::VAR_LIST: { func = ScalarFunction::UnaryCastExecFunction(GEN_RANDOM_UUID_FUNC_NAME, std::vector{}, - LogicalTypeID::UUID, ScalarFunction::PoniterExecFunction)); + LogicalTypeID::UUID, ScalarFunction::PoniterExecFunction)); return definitions; } diff --git a/src/include/common/type_utils.h b/src/include/common/type_utils.h index b51037202a1..43b03dbd2ae 100644 --- a/src/include/common/type_utils.h +++ b/src/include/common/type_utils.h @@ -16,8 +16,6 @@ namespace kuzu { namespace common { class ValueVector; -struct blob_t; -struct uuid_t; template struct overload : Funcs... { @@ -178,7 +176,7 @@ class TypeUtils { case LogicalTypeID::BLOB: return func(blob_t()); case LogicalTypeID::UUID: - return func(uuid_t()); + return func(ku_uuid_t()); case LogicalTypeID::VAR_LIST: return func(list_entry_t()); case LogicalTypeID::MAP: @@ -276,7 +274,7 @@ std::string TypeUtils::toString(const ku_string_t& val, void* valueVector); template<> std::string TypeUtils::toString(const blob_t& val, void* valueVector); template<> -std::string TypeUtils::toString(const uuid_t& val, void* valueVector); +std::string TypeUtils::toString(const ku_uuid_t& val, void* valueVector); template<> std::string TypeUtils::toString(const list_entry_t& val, void* valueVector); template<> diff --git a/src/include/common/types/uuid.h b/src/include/common/types/uuid.h index 9455d52172f..2b12d64a3a7 100644 --- a/src/include/common/types/uuid.h +++ b/src/include/common/types/uuid.h @@ -1,53 +1,33 @@ #pragma once -// pragma once doesn't appear to work properly on MSVC for this file -#ifndef KUZU_COMMON_TYPES_UUID -#define KUZU_COMMON_TYPES_UUID -#include "common/types/int128_t.h" +#include "int128_t.h" namespace kuzu { namespace common { class RandomEngine; -struct uuid_t { - constexpr static uint8_t UUID_STRING_LENGTH = 36; - constexpr static char HEX_DIGITS[] = "0123456789abcdef"; +// Note: uuid_t is a reserved keyword in MSVC, we have to use ku_uuid_t instead. +struct ku_uuid_t { + int128_t value; +}; + +struct UUID { + static constexpr const uint8_t UUID_STRING_LENGTH = 36; + static constexpr const char HEX_DIGITS[] = "0123456789abcdef"; static void byteToHex(char byteVal, char* buf, uint64_t& pos); static unsigned char hex2Char(char ch); - static inline bool isHex(char ch) { - return (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'); - } - - // Convert a uuid string to a int128_t object + static bool isHex(char ch); static bool fromString(std::string str, int128_t& result); - static inline int128_t fromString(std::string str) { - int128_t result; - fromString(str, result); - return result; - } - - static inline int128_t fromCString(const char* str, uint64_t len) { - return fromString(std::string(str, len)); - } - - // Convert a int128_t object to a uuid style string + static int128_t fromString(std::string str); + static int128_t fromCString(const char* str, uint64_t len); static void toString(int128_t input, char* buf); + static std::string toString(int128_t input); + static std::string toString(ku_uuid_t val); - static inline std::string toString(int128_t input) { - char buff[UUID_STRING_LENGTH]; - toString(input, buff); - return std::string(buff, UUID_STRING_LENGTH); - } - inline std::string toString() const { return toString(value); } - - int128_t value; - - // generate a random uuid object - static uuid_t generateRandomUUID(RandomEngine* engine); + static ku_uuid_t generateRandomUUID(RandomEngine* engine); }; } // namespace common } // namespace kuzu -#endif diff --git a/src/include/common/types/value/value.h b/src/include/common/types/value/value.h index b3cfacf7ad6..dc30bd38af2 100644 --- a/src/include/common/types/value/value.h +++ b/src/include/common/types/value/value.h @@ -90,7 +90,7 @@ class Value { /** * @param val_ the UUID value to set. */ - KUZU_API explicit Value(uuid_t val_); + KUZU_API explicit Value(ku_uuid_t val_); /** * @param val_ the double value to set. */ @@ -218,6 +218,7 @@ class Value { static Value createValue(T /*value*/) { throw std::runtime_error("Unimplemented template for Value::createValue()"); } + /** * @return a copy of the current value. */ diff --git a/src/include/function/cast/functions/cast_from_string_functions.h b/src/include/function/cast/functions/cast_from_string_functions.h index d9a24917a1c..49ab83099ac 100644 --- a/src/include/function/cast/functions/cast_from_string_functions.h +++ b/src/include/function/cast/functions/cast_from_string_functions.h @@ -162,7 +162,7 @@ void CastString::operation(const ku_string_t& input, blob_t& result, ValueVector uint64_t rowToAdd, const CSVOption* option); template<> -void CastString::operation(const ku_string_t& input, uuid_t& result, ValueVector* result_vector, +void CastString::operation(const ku_string_t& input, ku_uuid_t& result, ValueVector* result_vector, uint64_t rowToAdd, const CSVOption* option); template<> diff --git a/src/include/function/uuid/functions/gen_random_uuid.h b/src/include/function/uuid/functions/gen_random_uuid.h index 742ba5e56c8..c49cbf0228c 100644 --- a/src/include/function/uuid/functions/gen_random_uuid.h +++ b/src/include/function/uuid/functions/gen_random_uuid.h @@ -9,7 +9,7 @@ class ClientContext; } namespace common { -struct uuid_t; +struct ku_uuid_t; } // namespace common namespace function { @@ -17,10 +17,10 @@ namespace function { struct GenRandomUUID { static inline void operation(common::ValueVector& result, void* dataPtr) { KU_ASSERT(result.state->isFlat()); - auto resultValues = (common::uuid_t*)result.getData(); + auto resultValues = (common::ku_uuid_t*)result.getData(); auto idx = result.state->selVector->selectedPositions[0]; KU_ASSERT(idx == 0); - resultValues[idx] = common::uuid_t::generateRandomUUID( + resultValues[idx] = common::UUID::generateRandomUUID( reinterpret_cast(dataPtr)->getRandomEngine()); } }; diff --git a/tools/python_api/src_cpp/py_connection.cpp b/tools/python_api/src_cpp/py_connection.cpp index 2f555b41a64..ddb601c768e 100644 --- a/tools/python_api/src_cpp/py_connection.cpp +++ b/tools/python_api/src_cpp/py_connection.cpp @@ -7,6 +7,7 @@ #include "main/connection.h" #include "pandas/pandas_scan.h" #include "processor/result/factorized_table.h" +#include "common/types/uuid.h" using namespace kuzu::common; @@ -179,6 +180,7 @@ Value transformPythonValue(py::handle val) { auto datetime_datetime = datetime_mod.attr("datetime"); auto time_delta = datetime_mod.attr("timedelta"); auto datetime_date = datetime_mod.attr("date"); + auto uuid = py::module::import("uuid").attr("UUID"); if (py::isinstance(val)) { return Value::createValue(val.cast()); } else if (py::isinstance(val)) { @@ -215,6 +217,12 @@ Value transformPythonValue(py::handle val) { Interval::addition(interval, seconds, "seconds"); Interval::addition(interval, microseconds, "microseconds"); return Value::createValue(interval); + } else if (py::isinstance(val, uuid)) { + auto strVal = py::str(val).cast(); + auto uuidVal = UUID::fromString(strVal); + ku_uuid_t uuidToAppend; + uuidToAppend.value = uuidVal; + return Value{uuidToAppend}; } else { throw std::runtime_error( "Unknown parameter type " + py::str(val.get_type()).cast()); diff --git a/tools/python_api/src_cpp/py_query_result.cpp b/tools/python_api/src_cpp/py_query_result.cpp index b01e65b1ed6..a4024f87199 100644 --- a/tools/python_api/src_cpp/py_query_result.cpp +++ b/tools/python_api/src_cpp/py_query_result.cpp @@ -192,7 +192,7 @@ py::object PyQueryResult::convertValueToPyObject(const Value& value) { } case LogicalTypeID::UUID: { kuzu::common::int128_t result = value.getValue(); - std::string uuidString = kuzu::common::uuid_t::toString(result); + std::string uuidString = kuzu::common::UUID::toString(result); py::object UUID = py::module_::import("uuid").attr("UUID"); return UUID(uuidString); } diff --git a/tools/python_api/test/test_prepared_statement.py b/tools/python_api/test/test_prepared_statement.py index 4abf8f2ccb6..0b4c3e1d940 100644 --- a/tools/python_api/test/test_prepared_statement.py +++ b/tools/python_api/test/test_prepared_statement.py @@ -1,3 +1,5 @@ +import uuid + import pytest import datetime @@ -29,7 +31,6 @@ def test_read(establish_connection): assert result.get_next() == [0] assert not result.has_next() - def test_write(establish_connection): conn, _ = establish_connection orgs = [ @@ -89,6 +90,11 @@ def test_write(establish_connection): assert n['rating'] == expected_org['rating'] break + conn.execute('CREATE NODE TABLE uuid_table (id UUID, PRIMARY KEY(id));') + result = conn.execute('CREATE (:uuid_table {id: $1});', {'1': uuid.uuid5(uuid.NAMESPACE_DNS, 'kuzu')}) + assert result.is_success() + assert result.get_next() == [uuid.uuid5(uuid.NAMESPACE_DNS, 'kuzu')] + def test_error(establish_connection): prepared_statement = establish_connection[0].prepare( diff --git a/tools/rust_api/include/kuzu_rs.h b/tools/rust_api/include/kuzu_rs.h index 8bf184da274..f1d07c07549 100644 --- a/tools/rust_api/include/kuzu_rs.h +++ b/tools/rust_api/include/kuzu_rs.h @@ -175,7 +175,7 @@ std::unique_ptr create_value_internal_id(uint64_t offset, u inline std::unique_ptr create_value_uuid_t(int64_t high, uint64_t low) { return std::make_unique( - kuzu::common::uuid_t{kuzu::common::int128_t(low, high)}); + kuzu::common::ku_uuid_t{kuzu::common::int128_t(low, high)}); } template