diff --git a/src/binder/bind/CMakeLists.txt b/src/binder/bind/CMakeLists.txt index 6fa7ba366d..94a306f249 100644 --- a/src/binder/bind/CMakeLists.txt +++ b/src/binder/bind/CMakeLists.txt @@ -1,12 +1,12 @@ add_subdirectory(copy) add_subdirectory(ddl) +add_subdirectory(read) add_library( kuzu_binder_bind OBJECT bind_attach_database.cpp bind_comment_on.cpp - bind_copy.cpp bind_create_macro.cpp bind_ddl.cpp bind_detach_database.cpp diff --git a/src/binder/bind/bind_ddl.cpp b/src/binder/bind/bind_ddl.cpp index 8bb0d0d122..3a567d0c3a 100644 --- a/src/binder/bind/bind_ddl.cpp +++ b/src/binder/bind/bind_ddl.cpp @@ -302,7 +302,7 @@ std::unique_ptr Binder::bindRenameTable(const Statement& stateme static void validatePropertyExist(TableCatalogEntry* tableEntry, const std::string& propertyName) { if (!tableEntry->containProperty(propertyName)) { throw BinderException( - tableEntry->getName() + " table doesn't have property " + propertyName + "."); + tableEntry->getName() + " table does not have property " + propertyName + "."); } } diff --git a/src/binder/bind/bind_file_scan.cpp b/src/binder/bind/bind_file_scan.cpp index c866887e2a..2a2c4dff12 100644 --- a/src/binder/bind/bind_file_scan.cpp +++ b/src/binder/bind/bind_file_scan.cpp @@ -1,5 +1,6 @@ #include "binder/binder.h" #include "binder/bound_scan_source.h" +#include "binder/expression/expression_util.h" #include "binder/expression/literal_expression.h" #include "common/exception/binder.h" #include "common/exception/copy.h" @@ -102,7 +103,7 @@ std::unique_ptr Binder::bindScanSource(BaseScanSource* sour columns.size(), expectedColumnNames.size())); } for (auto i = 0u; i < columns.size(); ++i) { - expressionBinder.validateDataType(*columns[i], expectedColumnTypes[i]); + ExpressionUtil::validateDataType(*columns[i], expectedColumnTypes[i]); columns[i]->setAlias(expectedColumnNames[i]); } return std::make_unique(std::move(boundStatement)); diff --git a/src/binder/bind/bind_graph_pattern.cpp b/src/binder/bind/bind_graph_pattern.cpp index ccbece6cd5..b676f6840c 100644 --- a/src/binder/bind/bind_graph_pattern.cpp +++ b/src/binder/bind/bind_graph_pattern.cpp @@ -177,7 +177,7 @@ std::shared_ptr Binder::bindQueryRel(const RelPattern& relPattern auto expectedDataType = QueryRelTypeUtils::isRecursive(relPattern.getRelType()) ? LogicalTypeID::RECURSIVE_REL : LogicalTypeID::REL; - ExpressionBinder::validateExpectedDataType(*prevVariable, expectedDataType); + ExpressionUtil::validateDataType(*prevVariable, expectedDataType); throw BinderException("Bind relationship " + parsedName + " to relationship with same name is not supported."); } diff --git a/src/binder/bind/bind_query.cpp b/src/binder/bind/bind_query.cpp index 5a56b58227..9e80d59c26 100644 --- a/src/binder/bind/bind_query.cpp +++ b/src/binder/bind/bind_query.cpp @@ -1,4 +1,5 @@ #include "binder/binder.h" +#include "binder/expression/expression_util.h" #include "binder/query/return_with_clause/bound_return_clause.h" #include "binder/query/return_with_clause/bound_with_clause.h" #include "common/exception/binder.h" @@ -23,8 +24,7 @@ void validateUnionColumnsOfTheSameType( // Check whether the dataTypes in union expressions are exactly the same in each single // query. for (auto j = 0u; j < columns.size(); j++) { - ExpressionBinder::validateExpectedDataType(*otherColumns[j], - columns[j]->dataType.getLogicalTypeID()); + ExpressionUtil::validateDataType(*otherColumns[j], columns[j]->getDataType()); } } } diff --git a/src/binder/bind/bind_reading_clause.cpp b/src/binder/bind/bind_reading_clause.cpp index c758ee92ad..00bbca8b34 100644 --- a/src/binder/bind/bind_reading_clause.cpp +++ b/src/binder/bind/bind_reading_clause.cpp @@ -1,31 +1,7 @@ #include "binder/binder.h" -#include "binder/expression/literal_expression.h" -#include "binder/query/reading_clause/bound_in_query_call.h" -#include "binder/query/reading_clause/bound_load_from.h" -#include "binder/query/reading_clause/bound_match_clause.h" -#include "binder/query/reading_clause/bound_unwind_clause.h" -#include "catalog/catalog.h" -#include "catalog/catalog_entry/table_catalog_entry.h" -#include "common/exception/binder.h" -#include "common/exception/message.h" -#include "common/string_format.h" -#include "common/string_utils.h" -#include "function/built_in_function_utils.h" -#include "function/table/bind_input.h" -#include "main/attached_database.h" -#include "main/database.h" -#include "main/database_manager.h" -#include "parser/expression/parsed_function_expression.h" -#include "parser/expression/parsed_variable_expression.h" -#include "parser/query/reading_clause/in_query_call_clause.h" -#include "parser/query/reading_clause/load_from.h" -#include "parser/query/reading_clause/match_clause.h" -#include "parser/query/reading_clause/unwind_clause.h" using namespace kuzu::common; using namespace kuzu::parser; -using namespace kuzu::catalog; -using namespace kuzu::function; namespace kuzu { namespace binder { @@ -49,224 +25,5 @@ std::unique_ptr Binder::bindReadingClause(const ReadingClaus } } -std::unique_ptr Binder::bindMatchClause(const ReadingClause& readingClause) { - auto& matchClause = ku_dynamic_cast(readingClause); - auto boundGraphPattern = bindGraphPattern(matchClause.getPatternElementsRef()); - if (matchClause.hasWherePredicate()) { - boundGraphPattern.where = bindWhereExpression(*matchClause.getWherePredicate()); - } - rewriteMatchPattern(boundGraphPattern); - auto boundMatch = std::make_unique( - std::move(boundGraphPattern.queryGraphCollection), matchClause.getMatchClauseType()); - boundMatch->setPredicate(boundGraphPattern.where); - return boundMatch; -} - -void Binder::rewriteMatchPattern(BoundGraphPattern& boundGraphPattern) { - // Rewrite self loop edge - // e.g. rewrite (a)-[e]->(a) as [a]-[e]->(b) WHERE id(a) = id(b) - expression_vector selfLoopEdgePredicates; - auto& graphCollection = boundGraphPattern.queryGraphCollection; - for (auto i = 0u; i < graphCollection.getNumQueryGraphs(); ++i) { - auto queryGraph = graphCollection.getQueryGraphUnsafe(i); - for (auto& queryRel : queryGraph->getQueryRels()) { - if (!queryRel->isSelfLoop()) { - continue; - } - auto src = queryRel->getSrcNode(); - auto dst = queryRel->getDstNode(); - auto newDst = createQueryNode(dst->getVariableName(), dst->getTableIDs()); - queryGraph->addQueryNode(newDst); - queryRel->setDstNode(newDst); - auto predicate = expressionBinder.createEqualityComparisonExpression( - src->getInternalID(), newDst->getInternalID()); - selfLoopEdgePredicates.push_back(std::move(predicate)); - } - } - auto where = boundGraphPattern.where; - for (auto& predicate : selfLoopEdgePredicates) { - where = expressionBinder.combineBooleanExpressions(ExpressionType::AND, predicate, where); - } - // Rewrite key value pairs in MATCH clause as predicate - for (auto i = 0u; i < graphCollection.getNumQueryGraphs(); ++i) { - auto queryGraph = graphCollection.getQueryGraphUnsafe(i); - for (auto& pattern : queryGraph->getAllPatterns()) { - for (auto& [propertyName, rhs] : pattern->getPropertyDataExprRef()) { - auto propertyExpr = - expressionBinder.bindNodeOrRelPropertyExpression(*pattern, propertyName); - auto predicate = - expressionBinder.createEqualityComparisonExpression(propertyExpr, rhs); - where = expressionBinder.combineBooleanExpressions(ExpressionType::AND, predicate, - where); - } - } - } - boundGraphPattern.where = std::move(where); -} - -std::unique_ptr Binder::bindUnwindClause(const ReadingClause& readingClause) { - auto& unwindClause = ku_dynamic_cast(readingClause); - auto boundExpression = expressionBinder.bindExpression(*unwindClause.getExpression()); - ExpressionBinder::validateDataType(*boundExpression, LogicalTypeID::LIST); - auto aliasName = unwindClause.getAlias(); - auto alias = createVariable(aliasName, *ListType::getChildType(&boundExpression->dataType)); - std::shared_ptr idExpr = nullptr; - if (scope.hasMemorizedTableIDs(boundExpression->getAlias())) { - auto tableIDs = scope.getMemorizedTableIDs(boundExpression->getAlias()); - auto node = createQueryNode(aliasName, tableIDs); - idExpr = node->getInternalID(); - scope.addNodeReplacement(node); - } - return make_unique(std::move(boundExpression), std::move(alias), - std::move(idExpr)); -} - -std::unique_ptr Binder::bindInQueryCall(const ReadingClause& readingClause) { - auto& call = ku_dynamic_cast(readingClause); - auto expr = call.getFunctionExpression(); - auto functionExpr = - ku_dynamic_cast(expr); - // Bind parameters - std::unique_ptr replacementData; - expression_vector params; - for (auto i = 0u; i < functionExpr->getNumChildren(); i++) { - auto child = functionExpr->getChild(i); - try { - params.push_back(expressionBinder.bindExpression(*child)); - } catch (BinderException& exception) { - if (child->getExpressionType() != ExpressionType::VARIABLE) { - throw BinderException(exception.what()); // Cannot replace. Rethrow. - } - // Try replacement. - auto varExpr = ku_dynamic_cast(child); - auto var = varExpr->getVariableName(); - replacementData = clientContext->tryReplace(var); - if (replacementData == nullptr) { // Replacement fail. - throw BinderException(ExceptionMessage::variableNotInScope(var)); - } - } - } - TableFunction tableFunction; - std::unique_ptr bindData; - if (replacementData) { - tableFunction = replacementData->func; - bindData = tableFunction.bindFunc(clientContext, &replacementData->bindInput); - } else { - std::vector inputValues; - std::vector inputTypes; - for (auto& param : params) { - if (param->expressionType != ExpressionType::LITERAL) { - throw BinderException{ - stringFormat("Cannot evaluate {} as a literal.", param->toString())}; - } - auto literalExpr = - ku_dynamic_cast(param.get()); - inputTypes.push_back(literalExpr->getDataType()); - inputValues.push_back(*literalExpr->getValue()); - } - auto functions = clientContext->getCatalog()->getFunctions(clientContext->getTx()); - auto func = BuiltInFunctionsUtils::matchFunction(functionExpr->getFunctionName(), - inputTypes, functions); - tableFunction = *ku_dynamic_cast(func); - auto bindInput = function::TableFuncBindInput(); - bindInput.inputs = std::move(inputValues); - bindData = tableFunction.bindFunc(clientContext, &bindInput); - } - expression_vector columns; - for (auto i = 0u; i < bindData->columnTypes.size(); i++) { - columns.push_back(createVariable(bindData->columnNames[i], bindData->columnTypes[i])); - } - auto offset = expressionBinder.createVariableExpression(*LogicalType::INT64(), - std::string(InternalKeyword::ROW_OFFSET)); - auto boundInQueryCall = std::make_unique(tableFunction, std::move(bindData), - std::move(columns), offset); - if (call.hasWherePredicate()) { - auto wherePredicate = expressionBinder.bindExpression(*call.getWherePredicate()); - boundInQueryCall->setPredicate(std::move(wherePredicate)); - } - return boundInQueryCall; -} - -std::unique_ptr Binder::bindLoadFrom(const ReadingClause& readingClause) { - auto& loadFrom = ku_dynamic_cast(readingClause); - TableFunction scanFunction; - std::unique_ptr bindData; - auto source = loadFrom.getSource(); - switch (source->type) { - case ScanSourceType::OBJECT: { - auto objectSource = ku_dynamic_cast(source); - auto objectName = objectSource->objectName; - if (objectName.find("_") == std::string::npos) { - // Bind table - auto replacementData = clientContext->tryReplace(objectName); - if (replacementData == nullptr) { - throw BinderException(ExceptionMessage::variableNotInScope(objectName)); - } - scanFunction = replacementData->func; - bindData = scanFunction.bindFunc(clientContext, &replacementData->bindInput); - } else { - auto dbName = common::StringUtils::split(objectName, "_")[0]; - auto attachedDB = - clientContext->getDatabase()->getDatabaseManagerUnsafe()->getAttachedDatabase( - dbName); - if (attachedDB == nullptr) { - throw BinderException{ - common::stringFormat("No database named {} has been attached.", dbName)}; - } - auto tableName = common::StringUtils::split(objectName, "_")[1]; - auto tableID = attachedDB->getCatalogContent()->getTableID(tableName); - auto tableCatalogEntry = ku_dynamic_cast( - attachedDB->getCatalogContent()->getTableCatalogEntry(tableID)); - scanFunction = tableCatalogEntry->getScanFunction(); - auto bindInput = function::TableFuncBindInput(); - bindData = scanFunction.bindFunc(clientContext, &bindInput); - } - } break; - case ScanSourceType::FILE: { - auto fileSource = ku_dynamic_cast(source); - auto filePaths = bindFilePaths(fileSource->filePaths); - auto fileType = bindFileType(filePaths); - auto readerConfig = std::make_unique(fileType, std::move(filePaths)); - readerConfig->options = bindParsingOptions(loadFrom.getParsingOptionsRef()); - if (readerConfig->getNumFiles() > 1) { - throw BinderException("Load from multiple files is not supported."); - } - switch (fileType) { - case common::FileType::CSV: - case common::FileType::PARQUET: - case common::FileType::NPY: - break; - default: - throw BinderException( - stringFormat("Cannot load from file type {}.", FileTypeUtils::toString(fileType))); - } - // Bind columns from input. - std::vector expectedColumnNames; - std::vector expectedColumnTypes; - for (auto& [name, type] : loadFrom.getColumnNameDataTypesRef()) { - expectedColumnNames.push_back(name); - expectedColumnTypes.push_back(*bindDataType(type)); - } - scanFunction = getScanFunction(readerConfig->fileType, *readerConfig); - auto bindInput = ScanTableFuncBindInput(readerConfig->copy(), - std::move(expectedColumnNames), std::move(expectedColumnTypes), clientContext); - bindData = scanFunction.bindFunc(clientContext, &bindInput); - } break; - default: - throw BinderException(stringFormat("LOAD FROM subquery is not supported.")); - } - expression_vector columns; - for (auto i = 0u; i < bindData->columnTypes.size(); i++) { - columns.push_back(createVariable(bindData->columnNames[i], bindData->columnTypes[i])); - } - auto info = BoundFileScanInfo(scanFunction, std::move(bindData), std::move(columns)); - auto boundLoadFrom = std::make_unique(std::move(info)); - if (loadFrom.hasWherePredicate()) { - auto wherePredicate = expressionBinder.bindExpression(*loadFrom.getWherePredicate()); - boundLoadFrom->setPredicate(std::move(wherePredicate)); - } - return boundLoadFrom; -} - } // namespace binder } // namespace kuzu diff --git a/src/binder/bind/bind_standalone_call.cpp b/src/binder/bind/bind_standalone_call.cpp index 2f7c0bd0a9..f04f0f6fac 100644 --- a/src/binder/bind/bind_standalone_call.cpp +++ b/src/binder/bind/bind_standalone_call.cpp @@ -1,5 +1,6 @@ #include "binder/binder.h" #include "binder/bound_standalone_call.h" +#include "binder/expression/expression_util.h" #include "common/exception/binder.h" #include "extension/extension.h" #include "main/db_config.h" @@ -23,7 +24,7 @@ std::unique_ptr Binder::bindStandaloneCall(const parser::Stateme } auto optionValue = expressionBinder.bindLiteralExpression(*callStatement.getOptionValue()); // TODO(Ziyi): add casting rule for option value. - ExpressionBinder::validateExpectedDataType(*optionValue, option->parameterType); + ExpressionUtil::validateDataType(*optionValue, option->parameterType); return std::make_unique(option, std::move(optionValue)); } diff --git a/src/binder/bind/copy/CMakeLists.txt b/src/binder/bind/copy/CMakeLists.txt index bfdec0c6cf..318cd32c0d 100644 --- a/src/binder/bind/copy/CMakeLists.txt +++ b/src/binder/bind/copy/CMakeLists.txt @@ -1,6 +1,8 @@ add_library(kuzu_binder_bind_copy OBJECT - bind_copy_rdf_graph.cpp) + bind_copy_rdf_graph.cpp + bind_copy_to.cpp + bind_copy_from.cpp) set(ALL_OBJECT_FILES ${ALL_OBJECT_FILES} $ diff --git a/src/binder/bind/bind_copy.cpp b/src/binder/bind/copy/bind_copy_from.cpp similarity index 88% rename from src/binder/bind/bind_copy.cpp rename to src/binder/bind/copy/bind_copy_from.cpp index a3ba5aefa9..e456f3edff 100644 --- a/src/binder/bind/bind_copy.cpp +++ b/src/binder/bind/copy/bind_copy_from.cpp @@ -1,6 +1,5 @@ #include "binder/binder.h" #include "binder/copy/bound_copy_from.h" -#include "binder/copy/bound_copy_to.h" #include "catalog/catalog.h" #include "catalog/catalog_entry/node_table_catalog_entry.h" #include "catalog/catalog_entry/rdf_graph_catalog_entry.h" @@ -21,33 +20,6 @@ using namespace kuzu::function; namespace kuzu { namespace binder { -std::unique_ptr Binder::bindCopyToClause(const Statement& statement) { - auto& copyToStatement = ku_dynamic_cast(statement); - auto boundFilePath = copyToStatement.getFilePath(); - auto fileType = bindFileType(boundFilePath); - std::vector columnNames; - std::vector columnTypes; - auto parsedQuery = - ku_dynamic_cast(copyToStatement.getStatement()); - auto query = bindQuery(*parsedQuery); - auto columns = query->getStatementResult()->getColumns(); - for (auto& column : columns) { - auto columnName = column->hasAlias() ? column->getAlias() : column->toString(); - columnNames.push_back(columnName); - columnTypes.push_back(column->getDataType()); - } - if (fileType != FileType::CSV && fileType != FileType::PARQUET) { - throw BinderException("COPY TO currently only supports csv and parquet files."); - } - if (fileType != FileType::CSV && copyToStatement.getParsingOptionsRef().size() != 0) { - throw BinderException{"Only copy to csv can have options."}; - } - auto csvConfig = - CSVReaderConfig::construct(bindParsingOptions(copyToStatement.getParsingOptionsRef())); - return std::make_unique(boundFilePath, fileType, std::move(query), - csvConfig.option.copy()); -} - std::unique_ptr Binder::bindCopyFromClause(const Statement& statement) { auto& copyStatement = ku_dynamic_cast(statement); auto tableName = copyStatement.getTableName(); diff --git a/src/binder/bind/copy/bind_copy_to.cpp b/src/binder/bind/copy/bind_copy_to.cpp new file mode 100644 index 0000000000..51896fba0e --- /dev/null +++ b/src/binder/bind/copy/bind_copy_to.cpp @@ -0,0 +1,40 @@ +#include "binder/binder.h" +#include "binder/copy/bound_copy_to.h" +#include "common/exception/binder.h" +#include "parser/copy.h" + +using namespace kuzu::common; +using namespace kuzu::parser; + +namespace kuzu { +namespace binder { + +std::unique_ptr Binder::bindCopyToClause(const Statement& statement) { + auto& copyToStatement = statement.constCast(); + auto boundFilePath = copyToStatement.getFilePath(); + auto fileType = bindFileType(boundFilePath); + std::vector columnNames; + std::vector columnTypes; + auto parsedQuery = copyToStatement.getStatement()->constPtrCast(); + auto query = bindQuery(*parsedQuery); + auto columns = query->getStatementResult()->getColumns(); + for (auto& column : columns) { + auto columnName = column->hasAlias() ? column->getAlias() : column->toString(); + columnNames.push_back(columnName); + columnTypes.push_back(column->getDataType()); + } + if (fileType != FileType::CSV && fileType != FileType::PARQUET) { + throw BinderException("COPY TO currently only supports csv and parquet files."); + } + if (fileType != FileType::CSV && copyToStatement.getParsingOptionsRef().size() != 0) { + throw BinderException{"Only copy to csv can have options."}; + } + // TODO: check this. + auto csvConfig = + CSVReaderConfig::construct(bindParsingOptions(copyToStatement.getParsingOptionsRef())); + return std::make_unique(boundFilePath, fileType, std::move(query), + csvConfig.option.copy()); +} + +} // namespace binder +} // namespace kuzu diff --git a/src/binder/bind/read/CMakeLists.txt b/src/binder/bind/read/CMakeLists.txt new file mode 100644 index 0000000000..98c3c48e5f --- /dev/null +++ b/src/binder/bind/read/CMakeLists.txt @@ -0,0 +1,10 @@ +add_library(kuzu_binder_bind_read + OBJECT + bind_in_query_call.cpp + bind_load_from.cpp + bind_match.cpp + bind_unwind.cpp) + +set(ALL_OBJECT_FILES + ${ALL_OBJECT_FILES} $ + PARENT_SCOPE) diff --git a/src/binder/bind/read/bind_in_query_call.cpp b/src/binder/bind/read/bind_in_query_call.cpp new file mode 100644 index 0000000000..41389de6c7 --- /dev/null +++ b/src/binder/bind/read/bind_in_query_call.cpp @@ -0,0 +1,59 @@ +#include "binder/binder.h" +#include "binder/expression/expression_util.h" +#include "binder/expression/literal_expression.h" +#include "binder/query/reading_clause/bound_in_query_call.h" +#include "catalog/catalog.h" +#include "common/exception/binder.h" +#include "function/built_in_function_utils.h" +#include "parser/expression/parsed_function_expression.h" +#include "parser/query/reading_clause/in_query_call_clause.h" + +using namespace kuzu::common; +using namespace kuzu::parser; +using namespace kuzu::function; + +namespace kuzu { +namespace binder { + +std::unique_ptr Binder::bindInQueryCall(const ReadingClause& readingClause) { + auto& call = readingClause.constCast(); + auto expr = call.getFunctionExpression(); + auto functionExpr = expr->constPtrCast(); + expression_vector params; + for (auto i = 0u; i < functionExpr->getNumChildren(); i++) { + auto child = functionExpr->getChild(i); + params.push_back(expressionBinder.bindExpression(*child)); + } + TableFunction tableFunction; + std::vector inputValues; + std::vector inputTypes; + for (auto& param : params) { + ExpressionUtil::validateExpressionType(*param, ExpressionType::LITERAL); + auto literalExpr = param->constPtrCast(); + inputTypes.push_back(literalExpr->getDataType()); + inputValues.push_back(*literalExpr->getValue()); + } + auto functions = clientContext->getCatalog()->getFunctions(clientContext->getTx()); + auto func = BuiltInFunctionsUtils::matchFunction(functionExpr->getFunctionName(), inputTypes, + functions); + tableFunction = *ku_dynamic_cast(func); + auto bindInput = function::TableFuncBindInput(); + bindInput.inputs = std::move(inputValues); + auto bindData = tableFunction.bindFunc(clientContext, &bindInput); + expression_vector columns; + for (auto i = 0u; i < bindData->columnTypes.size(); i++) { + columns.push_back(createVariable(bindData->columnNames[i], bindData->columnTypes[i])); + } + auto offset = expressionBinder.createVariableExpression(*LogicalType::INT64(), + std::string(InternalKeyword::ROW_OFFSET)); + auto boundInQueryCall = std::make_unique(tableFunction, std::move(bindData), + std::move(columns), offset); + if (call.hasWherePredicate()) { + auto wherePredicate = expressionBinder.bindExpression(*call.getWherePredicate()); + boundInQueryCall->setPredicate(std::move(wherePredicate)); + } + return boundInQueryCall; +} + +} // namespace binder +} // namespace kuzu diff --git a/src/binder/bind/read/bind_load_from.cpp b/src/binder/bind/read/bind_load_from.cpp new file mode 100644 index 0000000000..75a64aba98 --- /dev/null +++ b/src/binder/bind/read/bind_load_from.cpp @@ -0,0 +1,101 @@ +#include "binder/binder.h" +#include "binder/query/reading_clause/bound_load_from.h" +#include "catalog/catalog_entry/table_catalog_entry.h" +#include "common/exception/binder.h" +#include "common/exception/message.h" +#include "common/string_utils.h" +#include "main/database.h" +#include "main/database_manager.h" +#include "parser/query/reading_clause/load_from.h" + +using namespace kuzu::function; +using namespace kuzu::common; +using namespace kuzu::parser; +using namespace kuzu::catalog; + +namespace kuzu { +namespace binder { + +std::unique_ptr Binder::bindLoadFrom(const ReadingClause& readingClause) { + auto& loadFrom = readingClause.constCast(); + TableFunction scanFunction; + std::unique_ptr bindData; + auto source = loadFrom.getSource(); + switch (source->type) { + case ScanSourceType::OBJECT: { + auto objectSource = source->constPtrCast(); + auto objectName = objectSource->objectName; + if (objectName.find("_") == std::string::npos) { + // Bind table + auto replacementData = clientContext->tryReplace(objectName); + if (replacementData == nullptr) { + throw BinderException(ExceptionMessage::variableNotInScope(objectName)); + } + scanFunction = replacementData->func; + bindData = scanFunction.bindFunc(clientContext, &replacementData->bindInput); + } else { + auto dbName = common::StringUtils::split(objectName, "_")[0]; + auto attachedDB = + clientContext->getDatabase()->getDatabaseManagerUnsafe()->getAttachedDatabase( + dbName); + if (attachedDB == nullptr) { + throw BinderException{ + common::stringFormat("No database named {} has been attached.", dbName)}; + } + auto tableName = common::StringUtils::split(objectName, "_")[1]; + auto tableID = attachedDB->getCatalogContent()->getTableID(tableName); + auto tableCatalogEntry = ku_dynamic_cast( + attachedDB->getCatalogContent()->getTableCatalogEntry(tableID)); + scanFunction = tableCatalogEntry->getScanFunction(); + auto bindInput = function::TableFuncBindInput(); + bindData = scanFunction.bindFunc(clientContext, &bindInput); + } + } break; + case ScanSourceType::FILE: { + auto fileSource = source->constPtrCast(); + auto filePaths = bindFilePaths(fileSource->filePaths); + auto fileType = bindFileType(filePaths); + auto readerConfig = std::make_unique(fileType, std::move(filePaths)); + readerConfig->options = bindParsingOptions(loadFrom.getParsingOptionsRef()); + if (readerConfig->getNumFiles() > 1) { + throw BinderException("Load from multiple files is not supported."); + } + switch (fileType) { + case common::FileType::CSV: + case common::FileType::PARQUET: + case common::FileType::NPY: + break; + default: + throw BinderException( + stringFormat("Cannot load from file type {}.", FileTypeUtils::toString(fileType))); + } + // Bind columns from input. + std::vector expectedColumnNames; + std::vector expectedColumnTypes; + for (auto& [name, type] : loadFrom.getColumnNameDataTypesRef()) { + expectedColumnNames.push_back(name); + expectedColumnTypes.push_back(*bindDataType(type)); + } + scanFunction = getScanFunction(readerConfig->fileType, *readerConfig); + auto bindInput = ScanTableFuncBindInput(readerConfig->copy(), + std::move(expectedColumnNames), std::move(expectedColumnTypes), clientContext); + bindData = scanFunction.bindFunc(clientContext, &bindInput); + } break; + default: + throw BinderException(stringFormat("LOAD FROM subquery is not supported.")); + } + expression_vector columns; + for (auto i = 0u; i < bindData->columnTypes.size(); i++) { + columns.push_back(createVariable(bindData->columnNames[i], bindData->columnTypes[i])); + } + auto info = BoundFileScanInfo(scanFunction, std::move(bindData), std::move(columns)); + auto boundLoadFrom = std::make_unique(std::move(info)); + if (loadFrom.hasWherePredicate()) { + auto wherePredicate = expressionBinder.bindExpression(*loadFrom.getWherePredicate()); + boundLoadFrom->setPredicate(std::move(wherePredicate)); + } + return boundLoadFrom; +} + +} // namespace binder +} // namespace kuzu diff --git a/src/binder/bind/read/bind_match.cpp b/src/binder/bind/read/bind_match.cpp new file mode 100644 index 0000000000..e5419bf4e8 --- /dev/null +++ b/src/binder/bind/read/bind_match.cpp @@ -0,0 +1,67 @@ +#include "binder/binder.h" +#include "binder/query/reading_clause/bound_match_clause.h" +#include "parser/query/reading_clause/match_clause.h" + +using namespace kuzu::common; +using namespace kuzu::parser; + +namespace kuzu { +namespace binder { + +std::unique_ptr Binder::bindMatchClause(const ReadingClause& readingClause) { + auto& matchClause = readingClause.constCast(); + auto boundGraphPattern = bindGraphPattern(matchClause.getPatternElementsRef()); + if (matchClause.hasWherePredicate()) { + boundGraphPattern.where = bindWhereExpression(*matchClause.getWherePredicate()); + } + rewriteMatchPattern(boundGraphPattern); + auto boundMatch = std::make_unique( + std::move(boundGraphPattern.queryGraphCollection), matchClause.getMatchClauseType()); + boundMatch->setPredicate(boundGraphPattern.where); + return boundMatch; +} + +void Binder::rewriteMatchPattern(BoundGraphPattern& boundGraphPattern) { + // Rewrite self loop edge + // e.g. rewrite (a)-[e]->(a) as [a]-[e]->(b) WHERE id(a) = id(b) + expression_vector selfLoopEdgePredicates; + auto& graphCollection = boundGraphPattern.queryGraphCollection; + for (auto i = 0u; i < graphCollection.getNumQueryGraphs(); ++i) { + auto queryGraph = graphCollection.getQueryGraphUnsafe(i); + for (auto& queryRel : queryGraph->getQueryRels()) { + if (!queryRel->isSelfLoop()) { + continue; + } + auto src = queryRel->getSrcNode(); + auto dst = queryRel->getDstNode(); + auto newDst = createQueryNode(dst->getVariableName(), dst->getTableIDs()); + queryGraph->addQueryNode(newDst); + queryRel->setDstNode(newDst); + auto predicate = expressionBinder.createEqualityComparisonExpression( + src->getInternalID(), newDst->getInternalID()); + selfLoopEdgePredicates.push_back(std::move(predicate)); + } + } + auto where = boundGraphPattern.where; + for (auto& predicate : selfLoopEdgePredicates) { + where = expressionBinder.combineBooleanExpressions(ExpressionType::AND, predicate, where); + } + // Rewrite key value pairs in MATCH clause as predicate + for (auto i = 0u; i < graphCollection.getNumQueryGraphs(); ++i) { + auto queryGraph = graphCollection.getQueryGraphUnsafe(i); + for (auto& pattern : queryGraph->getAllPatterns()) { + for (auto& [propertyName, rhs] : pattern->getPropertyDataExprRef()) { + auto propertyExpr = + expressionBinder.bindNodeOrRelPropertyExpression(*pattern, propertyName); + auto predicate = + expressionBinder.createEqualityComparisonExpression(propertyExpr, rhs); + where = expressionBinder.combineBooleanExpressions(ExpressionType::AND, predicate, + where); + } + } + } + boundGraphPattern.where = std::move(where); +} + +} // namespace binder +} // namespace kuzu diff --git a/src/binder/bind/read/bind_unwind.cpp b/src/binder/bind/read/bind_unwind.cpp new file mode 100644 index 0000000000..fec228019c --- /dev/null +++ b/src/binder/bind/read/bind_unwind.cpp @@ -0,0 +1,30 @@ +#include "binder/binder.h" +#include "binder/expression/expression_util.h" +#include "binder/query/reading_clause/bound_unwind_clause.h" +#include "parser/query/reading_clause/unwind_clause.h" + +using namespace kuzu::parser; +using namespace kuzu::common; + +namespace kuzu { +namespace binder { + +std::unique_ptr Binder::bindUnwindClause(const ReadingClause& readingClause) { + auto& unwindClause = readingClause.constCast(); + auto boundExpression = expressionBinder.bindExpression(*unwindClause.getExpression()); + ExpressionUtil::validateDataType(*boundExpression, LogicalTypeID::LIST); + auto aliasName = unwindClause.getAlias(); + auto alias = createVariable(aliasName, *ListType::getChildType(&boundExpression->dataType)); + std::shared_ptr idExpr = nullptr; + if (scope.hasMemorizedTableIDs(boundExpression->getAlias())) { + auto tableIDs = scope.getMemorizedTableIDs(boundExpression->getAlias()); + auto node = createQueryNode(aliasName, tableIDs); + idExpr = node->getInternalID(); + scope.addNodeReplacement(node); + } + return make_unique(std::move(boundExpression), std::move(alias), + std::move(idExpr)); +} + +} // namespace binder +} // namespace kuzu diff --git a/src/binder/bind_expression/bind_function_expression.cpp b/src/binder/bind_expression/bind_function_expression.cpp index bb26efa1d2..26c124377e 100644 --- a/src/binder/bind_expression/bind_function_expression.cpp +++ b/src/binder/bind_expression/bind_function_expression.cpp @@ -197,7 +197,7 @@ std::shared_ptr ExpressionBinder::rewriteFunctionExpression( const parser::ParsedExpression& parsedExpression, const std::string& functionName) { if (functionName == LabelFunction::name) { auto child = bindExpression(*parsedExpression.getChild(0)); - validateExpectedDataType(*child, + ExpressionUtil::validateDataType(*child, std::vector{LogicalTypeID::NODE, LogicalTypeID::REL}); return bindLabelFunction(*child); } else if (functionName == LengthFunction::name) { @@ -205,11 +205,11 @@ std::shared_ptr ExpressionBinder::rewriteFunctionExpression( return bindRecursiveJoinLengthFunction(*child); } else if (functionName == StartNodeFunction::name) { auto child = bindExpression(*parsedExpression.getChild(0)); - validateExpectedDataType(*child, std::vector{LogicalTypeID::REL}); + ExpressionUtil::validateDataType(*child, LogicalTypeID::REL); return bindStartNodeExpression(*child); } else if (functionName == EndNodeFunction::name) { auto child = bindExpression(*parsedExpression.getChild(0)); - validateExpectedDataType(*child, std::vector{LogicalTypeID::REL}); + ExpressionUtil::validateDataType(*child, LogicalTypeID::REL); return bindEndNodeExpression(*child); } return nullptr; diff --git a/src/binder/bind_expression/bind_property_expression.cpp b/src/binder/bind_expression/bind_property_expression.cpp index cc45fef1bf..53bdcb15e7 100644 --- a/src/binder/bind_expression/bind_property_expression.cpp +++ b/src/binder/bind_expression/bind_property_expression.cpp @@ -71,7 +71,7 @@ std::shared_ptr ExpressionBinder::bindPropertyExpression( } auto propertyName = propertyExpression.getPropertyName(); auto child = bindExpression(*parsedExpression.getChild(0)); - validateExpectedDataType(*child, + ExpressionUtil::validateDataType(*child, std::vector{LogicalTypeID::NODE, LogicalTypeID::REL, LogicalTypeID::STRUCT}); if (isNodeOrRelPattern(*child)) { if (Binder::isReservedPropertyName(propertyName)) { diff --git a/src/binder/expression/expression_util.cpp b/src/binder/expression/expression_util.cpp index 40e21c98fb..1a47e9626a 100644 --- a/src/binder/expression/expression_util.cpp +++ b/src/binder/expression/expression_util.cpp @@ -1,5 +1,7 @@ #include "binder/expression/expression_util.h" +#include "common/exception/binder.h" + using namespace kuzu::common; namespace kuzu { @@ -87,8 +89,7 @@ expression_vector ExpressionUtil::excludeExpressions(const expression_vector& ex return result; } -logical_type_vec_t ExpressionUtil::getDataTypes( - const kuzu::binder::expression_vector& expressions) { +logical_type_vec_t ExpressionUtil::getDataTypes(const expression_vector& expressions) { std::vector result; result.reserve(expressions.size()); for (auto& expression : expressions) { @@ -120,10 +121,46 @@ bool ExpressionUtil::isRelPattern(const Expression& expression) { expression.dataType.getLogicalTypeID() == LogicalTypeID::REL; } -bool ExpressionUtil::isRecursiveRelPattern(const kuzu::binder::Expression& expression) { +bool ExpressionUtil::isRecursiveRelPattern(const Expression& expression) { return expression.expressionType == ExpressionType::PATTERN && expression.dataType.getLogicalTypeID() == LogicalTypeID::RECURSIVE_REL; } +void ExpressionUtil::validateExpressionType(const Expression& expr, + common::ExpressionType expectedType) { + if (expr.expressionType == expectedType) { + return; + } + throw BinderException(stringFormat("{} has type {} but {} was expected.", expr.toString(), + expressionTypeToString(expr.expressionType), expressionTypeToString(expectedType))); +} + +void ExpressionUtil::validateDataType(const Expression& expr, const LogicalType& expectedType) { + if (expr.getDataType() == expectedType) { + return; + } + throw BinderException(stringFormat("{} has data type {} but {} was expected.", expr.toString(), + expr.getDataType().toString(), expectedType.toString())); +} + +void ExpressionUtil::validateDataType(const Expression& expr, LogicalTypeID expectedTypeID) { + if (expr.getDataType().getLogicalTypeID() == expectedTypeID) { + return; + } + throw BinderException(stringFormat("{} has data type {} but {} was expected.", expr.toString(), + expr.getDataType().toString(), LogicalTypeUtils::toString(expectedTypeID))); +} + +void ExpressionUtil::validateDataType(const Expression& expr, + const std::vector& expectedTypeIDs) { + auto targetsSet = + std::unordered_set{expectedTypeIDs.begin(), expectedTypeIDs.end()}; + if (targetsSet.contains(expr.getDataType().getLogicalTypeID())) { + return; + } + throw BinderException(stringFormat("{} has data type {} but {} was expected.", expr.toString(), + expr.getDataType().toString(), LogicalTypeUtils::toString(expectedTypeIDs))); +} + } // namespace binder } // namespace kuzu diff --git a/src/binder/expression_binder.cpp b/src/binder/expression_binder.cpp index 07eb0a1372..cfd2554961 100644 --- a/src/binder/expression_binder.cpp +++ b/src/binder/expression_binder.cpp @@ -126,32 +126,6 @@ std::shared_ptr ExpressionBinder::implicitCast( } } -void ExpressionBinder::validateExpectedDataType(const Expression& expression, - const std::vector& targets) { - auto dataType = expression.dataType; - auto targetsSet = std::unordered_set{targets.begin(), targets.end()}; - if (!targetsSet.contains(dataType.getLogicalTypeID())) { - throw BinderException(stringFormat("{} has data type {} but {} was expected.", - expression.toString(), LogicalTypeUtils::toString(dataType.getLogicalTypeID()), - LogicalTypeUtils::toString(targets))); - } -} - -void ExpressionBinder::validateDataType(const Expression& expr, const LogicalType& expectedType) { - if (expr.getDataType() != expectedType) { - throw BinderException(stringFormat("{} has data type {} but {} was expected.", - expr.toString(), expr.getDataType().toString(), expectedType.toString())); - } -} - -void ExpressionBinder::validateDataType(const Expression& expr, LogicalTypeID expectedTypeID) { - if (expr.getDataType().getLogicalTypeID() != expectedTypeID) { - throw BinderException( - stringFormat("{} has data type {} but {} was expected.", expr.toString(), - expr.getDataType().toString(), LogicalTypeUtils::toString(expectedTypeID))); - } -} - void ExpressionBinder::validateAggregationExpressionIsNotNested(const Expression& expression) { if (expression.getNumChildren() == 0) { return; diff --git a/src/include/binder/copy/bound_copy_to.h b/src/include/binder/copy/bound_copy_to.h index d306c8d05d..1c432b7ef5 100644 --- a/src/include/binder/copy/bound_copy_to.h +++ b/src/include/binder/copy/bound_copy_to.h @@ -15,11 +15,11 @@ class BoundCopyTo : public BoundStatement { 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; } + std::string getFilePath() const { return filePath; } + common::FileType getFileType() const { return fileType; } - inline const BoundStatement* getRegularQuery() const { return query.get(); } - inline const common::CSVOption* getCopyOption() const { return &csvOption; } + const BoundStatement* getRegularQuery() const { return query.get(); } + const common::CSVOption* getCopyOption() const { return &csvOption; } private: std::string filePath; diff --git a/src/include/binder/expression/expression_util.h b/src/include/binder/expression/expression_util.h index b692875d8b..431e260caa 100644 --- a/src/include/binder/expression/expression_util.h +++ b/src/include/binder/expression/expression_util.h @@ -32,6 +32,15 @@ struct ExpressionUtil { static bool isNodePattern(const Expression& expression); static bool isRelPattern(const Expression& expression); static bool isRecursiveRelPattern(const Expression& expression); + + static void validateExpressionType(const Expression& expr, common::ExpressionType expectedType); + + // Validate data type. + static void validateDataType(const Expression& expr, const common::LogicalType& expectedType); + // Validate recursive data type top level (used when child type is unknown). + static void validateDataType(const Expression& expr, common::LogicalTypeID expectedTypeID); + static void validateDataType(const Expression& expr, + const std::vector& expectedTypeIDs); }; } // namespace binder diff --git a/src/include/binder/expression_binder.h b/src/include/binder/expression_binder.h index 5f3fa343d7..3e523a2389 100644 --- a/src/include/binder/expression_binder.h +++ b/src/include/binder/expression_binder.h @@ -26,18 +26,6 @@ class ExpressionBinder { std::shared_ptr bindExpression(const parser::ParsedExpression& parsedExpression); - /****** validation *****/ - static void validateExpectedDataType(const Expression& expression, - common::LogicalTypeID target) { - validateExpectedDataType(expression, std::vector{target}); - } - static void validateExpectedDataType(const Expression& expression, - const std::vector& targets); - // Validate data type. - static void validateDataType(const Expression& expr, const common::LogicalType& expectedType); - // Validate recursive data type top level (used when child type is unknown). - static void validateDataType(const Expression& expr, common::LogicalTypeID expectedTypeID); - // TODO(Xiyang): move to an expression rewriter std::shared_ptr foldExpression(const std::shared_ptr& expression); diff --git a/src/include/parser/copy.h b/src/include/parser/copy.h index 82c8ff1ac2..a8c2f4c137 100644 --- a/src/include/parser/copy.h +++ b/src/include/parser/copy.h @@ -13,8 +13,8 @@ class Copy : public Statement { public: explicit Copy(common::StatementType type) : Statement{type} {} - inline void setParsingOption(parsing_option_t options) { parsingOptions = std::move(options); } - inline const parsing_option_t& getParsingOptionsRef() const { return parsingOptions; } + void setParsingOption(parsing_option_t options) { parsingOptions = std::move(options); } + const parsing_option_t& getParsingOptionsRef() const { return parsingOptions; } protected: parsing_option_t parsingOptions; @@ -26,15 +26,15 @@ class CopyFrom : public Copy { : Copy{common::StatementType::COPY_FROM}, byColumn_{false}, source{std::move(source)}, tableName{std::move(tableName)} {} - inline void setByColumn() { byColumn_ = true; } - inline bool byColumn() const { return byColumn_; } + void setByColumn() { byColumn_ = true; } + bool byColumn() const { return byColumn_; } - inline BaseScanSource* getSource() const { return source.get(); } + BaseScanSource* getSource() const { return source.get(); } - inline std::string getTableName() const { return tableName; } + std::string getTableName() const { return tableName; } - inline void setColumnNames(std::vector names) { columnNames = std::move(names); } - inline std::vector getColumnNames() const { return columnNames; } + void setColumnNames(std::vector names) { columnNames = std::move(names); } + std::vector getColumnNames() const { return columnNames; } private: bool byColumn_; @@ -49,8 +49,8 @@ class CopyTo : public Copy { : Copy{common::StatementType::COPY_TO}, filePath{std::move(filePath)}, statement{std::move(statement)} {} - inline std::string getFilePath() const { return filePath; } - inline const Statement* getStatement() const { return statement.get(); } + std::string getFilePath() const { return filePath; } + const Statement* getStatement() const { return statement.get(); } private: std::string filePath; diff --git a/src/include/parser/expression/parsed_expression.h b/src/include/parser/expression/parsed_expression.h index 2033910f01..968cc0d3df 100644 --- a/src/include/parser/expression/parsed_expression.h +++ b/src/include/parser/expression/parsed_expression.h @@ -5,6 +5,7 @@ #include #include +#include "common/cast.h" #include "common/copy_constructors.h" #include "common/enums/expression_type.h" @@ -70,6 +71,11 @@ class ParsedExpression { static std::unique_ptr deserialize(common::Deserializer& deserializer); + template + const TARGET* constPtrCast() const { + return common::ku_dynamic_cast(this); + } + protected: parsed_expr_vector copyChildren() const; diff --git a/src/include/parser/query/reading_clause/in_query_call_clause.h b/src/include/parser/query/reading_clause/in_query_call_clause.h index 309da65725..425eb2a00d 100644 --- a/src/include/parser/query/reading_clause/in_query_call_clause.h +++ b/src/include/parser/query/reading_clause/in_query_call_clause.h @@ -12,15 +12,13 @@ class InQueryCallClause final : public ReadingClause { : ReadingClause{common::ClauseType::IN_QUERY_CALL}, functionExpression{std::move(functionExpression)} {} - inline const ParsedExpression* getFunctionExpression() const { - return functionExpression.get(); - } + const ParsedExpression* getFunctionExpression() const { return functionExpression.get(); } - inline void setWherePredicate(std::unique_ptr expression) { + void setWherePredicate(std::unique_ptr expression) { wherePredicate = std::move(expression); } - inline bool hasWherePredicate() const { return wherePredicate != nullptr; } - inline const ParsedExpression* getWherePredicate() const { return wherePredicate.get(); } + bool hasWherePredicate() const { return wherePredicate != nullptr; } + const ParsedExpression* getWherePredicate() const { return wherePredicate.get(); } private: std::unique_ptr functionExpression; diff --git a/src/include/parser/query/reading_clause/reading_clause.h b/src/include/parser/query/reading_clause/reading_clause.h index 2aff2c1940..2448e259ca 100644 --- a/src/include/parser/query/reading_clause/reading_clause.h +++ b/src/include/parser/query/reading_clause/reading_clause.h @@ -1,5 +1,6 @@ #pragma once +#include "common/cast.h" #include "common/enums/clause_type.h" namespace kuzu { @@ -10,7 +11,12 @@ class ReadingClause { explicit ReadingClause(common::ClauseType clauseType) : clauseType{clauseType} {}; virtual ~ReadingClause() = default; - inline common::ClauseType getClauseType() const { return clauseType; } + common::ClauseType getClauseType() const { return clauseType; } + + template + const TARGET& constCast() const { + return common::ku_dynamic_cast(*this); + } private: common::ClauseType clauseType; diff --git a/src/include/parser/scan_source.h b/src/include/parser/scan_source.h index c5345116c2..fa9caf4ba2 100644 --- a/src/include/parser/scan_source.h +++ b/src/include/parser/scan_source.h @@ -17,6 +17,11 @@ struct BaseScanSource { explicit BaseScanSource(common::ScanSourceType type) : type{type} {} virtual ~BaseScanSource() = default; DELETE_COPY_AND_MOVE(BaseScanSource); + + template + const TARGET* constPtrCast() const { + return common::ku_dynamic_cast(this); + } }; struct FileScanSource : public BaseScanSource { diff --git a/src/include/parser/statement.h b/src/include/parser/statement.h index 45e3d1bb63..5e0ff193f0 100644 --- a/src/include/parser/statement.h +++ b/src/include/parser/statement.h @@ -1,5 +1,6 @@ #pragma once +#include "common/cast.h" #include "common/enums/statement_type.h" namespace kuzu { @@ -11,9 +12,9 @@ class Statement { virtual ~Statement() = default; - inline common::StatementType getStatementType() const { return statementType; } + common::StatementType getStatementType() const { return statementType; } - inline bool requireTx() { + bool requireTx() { switch (statementType) { case common::StatementType::TRANSACTION: return false; @@ -22,6 +23,15 @@ class Statement { } } + template + const TARGET& constCast() const { + return common::ku_dynamic_cast(*this); + } + template + const TARGET* constPtrCast() const { + return common::ku_dynamic_cast(this); + } + private: common::StatementType statementType; }; diff --git a/src/transaction/transaction_context.cpp b/src/transaction/transaction_context.cpp index b88cac40ae..bc45978d77 100644 --- a/src/transaction/transaction_context.cpp +++ b/src/transaction/transaction_context.cpp @@ -44,7 +44,7 @@ void TransactionContext::validateManualTransaction(bool allowActiveTransaction, bool readOnlyStatement) { KU_ASSERT(hasActiveTransaction()); if (activeTransaction->isReadOnly() && !readOnlyStatement) { - throw ConnectionException("Can't execute a write query inside a read-only transaction."); + throw ConnectionException("Can not execute a write query inside a read-only transaction."); } if (!allowActiveTransaction) { throw ConnectionException( diff --git a/test/test_files/exceptions/binder/binder_error.test b/test/test_files/exceptions/binder/binder_error.test index 8030e349fb..d978ac70f0 100644 --- a/test/test_files/exceptions/binder/binder_error.test +++ b/test/test_files/exceptions/binder/binder_error.test @@ -229,7 +229,7 @@ Binder exception: The number of columns to union/union all must be the same. -LOG UnionAllUnmatchedDataTypesOfExpressions -STATEMENT MATCH (p:person) RETURN p.fName UNION ALL MATCH (p1:person) RETURN p1.age ---- error -Binder exception: p1.age has data type INT64 but (STRING) was expected. +Binder exception: p1.age has data type INT64 but STRING was expected. -LOG UnionAndUnionAllInSingleQuery -STATEMENT MATCH (p:person) RETURN p.age UNION ALL MATCH (p1:person) RETURN p1.age UNION MATCH (p1:person) RETURN p1.age @@ -444,7 +444,7 @@ Catalog exception: Table: person1 does not exist. -LOG DropNonExistedColumn -STATEMENT alter table person drop random ---- error -Binder exception: person table doesn't have property random. +Binder exception: person table does not have property random. -LOG DropPrimaryKeyColumn -STATEMENT alter table person drop ID @@ -535,7 +535,7 @@ Binder exception: Invalid option name: thread. -LOG InvalidCallOptionValue -STATEMENT CALL threads='abc' ---- error -Binder exception: abc has data type STRING but (INT64) was expected. +Binder exception: abc has data type STRING but INT64 was expected. -LOG AllShortestPathInvalidLowerBound -STATEMENT MATCH p = (a)-[* ALL SHORTEST 2..3]-(b) RETURN p diff --git a/test/test_files/tck/match/match1.test b/test/test_files/tck/match/match1.test index d1c3b85f9b..42f21de80c 100644 --- a/test/test_files/tck/match/match1.test +++ b/test/test_files/tck/match/match1.test @@ -180,13 +180,13 @@ Binder exception: Cannot bind r as node pattern. ---- ok -STATEMENT MATCH ()-[r]-(r) RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH ()-[r]->(r) RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH ()<-[r]-(r) RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH ()-[r]-()-[]-(r) RETURN r; ---- error Binder exception: Cannot bind r as node pattern. diff --git a/test/test_files/tck/match/match2.test b/test/test_files/tck/match/match2.test index 4c06b5229e..2356393228 100644 --- a/test/test_files/tck/match/match2.test +++ b/test/test_files/tck/match/match2.test @@ -130,82 +130,82 @@ Parser exception: Invalid input : expected rule oC_SingleQuer ---- ok -STATEMENT MATCH (r) MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH (r)-[]-() MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH (r)-[]->() MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH (r)<-[]-() MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH (r)-[]-(r) MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH ()-[]->(r) MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH ()<-[]-(r) MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH ()-[]-(r) MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH (r)-[]->(r) MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH (r)<-[]-(r) MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH (r)-[]-()-[]-() MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH ()-[]-(r)-[]-() MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH (r)-[]-()-[*1..30]-() MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH ()-[]-(r)-[*1..30]-() MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH (r), ()-[]-() MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH (r)-[]-(), ()-[]-() MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH ()-[]-(r), ()-[]-() MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH ()-[]-(), (r)-[]-() MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH ()-[]-(), ()-[]-(r) MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH (r)-[]-(t), (s)-[]-(t) MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH (s)-[]-(r), (s)-[]-(t) MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH (s)-[]-(t), (r)-[]-(t) MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH (s)-[]-(t), (s)-[]-(r) MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH (s), (a)-[q]-(b), (r), (s)-[]-(t)-[]-(b) MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH (s), (a)-[q]-(b), (r), (s)-[]->(t)<-[]-(b) MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH (s), (a)-[q]-(b), (t), (s)-[]->(r)<-[]-(b) MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. # Fail when a path has the same variable in a preceding MATCH -CASE Scenario10 @@ -215,61 +215,61 @@ Binder exception: r has data type NODE but (REL) was expected. ---- ok -STATEMENT MATCH r = ()-[]-() MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type RECURSIVE_REL but (REL) was expected. +Binder exception: r has data type RECURSIVE_REL but REL was expected. -STATEMENT MATCH r = ()-[]->() MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type RECURSIVE_REL but (REL) was expected. +Binder exception: r has data type RECURSIVE_REL but REL was expected. -STATEMENT MATCH r = ()<-[]-() MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type RECURSIVE_REL but (REL) was expected. +Binder exception: r has data type RECURSIVE_REL but REL was expected. -STATEMENT MATCH r = ()-[*1..30]-() MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type RECURSIVE_REL but (REL) was expected. +Binder exception: r has data type RECURSIVE_REL but REL was expected. -STATEMENT MATCH r = ()-[*1..30]->() MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type RECURSIVE_REL but (REL) was expected. +Binder exception: r has data type RECURSIVE_REL but REL was expected. -STATEMENT MATCH r = ()<-[*1..30]-() MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type RECURSIVE_REL but (REL) was expected. +Binder exception: r has data type RECURSIVE_REL but REL was expected. -STATEMENT MATCH r = ()-[p*1..30]-() MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type RECURSIVE_REL but (REL) was expected. +Binder exception: r has data type RECURSIVE_REL but REL was expected. -STATEMENT MATCH r = ()-[p*1..30]->() MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type RECURSIVE_REL but (REL) was expected. +Binder exception: r has data type RECURSIVE_REL but REL was expected. -STATEMENT MATCH r = ()<-[p*1..30]-() MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type RECURSIVE_REL but (REL) was expected. +Binder exception: r has data type RECURSIVE_REL but REL was expected. -STATEMENT MATCH (), r = ()-[]-() MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type RECURSIVE_REL but (REL) was expected. +Binder exception: r has data type RECURSIVE_REL but REL was expected. -STATEMENT MATCH ()-[]-(), r = ()-[]-() MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type RECURSIVE_REL but (REL) was expected. +Binder exception: r has data type RECURSIVE_REL but REL was expected. -STATEMENT MATCH ()-[]->(), r = ()<-[]-() MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type RECURSIVE_REL but (REL) was expected. +Binder exception: r has data type RECURSIVE_REL but REL was expected. -STATEMENT MATCH ()<-[]-(), r = ()-[]->() MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type RECURSIVE_REL but (REL) was expected. +Binder exception: r has data type RECURSIVE_REL but REL was expected. -STATEMENT MATCH ()-[*1..30]->(), r = ()<-[]-() MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type RECURSIVE_REL but (REL) was expected. +Binder exception: r has data type RECURSIVE_REL but REL was expected. -STATEMENT MATCH ()<-[p*1..30]-(), r = ()-[*1..30]->() MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type RECURSIVE_REL but (REL) was expected. +Binder exception: r has data type RECURSIVE_REL but REL was expected. -STATEMENT MATCH (x), (a)-[q]-(b), (r), (s)-[]->(t)<-[]-(b) MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH (x), (a)-[q]-(b), r = (s)-[p]->(t)<-[]-(b) MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type RECURSIVE_REL but (REL) was expected. +Binder exception: r has data type RECURSIVE_REL but REL was expected. -STATEMENT MATCH (x), (a)-[q*1..30]-(b), r = (s)-[p]->(t)<-[]-(b) MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type RECURSIVE_REL but (REL) was expected. +Binder exception: r has data type RECURSIVE_REL but REL was expected. -STATEMENT MATCH (x), (a)-[q]-(b), r = (s)-[p*1..30]->(t)<-[]-(b) MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type RECURSIVE_REL but (REL) was expected. +Binder exception: r has data type RECURSIVE_REL but REL was expected. # Fail when a node has the same variable in the same pattern -CASE Scenario11 @@ -279,55 +279,55 @@ Binder exception: r has data type RECURSIVE_REL but (REL) was expected. ---- ok -STATEMENT MATCH (r)-[r]-() RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH (r)-[r]->() RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH (r)<-[r]-() RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH (r)-[r]-(r) RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH (r)-[r]->(r) RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH (r)<-[r]-(r) RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH (r)-[]-()-[r]-() RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH ()-[]-(r)-[r]-() RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH (r)-[]-()-[r*1..30]-() RETURN r; ---- error -Binder exception: r has data type NODE but (RECURSIVE_REL) was expected. +Binder exception: r has data type NODE but RECURSIVE_REL was expected. -STATEMENT MATCH ()-[]-(r)-[r*1..30]-() RETURN r; ---- error -Binder exception: r has data type NODE but (RECURSIVE_REL) was expected. +Binder exception: r has data type NODE but RECURSIVE_REL was expected. -STATEMENT MATCH (r), ()-[r]-() RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH (r)-[]-(), ()-[r]-() RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH ()-[]-(r), ()-[r]-() RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH (r)-[]-(t), (s)-[r]-(t) RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH (s)-[]-(r), (s)-[r]-(t) RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH (r), (a)-[q]-(b), (s), (s)-[r]-(t)-[]-(b) RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. -STATEMENT MATCH (r), (a)-[q]-(b), (s), (s)-[r]->(t)<-[]-(b) RETURN r; ---- error -Binder exception: r has data type NODE but (REL) was expected. +Binder exception: r has data type NODE but REL was expected. # Fail when a path has the same variable in the same pattern -CASE Scenario12 @@ -337,13 +337,13 @@ Binder exception: r has data type NODE but (REL) was expected. ---- ok -STATEMENT MATCH r = ()-[]-(), ()-[r]-() RETURN r; ---- error -Binder exception: r has data type RECURSIVE_REL but (REL) was expected. +Binder exception: r has data type RECURSIVE_REL but REL was expected. -STATEMENT MATCH r = ()-[]-(), ()-[r*1..30]-() RETURN r; ---- error Binder exception: Bind relationship r to relationship with same name is not supported. -STATEMENT MATCH r = (a)-[p]-(s)-[]-(b), (s)-[]-(t), (t), (t)-[r]-(b) RETURN r; ---- error -Binder exception: r has data type RECURSIVE_REL but (REL) was expected. +Binder exception: r has data type RECURSIVE_REL but REL was expected. -STATEMENT MATCH r = (a)-[p]-(s)-[]-(b), (s)-[]-(t), (t), (t)-[r*1..2]-(b) RETURN r; ---- error Binder exception: Bind relationship r to relationship with same name is not supported. @@ -355,7 +355,7 @@ Binder exception: Bind relationship r to relationship with same name is not supp Binder exception: Bind relationship r to relationship with same name is not supported. -STATEMENT MATCH (a)-[p]-(s)-[]-(b), r = (s)-[*1..2]-(t), (t), (t)-[r]-(b) RETURN r; ---- error -Binder exception: r has data type RECURSIVE_REL but (REL) was expected. +Binder exception: r has data type RECURSIVE_REL but REL was expected. -STATEMENT MATCH (a)-[p]-(s)-[]-(b), r = (s)-[*1..2]-(t), (t), (t)-[r*1..2]-(b) RETURN r; ---- error Binder exception: Bind relationship r to relationship with same name is not supported. @@ -368,22 +368,22 @@ Binder exception: Bind relationship r to relationship with same name is not supp ---- ok -STATEMENT WITH true AS r MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type BOOL but (REL) was expected. +Binder exception: r has data type BOOL but REL was expected. -STATEMENT WITH 123 AS r MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type INT64 but (REL) was expected. +Binder exception: r has data type INT64 but REL was expected. -STATEMENT WITH 123.4 AS r MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type DOUBLE but (REL) was expected. +Binder exception: r has data type DOUBLE but REL was expected. -STATEMENT WITH 'foo' AS r MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type STRING but (REL) was expected. +Binder exception: r has data type STRING but REL was expected. -STATEMENT WITH [10] AS r MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type LIST but (REL) was expected. +Binder exception: r has data type INT64[] but REL was expected. -STATEMENT WITH {x: 1} AS r MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type STRUCT but (REL) was expected. +Binder exception: r has data type STRUCT(x INT64) but REL was expected. -STATEMENT WITH {x: [1]} AS r MATCH ()-[r]-() RETURN r; ---- error -Binder exception: r has data type STRUCT but (REL) was expected. +Binder exception: r has data type STRUCT(x INT64[]) but REL was expected. diff --git a/test/test_files/tck/match/match4.test b/test/test_files/tck/match/match4.test index 9802b38c3c..4432a731de 100644 --- a/test/test_files/tck/match/match4.test +++ b/test/test_files/tck/match/match4.test @@ -160,7 +160,7 @@ Binder exception: Bind relationship r to relationship with same name is not supp MATCH (first)-[rs*]->(second) RETURN first, second; ---- error -Binder exception: rs has data type LIST but (RECURSIVE_REL) was expected. +Binder exception: rs has data type REL[] but RECURSIVE_REL was expected. # Fail when asterisk operator is missing # Fail on negative bound diff --git a/test/test_files/tinysnb/call/call.test b/test/test_files/tinysnb/call/call.test index 68525967d3..4c59449abd 100644 --- a/test/test_files/tinysnb/call/call.test +++ b/test/test_files/tinysnb/call/call.test @@ -83,9 +83,7 @@ False ---- ok -STATEMENT CALL var_length_extend_max_depth=10 ---- error -Can't execute a write query inside a read-only transaction. - --CASE CallFunctionTable +Can not execute a write query inside a read-only transaction. -LOG NodeTableInfo -STATEMENT CALL table_info('person') RETURN * @@ -162,6 +160,20 @@ height 2:2|STRUCT(locations STRING[], transfer STRUCT(day DATE, amount INT64[])) 2:2|UNION(firstmet DATE, type INT16, comment STRING) +-LOG StorageInfo +-STATEMENT MATCH (p:person) RETURN COUNT(p) +---- 1 +8 +-STATEMENT CALL storage_info('person') RETURN COUNT(*) +---- 1 +38 +-STATEMENT CALL storage_info('knows') RETURN COUNT(*) +---- 1 +80 +-STATEMENT CALL storage_info('workAt') RETURN COUNT(*) +---- 1 +22 + -CASE CallNodeTableWith300ColumnsInfo -DEFINE COLS REPEAT 2400 "col${count} INT64," @@ -210,19 +222,4 @@ Binder exception: Show connection can only bind to String! Binder exception: Show connection can only be called on a rel table! -STATEMENT MATCH (a:person) CALL show_connection(a.fName) RETURN * ---- error -Binder exception: Cannot evaluate a.fName as a literal. - --CASE StorageInfo --PARALLELISM 1 --STATEMENT MATCH (p:person) RETURN COUNT(p) ----- 1 -8 --STATEMENT CALL storage_info('person') RETURN COUNT(*) ----- 1 -38 --STATEMENT CALL storage_info('knows') RETURN COUNT(*) ----- 1 -80 --STATEMENT CALL storage_info('workAt') RETURN COUNT(*) ----- 1 -22 +Binder exception: a.fName has type PROPERTY but LITERAL was expected. diff --git a/test/test_files/tinysnb/function/start_end_node.test b/test/test_files/tinysnb/function/start_end_node.test index 95d3743f49..b457779d92 100644 --- a/test/test_files/tinysnb/function/start_end_node.test +++ b/test/test_files/tinysnb/function/start_end_node.test @@ -56,7 +56,7 @@ -LOG StartNodeTestRecursiveRel -STATEMENT MATCH (:person { fName: "Alice" })-[r:knows *1..2]->(friend:person) RETURN START_NODE(r) ---- error -Binder exception: r has data type RECURSIVE_REL but (REL) was expected. +Binder exception: r has data type RECURSIVE_REL but REL was expected. -CASE FunctionEndNode @@ -112,4 +112,4 @@ Binder exception: r has data type RECURSIVE_REL but (REL) was expected. -LOG EndNodeTestRecursiveRel -STATEMENT MATCH (:person { fName: "Alice" })-[r:knows *1..2]->(friend:person) RETURN END_NODE(r) ---- error -Binder exception: r has data type RECURSIVE_REL but (REL) was expected. +Binder exception: r has data type RECURSIVE_REL but REL was expected. diff --git a/test/test_files/transaction/create_macro/create_macro.test b/test/test_files/transaction/create_macro/create_macro.test index e0a2d2cf85..357b32536e 100644 --- a/test/test_files/transaction/create_macro/create_macro.test +++ b/test/test_files/transaction/create_macro/create_macro.test @@ -152,4 +152,4 @@ result|6|5.600000|00:20:00|[1,3,2] ---- ok -STATEMENT CREATE MACRO var_macro(x) AS x ---- error -Can't execute a write query inside a read-only transaction. +Can not execute a write query inside a read-only transaction. diff --git a/tools/python_api/test/test_df_pyarrow.py b/tools/python_api/test/test_df_pyarrow.py index 4feca49763..e5ae62600e 100644 --- a/tools/python_api/test/test_df_pyarrow.py +++ b/tools/python_api/test/test_df_pyarrow.py @@ -71,7 +71,7 @@ def pyarrow_test_helper(establish_connection, n, k): df = generate_primitive_df(n, names, schema).sort_values(by=['int32col', 'int64col', 'uint64col', 'floatcol']) patable = pa.Table.from_pandas(df).select(names) result = conn.execute( - 'CALL READ_PANDAS(df) RETURN boolcol, int32col, int64col, uint64col, floatcol ORDER BY int32col, int64col, uint64col, floatcol' + 'LOAD FROM df RETURN boolcol, int32col, int64col, uint64col, floatcol ORDER BY int32col, int64col, uint64col, floatcol' ).get_as_arrow(n) if (not tables_equal(patable, result)): print(patable) @@ -127,7 +127,7 @@ def test_pyarrow_time(conn_db_readonly : ConnDB) -> None: 'col10': arrowtopd(col10) #'col11': arrowtopd(col11) }) - result = conn.execute('CALL READ_PANDAS(df) RETURN *').get_as_df() + result = conn.execute('LOAD FROM df RETURN *').get_as_df() for colname in ['col1', 'col2', 'col3']: for expected, actual in zip(df[colname], result[colname]): tmp1 = expected if type(expected) is timedelta else expected.to_pytimedelta() @@ -166,7 +166,7 @@ def test_pyarrow_blob(conn_db_readonly : ConnDB) -> None: 'col3' : arrowtopd(col3), 'col4' : arrowtopd(col4) }).sort_values(by=['index']) - result = conn.execute('CALL READ_PANDAS(df) RETURN * ORDER BY index').get_as_df() + result = conn.execute('LOAD FROM df RETURN * ORDER BY index').get_as_df() for colname in ['col1', 'col2', 'col3', 'col4']: for expected, actual in zip(df[colname], result[colname]): if is_null(expected) or is_null(actual): @@ -203,7 +203,7 @@ def test_pyarrow_string(conn_db_readonly : ConnDB) -> None: 'col2' : arrowtopd(col2), 'col3' : arrowtopd(col3), }).sort_values(by=['index']) - result = conn.execute('CALL READ_PANDAS(df) RETURN * ORDER BY index').get_as_df() + result = conn.execute('LOAD FROM df RETURN * ORDER BY index').get_as_df() for colname in ['col1', 'col2', 'col3']: for expected, actual in zip(df[colname], result[colname]): if is_null(expected) or is_null(actual): @@ -228,7 +228,7 @@ def test_pyarrow_dict(conn_db_readonly : ConnDB) -> None: 'col1' : arrowtopd(col1), 'col2' : arrowtopd(col2) }) - result = conn.execute('CALL READ_PANDAS(df) RETURN * ORDER BY index').get_as_df() + result = conn.execute('LOAD FROM df RETURN * ORDER BY index').get_as_df() for colname in ['col1', 'col2']: for expected, actual in zip(df[colname], result[colname]): assert expected == actual @@ -248,7 +248,7 @@ def test_pyarrow_list(conn_db_readonly : ConnDB) -> None: 'col1': arrowtopd(col1), 'col2': arrowtopd(col2) }) - result = conn.execute('CALL READ_PANDAS(df) RETURN * ORDER BY index') + result = conn.execute('LOAD FROM df RETURN * ORDER BY index') idx = 0 while result.has_next(): assert idx < len(index) @@ -276,7 +276,7 @@ def test_pyarrow_struct(conn_db_readonly : ConnDB) -> None: 'index': arrowtopd(index), 'col1': arrowtopd(col1) }) - result = conn.execute('CALL READ_PANDAS(df) RETURN * ORDER BY index') + result = conn.execute('LOAD FROM df RETURN * ORDER BY index') idx = 0 while result.has_next(): assert idx < len(index) @@ -302,7 +302,7 @@ def test_pyarrow_union(conn_db_readonly : ConnDB) -> None: 'index': arrowtopd(index), 'col1': arrowtopd(col1) }) - result = conn.execute('CALL READ_PANDAS(df) RETURN * ORDER BY index') + result = conn.execute('LOAD FROM df RETURN * ORDER BY index') idx = 0 while result.has_next(): assert idx < len(index) @@ -328,7 +328,7 @@ def test_pyarrow_map(conn_db_readonly : ConnDB) -> None: df = pd.DataFrame({ 'index': arrowtopd(index), 'col1': arrowtopd(col1)}) - result = conn.execute('CALL READ_PANDAS(df) RETURN * ORDER BY index') + result = conn.execute('LOAD FROM df RETURN * ORDER BY index') idx = 0 while result.has_next(): assert idx < len(index) diff --git a/tools/python_api/test/test_scan_pandas.py b/tools/python_api/test/test_scan_pandas.py index 0ce2323212..93ab2231e5 100644 --- a/tools/python_api/test/test_scan_pandas.py +++ b/tools/python_api/test/test_scan_pandas.py @@ -192,10 +192,8 @@ def test_scan_pandas(tmp_path: Path) -> None: } df = pd.DataFrame(data) df["datetime_microseconds_tz"] = df["datetime_microseconds_tz"].dt.tz_localize("US/Eastern") - results = conn.execute("CALL READ_PANDAS(df) RETURN *") + results = conn.execute("LOAD FROM df RETURN *") validate_scan_pandas_results(results) - results2 = conn.execute("LOAD FROM df RETURN *") - validate_scan_pandas_results(results2) def test_scan_pandas_timestamp(tmp_path: Path) -> None: @@ -213,7 +211,7 @@ def test_scan_pandas_timestamp(tmp_path: Path) -> None: df = pd.DataFrame({"timestamp": ts}) # Pandas automatically converts the column from object to timestamp, so we need to manually cast back to object. df = df.astype({"timestamp": "object"}, copy=False) - results = conn.execute("CALL READ_PANDAS(df) RETURN *") + results = conn.execute("LOAD FROM df RETURN *") assert results.get_next() == [datetime.datetime(1996, 2, 15, hour=12, minute=22, second=54)] assert results.get_next() == [datetime.datetime(2011, 3, 11, minute=11, hour=5)] assert results.get_next() == [None] @@ -262,7 +260,7 @@ def test_scan_pandas_with_filter(tmp_path: Path) -> None: df = pd.DataFrame(data) # Dummy query to ensure the READ_PANDAS function is persistent after a write transaction. conn.execute("CREATE NODE TABLE PERSON1(ID INT64, PRIMARY KEY(ID))") - results = conn.execute("CALL READ_PANDAS(df) WHERE id > 20 RETURN id + 5, weight, name") + results = conn.execute("LOAD FROM df WHERE id > 20 RETURN id + 5, weight, name") assert results.get_next() == [27, 23.2, "ñ"] assert results.get_next() == [105, 42.9, "😊"] @@ -277,7 +275,7 @@ def test_large_pd(tmp_path: Path) -> None: "odd": np.array(odd_numbers, dtype=np.int64), "even": np.array(even_numbers, dtype=np.int64), }) - result = conn.execute("CALL READ_PANDAS(df) RETURN *").get_as_df() + result = conn.execute("LOAD FROM df RETURN *").get_as_df() assert result["odd"].to_list() == odd_numbers assert result["even"].to_list() == even_numbers @@ -299,7 +297,7 @@ def test_pandas_scan_demo(tmp_path: Path) -> None: person = pd.DataFrame({"id": id, "age": age, "height": height_in_cm, "is_student": is_student}) result = conn.execute( - "CALL READ_PANDAS(person) with avg(height / 2.54) as height_in_inch MATCH (s:student) WHERE s.height > " + "LOAD FROM person with avg(height / 2.54) as height_in_inch MATCH (s:student) WHERE s.height > " "height_in_inch RETURN s" ).get_as_df() assert len(result) == 2 @@ -308,7 +306,7 @@ def test_pandas_scan_demo(tmp_path: Path) -> None: conn.execute("CREATE NODE TABLE person(ID INT64, age UINT16, height UINT32, is_student BOOLean, PRIMARY KEY(ID))") conn.execute( - "CALL READ_PANDAS(person) CREATE (p:person {ID: id, age: age, height: height, is_student: is_student})" + "LOAD FROM person CREATE (p:person {ID: id, age: age, height: height, is_student: is_student})" ) result = conn.execute("MATCH (p:person) return p.*").get_as_df() assert np.all(result["p.ID"].to_list() == id) @@ -334,7 +332,7 @@ def test_scan_all_null(tmp_path: Path) -> None: conn = kuzu.Connection(db) data = {"id": np.array([None, None, None], dtype=object)} df = pd.DataFrame(data) - result = conn.execute("CALL READ_PANDAS(df) RETURN *") + result = conn.execute("LOAD FROM df RETURN *") assert result.get_next() == [None] assert result.get_next() == [None] assert result.get_next() == [None]