Skip to content
This repository was archived by the owner on Oct 10, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions src/function/function_collection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,9 +196,8 @@ FunctionCollection* FunctionCollection::getFunctions() {

// Path functions
SCALAR_FUNCTION(NodesFunction), SCALAR_FUNCTION(RelsFunction),
SCALAR_FUNCTION_ALIAS(RelationshipsFunction), SCALAR_FUNCTION(PropertiesFunction),
SCALAR_FUNCTION(IsTrailFunction), SCALAR_FUNCTION(IsACyclicFunction),
REWRITE_FUNCTION(LengthFunction),
SCALAR_FUNCTION_ALIAS(RelationshipsFunction), SCALAR_FUNCTION(IsTrailFunction),
SCALAR_FUNCTION(IsACyclicFunction), REWRITE_FUNCTION(LengthFunction),

// Hash functions
SCALAR_FUNCTION(MD5Function), SCALAR_FUNCTION(SHA256Function),
Expand All @@ -208,7 +207,7 @@ FunctionCollection* FunctionCollection::getFunctions() {
SCALAR_FUNCTION(CoalesceFunction), SCALAR_FUNCTION(IfNullFunction),
SCALAR_FUNCTION(ConstantOrNullFunction), SCALAR_FUNCTION(CountIfFunction),
SCALAR_FUNCTION(ErrorFunction), REWRITE_FUNCTION(NullIfFunction),
SCALAR_FUNCTION(TypeOfFunction),
SCALAR_FUNCTION(TypeOfFunction), SCALAR_FUNCTION(PropertiesFunctions),

// Sequence functions
SCALAR_FUNCTION(CurrValFunction), SCALAR_FUNCTION(NextValFunction),
Expand Down
1 change: 0 additions & 1 deletion src/function/path/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ add_library(kuzu_function_path
OBJECT
length_function.cpp
nodes_function.cpp
properties_function.cpp
rels_function.cpp
semantic_function.cpp)

Expand Down
71 changes: 0 additions & 71 deletions src/function/path/properties_function.cpp

This file was deleted.

3 changes: 2 additions & 1 deletion src/function/utility/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ add_library(kuzu_utility_function
count_if.cpp
error.cpp
nullif.cpp
typeof.cpp)
typeof.cpp
properties.cpp)

set(ALL_OBJECT_FILES
${ALL_OBJECT_FILES} $<TARGET_OBJECTS:kuzu_utility_function>
Expand Down
124 changes: 124 additions & 0 deletions src/function/utility/properties.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#include "binder/expression/literal_expression.h"
#include "binder/expression_binder.h"
#include "common/exception/binder.h"
#include "common/string_format.h"
#include "common/vector/value_vector.h"
#include "function/scalar_function.h"
#include "function/utility/vector_utility_functions.h"

using namespace kuzu::common;
using namespace kuzu::binder;
using namespace kuzu::catalog;

namespace kuzu {
namespace function {

static std::unique_ptr<FunctionBindData> bindStructFunc(const ScalarBindFuncInput& input) {
std::vector<StructField> fields;
const auto& structType = input.arguments[0]->getDataType();
auto keys = StructType::getFieldNames(structType);
std::vector<common::idx_t> fieldIdxs;
for (auto& key : keys) {
if (key == InternalKeyword::ID || key == InternalKeyword::LABEL ||
key == InternalKeyword::SRC || key == InternalKeyword::DST) {
continue;
}
auto fieldIdx = StructType::getFieldIdx(structType, key);
auto fieldType = StructType::getField(structType, fieldIdx).getType().copy();
if (fieldIdx == INVALID_STRUCT_FIELD_IDX) {
throw BinderException(stringFormat("Invalid struct field name: {}.", key));
}
fieldIdxs.push_back(fieldIdx);
fields.emplace_back(key, std::move(fieldType));
}
const auto resultType = LogicalType::STRUCT(std::move(fields));
auto bindData = std::make_unique<StructPropertiesBindData>(resultType.copy(), fieldIdxs);
bindData->paramTypes.push_back(input.arguments[0]->getDataType().copy());
return bindData;
}

static void compileStructFunc(FunctionBindData* bindData,
const std::vector<std::shared_ptr<ValueVector>>& parameters,
std::shared_ptr<ValueVector>& result) {
auto& propertiesBindData = bindData->cast<StructPropertiesBindData>();
std::vector<std::shared_ptr<ValueVector>> fieldVectors;
for (auto fieldIdx : propertiesBindData.childIdxs) {
auto fieldVector = StructVector::getFieldVector(parameters[0].get(), fieldIdx);
fieldVectors.push_back(fieldVector);
}
for (auto i = 0u; i < fieldVectors.size(); ++i) {
StructVector::referenceVector(result.get(), i, fieldVectors[i]);
}
}

static std::unique_ptr<FunctionBindData> bindPathFunc(const ScalarBindFuncInput& input) {
if (input.arguments[1]->expressionType != ExpressionType::LITERAL) {
throw BinderException(stringFormat(
"Expected literal input as the second argument for {}().", PropertiesFunctions::name));
}
auto literalExpr = input.arguments[1]->constPtrCast<LiteralExpression>();
auto key = literalExpr->getValue().getValue<std::string>();
const auto& listType = input.arguments[0]->getDataType();
const auto& childType = ListType::getChildType(listType);
struct_field_idx_t fieldIdx = 0;
if (childType.getLogicalTypeID() == LogicalTypeID::NODE ||
childType.getLogicalTypeID() == LogicalTypeID::REL) {
fieldIdx = StructType::getFieldIdx(childType, key);
if (fieldIdx == INVALID_STRUCT_FIELD_IDX) {
throw BinderException(stringFormat("Invalid property name: {}.", key));
}
} else {
throw BinderException(
stringFormat("Cannot extract properties from {}.", listType.toString()));
}
const auto& field = StructType::getField(childType, fieldIdx);
auto returnType = LogicalType::LIST(field.getType().copy());
auto bindData = std::make_unique<PathPropertiesBindData>(std::move(returnType), fieldIdx);
bindData->paramTypes.push_back(input.arguments[0]->getDataType().copy());
bindData->paramTypes.push_back(LogicalType(input.definition->parameterTypeIDs[1]));
return bindData;
}

static void compilePathFunc(FunctionBindData* bindData,
const std::vector<std::shared_ptr<ValueVector>>& parameters,
std::shared_ptr<ValueVector>& result) {
KU_ASSERT(parameters[0]->dataType.getPhysicalType() == PhysicalTypeID::LIST);
auto& propertiesBindData = bindData->cast<PathPropertiesBindData>();
auto fieldVector = StructVector::getFieldVector(ListVector::getDataVector(parameters[0].get()),
propertiesBindData.childIdx);
ListVector::setDataVector(result.get(), fieldVector);
}

static void execPathFunc(const std::vector<std::shared_ptr<common::ValueVector>>& parameters,
const std::vector<common::SelectionVector*>& parameterSelVectors, common::ValueVector& result,
common::SelectionVector* resultSelVector, void* /*dataPtr*/) {
ListVector::copyListEntryAndBufferMetaData(result, *resultSelVector, *parameters[0],
*parameterSelVectors[0]);
}

static std::unique_ptr<Function> getStructPropertiesFunction(LogicalTypeID logicalTypeID) {
auto function = std::make_unique<ScalarFunction>(PropertiesFunctions::name,
std::vector<LogicalTypeID>{logicalTypeID}, LogicalTypeID::STRUCT);
function->bindFunc = bindStructFunc;
function->compileFunc = compileStructFunc;
return function;
}

function_set PropertiesFunctions::getFunctionSet() {
function_set functions;
auto inputTypeIDs = // PROPERTIES(STRUCT)
std::vector<LogicalTypeID>{LogicalTypeID::STRUCT, LogicalTypeID::NODE, LogicalTypeID::REL};
for (auto inputTypeID : inputTypeIDs) {
functions.push_back(getStructPropertiesFunction(inputTypeID));
}
auto function = std::make_unique<ScalarFunction>(name, // PROPERTIES(PATH)
std::vector<LogicalTypeID>{LogicalTypeID::LIST, LogicalTypeID::STRING}, LogicalTypeID::ANY,
execPathFunc);
function->bindFunc = bindPathFunc;
function->compileFunc = compilePathFunc;
functions.push_back(std::move(function));
return functions;
}

} // namespace function
} // namespace kuzu
17 changes: 0 additions & 17 deletions src/include/function/path/vector_path_functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,6 @@ struct RelationshipsFunction {
static constexpr const char* name = "RELATIONSHIPS";
};

struct PropertiesBindData : public FunctionBindData {
common::idx_t childIdx;

PropertiesBindData(common::LogicalType dataType, common::idx_t childIdx)
: FunctionBindData{std::move(dataType)}, childIdx{childIdx} {}

inline std::unique_ptr<FunctionBindData> copy() const override {
return std::make_unique<PropertiesBindData>(resultType.copy(), childIdx);
}
};

struct PropertiesFunction {
static constexpr const char* name = "PROPERTIES";

static function_set getFunctionSet();
};

struct IsTrailFunction {
static constexpr const char* name = "IS_TRAIL";

Expand Down
28 changes: 28 additions & 0 deletions src/include/function/utility/vector_utility_functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,33 @@ struct TypeOfFunction {
static function_set getFunctionSet();
};

struct PathPropertiesBindData : public FunctionBindData {
common::idx_t childIdx;

PathPropertiesBindData(common::LogicalType dataType, common::idx_t childIdx)
: FunctionBindData{std::move(dataType)}, childIdx{childIdx} {}

inline std::unique_ptr<FunctionBindData> copy() const override {
return std::make_unique<PathPropertiesBindData>(resultType.copy(), childIdx);
}
};

struct StructPropertiesBindData : public FunctionBindData {
std::vector<common::idx_t> childIdxs;

StructPropertiesBindData(common::LogicalType dataType, std::vector<common::idx_t> childIdxs)
: FunctionBindData{std::move(dataType)}, childIdxs{std::move(childIdxs)} {}

std::unique_ptr<FunctionBindData> copy() const override {
return std::make_unique<StructPropertiesBindData>(resultType.copy(), childIdxs);
}
};

struct PropertiesFunctions {
static constexpr const char* name = "PROPERTIES";

static function_set getFunctionSet();
};

} // namespace function
} // namespace kuzu
Loading
Loading