From f830e7e0d9186e23cf258ba61837ad6550742951 Mon Sep 17 00:00:00 2001 From: xiyang Date: Tue, 12 Mar 2024 10:15:39 -0400 Subject: [PATCH] Fix issue-3004 --- src/binder/bind/bind_copy.cpp | 4 +-- src/binder/bind/bind_projection_clause.cpp | 10 -------- src/binder/bound_statement_rewriter.cpp | 4 +++ src/binder/bound_statement_visitor.cpp | 16 ++++++++++++ src/binder/expression/CMakeLists.txt | 4 ++- src/binder/expression/expression.cpp | 9 +++++++ src/binder/expression/literal_expression.cpp | 23 +++++++++++++++++ .../expression/parameter_expression.cpp | 23 +++++++++++++++++ src/binder/expression_binder.cpp | 11 +------- src/binder/visitor/CMakeLists.txt | 1 + src/binder/visitor/default_type_solver.cpp | 25 +++++++++++++++++++ src/common/vector/value_vector.cpp | 7 ++++++ src/function/vector_list_functions.cpp | 2 +- src/function/vector_struct_functions.cpp | 3 +-- src/function/vector_union_functions.cpp | 3 +-- src/include/binder/binder.h | 1 - src/include/binder/bound_statement_visitor.h | 4 +-- src/include/binder/copy/bound_copy_to.h | 18 +++++-------- src/include/binder/expression/expression.h | 11 ++++---- .../binder/expression/literal_expression.h | 14 ++++------- .../binder/expression/parameter_expression.h | 13 +++------- src/include/binder/expression_binder.h | 2 -- .../binder/visitor/default_type_solver.h | 21 ++++++++++++++++ .../binder/visitor/property_collector.h | 1 + src/planner/plan/plan_copy.cpp | 9 +++++-- test/test_files/common/types/null.test | 16 ++++++++++++ test/test_files/copy/copy_to_parquet.test | 1 - 27 files changed, 185 insertions(+), 71 deletions(-) create mode 100644 src/binder/expression/literal_expression.cpp create mode 100644 src/binder/expression/parameter_expression.cpp create mode 100644 src/binder/visitor/default_type_solver.cpp create mode 100644 src/include/binder/visitor/default_type_solver.h create mode 100644 test/test_files/common/types/null.test diff --git a/src/binder/bind/bind_copy.cpp b/src/binder/bind/bind_copy.cpp index d8e0620d1a8..f79f7c1f36f 100644 --- a/src/binder/bind/bind_copy.cpp +++ b/src/binder/bind/bind_copy.cpp @@ -44,8 +44,8 @@ std::unique_ptr Binder::bindCopyToClause(const Statement& statem } auto csvConfig = CSVReaderConfig::construct(bindParsingOptions(copyToStatement.getParsingOptionsRef())); - return std::make_unique(boundFilePath, fileType, std::move(columnNames), - std::move(columnTypes), std::move(query), csvConfig.option.copy()); + return std::make_unique( + boundFilePath, fileType, std::move(query), csvConfig.option.copy()); } std::unique_ptr Binder::bindCopyFromClause(const Statement& statement) { diff --git a/src/binder/bind/bind_projection_clause.cpp b/src/binder/bind/bind_projection_clause.cpp index 63e0e9c41bf..5bb71c68b94 100644 --- a/src/binder/bind/bind_projection_clause.cpp +++ b/src/binder/bind/bind_projection_clause.cpp @@ -207,7 +207,6 @@ expression_vector Binder::bindProjectionExpressions( result.push_back(expressionBinder.bindExpression(*expression)); } } - resolveAnyDataTypeWithDefaultType(result); validateProjectionColumnNamesAreUnique(result); return result; } @@ -224,7 +223,6 @@ expression_vector Binder::bindOrderByExpressions( } boundOrderByExpressions.push_back(std::move(boundExpression)); } - resolveAnyDataTypeWithDefaultType(boundOrderByExpressions); return boundOrderByExpressions; } @@ -264,13 +262,5 @@ void Binder::addExpressionsToScope(const expression_vector& projectionExpression } } -void Binder::resolveAnyDataTypeWithDefaultType(const expression_vector& expressions) { - for (auto& expression : expressions) { - if (expression->dataType.getLogicalTypeID() == LogicalTypeID::ANY) { - ExpressionBinder::implicitCastIfNecessary(expression, LogicalTypeID::STRING); - } - } -} - } // namespace binder } // namespace kuzu diff --git a/src/binder/bound_statement_rewriter.cpp b/src/binder/bound_statement_rewriter.cpp index 3bdcac3799e..39595982077 100644 --- a/src/binder/bound_statement_rewriter.cpp +++ b/src/binder/bound_statement_rewriter.cpp @@ -2,6 +2,7 @@ #include "binder/rewriter/match_clause_pattern_label_rewriter.h" #include "binder/rewriter/with_clause_projection_rewriter.h" +#include "binder/visitor/default_type_solver.h" namespace kuzu { namespace binder { @@ -13,6 +14,9 @@ void BoundStatementRewriter::rewrite( auto matchClausePatternLabelRewriter = MatchClausePatternLabelRewriter(catalog); matchClausePatternLabelRewriter.visit(boundStatement); + + auto defaultTypeSolver = DefaultTypeSolver(); + defaultTypeSolver.visit(boundStatement); } } // namespace binder diff --git a/src/binder/bound_statement_visitor.cpp b/src/binder/bound_statement_visitor.cpp index 880a5793197..fe67f121116 100644 --- a/src/binder/bound_statement_visitor.cpp +++ b/src/binder/bound_statement_visitor.cpp @@ -1,6 +1,8 @@ #include "binder/bound_statement_visitor.h" #include "binder/bound_explain.h" +#include "binder/copy/bound_copy_from.h" +#include "binder/copy/bound_copy_to.h" #include "binder/query/bound_regular_query.h" #include "common/cast.h" @@ -68,6 +70,20 @@ void BoundStatementVisitor::visitUnsafe(BoundStatement& statement) { } } +void BoundStatementVisitor::visitCopyFrom(const BoundStatement& statement) { + auto& copyFrom = ku_dynamic_cast(statement); + if (copyFrom.getInfo()->source->type == ScanSourceType::QUERY) { + auto querySource = ku_dynamic_cast( + copyFrom.getInfo()->source.get()); + visit(*querySource->statement); + } +} + +void BoundStatementVisitor::visitCopyTo(const BoundStatement& statement) { + auto& copyTo = ku_dynamic_cast(statement); + visitRegularQuery(*copyTo.getRegularQuery()); +} + void BoundStatementVisitor::visitRegularQuery(const BoundStatement& statement) { auto& regularQuery = ku_dynamic_cast(statement); diff --git a/src/binder/expression/CMakeLists.txt b/src/binder/expression/CMakeLists.txt index fbfacda7697..ee106d6723d 100644 --- a/src/binder/expression/CMakeLists.txt +++ b/src/binder/expression/CMakeLists.txt @@ -4,7 +4,9 @@ add_library( case_expression.cpp expression.cpp expression_util.cpp - function_expression.cpp) + function_expression.cpp + literal_expression.cpp + parameter_expression.cpp) set(ALL_OBJECT_FILES ${ALL_OBJECT_FILES} $ diff --git a/src/binder/expression/expression.cpp b/src/binder/expression/expression.cpp index 25192ffe963..bbcfc82fd5c 100644 --- a/src/binder/expression/expression.cpp +++ b/src/binder/expression/expression.cpp @@ -1,10 +1,19 @@ #include "binder/expression/expression.h" +#include "common/exception/binder.h" + using namespace kuzu::common; namespace kuzu { namespace binder { +void Expression::cast(const LogicalType&) { + // LCOV_EXCL_START + throw BinderException( + stringFormat("Data type of expression {} should not be modified.", toString())); + // LCOV_EXCL_STOP +} + expression_vector Expression::splitOnAND() { expression_vector result; if (ExpressionType::AND == expressionType) { diff --git a/src/binder/expression/literal_expression.cpp b/src/binder/expression/literal_expression.cpp new file mode 100644 index 00000000000..c0ed03e85a3 --- /dev/null +++ b/src/binder/expression/literal_expression.cpp @@ -0,0 +1,23 @@ +#include "binder/expression/literal_expression.h" + +#include "common/exception/binder.h" + +namespace kuzu { +using namespace common; + +namespace binder { + +void LiteralExpression::cast(const LogicalType& type) { + if (dataType.getLogicalTypeID() != LogicalTypeID::ANY) { + // LCOV_EXCL_START + throw BinderException( + stringFormat("Cannot change literal expression data type from {} to {}.", + dataType.toString(), type.toString())); + // LCOV_EXCL_STOP + } + dataType = type; + value->setDataType(type); +} + +} // namespace binder +} // namespace kuzu diff --git a/src/binder/expression/parameter_expression.cpp b/src/binder/expression/parameter_expression.cpp new file mode 100644 index 00000000000..c0a93cbf2ed --- /dev/null +++ b/src/binder/expression/parameter_expression.cpp @@ -0,0 +1,23 @@ +#include "binder/expression/parameter_expression.h" + +#include "common/exception/binder.h" + +namespace kuzu { +using namespace common; + +namespace binder { + +void ParameterExpression::cast(const LogicalType& type) { + if (dataType.getLogicalTypeID() != LogicalTypeID::ANY) { + // LCOV_EXCL_START + throw BinderException( + stringFormat("Cannot change parameter expression data type from {} to {}.", + dataType.toString(), type.toString())); + // LCOV_EXCL_STOP + } + dataType = type; + value->setDataType(type); +} + +} // namespace binder +} // namespace kuzu diff --git a/src/binder/expression_binder.cpp b/src/binder/expression_binder.cpp index 48de08098c5..6266ef6e402 100644 --- a/src/binder/expression_binder.cpp +++ b/src/binder/expression_binder.cpp @@ -104,7 +104,7 @@ std::shared_ptr ExpressionBinder::implicitCastIfNecessary( return expression; } if (expression->dataType.getLogicalTypeID() == LogicalTypeID::ANY) { - resolveAnyDataType(*expression, targetType); + expression->cast(targetType); return expression; } return implicitCast(expression, targetType); @@ -127,15 +127,6 @@ std::shared_ptr ExpressionBinder::implicitCast( } } -void ExpressionBinder::resolveAnyDataType(Expression& expression, const LogicalType& targetType) { - if (expression.expressionType == ExpressionType::PARAMETER) { // expression is parameter - ((ParameterExpression&)expression).setDataType(targetType); - } else { // expression is null literal - KU_ASSERT(expression.expressionType == ExpressionType::LITERAL); - ((LiteralExpression&)expression).setDataType(targetType); - } -} - void ExpressionBinder::validateExpectedDataType( const Expression& expression, const std::vector& targets) { auto dataType = expression.dataType; diff --git a/src/binder/visitor/CMakeLists.txt b/src/binder/visitor/CMakeLists.txt index ddf93f29ddc..5bd4ed88b07 100644 --- a/src/binder/visitor/CMakeLists.txt +++ b/src/binder/visitor/CMakeLists.txt @@ -1,6 +1,7 @@ add_library( kuzu_binder_visitor OBJECT + default_type_solver.cpp property_collector.cpp) set(ALL_OBJECT_FILES diff --git a/src/binder/visitor/default_type_solver.cpp b/src/binder/visitor/default_type_solver.cpp new file mode 100644 index 00000000000..8315f654a8d --- /dev/null +++ b/src/binder/visitor/default_type_solver.cpp @@ -0,0 +1,25 @@ +#include "binder/visitor/default_type_solver.h" + +using namespace kuzu::common; + +namespace kuzu { +namespace binder { + +static void resolveAnyType(Expression& expr) { + if (expr.getDataType().getLogicalTypeID() != LogicalTypeID::ANY) { + return; + } + expr.cast(*LogicalType::STRING()); +} + +void DefaultTypeSolver::visitProjectionBody(const BoundProjectionBody& projectionBody) { + for (auto& expr : projectionBody.getProjectionExpressions()) { + resolveAnyType(*expr); + } + for (auto& expr : projectionBody.getOrderByExpressions()) { + resolveAnyType(*expr); + } +} + +} // namespace binder +} // namespace kuzu diff --git a/src/common/vector/value_vector.cpp b/src/common/vector/value_vector.cpp index ef06921fd6b..b99d1bb4e7f 100644 --- a/src/common/vector/value_vector.cpp +++ b/src/common/vector/value_vector.cpp @@ -12,6 +12,13 @@ namespace common { ValueVector::ValueVector(LogicalType dataType, storage::MemoryManager* memoryManager) : dataType{std::move(dataType)} { + if (this->dataType.getLogicalTypeID() == LogicalTypeID::ANY) { + // LCOV_EXCL_START + // Alternatively we can assign + throw RuntimeException("Trying to a create a vector with ANY type. This should not happen. " + "Data type is expected to be resolved during binding."); + // LCOV_EXCL_STOP + } numBytesPerValue = getDataTypeSize(this->dataType); initializeValueBuffer(); nullMask = std::make_unique(); diff --git a/src/function/vector_list_functions.cpp b/src/function/vector_list_functions.cpp index 4b2b5e810e5..c731cfa7d28 100644 --- a/src/function/vector_list_functions.cpp +++ b/src/function/vector_list_functions.cpp @@ -76,7 +76,7 @@ std::unique_ptr ListCreationFunction::bindFunc( auto& parameterType = argument->getDataTypeReference(); if (parameterType != childType) { if (parameterType.getLogicalTypeID() == LogicalTypeID::ANY) { - binder::ExpressionBinder::resolveAnyDataType(*argument, childType); + argument->cast(childType); } else { throw BinderException(getListFunctionIncompatibleChildrenTypeErrorMsg( LIST_CREATION_FUNC_NAME, arguments[0]->getDataType(), argument->getDataType())); diff --git a/src/function/vector_struct_functions.cpp b/src/function/vector_struct_functions.cpp index dde88007805..5c5f74e3ab8 100644 --- a/src/function/vector_struct_functions.cpp +++ b/src/function/vector_struct_functions.cpp @@ -24,8 +24,7 @@ std::unique_ptr StructPackFunctions::bindFunc( std::vector fields; for (auto& argument : arguments) { if (argument->getDataType().getLogicalTypeID() == LogicalTypeID::ANY) { - binder::ExpressionBinder::resolveAnyDataType( - *argument, LogicalType{LogicalTypeID::STRING}); + argument->cast(*LogicalType::STRING()); } fields.emplace_back(argument->getAlias(), argument->getDataType().copy()); } diff --git a/src/function/vector_union_functions.cpp b/src/function/vector_union_functions.cpp index 33c720209c2..1082279b1d9 100644 --- a/src/function/vector_union_functions.cpp +++ b/src/function/vector_union_functions.cpp @@ -25,8 +25,7 @@ std::unique_ptr UnionValueFunction::bindFunc( fields.emplace_back( UnionType::TAG_FIELD_NAME, std::make_unique(UnionType::TAG_FIELD_TYPE)); if (arguments[0]->getDataType().getLogicalTypeID() == common::LogicalTypeID::ANY) { - binder::ExpressionBinder::resolveAnyDataType( - *arguments[0], LogicalType(LogicalTypeID::STRING)); + arguments[0]->cast(*LogicalType::STRING()); } fields.emplace_back(arguments[0]->getAlias(), arguments[0]->getDataType().copy()); auto resultType = LogicalType::UNION(std::move(fields)); diff --git a/src/include/binder/binder.h b/src/include/binder/binder.h index 8e07a2b009f..faa1a8275be 100644 --- a/src/include/binder/binder.h +++ b/src/include/binder/binder.h @@ -220,7 +220,6 @@ class Binder { uint64_t bindSkipLimitExpression(const parser::ParsedExpression& expression); void addExpressionsToScope(const expression_vector& projectionExpressions); - void resolveAnyDataTypeWithDefaultType(const expression_vector& expressions); /*** bind graph pattern ***/ BoundGraphPattern bindGraphPattern(const std::vector& graphPattern); diff --git a/src/include/binder/bound_statement_visitor.h b/src/include/binder/bound_statement_visitor.h index 45a1652b193..2691255797c 100644 --- a/src/include/binder/bound_statement_visitor.h +++ b/src/include/binder/bound_statement_visitor.h @@ -20,8 +20,8 @@ class BoundStatementVisitor { virtual void visitCreateTable(const BoundStatement&) {} virtual void visitDropTable(const BoundStatement&) {} virtual void visitAlter(const BoundStatement&) {} - virtual void visitCopyFrom(const BoundStatement&) {} - virtual void visitCopyTo(const BoundStatement&) {} + virtual void visitCopyFrom(const BoundStatement&); + virtual void visitCopyTo(const BoundStatement&); virtual void visitExportDatabase(const BoundStatement&) {} virtual void visitImportDatabase(const BoundStatement&) {} virtual void visitStandaloneCall(const BoundStatement&) {} diff --git a/src/include/binder/copy/bound_copy_to.h b/src/include/binder/copy/bound_copy_to.h index c7dac956f1d..d306c8d05d7 100644 --- a/src/include/binder/copy/bound_copy_to.h +++ b/src/include/binder/copy/bound_copy_to.h @@ -1,6 +1,6 @@ #pragma once -#include "binder/query/bound_regular_query.h" +#include "binder/bound_statement.h" #include "common/copier_config/csv_reader_config.h" #include "common/copier_config/reader_config.h" @@ -10,27 +10,21 @@ namespace binder { class BoundCopyTo : public BoundStatement { public: BoundCopyTo(std::string filePath, common::FileType fileType, - std::vector columnNames, std::vector columnTypes, - std::unique_ptr regularQuery, common::CSVOption csvOption) + std::unique_ptr query, common::CSVOption csvOption) : BoundStatement{common::StatementType::COPY_TO, BoundStatementResult::createEmptyResult()}, - filePath{std::move(filePath)}, fileType{fileType}, columnNames{std::move(columnNames)}, - columnTypes{std::move(columnTypes)}, - regularQuery{std::move(regularQuery)}, csvOption{std::move(csvOption)} {} + filePath{std::move(filePath)}, fileType{fileType}, query{std::move(query)}, + csvOption{std::move(csvOption)} {} inline std::string getFilePath() const { return filePath; } inline common::FileType getFileType() const { return fileType; } - inline std::vector getColumnNames() const { return columnNames; } - inline const std::vector& getColumnTypesRef() const { return columnTypes; } - inline const BoundRegularQuery* getRegularQuery() const { return regularQuery.get(); } + inline const BoundStatement* getRegularQuery() const { return query.get(); } inline const common::CSVOption* getCopyOption() const { return &csvOption; } private: std::string filePath; common::FileType fileType; - std::vector columnNames; - std::vector columnTypes; - std::unique_ptr regularQuery; + std::unique_ptr query; common::CSVOption csvOption; }; diff --git a/src/include/binder/expression/expression.h b/src/include/binder/expression/expression.h index 59b67b717d6..3275f0be250 100644 --- a/src/include/binder/expression/expression.h +++ b/src/include/binder/expression/expression.h @@ -53,16 +53,17 @@ class Expression : public std::enable_shared_from_this { DELETE_COPY_DEFAULT_MOVE(Expression); virtual ~Expression() = default; - inline void setAlias(const std::string& name) { alias = name; } + void setAlias(const std::string& name) { alias = name; } - inline void setUniqueName(const std::string& name) { uniqueName = name; } - inline std::string getUniqueName() const { + void setUniqueName(const std::string& name) { uniqueName = name; } + std::string getUniqueName() const { KU_ASSERT(!uniqueName.empty()); return uniqueName; } - inline common::LogicalType getDataType() const { return dataType; } - inline common::LogicalType& getDataTypeReference() { return dataType; } + virtual void cast(const common::LogicalType& type); + common::LogicalType getDataType() const { return dataType; } + common::LogicalType& getDataTypeReference() { return dataType; } inline bool hasAlias() const { return !alias.empty(); } inline std::string getAlias() const { return alias; } diff --git a/src/include/binder/expression/literal_expression.h b/src/include/binder/expression/literal_expression.h index b8f7ab0ac77..5a49e36603c 100644 --- a/src/include/binder/expression/literal_expression.h +++ b/src/include/binder/expression/literal_expression.h @@ -6,25 +6,21 @@ namespace kuzu { namespace binder { -class LiteralExpression : public Expression { +class LiteralExpression final : public Expression { public: LiteralExpression(std::unique_ptr value, const std::string& uniqueName) : Expression{common::ExpressionType::LITERAL, *value->getDataType(), uniqueName}, value{std::move(value)} {} - inline bool isNull() const { return value->isNull(); } + bool isNull() const { return value->isNull(); } - inline void setDataType(const common::LogicalType& targetType) { - KU_ASSERT(dataType.getLogicalTypeID() == common::LogicalTypeID::ANY && isNull()); - dataType = targetType; - value->setDataType(targetType); - } + void cast(const common::LogicalType& type) override; - inline common::Value* getValue() const { return value.get(); } + common::Value* getValue() const { return value.get(); } std::string toStringInternal() const final { return value->toString(); } - inline std::unique_ptr copy() const final { + std::unique_ptr copy() const final { return std::make_unique(value->copy(), uniqueName); } diff --git a/src/include/binder/expression/parameter_expression.h b/src/include/binder/expression/parameter_expression.h index 7eae97087f4..12598a63d45 100644 --- a/src/include/binder/expression/parameter_expression.h +++ b/src/include/binder/expression/parameter_expression.h @@ -14,18 +14,13 @@ class ParameterExpression : public Expression { common::LogicalType(common::LogicalTypeID::ANY), createUniqueName(parameterName)}, parameterName(parameterName), value{std::move(value)} {} - inline void setDataType(const common::LogicalType& targetType) { - KU_ASSERT(dataType.getLogicalTypeID() == common::LogicalTypeID::ANY); - dataType = targetType; - value->setDataType(targetType); - } + void cast(const common::LogicalType& type) override; - inline std::shared_ptr getLiteral() const { return value; } - - inline std::string toStringInternal() const final { return "$" + parameterName; } + std::shared_ptr getLiteral() const { return value; } private: - inline static std::string createUniqueName(const std::string& input) { return "$" + input; } + std::string toStringInternal() const final { return "$" + parameterName; } + static std::string createUniqueName(const std::string& input) { return "$" + input; } private: std::string parameterName; diff --git a/src/include/binder/expression_binder.h b/src/include/binder/expression_binder.h index f26cb2a9a91..70221ddcf8e 100644 --- a/src/include/binder/expression_binder.h +++ b/src/include/binder/expression_binder.h @@ -26,8 +26,6 @@ class ExpressionBinder { std::shared_ptr bindExpression(const parser::ParsedExpression& parsedExpression); - static void resolveAnyDataType(Expression& expression, const common::LogicalType& targetType); - /****** validation *****/ static void validateExpectedDataType( const Expression& expression, common::LogicalTypeID target) { diff --git a/src/include/binder/visitor/default_type_solver.h b/src/include/binder/visitor/default_type_solver.h new file mode 100644 index 00000000000..3fc5ec965ba --- /dev/null +++ b/src/include/binder/visitor/default_type_solver.h @@ -0,0 +1,21 @@ +#pragma once + +#include "binder/bound_statement_visitor.h" + +namespace kuzu { +namespace binder { + +// Assign a default data type (STRING) for expressions with ANY data type for a given statement. +// E.g. RETURN NULL; Expression NULL can be resolved as any type based on semantic. +// We don't iterate all expressions because +// - predicates must have been resolved to BOOL type +// - lhs expressions for update must have been resolved to column type +// So we only need to resolve for expressions appear in the projection clause. This assumption might +// change as we add more features. +class DefaultTypeSolver final : public BoundStatementVisitor { +private: + void visitProjectionBody(const BoundProjectionBody& projectionBody) override; +}; + +} // namespace binder +} // namespace kuzu diff --git a/src/include/binder/visitor/property_collector.h b/src/include/binder/visitor/property_collector.h index d592de959ed..7c7cb352e17 100644 --- a/src/include/binder/visitor/property_collector.h +++ b/src/include/binder/visitor/property_collector.h @@ -5,6 +5,7 @@ namespace kuzu { namespace binder { +// Collect all property expressions for a given statement. class PropertyCollector final : public BoundStatementVisitor { public: expression_vector getProperties(); diff --git a/src/planner/plan/plan_copy.cpp b/src/planner/plan/plan_copy.cpp index c4fe93505c5..3f0fb909669 100644 --- a/src/planner/plan/plan_copy.cpp +++ b/src/planner/plan/plan_copy.cpp @@ -170,11 +170,16 @@ std::unique_ptr Planner::planCopyRdfFrom( std::unique_ptr Planner::planCopyTo(const BoundStatement& statement) { auto& boundCopy = ku_dynamic_cast(statement); auto regularQuery = boundCopy.getRegularQuery(); + std::vector columnNames; + std::vector columnTypes; + for (auto& column : regularQuery->getStatementResult()->getColumns()) { + columnNames.push_back(column->toString()); + columnTypes.push_back(column->dataType); + } KU_ASSERT(regularQuery->getStatementType() == StatementType::QUERY); auto plan = getBestPlan(*regularQuery); auto copyTo = make_shared(boundCopy.getFilePath(), boundCopy.getFileType(), - boundCopy.getColumnNames(), boundCopy.getColumnTypesRef(), - boundCopy.getCopyOption()->copy(), plan->getLastOperator()); + columnNames, columnTypes, boundCopy.getCopyOption()->copy(), plan->getLastOperator()); plan->setLastOperator(std::move(copyTo)); return plan; } diff --git a/test/test_files/common/types/null.test b/test/test_files/common/types/null.test new file mode 100644 index 00000000000..f66647a64d3 --- /dev/null +++ b/test/test_files/common/types/null.test @@ -0,0 +1,16 @@ +-GROUP IntervalTests +-DATASET CSV empty + +-- + +-CASE NullTest + +-STATEMENT CREATE NODE TABLE V1 (id UUID, PRIMARY KEY(id)); +---- ok +-STATEMENT CREATE NODE TABLE V2 (id INT64, PRIMARY KEY(id)); +---- ok +-STATEMENT WITH NULL as bid MATCH (b:V1 {id: bid}) RETURN b; +---- 0 + +-STATEMENT WITH NULL as bid MATCH (b:V2 {id: bid}) RETURN b; +---- 0 diff --git a/test/test_files/copy/copy_to_parquet.test b/test/test_files/copy/copy_to_parquet.test index 344abba4ad9..c855d84bb01 100644 --- a/test/test_files/copy/copy_to_parquet.test +++ b/test/test_files/copy/copy_to_parquet.test @@ -5,7 +5,6 @@ -CASE TinySnbCopyToParquet --CASE CopyPersonToParquet -STATEMENT COPY (MATCH (p:person) return p.ID, p.fName, p.gender, p.isStudent, p.isWorker, p.age, p.eyeSight, p.birthdate, p.registerTime, p.lastJobDuration, p.workedHours, p.usedNames, p.courseScoresPerTerm, p.height) to '${DATABASE_PATH}/tinysnb.parquet'; ---- ok -STATEMENT LOAD FROM '${DATABASE_PATH}/tinysnb.parquet' RETURN *;