diff --git a/.github/workflows/Linux.yml b/.github/workflows/Linux.yml index 25393dee..82444adf 100644 --- a/.github/workflows/Linux.yml +++ b/.github/workflows/Linux.yml @@ -15,7 +15,7 @@ jobs: strategy: matrix: # Add commits/tags to build against other DuckDB versions - duckdb_version: [ 'v0.8.1' ] + duckdb_version: [ 'lattest' ] arch: ['linux_amd64', 'linux_arm64', 'linux_amd64_gcc4'] include: - arch: 'linux_amd64' diff --git a/.github/workflows/MacOS.yml b/.github/workflows/MacOS.yml index b610fb91..b652bb6e 100644 --- a/.github/workflows/MacOS.yml +++ b/.github/workflows/MacOS.yml @@ -14,7 +14,7 @@ jobs: strategy: matrix: # Add commits/tags to build against other DuckDB versions - duckdb_version: [ 'v0.8.1' ] + duckdb_version: [ 'latest' ] env: OSX_BUILD_UNIVERSAL: 1 @@ -39,7 +39,7 @@ jobs: cd duckdb-pgq git checkout ${{ matrix.duckdb_version }} - # Build extension + # Build extension - name: Build extension shell: bash run: | diff --git a/.github/workflows/Windows.yml b/.github/workflows/Windows.yml index a0c17956..3fecc14a 100644 --- a/.github/workflows/Windows.yml +++ b/.github/workflows/Windows.yml @@ -14,7 +14,7 @@ jobs: strategy: matrix: # Add commits/tags to build against other DuckDB versions - duckdb_version: [ 'v0.8.1' ] + duckdb_version: [ 'latest' ] steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/_extension_deploy.yml b/.github/workflows/_extension_deploy.yml index 53493dc1..686de0b1 100644 --- a/.github/workflows/_extension_deploy.yml +++ b/.github/workflows/_extension_deploy.yml @@ -47,7 +47,7 @@ on: matrix_parse_script: required: false type: string - default: "./duckdb/scripts/modify_distribution_matrix.py" + default: "./duckdb-pgq/scripts/modify_distribution_matrix.py" jobs: generate_matrix: @@ -63,13 +63,13 @@ jobs: - name: Checkout DuckDB to version run: | - cd duckdb + cd duckdb-pgq git checkout ${{ inputs.duckdb_version }} - id: parse-matrices run: | - cat ./duckdb/.github/config/distribution_matrix.json > distribution_matrix.json - grep wasm distribution_matrix.json || (head -n -1 ./duckdb/.github/config/distribution_matrix.json > distribution_matrix.json && echo ',"wasm":{"include":[{"duckdb_arch":"wasm_mvp","vcpkg_triplet":"wasm32-emscripten"},{"duckdb_arch":"wasm_eh","vcpkg_triplet":"wasm32-emscripten"},{"duckdb_arch":"wasm_threads","vcpkg_triplet":"wasm32-emscripten"}]}}' >> distribution_matrix.json) + cat ./duckdb-pgq/.github/config/distribution_matrix.json > distribution_matrix.json + grep wasm distribution_matrix.json || (head -n -1 ./duckdb-pgq/.github/config/distribution_matrix.json > distribution_matrix.json && echo ',"wasm":{"include":[{"duckdb_arch":"wasm_mvp","vcpkg_triplet":"wasm32-emscripten"},{"duckdb_arch":"wasm_eh","vcpkg_triplet":"wasm32-emscripten"},{"duckdb_arch":"wasm_threads","vcpkg_triplet":"wasm32-emscripten"}]}}' >> distribution_matrix.json) python3 ${{ inputs.matrix_parse_script }} --input distribution_matrix.json --deploy_matrix --output deploy_matrix.json --exclude "${{ inputs.exclude_archs }}" --pretty deploy_matrix="`cat deploy_matrix.json`" echo deploy_matrix=$deploy_matrix >> $GITHUB_OUTPUT @@ -91,7 +91,7 @@ jobs: - name: Checkout DuckDB to version run: | - cd duckdb + cd duckdb-pgq git checkout ${{ inputs.duckdb_version }} - uses: actions/download-artifact@v2 @@ -112,7 +112,7 @@ jobs: pwd python3 -m pip install pip awscli git config --global --add safe.directory '*' - cd duckdb + cd duckdb-pgq git fetch --tags export DUCKDB_VERSION=`git tag --points-at HEAD` export DUCKDB_VERSION=${DUCKDB_VERSION:=`git log -1 --format=%h`} diff --git a/.gitmodules b/.gitmodules index 7e217514..2eae8b8d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,3 +2,7 @@ path = duckdb-pgq url = git@github.com:cwida/duckdb-pgq.git branch = master +[submodule "duckdb"] + path = duckdb + url = git@github.com:duckdb/duckdb.git + branch = main diff --git a/CMakeLists.txt b/CMakeLists.txt index 48cc12d4..97e93588 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,28 +1,25 @@ cmake_minimum_required(VERSION 2.8.12) -# Set extension name here -#<<<<<<< HEAD -#set(TARGET_NAME duckpgq) +# Set extension name here <<<<<<< HEAD set(TARGET_NAME duckpgq) # -#set(EXTENSION_NAME ${TARGET_NAME}_extension) -#project(${TARGET_NAME}) -#set(CMAKE_CXX_STANDARD 11) +# set(EXTENSION_NAME ${TARGET_NAME}_extension) project(${TARGET_NAME}) +# set(CMAKE_CXX_STANDARD 11) # -#include_directories(duckpgq/include) -#add_subdirectory(duckpgq/src) +# include_directories(duckpgq/include) add_subdirectory(duckpgq/src) # -#include_directories(../duckdb-pgq/third_party/libpg_query/include) +# include_directories(../duckdb-pgq/third_party/libpg_query/include) # -#add_library(${EXTENSION_NAME} STATIC ${EXTENSION_SOURCES}) +# add_library(${EXTENSION_NAME} STATIC ${EXTENSION_SOURCES}) # -#set(PARAMETERS "-warnings") -#build_loadable_extension(${TARGET_NAME} ${PARAMETERS} ${EXTENSION_SOURCES}) -#======= +# set(PARAMETERS "-warnings") build_loadable_extension(${TARGET_NAME} +# ${PARAMETERS} ${EXTENSION_SOURCES}) +# ======= set(TARGET_NAME duckpgq) set(CMAKE_CXX_STANDARD 11) -# DuckDB's extension distribution supports vcpkg. As such, dependencies can be added in ./vcpkg.json and then -# used in cmake with find_package. Feel free to remove or replace with other dependencies. -# Note that it should also be removed from vcpkg.json to prevent needlessly installing it.. +# DuckDB's extension distribution supports vcpkg. As such, dependencies can be +# added in ./vcpkg.json and then used in cmake with find_package. Feel free to +# remove or replace with other dependencies. Note that it should also be removed +# from vcpkg.json to prevent needlessly installing it.. find_package(OpenSSL REQUIRED) set(EXTENSION_NAME ${TARGET_NAME}_extension) @@ -33,7 +30,7 @@ include_directories(duckpgq/include) add_subdirectory(duckpgq/src) include_directories(../duckdb-pgq/third_party/libpg_query/include) -#set(EXTENSION_SOURCES duckpgq/src/duckpgq_extension.cpp) +# set(EXTENSION_SOURCES duckpgq/src/duckpgq_extension.cpp) build_static_extension(${TARGET_NAME} ${EXTENSION_SOURCES}) build_loadable_extension(${TARGET_NAME} " " ${EXTENSION_SOURCES}) @@ -41,7 +38,7 @@ build_loadable_extension(${TARGET_NAME} " " ${EXTENSION_SOURCES}) # Link OpenSSL in both the static library as the loadable extension target_link_libraries(${EXTENSION_NAME} OpenSSL::SSL OpenSSL::Crypto) target_link_libraries(${LOADABLE_EXTENSION_NAME} OpenSSL::SSL OpenSSL::Crypto) -#>>>>>>> template/main +# >>>>>>> template/main install( TARGETS ${EXTENSION_NAME} diff --git a/Makefile b/Makefile index 98f1215a..8531f624 100644 --- a/Makefile +++ b/Makefile @@ -98,7 +98,7 @@ test_release_python: release_python #### Misc format: - find src/ -iname *.hpp -o -iname *.cpp | xargs clang-format --sort-includes=0 -style=file -i + find duckpgq/ -iname *.hpp -o -iname *.cpp | xargs clang-format --sort-includes=0 -style=file -i cmake-format -i CMakeLists.txt update: git submodule update --remote --merge diff --git a/duckdb-pgq b/duckdb-pgq index f484fe08..bdbc6067 160000 --- a/duckdb-pgq +++ b/duckdb-pgq @@ -1 +1 @@ -Subproject commit f484fe0899e67fc29b6aec7ef1734925dca7ef45 +Subproject commit bdbc6067198d19bf8d1455d1fb6aa534d0d2785e diff --git a/duckpgq/include/duckpgq/functions/tablefunctions/match.hpp b/duckpgq/include/duckpgq/functions/tablefunctions/match.hpp index 3576bc00..4144d22a 100644 --- a/duckpgq/include/duckpgq/functions/tablefunctions/match.hpp +++ b/duckpgq/include/duckpgq/functions/tablefunctions/match.hpp @@ -7,6 +7,8 @@ //===----------------------------------------------------------------------===// #pragma once +#include + #include "duckdb/function/table_function.hpp" #include "duckdb/parser/parsed_data/create_property_graph_info.hpp" #include "duckdb/parser/path_element.hpp" @@ -14,21 +16,22 @@ #include "duckdb/parser/path_pattern.hpp" namespace duckdb { - struct PGQMatchFunction : public TableFunction { public: - PGQMatchFunction() { + PGQMatchFunction() { name = "duckpgq_match"; bind_replace = MatchBindReplace; } + struct MatchBindData : public TableFunctionData { bool done = false; }; static shared_ptr FindGraphTable(const string &label, CreatePropertyGraphInfo &pg_table); + static void - CheckInheritance(shared_ptr &tableref, + CheckInheritance(const shared_ptr &tableref, PathElement *element, vector> &conditions); @@ -42,8 +45,7 @@ struct PGQMatchFunction : public TableFunction { const string &vertex_alias, const string &edge_alias); static PathElement * - GetPathElement(unique_ptr &path_reference, - vector> &conditions); + GetPathElement(const unique_ptr &path_reference); static unique_ptr GetCountTable(const shared_ptr &edge_table, @@ -61,13 +63,13 @@ struct PGQMatchFunction : public TableFunction { const string &edge_binding, const string &prev_binding, const string &next_binding); - static void EdgeTypeAny(shared_ptr &edge_table, + static void EdgeTypeAny(const shared_ptr &edge_table, const string &edge_binding, const string &prev_binding, const string &next_binding, vector> &conditions); - static void EdgeTypeLeft(shared_ptr &edge_table, + static void EdgeTypeLeft(const shared_ptr &edge_table, const string &next_table_name, const string &prev_table_name, const string &edge_binding, @@ -75,7 +77,7 @@ struct PGQMatchFunction : public TableFunction { const string &next_binding, vector> &conditions); - static void EdgeTypeRight(shared_ptr &edge_table, + static void EdgeTypeRight(const shared_ptr &edge_table, const string &next_table_name, const string &prev_table_name, const string &edge_binding, @@ -83,11 +85,13 @@ struct PGQMatchFunction : public TableFunction { const string &next_binding, vector> &conditions); - static void EdgeTypeLeftRight( - shared_ptr &edge_table, const string &edge_binding, - const string &prev_binding, const string &next_binding, - vector> &conditions, - unordered_map &alias_map, int32_t &extra_alias_counter); + static void + EdgeTypeLeftRight(const shared_ptr &edge_table, + const string &edge_binding, const string &prev_binding, + const string &next_binding, + vector> &conditions, + unordered_map &alias_map, + int32_t &extra_alias_counter); static PathElement * HandleNestedSubPath(unique_ptr &path_reference, @@ -102,10 +106,41 @@ struct PGQMatchFunction : public TableFunction { vector> &column_list, unordered_set &named_subpaths); - static unique_ptr - CreatePathFindingFunction(const string &prev_binding, - const string &next_binding, - shared_ptr &edge_table, - const string &path_finding_udf); + static unique_ptr + CreatePathFindingFunction(vector> &path_list, + CreatePropertyGraphInfo &pg_table); + + static void AddPathFinding(const unique_ptr &select_node, + unique_ptr &from_clause, + vector> &conditions, + const string &prev_binding, + const string &edge_binding, + const string &next_binding, + const shared_ptr &edge_table, + const SubPath *subpath); + + static void + AddEdgeJoins(const unique_ptr &select_node, + const shared_ptr &edge_table, + const shared_ptr &previous_vertex_table, + const shared_ptr &next_vertex_table, + PGQMatchType edge_type, const string &edge_binding, + const string &prev_binding, const string &next_binding, + vector> &conditions, + unordered_map &alias_map, + int32_t &extra_alias_counter); + + static void ProcessPathList( + vector> &path_pattern, + vector> &conditions, + unique_ptr &from_clause, unique_ptr &select_node, + unordered_map &alias_map, + CreatePropertyGraphInfo &pg_table, int32_t &extra_alias_counter, + vector> &column_list); + + static void + CheckNamedSubpath(SubPath &subpath, + vector> &column_list, + CreatePropertyGraphInfo &pg_table); }; -} // namespace duckdb \ No newline at end of file +} // namespace duckdb diff --git a/duckpgq/include/duckpgq/functions/tablefunctions/pgq_scan.hpp b/duckpgq/include/duckpgq/functions/tablefunctions/pgq_scan.hpp index d9f466ff..89f2a2ee 100644 --- a/duckpgq/include/duckpgq/functions/tablefunctions/pgq_scan.hpp +++ b/duckpgq/include/duckpgq/functions/tablefunctions/pgq_scan.hpp @@ -33,13 +33,13 @@ struct CSRScanPtrData : public TableFunctionData { public: static unique_ptr ScanCSRPtrBind(ClientContext &context, TableFunctionBindInput &input, - vector &return_types, vector &names) { + vector &return_types, vector &names) { auto result = make_uniq(); result->csr_id = input.inputs[0].GetValue(); return_types.emplace_back(LogicalType::UBIGINT); names.emplace_back("ptr"); return std::move(result); - } + } public: int32_t csr_id; diff --git a/duckpgq/src/duckpgq/functions/tablefunctions/create_property_graph.cpp b/duckpgq/src/duckpgq/functions/tablefunctions/create_property_graph.cpp index 6c219f19..f84fc1af 100644 --- a/duckpgq/src/duckpgq/functions/tablefunctions/create_property_graph.cpp +++ b/duckpgq/src/duckpgq/functions/tablefunctions/create_property_graph.cpp @@ -94,9 +94,9 @@ CreatePropertyGraphFunction::CreatePropertyGraphBind( CheckPropertyGraphTableLabels(vertex_table, table); v_table_names.insert(vertex_table->table_name); - if (vertex_table->hasTableNameAlias()) { - v_table_names.insert(vertex_table->table_name_alias); - } + if (vertex_table->hasTableNameAlias()) { + v_table_names.insert(vertex_table->table_name_alias); + } } for (auto &edge_table : info->edge_tables) { diff --git a/duckpgq/src/duckpgq/functions/tablefunctions/match.cpp b/duckpgq/src/duckpgq/functions/tablefunctions/match.cpp index 49494c6c..61fcec74 100644 --- a/duckpgq/src/duckpgq/functions/tablefunctions/match.cpp +++ b/duckpgq/src/duckpgq/functions/tablefunctions/match.cpp @@ -3,14 +3,12 @@ #include "duckdb/parser/tableref/matchref.hpp" #include "duckdb/parser/tableref/subqueryref.hpp" -#include "duckdb/parser/tableref/table_function_ref.hpp" #include "duckdb/parser/tableref/joinref.hpp" #include "duckdb/parser/tableref/basetableref.hpp" #include "duckdb/parser/expression/function_expression.hpp" #include "duckdb/parser/expression/subquery_expression.hpp" #include "duckdb/parser/expression/cast_expression.hpp" -#include "duckdb/parser/expression/operator_expression.hpp" #include "duckdb/parser/expression/between_expression.hpp" #include "duckdb/parser/expression/constant_expression.hpp" #include "duckdb/parser/expression/comparison_expression.hpp" @@ -24,13 +22,13 @@ #include "duckdb/parser/property_graph_table.hpp" #include "duckdb/parser/subpath_element.hpp" +#include namespace duckdb { - shared_ptr PGQMatchFunction::FindGraphTable(const string &label, - CreatePropertyGraphInfo &pg_table) { - auto graph_table_entry = pg_table.label_map.find(label); + CreatePropertyGraphInfo &pg_table) { + const auto graph_table_entry = pg_table.label_map.find(label); if (graph_table_entry == pg_table.label_map.end()) { throw BinderException("The label %s is not registered in property graph %s", label, pg_table.property_graph_name); @@ -40,19 +38,19 @@ PGQMatchFunction::FindGraphTable(const string &label, } void PGQMatchFunction::CheckInheritance( - shared_ptr &tableref, PathElement *element, + const shared_ptr &tableref, PathElement *element, vector> &conditions) { if (tableref->main_label == element->label) { return; } auto constant_expression_two = make_uniq(Value::INTEGER((int32_t)2)); - auto itr = std::find(tableref->sub_labels.begin(), tableref->sub_labels.end(), - element->label); + const auto itr = std::find(tableref->sub_labels.begin(), + tableref->sub_labels.end(), element->label); - auto idx_of_element = std::distance(tableref->sub_labels.begin(), itr); - auto constant_expression_idx_label = - make_uniq(Value::INTEGER((int32_t)idx_of_element)); + const auto idx_of_element = std::distance(tableref->sub_labels.begin(), itr); + auto constant_expression_idx_label = make_uniq( + Value::INTEGER(static_cast(idx_of_element))); vector> power_of_children; power_of_children.push_back(std::move(constant_expression_two)); @@ -71,7 +69,7 @@ void PGQMatchFunction::CheckInheritance( make_uniq("&", std::move(and_children)); auto constant_expression_idx_label_comparison = make_uniq( - Value::INTEGER((int32_t)idx_of_element + 1)); + Value::INTEGER(static_cast(idx_of_element + 1))); auto subset_compare = make_uniq( ExpressionType::COMPARE_EQUAL, std::move(and_expression), @@ -126,33 +124,20 @@ unique_ptr PGQMatchFunction::CreateMatchJoinExpression( } PathElement *PGQMatchFunction::GetPathElement( - unique_ptr &path_reference, - vector> &conditions) { + const unique_ptr &path_reference) { if (path_reference->path_reference_type == PGQPathReferenceType::PATH_ELEMENT) { return reinterpret_cast(path_reference.get()); - } else if (path_reference->path_reference_type == - PGQPathReferenceType::SUBPATH) { - auto subpath = reinterpret_cast(path_reference.get()); - - if (subpath->where_clause) { - conditions.push_back(std::move(subpath->where_clause)); - } - // If the subpath has only one element (the case when there is a WHERE in - // the element) we unpack the subpath into a PathElement. - if (subpath->path_list.size() == 1) { - return reinterpret_cast(subpath->path_list[0].get()); - } else { - return nullptr; - } - } else { - throw InternalException("Unknown path reference type detected"); } + if (path_reference->path_reference_type == PGQPathReferenceType::SUBPATH) { + return nullptr; + } + throw InternalException("Unknown path reference type detected"); } -unique_ptr -PGQMatchFunction::GetCountTable(const shared_ptr &edge_table, - const string &prev_binding) { +unique_ptr PGQMatchFunction::GetCountTable( + const shared_ptr &edge_table, + const string &prev_binding) { // SELECT count(s.id) FROM src s auto select_count = make_uniq(); auto select_inner = make_uniq(); @@ -177,9 +162,9 @@ PGQMatchFunction::GetCountTable(const shared_ptr &edge_table unique_ptr PGQMatchFunction::GetJoinRef(const shared_ptr &edge_table, - const string &edge_binding, - const string &prev_binding, - const string &next_binding) { + const string &edge_binding, + const string &prev_binding, + const string &next_binding) { auto first_join_ref = make_uniq(JoinRefType::REGULAR); first_join_ref->type = JoinType::INNER; @@ -253,11 +238,10 @@ unique_ptr PGQMatchFunction::CreateCountCTESubquery() { unique_ptr PGQMatchFunction::CreateCSRCTE(const shared_ptr &edge_table, - const string &edge_binding, - const string &prev_binding, - const string &next_binding) { - auto csr_edge_id_constant = - make_uniq(Value::INTEGER((int32_t)0)); + const string &prev_binding, + const string &edge_binding, + const string &next_binding) { + auto csr_edge_id_constant = make_uniq(Value::INTEGER(0)); auto count_create_edge_select = GetCountTable(edge_table, prev_binding); auto cast_subquery_expr = make_uniq(); @@ -265,7 +249,7 @@ PGQMatchFunction::CreateCSRCTE(const shared_ptr &edge_table, vector> csr_vertex_children; csr_vertex_children.push_back( - make_uniq(Value::INTEGER((int32_t)0))); + make_uniq(Value::INTEGER(0))); auto count_create_vertex_expr = GetCountTable(edge_table, prev_binding); @@ -376,17 +360,17 @@ PGQMatchFunction::CreateCSRCTE(const shared_ptr &edge_table, } void PGQMatchFunction::EdgeTypeAny( - shared_ptr &edge_table, const string &edge_binding, - const string &prev_binding, const string &next_binding, + const shared_ptr &edge_table, + const string &edge_binding, const string &prev_binding, + const string &next_binding, vector> &conditions) { // (a) src.key = edge.src auto src_left_expr = CreateMatchJoinExpression( - edge_table->source_pk, edge_table->source_fk, - prev_binding, edge_binding); + edge_table->source_pk, edge_table->source_fk, prev_binding, edge_binding); // (b) dst.key = edge.dst - auto dst_left_expr = CreateMatchJoinExpression( - edge_table->destination_pk,edge_table->destination_fk, - next_binding, edge_binding); + auto dst_left_expr = CreateMatchJoinExpression(edge_table->destination_pk, + edge_table->destination_fk, + next_binding, edge_binding); // (a) AND (b) auto combined_left_expr = make_uniq( ExpressionType::CONJUNCTION_AND, std::move(src_left_expr), @@ -411,9 +395,10 @@ void PGQMatchFunction::EdgeTypeAny( } void PGQMatchFunction::EdgeTypeLeft( - shared_ptr &edge_table, const string &next_table_name, - const string &prev_table_name, const string &edge_binding, - const string &prev_binding, const string &next_binding, + const shared_ptr &edge_table, + const string &next_table_name, const string &prev_table_name, + const string &edge_binding, const string &prev_binding, + const string &next_binding, vector> &conditions) { CheckEdgeTableConstraints(next_table_name, prev_table_name, edge_table); conditions.push_back(CreateMatchJoinExpression(edge_table->source_pk, @@ -425,9 +410,10 @@ void PGQMatchFunction::EdgeTypeLeft( } void PGQMatchFunction::EdgeTypeRight( - shared_ptr &edge_table, const string &next_table_name, - const string &prev_table_name, const string &edge_binding, - const string &prev_binding, const string &next_binding, + const shared_ptr &edge_table, + const string &next_table_name, const string &prev_table_name, + const string &edge_binding, const string &prev_binding, + const string &next_binding, vector> &conditions) { CheckEdgeTableConstraints(prev_table_name, next_table_name, edge_table); conditions.push_back(CreateMatchJoinExpression(edge_table->source_pk, @@ -439,8 +425,9 @@ void PGQMatchFunction::EdgeTypeRight( } void PGQMatchFunction::EdgeTypeLeftRight( - shared_ptr &edge_table, const string &edge_binding, - const string &prev_binding, const string &next_binding, + const shared_ptr &edge_table, + const string &edge_binding, const string &prev_binding, + const string &next_binding, vector> &conditions, unordered_map &alias_map, int32_t &extra_alias_counter) { auto src_left_expr = CreateMatchJoinExpression( @@ -453,7 +440,7 @@ void PGQMatchFunction::EdgeTypeLeftRight( ExpressionType::CONJUNCTION_AND, std::move(src_left_expr), std::move(dst_left_expr)); - auto additional_edge_alias = + const auto additional_edge_alias = edge_binding + std::to_string(extra_alias_counter); extra_alias_counter++; @@ -479,7 +466,7 @@ PathElement *PGQMatchFunction::HandleNestedSubPath( unique_ptr &path_reference, vector> &conditions, idx_t element_idx) { auto subpath = reinterpret_cast(path_reference.get()); - return GetPathElement(subpath->path_list[element_idx], conditions); + return GetPathElement(subpath->path_list[element_idx]); } unique_ptr @@ -497,13 +484,183 @@ CreateWhereClause(vector> &conditions) { return where_clause; } -unique_ptr PGQMatchFunction::CreatePathFindingFunction( +unique_ptr PGQMatchFunction::CreatePathFindingFunction( + vector> &path_list, + CreatePropertyGraphInfo &pg_table) { + // This method will return a SubqueryRef of a list of rowids + // For every vertex and edge element, we add the rowid to the list using + // list_append, or list_prepend The difficulty is that there may be a + // (un)bounded path pattern at some point in the query This is computed using + // the shortestpath() UDF and returns a list. This list will be part of the + // full list of element rowids, using list_concat. For now we will only + // support returning rowids + unique_ptr final_list; + + auto previous_vertex_element = GetPathElement(path_list[0]); + if (!previous_vertex_element) { + // We hit a vertex element with a WHERE, but we only care about the rowid + // here + auto previous_vertex_subpath = + reinterpret_cast(path_list[0].get()); + previous_vertex_element = + GetPathElement(previous_vertex_subpath->path_list[0]); + } + + for (idx_t idx_i = 1; idx_i < path_list.size(); idx_i = idx_i + 2) { + auto next_vertex_element = GetPathElement(path_list[idx_i + 1]); + if (!next_vertex_element) { + auto next_vertex_subpath = + reinterpret_cast(path_list[idx_i + 1].get()); + next_vertex_element = GetPathElement(next_vertex_subpath->path_list[0]); + } + + auto edge_element = GetPathElement(path_list[idx_i]); + if (!edge_element) { + auto edge_subpath = reinterpret_cast(path_list[idx_i].get()); + if (edge_subpath->upper > 1) { + // (un)bounded shortest path + // Add the shortest path UDF + edge_element = GetPathElement(edge_subpath->path_list[0]); + auto edge_table = FindGraphTable(edge_element->label, pg_table); + auto src_row_id = make_uniq( + "rowid", previous_vertex_element->variable_binding); + auto dst_row_id = make_uniq( + "rowid", next_vertex_element->variable_binding); + auto csr_id = make_uniq(Value::INTEGER(0)); + + vector> pathfinding_children; + pathfinding_children.push_back(std::move(csr_id)); + pathfinding_children.push_back(std::move(GetCountTable( + edge_table, previous_vertex_element->variable_binding))); + pathfinding_children.push_back(std::move(src_row_id)); + pathfinding_children.push_back(std::move(dst_row_id)); + + auto shortest_path_function = make_uniq( + "shortestpath", std::move(pathfinding_children)); + + if (!final_list) { + final_list = std::move(shortest_path_function); + } else { + auto pop_front_shortest_path_children = + vector>(); + pop_front_shortest_path_children.push_back( + std::move(shortest_path_function)); + auto pop_front = make_uniq( + "array_pop_front", std::move(pop_front_shortest_path_children)); + + auto final_list_children = vector>(); + final_list_children.push_back(std::move(final_list)); + final_list_children.push_back(std::move(pop_front)); + final_list = make_uniq( + "list_concat", std::move(final_list_children)); + } + // Set next vertex to be previous + previous_vertex_element = next_vertex_element; + continue; + } + edge_element = GetPathElement(edge_subpath->path_list[0]); + } + auto previous_rowid = make_uniq( + "rowid", previous_vertex_element->variable_binding); + auto edge_rowid = + make_uniq("rowid", edge_element->variable_binding); + auto next_rowid = make_uniq( + "rowid", next_vertex_element->variable_binding); + auto starting_list_children = vector>(); + + if (!final_list) { + starting_list_children.push_back(std::move(previous_rowid)); + starting_list_children.push_back(std::move(edge_rowid)); + starting_list_children.push_back(std::move(next_rowid)); + final_list = make_uniq( + "list_value", std::move(starting_list_children)); + } else { + starting_list_children.push_back(std::move(edge_rowid)); + starting_list_children.push_back(std::move(next_rowid)); + auto next_elements_list = make_uniq( + "list_value", std::move(starting_list_children)); + auto final_list_children = vector>(); + final_list_children.push_back(std::move(final_list)); + final_list_children.push_back(std::move(next_elements_list)); + final_list = make_uniq( + "list_concat", std::move(final_list_children)); + } + previous_vertex_element = next_vertex_element; + } + + return final_list; +} + +void PGQMatchFunction::AddEdgeJoins( + const unique_ptr &select_node, + const shared_ptr &edge_table, + const shared_ptr &previous_vertex_table, + const shared_ptr &next_vertex_table, + PGQMatchType edge_type, const string &edge_binding, const string &prev_binding, const string &next_binding, - shared_ptr &edge_table, - const string &path_finding_udf) { + vector> &conditions, + unordered_map &alias_map, int32_t &extra_alias_counter) { + switch (edge_type) { + case PGQMatchType::MATCH_EDGE_ANY: { + select_node->modifiers.push_back(make_uniq()); + EdgeTypeAny(edge_table, edge_binding, prev_binding, next_binding, + conditions); + break; + } + case PGQMatchType::MATCH_EDGE_LEFT: + EdgeTypeLeft(edge_table, next_vertex_table->table_name, + previous_vertex_table->table_name, edge_binding, prev_binding, + next_binding, conditions); + break; + case PGQMatchType::MATCH_EDGE_RIGHT: + EdgeTypeRight(edge_table, next_vertex_table->table_name, + previous_vertex_table->table_name, edge_binding, prev_binding, + next_binding, conditions); + break; + case PGQMatchType::MATCH_EDGE_LEFT_RIGHT: { + EdgeTypeLeftRight(edge_table, edge_binding, prev_binding, next_binding, + conditions, alias_map, extra_alias_counter); + break; + } + default: + throw InternalException("Unknown match type found"); + } +} + +void PGQMatchFunction::AddPathFinding( + const unique_ptr &select_node, + unique_ptr &from_clause, + vector> &conditions, + const string &prev_binding, const string &edge_binding, + const string &next_binding, + const shared_ptr &edge_table, const SubPath *subpath) { + //! START + //! FROM (SELECT count(cte1.temp) * 0 as temp from cte1) __x + select_node->cte_map.map["cte1"] = + CreateCSRCTE(edge_table, prev_binding, edge_binding, next_binding); + + auto temp_cte_select_subquery = CreateCountCTESubquery(); + + if (from_clause) { + // create a cross join since there is already something in the + // from clause + auto from_join = make_uniq(JoinRefType::CROSS); + from_join->left = std::move(from_clause); + from_join->right = std::move(temp_cte_select_subquery); + from_clause = std::move(from_join); + } else { + from_clause = std::move(temp_cte_select_subquery); + } + //! END + //! FROM (SELECT count(cte1.temp) * 0 as temp from cte1) __x + + //! START + //! WHERE __x.temp + iterativelength(, (SELECT count(c.id) + //! from dst c, a.rowid, b.rowid) between lower and upper + auto src_row_id = make_uniq("rowid", prev_binding); auto dst_row_id = make_uniq("rowid", next_binding); - auto csr_id = make_uniq(Value::INTEGER((int32_t)0)); + auto csr_id = make_uniq(Value::INTEGER(0)); vector> pathfinding_children; pathfinding_children.push_back(std::move(csr_id)); @@ -512,254 +669,279 @@ unique_ptr PGQMatchFunction::CreatePathFindingFunction( pathfinding_children.push_back(std::move(src_row_id)); pathfinding_children.push_back(std::move(dst_row_id)); - return make_uniq(path_finding_udf, - std::move(pathfinding_children)); + auto reachability_function = make_uniq( + "iterativelength", std::move(pathfinding_children)); + + auto cte_col_ref = make_uniq("temp", "__x"); + + vector> addition_children; + addition_children.push_back(std::move(cte_col_ref)); + addition_children.push_back(std::move(reachability_function)); + + auto addition_function = + make_uniq("add", std::move(addition_children)); + auto lower_limit = make_uniq( + Value::INTEGER(static_cast(subpath->lower))); + auto upper_limit = make_uniq( + Value::INTEGER(static_cast(subpath->upper))); + auto between_expression = make_uniq( + std::move(addition_function), std::move(lower_limit), + std::move(upper_limit)); + conditions.push_back(std::move(between_expression)); + + //! END + //! WHERE __x.temp + iterativelength(, (SELECT count(s.id) + //! from src s, a.rowid, b.rowid) between lower and upper } -unique_ptr PGQMatchFunction::MatchBindReplace(ClientContext &context, - TableFunctionBindInput &) { - auto data = make_uniq(); +void PGQMatchFunction::CheckNamedSubpath( + SubPath &subpath, vector> &column_list, + CreatePropertyGraphInfo &pg_table) { + for (idx_t idx_i = 0; idx_i < column_list.size(); idx_i++) { + FunctionExpression *parsed_ref = + dynamic_cast(column_list[idx_i].get()); + if (parsed_ref == nullptr) { + continue; + } + auto column_ref = + dynamic_cast(parsed_ref->children[0].get()); + if (column_ref == nullptr) { + continue; + } + // Trying to check parsed_ref->alias directly leads to a segfault + string column_alias = parsed_ref->alias; + + if (column_ref->column_names[0] != subpath.path_variable) { + continue; + } + if (parsed_ref->function_name == "element_id") { + // Check subpath name matches the column referenced in the function --> + // element_id(named_subpath) + auto shortest_path_function = + CreatePathFindingFunction(subpath.path_list, pg_table); + + if (column_alias.empty()) { + shortest_path_function->alias = + "element_id(" + subpath.path_variable + ")"; + } else { + shortest_path_function->alias = column_alias; + } + column_list.erase(column_list.begin() + idx_i); + column_list.insert(column_list.begin() + idx_i, + std::move(shortest_path_function)); + } else if (parsed_ref->function_name == "path_length") { + auto shortest_path_function = + CreatePathFindingFunction(subpath.path_list, pg_table); + auto path_len_children = vector>(); + path_len_children.push_back(std::move(shortest_path_function)); + auto path_len = + make_uniq("len", std::move(path_len_children)); + auto constant_two = make_uniq(Value::INTEGER(2)); + vector> div_children; + div_children.push_back(std::move(path_len)); + div_children.push_back(std::move(constant_two)); + auto path_length_function = + make_uniq("//", std::move(div_children)); + path_length_function->alias = + column_alias.empty() ? "path_length(" + subpath.path_variable + ")" + : column_alias; + column_list.erase(column_list.begin() + idx_i); + column_list.insert(column_list.begin() + idx_i, + std::move(path_length_function)); + } else if (parsed_ref->function_name == "vertices" || + parsed_ref->function_name == "edges") { + auto shortest_path_function = + CreatePathFindingFunction(subpath.path_list, pg_table); + auto list_slice_children = vector>(); + list_slice_children.push_back(std::move(shortest_path_function)); + + if (parsed_ref->function_name == "vertices") { + list_slice_children.push_back( + make_uniq(Value::INTEGER(1))); + } else { + list_slice_children.push_back( + make_uniq(Value::INTEGER(2))); + } + auto slice_end = make_uniq(Value::INTEGER(-1)); + auto slice_step = make_uniq(Value::INTEGER(2)); + + list_slice_children.push_back(std::move(slice_end)); + list_slice_children.push_back(std::move(slice_step)); + auto list_slice = make_uniq( + "list_slice", std::move(list_slice_children)); + if (parsed_ref->function_name == "vertices") { + list_slice->alias = column_alias.empty() + ? "vertices(" + subpath.path_variable + ")" + : column_alias; + } else { + list_slice->alias = column_alias.empty() + ? "edges(" + subpath.path_variable + ")" + : column_alias; + } + column_list.erase(column_list.begin() + idx_i); + column_list.insert(column_list.begin() + idx_i, std::move(list_slice)); + } + } +} + +void PGQMatchFunction::ProcessPathList( + vector> &path_list, + vector> &conditions, + unique_ptr &from_clause, unique_ptr &select_node, + unordered_map &alias_map, CreatePropertyGraphInfo &pg_table, + int32_t &extra_alias_counter, + vector> &column_list) { + PathElement *previous_vertex_element = GetPathElement(path_list[0]); + if (!previous_vertex_element) { + const auto previous_vertex_subpath = + reinterpret_cast(path_list[0].get()); + CheckNamedSubpath(*previous_vertex_subpath, column_list, pg_table); + if (previous_vertex_subpath->where_clause) { + conditions.push_back(std::move(previous_vertex_subpath->where_clause)); + } + if (previous_vertex_subpath->path_list.size() == 1) { + previous_vertex_element = + GetPathElement(previous_vertex_subpath->path_list[0]); + } else { + // Add the shortest path if the name is found in the column_list + ProcessPathList(previous_vertex_subpath->path_list, conditions, + from_clause, select_node, alias_map, pg_table, + extra_alias_counter, column_list); + return; + } + } + auto previous_vertex_table = + FindGraphTable(previous_vertex_element->label, pg_table); + CheckInheritance(previous_vertex_table, previous_vertex_element, conditions); + alias_map[previous_vertex_element->variable_binding] = + previous_vertex_table->table_name; + + for (idx_t idx_j = 1; idx_j < path_list.size(); idx_j = idx_j + 2) { + PathElement *next_vertex_element = GetPathElement(path_list[idx_j + 1]); + if (!next_vertex_element) { + auto next_vertex_subpath = + reinterpret_cast(path_list[idx_j + 1].get()); + if (next_vertex_subpath->path_list.size() > 1) { + throw NotImplementedException( + "Recursive patterns are not yet supported."); + } + if (next_vertex_subpath->where_clause) { + conditions.push_back(std::move(next_vertex_subpath->where_clause)); + } + next_vertex_element = GetPathElement(next_vertex_subpath->path_list[0]); + } + if (next_vertex_element->match_type != PGQMatchType::MATCH_VERTEX || + previous_vertex_element->match_type != PGQMatchType::MATCH_VERTEX) { + throw BinderException("Vertex and edge patterns must be alternated."); + } + auto next_vertex_table = + FindGraphTable(next_vertex_element->label, pg_table); + CheckInheritance(next_vertex_table, next_vertex_element, conditions); + alias_map[next_vertex_element->variable_binding] = + next_vertex_table->table_name; + + PathElement *edge_element = GetPathElement(path_list[idx_j]); + if (!edge_element) { + // We are dealing with a subpath + auto edge_subpath = reinterpret_cast(path_list[idx_j].get()); + if (edge_subpath->where_clause) { + conditions.push_back(std::move(edge_subpath->where_clause)); + } + if (edge_subpath->path_list.size() > 1) { + throw NotImplementedException( + "Subpath on an edge is not yet supported."); + } + edge_element = GetPathElement(edge_subpath->path_list[0]); + auto edge_table = FindGraphTable(edge_element->label, pg_table); + + if (edge_subpath->upper > 1) { + // Add the path-finding + AddPathFinding(select_node, from_clause, conditions, + previous_vertex_element->variable_binding, + edge_element->variable_binding, + next_vertex_element->variable_binding, edge_table, + edge_subpath); + } else { + alias_map[edge_element->variable_binding] = + edge_table->source_reference; + AddEdgeJoins(select_node, edge_table, previous_vertex_table, + next_vertex_table, edge_element->match_type, + edge_element->variable_binding, + previous_vertex_element->variable_binding, + next_vertex_element->variable_binding, conditions, + alias_map, extra_alias_counter); + } + } else { + // The edge element is a path element without WHERE or path-finding. + auto edge_table = FindGraphTable(edge_element->label, pg_table); + CheckInheritance(edge_table, edge_element, conditions); + // check aliases + alias_map[edge_element->variable_binding] = edge_table->table_name; + AddEdgeJoins(select_node, edge_table, previous_vertex_table, + next_vertex_table, edge_element->match_type, + edge_element->variable_binding, + previous_vertex_element->variable_binding, + next_vertex_element->variable_binding, conditions, alias_map, + extra_alias_counter); + // Check the edge type + // If (a)-[b]->(c) -> b.src = a.id AND b.dst = c.id + // If (a)<-[b]-(c) -> b.dst = a.id AND b.src = c.id + // If (a)-[b]-(c) -> (b.src = a.id AND b.dst = c.id) OR + // (b.dst = a.id AND b.src + // = c.id) If (a)<-[b]->(c) -> (b.src = a.id AND b.dst = c.id) AND + // (b.dst = a.id AND b.src + //= c.id) + } + previous_vertex_element = next_vertex_element; + previous_vertex_table = next_vertex_table; + } +} + +unique_ptr +PGQMatchFunction::MatchBindReplace(ClientContext &context, + TableFunctionBindInput &) { auto duckpgq_state_entry = context.registered_state.find("duckpgq"); - auto duckpgq_state = (DuckPGQState *)duckpgq_state_entry->second.get(); + auto duckpgq_state = + dynamic_cast(duckpgq_state_entry->second.get()); auto ref = dynamic_cast( duckpgq_state->transform_expression.get()); auto pg_table = duckpgq_state->GetPropertyGraph(ref->pg_name); + auto data = make_uniq(); + vector> conditions; auto select_node = make_uniq(); unordered_map alias_map; - unordered_set named_subpaths; unique_ptr from_clause; int32_t extra_alias_counter = 0; - bool path_finding = false; for (idx_t idx_i = 0; idx_i < ref->path_patterns.size(); idx_i++) { auto &path_pattern = ref->path_patterns[idx_i]; // Check if the element is PathElement or a Subpath with potentially many // items - PathElement *previous_vertex_element = - GetPathElement(path_pattern->path_elements[0], conditions); - if (!previous_vertex_element) { - auto subpath_pattern_subquery = GenerateSubpathPatternSubquery( - path_pattern, pg_table, ref->column_list, named_subpaths); - if (from_clause) { - // The from clause already contains TableRefs, so we need to make a join - // with the subquery - auto from_join = make_uniq(JoinRefType::CROSS); - from_join->left = std::move(from_clause); - from_join->right = std::move(subpath_pattern_subquery); - from_clause = std::move(from_join); - } else { - // The from clause was still empty, so we can just place the subquery - // there - from_clause = std::move(subpath_pattern_subquery); - } - } else { - auto previous_vertex_table = - FindGraphTable(previous_vertex_element->label, *pg_table); - CheckInheritance(previous_vertex_table, previous_vertex_element, - conditions); - alias_map[previous_vertex_element->variable_binding] = - previous_vertex_table->table_name; - - for (idx_t idx_j = 1; - idx_j < ref->path_patterns[idx_i]->path_elements.size(); - idx_j = idx_j + 2) { - PathElement *edge_element = - GetPathElement(path_pattern->path_elements[idx_j], conditions); - if (!edge_element) { - auto subpath = - reinterpret_cast(path_pattern->path_elements[0].get()); - edge_element = GetPathElement(subpath->path_list[idx_j], conditions); - } - PathElement *next_vertex_element = - GetPathElement(path_pattern->path_elements[idx_j + 1], conditions); - if (!next_vertex_element) { - auto subpath = - reinterpret_cast(path_pattern->path_elements[0].get()); - next_vertex_element = - GetPathElement(subpath->path_list[idx_j + 1], conditions); - } - if (next_vertex_element->match_type != PGQMatchType::MATCH_VERTEX || - previous_vertex_element->match_type != PGQMatchType::MATCH_VERTEX) { - throw BinderException("Vertex and edge patterns must be alternated."); - } - - auto edge_table = FindGraphTable(edge_element->label, *pg_table); - CheckInheritance(edge_table, edge_element, conditions); - auto next_vertex_table = - FindGraphTable(next_vertex_element->label, *pg_table); - CheckInheritance(next_vertex_table, next_vertex_element, conditions); - - if (path_pattern->path_elements[idx_j]->path_reference_type == - PGQPathReferenceType::SUBPATH) { - auto *subpath = reinterpret_cast( - path_pattern->path_elements[idx_j].get()); - if (subpath->upper > 1) { - path_finding = true; - - //! START - //! FROM (SELECT count(cte1.temp) * 0 as temp from cte1) __x, src a, - //! dst b - select_node->cte_map.map["cte1"] = CreateCSRCTE( - edge_table, previous_vertex_element->variable_binding, - edge_element->variable_binding, - next_vertex_element->variable_binding); - - //! (SELECT count(cte1.temp) * 0 as temp from cte1) __x - auto temp_cte_select_subquery = CreateCountCTESubquery(); - - auto cross_join_src_dst = make_uniq(JoinRefType::CROSS); - - //! src alias (FROM src a) - auto src_vertex_ref = make_uniq(); - src_vertex_ref->table_name = edge_table->source_reference; - src_vertex_ref->alias = previous_vertex_element->variable_binding; - - cross_join_src_dst->left = std::move(src_vertex_ref); - - //! dst alias (FROM dst b) - auto dst_vertex_ref = make_uniq(); - dst_vertex_ref->table_name = edge_table->destination_reference; - dst_vertex_ref->alias = next_vertex_element->variable_binding; - - cross_join_src_dst->right = std::move(dst_vertex_ref); - - auto cross_join_with_cte = make_uniq(JoinRefType::CROSS); - cross_join_with_cte->left = std::move(temp_cte_select_subquery); - cross_join_with_cte->right = std::move(cross_join_src_dst); - - if (from_clause) { - // create a cross join since there is already something in the - // from clause - auto from_join = make_uniq(JoinRefType::CROSS); - from_join->left = std::move(from_clause); - from_join->right = std::move(cross_join_with_cte); - from_clause = std::move(from_join); - } else { - from_clause = std::move(cross_join_with_cte); - } - //! END - //! FROM (SELECT count(cte1.temp) * 0 as temp from cte1) __x, src a, - //! dst b - - //! START - //! WHERE __x.temp + iterativelength(, (SELECT count(c.id) - //! from dst c, a.rowid, b.rowid) between lower and upper - - auto src_row_id = make_uniq( - "rowid", previous_vertex_element->variable_binding); - auto dst_row_id = make_uniq( - "rowid", next_vertex_element->variable_binding); - auto csr_id = - make_uniq(Value::INTEGER((int32_t)0)); - - vector> pathfinding_children; - pathfinding_children.push_back(std::move(csr_id)); - pathfinding_children.push_back(std::move(GetCountTable( - edge_table, previous_vertex_element->variable_binding))); - pathfinding_children.push_back(std::move(src_row_id)); - pathfinding_children.push_back(std::move(dst_row_id)); - - auto reachability_function = make_uniq( - "iterativelength", std::move(pathfinding_children)); - - auto cte_col_ref = make_uniq("temp", "__x"); - - vector> addition_children; - addition_children.push_back(std::move(cte_col_ref)); - addition_children.push_back(std::move(reachability_function)); - - auto addition_function = make_uniq( - "add", std::move(addition_children)); - auto lower_limit = - make_uniq(Value::INTEGER(subpath->lower)); - auto upper_limit = - make_uniq(Value::INTEGER(subpath->upper)); - auto between_expression = make_uniq( - std::move(addition_function), std::move(lower_limit), - std::move(upper_limit)); - conditions.push_back(std::move(between_expression)); - - //! END - //! WHERE __x.temp + iterativelength(, (SELECT count(s.id) - //! from src s, a.rowid, b.rowid) between lower and upper - } - } - // check aliases - alias_map[next_vertex_element->variable_binding] = - next_vertex_table->table_name; - alias_map[edge_element->variable_binding] = edge_table->table_name; - if (!path_finding) { - switch (edge_element->match_type) { - case PGQMatchType::MATCH_EDGE_ANY: { - select_node->modifiers.push_back(make_uniq()); - EdgeTypeAny(edge_table, edge_element->variable_binding, - previous_vertex_element->variable_binding, - next_vertex_element->variable_binding, conditions); - break; - } - case PGQMatchType::MATCH_EDGE_LEFT: - EdgeTypeLeft(edge_table, next_vertex_table->table_name, - previous_vertex_table->table_name, - edge_element->variable_binding, - previous_vertex_element->variable_binding, - next_vertex_element->variable_binding, conditions); - break; - case PGQMatchType::MATCH_EDGE_RIGHT: - EdgeTypeRight(edge_table, next_vertex_table->table_name, - previous_vertex_table->table_name, - edge_element->variable_binding, - previous_vertex_element->variable_binding, - next_vertex_element->variable_binding, conditions); - break; - case PGQMatchType::MATCH_EDGE_LEFT_RIGHT: { - EdgeTypeLeftRight(edge_table, edge_element->variable_binding, - previous_vertex_element->variable_binding, - next_vertex_element->variable_binding, conditions, - alias_map, extra_alias_counter); - break; - } - - default: - throw InternalException("Unknown match type found"); - } - } - - previous_vertex_element = next_vertex_element; - previous_vertex_table = next_vertex_table; - - // Check the edge type - // If (a)-[b]->(c) -> b.src = a.id AND b.dst = c.id - // If (a)<-[b]-(c) -> b.dst = a.id AND b.src = c.id - // If (a)-[b]-(c) -> (b.src = a.id AND b.dst = c.id) OR - // (b.dst = a.id AND b.src - // = c.id) If (a)<-[b]->(c) -> (b.src = a.id AND b.dst = c.id) AND - // (b.dst = a.id AND b.src - //= c.id) - } - } + ProcessPathList(path_pattern->path_elements, conditions, from_clause, + select_node, alias_map, *pg_table, extra_alias_counter, + ref->column_list); } - if (!path_finding) { - // Go through all aliases encountered - for (auto &table_alias_entry : alias_map) { - auto table_ref = make_uniq(); - table_ref->table_name = table_alias_entry.second; - table_ref->alias = table_alias_entry.first; - - if (from_clause) { - auto new_root = make_uniq(JoinRefType::CROSS); - new_root->left = std::move(from_clause); - new_root->right = std::move(table_ref); - from_clause = std::move(new_root); - } else { - from_clause = std::move(table_ref); - } + // Go through all aliases encountered + for (auto &table_alias_entry : alias_map) { + auto table_ref = make_uniq(); + table_ref->table_name = table_alias_entry.second; + table_ref->alias = table_alias_entry.first; + + if (from_clause) { + auto new_root = make_uniq(JoinRefType::CROSS); + new_root->left = std::move(from_clause); + new_root->right = std::move(table_ref); + from_clause = std::move(new_root); + } else { + from_clause = std::move(table_ref); } } + select_node->from_table = std::move(from_clause); if (ref->where_clause) { @@ -768,6 +950,7 @@ unique_ptr PGQMatchFunction::MatchBindReplace(ClientContext &context, std::vector> final_column_list; for (auto &expression : ref->column_list) { + unordered_set named_subpaths; auto column_ref = dynamic_cast(expression.get()); if (column_ref != nullptr) { if (named_subpaths.count(column_ref->column_names[0]) && @@ -801,8 +984,7 @@ unique_ptr PGQMatchFunction::MatchBindReplace(ClientContext &context, div_children.push_back(std::move(constant_two)); auto div_expression = make_uniq("//", std::move(div_children)); - div_expression->alias = - "path_length_" + column_ref->column_names[0]; + div_expression->alias = "path_length_" + column_ref->column_names[0]; final_column_list.emplace_back(std::move(div_expression)); } } else { @@ -825,215 +1007,4 @@ unique_ptr PGQMatchFunction::MatchBindReplace(ClientContext &context, return std::move(result); } - -unique_ptr PGQMatchFunction::GenerateSubpathPatternSubquery( - unique_ptr &path_pattern, CreatePropertyGraphInfo *pg_table, - vector> &column_list, - unordered_set &named_subpaths) { - vector> conditions; - auto path_element = - reinterpret_cast(path_pattern->path_elements[0].get()); - auto select_node = make_uniq(); - unordered_map alias_map; - string named_subpath = path_element->path_variable; - named_subpaths.insert(named_subpath); - int32_t extra_alias_counter = 0; - bool path_finding = false; - auto previous_vertex_element = - GetPathElement(path_element->path_list[0], conditions); - auto previous_vertex_table = - FindGraphTable(previous_vertex_element->label, *pg_table); - CheckInheritance(previous_vertex_table, previous_vertex_element, conditions); - alias_map[previous_vertex_element->variable_binding] = - previous_vertex_table->table_name; - for (idx_t idx_j = 1; idx_j < path_element->path_list.size(); - idx_j = idx_j + 2) { - PathElement *edge_element = - GetPathElement(path_element->path_list[idx_j], conditions); - PathElement *next_vertex_element = - GetPathElement(path_element->path_list[idx_j + 1], conditions); - if (next_vertex_element->match_type != PGQMatchType::MATCH_VERTEX || - previous_vertex_element->match_type != PGQMatchType::MATCH_VERTEX) { - throw BinderException("Vertex and edge patterns must be alternated."); - } - - auto edge_table = FindGraphTable(edge_element->label, *pg_table); - CheckInheritance(edge_table, edge_element, conditions); - auto next_vertex_table = - FindGraphTable(next_vertex_element->label, *pg_table); - CheckInheritance(next_vertex_table, next_vertex_element, conditions); - - if (path_element->path_list[idx_j]->path_reference_type == - PGQPathReferenceType::SUBPATH) { - auto *subpath = - reinterpret_cast(path_element->path_list[idx_j].get()); - if (subpath->upper > 1) { - path_finding = true; - if (!named_subpath.empty() && path_pattern->shortest) { - // todo(dtenwolde) does not necessarily have to be a shortest path - // query if it is a named subpath. It can also be a basic pattern - // matching that is named. - auto shortest_path_function = CreatePathFindingFunction( - previous_vertex_element->variable_binding, - next_vertex_element->variable_binding, edge_table, - "shortestpath"); - shortest_path_function->alias = "path"; - select_node->select_list.push_back(std::move(shortest_path_function)); - } - select_node->cte_map.map["cte1"] = - CreateCSRCTE(edge_table, previous_vertex_element->variable_binding, - edge_element->variable_binding, - next_vertex_element->variable_binding); - - //! (SELECT count(cte1.temp) * 0 as temp from cte1) __x - auto temp_cte_select_subquery = CreateCountCTESubquery(); - - auto cross_join_src_dst = make_uniq(JoinRefType::CROSS); - - //! src alias (FROM src a) - auto src_vertex_ref = make_uniq(); - src_vertex_ref->table_name = edge_table->source_reference; - src_vertex_ref->alias = previous_vertex_element->variable_binding; - - cross_join_src_dst->left = std::move(src_vertex_ref); - - //! dst alias (FROM dst b) - auto dst_vertex_ref = make_uniq(); - dst_vertex_ref->table_name = edge_table->destination_reference; - dst_vertex_ref->alias = next_vertex_element->variable_binding; - - cross_join_src_dst->right = std::move(dst_vertex_ref); - - auto cross_join_with_cte = make_uniq(JoinRefType::CROSS); - cross_join_with_cte->left = std::move(temp_cte_select_subquery); - cross_join_with_cte->right = std::move(cross_join_src_dst); - - if (select_node->from_table) { - // create a cross join since there is already something in the from - // clause - auto from_join = make_uniq(JoinRefType::CROSS); - from_join->left = std::move(select_node->from_table); - from_join->right = std::move(cross_join_with_cte); - select_node->from_table = std::move(from_join); - } else { - select_node->from_table = std::move(cross_join_with_cte); - } - //! END - //! FROM (SELECT count(cte1.temp) * 0 as temp from cte1) __x, src a, dst - //! b - - //! START - //! WHERE __x.temp + iterativelength(, (SELECT count(c.id) from - //! dst c, a.rowid, b.rowid) between lower and upper - auto reachability_function = - CreatePathFindingFunction(previous_vertex_element->variable_binding, - next_vertex_element->variable_binding, - edge_table, "iterativelength"); - - auto cte_col_ref = make_uniq("temp", "__x"); - - vector> addition_children; - addition_children.push_back(std::move(cte_col_ref)); - addition_children.push_back(std::move(reachability_function)); - - auto addition_function = - make_uniq("add", std::move(addition_children)); - auto lower_limit = - make_uniq(Value::BIGINT(subpath->lower)); - auto upper_limit = - make_uniq(Value::BIGINT(subpath->upper)); - auto between_expression = make_uniq( - std::move(addition_function), std::move(lower_limit), - std::move(upper_limit)); - conditions.push_back(std::move(between_expression)); - - //! END - //! WHERE __x.temp + iterativelength(, (SELECT count(s.id) from - //! src s, a.rowid, b.rowid) between lower and upper - } - // check aliases - alias_map[next_vertex_element->variable_binding] = - next_vertex_table->table_name; - alias_map[edge_element->variable_binding] = edge_table->table_name; - if (!path_finding) { - switch (edge_element->match_type) { - case PGQMatchType::MATCH_EDGE_ANY: { - select_node->modifiers.push_back(make_uniq()); - EdgeTypeAny(edge_table, edge_element->variable_binding, - previous_vertex_element->variable_binding, - next_vertex_element->variable_binding, conditions); - break; - } - case PGQMatchType::MATCH_EDGE_LEFT: - EdgeTypeLeft(edge_table, next_vertex_table->table_name, - previous_vertex_table->table_name, - edge_element->variable_binding, - previous_vertex_element->variable_binding, - next_vertex_element->variable_binding, conditions); - break; - case PGQMatchType::MATCH_EDGE_RIGHT: - EdgeTypeRight(edge_table, next_vertex_table->table_name, - previous_vertex_table->table_name, - edge_element->variable_binding, - previous_vertex_element->variable_binding, - next_vertex_element->variable_binding, conditions); - break; - case PGQMatchType::MATCH_EDGE_LEFT_RIGHT: { - EdgeTypeLeftRight(edge_table, edge_element->variable_binding, - previous_vertex_element->variable_binding, - next_vertex_element->variable_binding, conditions, - alias_map, extra_alias_counter); - break; - } - default: - throw InternalException("Unknown match type found"); - } - } - previous_vertex_element = next_vertex_element; - previous_vertex_table = next_vertex_table; - } - } - - select_node->where_clause = CreateWhereClause(conditions); - vector> substitute_column_list; - for (auto &expression : column_list) { - const auto &column_ref = - dynamic_cast(expression.get()); - if (column_ref == nullptr) { - continue; - } - // If the table is referenced in this subquery (count() > 0) - if (alias_map.count(column_ref->column_names[0])) { - select_node->select_list.push_back(std::move(expression)); - // Create a substitute - unique_ptr new_upper_column_ref; - if (column_ref->alias.empty()) { - new_upper_column_ref = make_uniq( - column_ref->column_names[1], named_subpath); - } else { - new_upper_column_ref = - make_uniq(column_ref->alias, named_subpath); - } - new_upper_column_ref->alias = column_ref->alias; - substitute_column_list.push_back(std::move(new_upper_column_ref)); - } - } - // Remove the elements from the original column_list that are now NULL - for (auto it = column_list.begin(); it != column_list.end();) { - if (!*it) { - it = column_list.erase(it); - } else { - ++it; - } - } - // Add the ColumnRefs that were previously moved to the subquery with the - // subquery name as table_name - for (auto &expression : substitute_column_list) { - column_list.push_back(std::move(expression)); - } - auto subquery = make_uniq(); - subquery->node = std::move(select_node); - - return make_uniq(std::move(subquery), named_subpath); -} } // namespace duckdb diff --git a/duckpgq/src/duckpgq/functions/tablefunctions/pgq_scan.cpp b/duckpgq/src/duckpgq/functions/tablefunctions/pgq_scan.cpp index dfdbcd67..ba646aac 100644 --- a/duckpgq/src/duckpgq/functions/tablefunctions/pgq_scan.cpp +++ b/duckpgq/src/duckpgq/functions/tablefunctions/pgq_scan.cpp @@ -39,8 +39,8 @@ static void ScanCSREFunction(ClientContext &context, TableFunctionInput &data_p, FlatVector::SetData(output.data[0], (data_ptr_t)csr->e.data()); } -static void ScanCSRPtrFunction(ClientContext &context, TableFunctionInput &data_p, - DataChunk &output) { +static void ScanCSRPtrFunction(ClientContext &context, + TableFunctionInput &data_p, DataChunk &output) { bool &gstate = ((CSRScanState &)*data_p.global_state).finished; if (gstate) { @@ -59,7 +59,7 @@ static void ScanCSRPtrFunction(ClientContext &context, TableFunctionInput &data_ } auto duckpgq_state = reinterpret_cast(duckpgq_state_entry->second.get()); - auto csr_id = data_p.bind_data->Cast().csr_id; + auto csr_id = data_p.bind_data->Cast().csr_id; CSR *csr = duckpgq_state->GetCSR(csr_id); output.SetCardinality(5); output.data[0].SetVectorType(VectorType::FLAT_VECTOR); @@ -74,7 +74,7 @@ static void ScanCSRPtrFunction(ClientContext &context, TableFunctionInput &data_ // the third element is the address of the weight array // the fifth element is the type of the weight array // 0 if the weights are integres, 1 if they are doubles, and 2 for unweighted - if(csr->w.size()) { + if (csr->w.size()) { result_data[2] = (uint64_t)(&(csr->w)); result_data[4] = (uint64_t)(0); } else if (csr->w_double.size()) { @@ -84,7 +84,8 @@ static void ScanCSRPtrFunction(ClientContext &context, TableFunctionInput &data_ result_data[2] = (uint64_t)(0); result_data[4] = (uint64_t)(2); } - // we also need the number of elements in the vertex array, since its C-array not a vector. + // we also need the number of elements in the vertex array, since its C-array + // not a vector. result_data[3] = (uint64_t)(csr->vsize); } diff --git a/duckpgq/src/duckpgq_extension.cpp b/duckpgq/src/duckpgq_extension.cpp index 5cc1404d..1cadbe71 100644 --- a/duckpgq/src/duckpgq_extension.cpp +++ b/duckpgq/src/duckpgq_extension.cpp @@ -89,16 +89,18 @@ BoundStatement duckpgq_bind(ClientContext &context, Binder &binder, OperatorExtensionInfo *info, SQLStatement &statement) { auto lookup = context.registered_state.find("duckpgq"); - if (lookup != context.registered_state.end()) { - auto duckpgq_state = (DuckPGQState *)lookup->second.get(); - auto duckpgq_binder = Binder::CreateBinder(context); - auto duckpgq_parse_data = - dynamic_cast(duckpgq_state->parse_data.get()); - if (duckpgq_parse_data) { - return duckpgq_binder->Bind(*(duckpgq_parse_data->statement)); - } + if (lookup == context.registered_state.end()) { + throw BinderException("Registered state not found"); } - throw BinderException("Registered state not found"); + + auto duckpgq_state = (DuckPGQState *)lookup->second.get(); + auto duckpgq_binder = Binder::CreateBinder(context); + auto duckpgq_parse_data = + dynamic_cast(duckpgq_state->parse_data.get()); + if (duckpgq_parse_data) { + return duckpgq_binder->Bind(*(duckpgq_parse_data->statement)); + } + throw BinderException("Unable to find DuckPGQ Parse Data"); } ParserExtensionPlanResult @@ -118,10 +120,9 @@ duckpgq_plan(ParserExtensionInfo *, ClientContext &context, dynamic_cast(duckpgq_state->parse_data.get()); if (!duckpgq_parse_data) { - throw BinderException("Not DuckPGQ parse data"); + throw BinderException("No DuckPGQ parse data found"); } - auto statement = - dynamic_cast(duckpgq_parse_data->statement.get()); + auto statement = duckpgq_parse_data->statement.get(); if (statement->type == StatementType::SELECT_STATEMENT) { auto select_statement = dynamic_cast(statement); auto select_node = dynamic_cast(select_statement->node.get()); @@ -135,13 +136,15 @@ duckpgq_plan(ParserExtensionInfo *, ClientContext &context, function->children.pop_back(); } throw Exception("use duckpgq_bind instead"); - } else if (statement->type == StatementType::CREATE_STATEMENT) { + } + if (statement->type == StatementType::CREATE_STATEMENT) { ParserExtensionPlanResult result; result.function = CreatePropertyGraphFunction(); result.requires_valid_transaction = true; result.return_type = StatementReturnType::QUERY_RESULT; return result; - } else if (statement->type == StatementType::DROP_STATEMENT) { + } + if (statement->type == StatementType::DROP_STATEMENT) { ParserExtensionPlanResult result; result.function = DropPropertyGraphFunction(); result.requires_valid_transaction = true; diff --git a/test/sql/path-finding/complex_matching.test b/test/sql/path-finding/complex_matching.test index e2eb792d..9798916b 100644 --- a/test/sql/path-finding/complex_matching.test +++ b/test/sql/path-finding/complex_matching.test @@ -49,10 +49,321 @@ EDGE TABLES ( LABEL replyOf ); -query II +query IIIIIII +-FROM GRAPH_TABLE (snb + MATCH o = ANY SHORTEST (p4:Person where p4.rowid = 0)-[w3:knows]->(p:Person)-[w:knows]->{1,3}(p2:Person)-[w2:knows]->(p3:Person) + COLUMNS (p3.id, element_id(o), path_length(o), vertices(o), edges(o), p4.id, p.id) + ) tmp; +---- +28587302322180 [0, 0, 13, 42, 29, 68, 33] 3 [0, 13, 29, 33] [0, 42, 68] 14 10995116277782 +28587302322204 [0, 0, 13, 42, 29, 69, 36] 3 [0, 13, 29, 36] [0, 42, 69] 14 10995116277782 +28587302322196 [0, 0, 13, 43, 31, 71, 35] 3 [0, 13, 31, 35] [0, 43, 71] 14 10995116277782 +30786325577740 [0, 0, 13, 43, 31, 72, 40] 3 [0, 13, 31, 40] [0, 43, 72] 14 10995116277782 +35184372088850 [0, 0, 13, 43, 31, 73, 45] 3 [0, 13, 31, 45] [0, 43, 73] 14 10995116277782 +35184372088856 [0, 0, 13, 43, 31, 74, 46] 3 [0, 13, 31, 46] [0, 43, 74] 14 10995116277782 +28587302322204 [0, 0, 13, 44, 33, 77, 36] 3 [0, 13, 33, 36] [0, 44, 77] 14 10995116277782 +28587302322223 [0, 0, 13, 44, 33, 78, 38] 3 [0, 13, 33, 38] [0, 44, 78] 14 10995116277782 +30786325577731 [0, 0, 13, 44, 33, 79, 39] 3 [0, 13, 33, 39] [0, 44, 79] 14 10995116277782 +32985348833329 [0, 0, 13, 44, 33, 80, 43] 3 [0, 13, 33, 43] [0, 44, 80] 14 10995116277782 +35184372088850 [0, 0, 13, 45, 36, 82, 45] 3 [0, 13, 36, 45] [0, 45, 82] 14 10995116277782 +28587302322196 [0, 1, 26, 62, 31, 71, 35] 3 [0, 26, 31, 35] [1, 62, 71] 14 24189255811081 +30786325577740 [0, 1, 26, 62, 31, 72, 40] 3 [0, 26, 31, 40] [1, 62, 72] 14 24189255811081 +35184372088850 [0, 1, 26, 62, 31, 73, 45] 3 [0, 26, 31, 45] [1, 62, 73] 14 24189255811081 +35184372088856 [0, 1, 26, 62, 31, 74, 46] 3 [0, 26, 31, 46] [1, 62, 74] 14 24189255811081 +28587302322180 [0, 1, 26, 63, 32, 75, 33] 3 [0, 26, 32, 33] [1, 63, 75] 14 24189255811081 +28587302322204 [0, 1, 26, 63, 32, 76, 36] 3 [0, 26, 32, 36] [1, 63, 76] 14 24189255811081 +28587302322204 [0, 1, 26, 64, 33, 77, 36] 3 [0, 26, 33, 36] [1, 64, 77] 14 24189255811081 +28587302322223 [0, 1, 26, 64, 33, 78, 38] 3 [0, 26, 33, 38] [1, 64, 78] 14 24189255811081 +30786325577731 [0, 1, 26, 64, 33, 79, 39] 3 [0, 26, 33, 39] [1, 64, 79] 14 24189255811081 +32985348833329 [0, 1, 26, 64, 33, 80, 43] 3 [0, 26, 33, 43] [1, 64, 80] 14 24189255811081 +35184372088850 [0, 1, 26, 63, 32, 76, 36, 82, 45] 4 [0, 26, 32, 36, 45] [1, 63, 76, 82] 14 24189255811081 +28587302322204 [0, 2, 32, 75, 33, 77, 36] 3 [0, 32, 33, 36] [2, 75, 77] 14 26388279066668 +28587302322223 [0, 2, 32, 75, 33, 78, 38] 3 [0, 32, 33, 38] [2, 75, 78] 14 26388279066668 +30786325577731 [0, 2, 32, 75, 33, 79, 39] 3 [0, 32, 33, 39] [2, 75, 79] 14 26388279066668 +32985348833329 [0, 2, 32, 75, 33, 80, 43] 3 [0, 32, 33, 43] [2, 75, 80] 14 26388279066668 +35184372088850 [0, 2, 32, 76, 36, 82, 45] 3 [0, 32, 36, 45] [2, 76, 82] 14 26388279066668 + +statement error +-FROM GRAPH_TABLE (snb + MATCH o = ANY SHORTEST (p:Person)-[w:knows]->(p2:Person)-[w2:knows]->(p3:Person) + COLUMNS (o) + ) tmp + limit 10; +---- +Binder Error: Referenced column "o" not found in FROM clause! + + +# https://github.com/cwida/duckpgq-extension/issues/68 +statement error +-FROM GRAPH_TABLE (snb + MATCH o = ANY SHORTEST (p:Person)-[w:knows]->(p2:Person)-[w2:knows]->(p3:Person) + COLUMNS (element_id(a)) + ) tmp + limit 10; +---- +Catalog Error: Scalar Function with name element_id does not exist! +Did you mean "element_at"? + +query III -FROM GRAPH_TABLE (snb MATCH o = ANY SHORTEST (p:Person)-[w:knows]-> {1,3}(p2:Person)-[i:hasInterest]->(t:Tag) COLUMNS (p.id as p_id, p2.id as p2_id, t.id) ) tmp limit 10; ----- \ No newline at end of file +---- +14 32985348833329 3 +14 32985348833329 139 +14 30786325577731 196 +14 28587302322196 280 +14 28587302322180 294 +14 24189255811081 295 +14 28587302322196 448 +14 32985348833329 470 +14 28587302322196 540 +14 24189255811109 543 + +query IIIII +WITH CTE1 AS (SELECT CREATE_CSR_EDGE( + 0, + (SELECT count(a.id) FROM Person a), + CAST ( + (SELECT sum(CREATE_CSR_VERTEX( + 0, + (SELECT count(a.id) FROM Person a), + sub.dense_id, + sub.cnt) + ) + FROM ( + SELECT a.rowid as dense_id, count(k.person1id) as cnt + FROM Person a + LEFT JOIN Person_knows_Person k ON k.person1id = a.id + GROUP BY a.rowid) sub + ) + AS BIGINT), + a.rowid, + b.rowid, + k.rowid) as temp + FROM Person_knows_Person k + JOIN Person a on a.id = k.person1id + JOIN Person b on b.id = k.person2id) +SELECT shortestpath(0, (select count(*) from Person), a.rowid, b.rowid) as path, + a.firstname as a_name, + b.rowid as b_rowid, + b.id as b_id, + t.id as t_id +FROM Person a, + Person b, + person_hasInterest_Tag i, + Tag t, + (select count(cte1.temp) as temp from cte1) __x +WHERE a.id = 28587302322180 + and b.id = i.PersonId + and t.id = i.TagId + and __x.temp * 0 + iterativelength(0, (select count(*) from Person), a.rowid, b.rowid) between 1 and 3 +ORDER BY b_id, t_id +---- +[33, 77, 36] Bryn 36 28587302322204 6 +[33, 77, 36] Bryn 36 28587302322204 588 +[33, 77, 36] Bryn 36 28587302322204 1021 +[33, 77, 36] Bryn 36 28587302322204 1767 +[33, 77, 36] Bryn 36 28587302322204 1940 +[33, 77, 36] Bryn 36 28587302322204 1995 +[33, 77, 36] Bryn 36 28587302322204 2018 +[33, 77, 36] Bryn 36 28587302322204 5174 +[33, 77, 36] Bryn 36 28587302322204 6413 +[33, 77, 36] Bryn 36 28587302322204 7328 +[33, 77, 36] Bryn 36 28587302322204 9170 +[33, 77, 36] Bryn 36 28587302322204 11695 +[33, 77, 36] Bryn 36 28587302322204 12002 +[33, 78, 38] Bryn 38 28587302322223 775 +[33, 78, 38] Bryn 38 28587302322223 1938 +[33, 79, 39] Bryn 39 30786325577731 196 +[33, 79, 39] Bryn 39 30786325577731 1031 +[33, 80, 43] Bryn 43 32985348833329 3 +[33, 80, 43] Bryn 43 32985348833329 139 +[33, 80, 43] Bryn 43 32985348833329 470 +[33, 80, 43] Bryn 43 32985348833329 580 +[33, 80, 43] Bryn 43 32985348833329 1985 +[33, 80, 43] Bryn 43 32985348833329 2058 +[33, 80, 43] Bryn 43 32985348833329 2777 +[33, 80, 43] Bryn 43 32985348833329 2836 +[33, 80, 43] Bryn 43 32985348833329 5114 +[33, 77, 36, 82, 45] Bryn 45 35184372088850 804 +[33, 77, 36, 82, 45] Bryn 45 35184372088850 973 +[33, 77, 36, 82, 45] Bryn 45 35184372088850 1170 +[33, 77, 36, 82, 45] Bryn 45 35184372088850 1185 +[33, 77, 36, 82, 45] Bryn 45 35184372088850 1206 +[33, 77, 36, 82, 45] Bryn 45 35184372088850 1749 +[33, 77, 36, 82, 45] Bryn 45 35184372088850 1908 +[33, 77, 36, 82, 45] Bryn 45 35184372088850 1954 +[33, 77, 36, 82, 45] Bryn 45 35184372088850 2003 +[33, 77, 36, 82, 45] Bryn 45 35184372088850 2786 +[33, 77, 36, 82, 45] Bryn 45 35184372088850 2816 +[33, 77, 36, 82, 45] Bryn 45 35184372088850 2969 +[33, 77, 36, 82, 45] Bryn 45 35184372088850 2985 +[33, 77, 36, 82, 45] Bryn 45 35184372088850 4865 +[33, 77, 36, 82, 45] Bryn 45 35184372088850 6399 +[33, 77, 36, 82, 45] Bryn 45 35184372088850 6815 +[33, 77, 36, 82, 45] Bryn 45 35184372088850 7025 +[33, 77, 36, 82, 45] Bryn 45 35184372088850 7142 +[33, 77, 36, 82, 45] Bryn 45 35184372088850 7689 +[33, 77, 36, 82, 45] Bryn 45 35184372088850 9929 + +query IIII +-FROM GRAPH_TABLE (snb + MATCH (a:Person)-[w:knows]-> {1,3}(b:Person)-[i:hasInterest]->(t:Tag) + WHERE a.id = 28587302322180 + COLUMNS (a.firstname as p_name, b.rowid as b_rowid, b.id as b_id, t.id as t_id) + ) tmp +ORDER BY b_id, t_id +---- +Bryn 36 28587302322204 6 +Bryn 36 28587302322204 588 +Bryn 36 28587302322204 1021 +Bryn 36 28587302322204 1767 +Bryn 36 28587302322204 1940 +Bryn 36 28587302322204 1995 +Bryn 36 28587302322204 2018 +Bryn 36 28587302322204 5174 +Bryn 36 28587302322204 6413 +Bryn 36 28587302322204 7328 +Bryn 36 28587302322204 9170 +Bryn 36 28587302322204 11695 +Bryn 36 28587302322204 12002 +Bryn 38 28587302322223 775 +Bryn 38 28587302322223 1938 +Bryn 39 30786325577731 196 +Bryn 39 30786325577731 1031 +Bryn 43 32985348833329 3 +Bryn 43 32985348833329 139 +Bryn 43 32985348833329 470 +Bryn 43 32985348833329 580 +Bryn 43 32985348833329 1985 +Bryn 43 32985348833329 2058 +Bryn 43 32985348833329 2777 +Bryn 43 32985348833329 2836 +Bryn 43 32985348833329 5114 +Bryn 45 35184372088850 804 +Bryn 45 35184372088850 973 +Bryn 45 35184372088850 1170 +Bryn 45 35184372088850 1185 +Bryn 45 35184372088850 1206 +Bryn 45 35184372088850 1749 +Bryn 45 35184372088850 1908 +Bryn 45 35184372088850 1954 +Bryn 45 35184372088850 2003 +Bryn 45 35184372088850 2786 +Bryn 45 35184372088850 2816 +Bryn 45 35184372088850 2969 +Bryn 45 35184372088850 2985 +Bryn 45 35184372088850 4865 +Bryn 45 35184372088850 6399 +Bryn 45 35184372088850 6815 +Bryn 45 35184372088850 7025 +Bryn 45 35184372088850 7142 +Bryn 45 35184372088850 7689 +Bryn 45 35184372088850 9929 + +query IIII +-FROM GRAPH_TABLE (snb + MATCH (a:Person WHERE a.id = 28587302322180)-[w:knows]-> {1,3}(b:Person)-[i:hasInterest]->(t:Tag) + COLUMNS (a.firstname as p_name, b.rowid as b_rowid, b.id as b_id, t.id as t_id) + ) tmp +ORDER BY b_id, t_id +---- +Bryn 36 28587302322204 6 +Bryn 36 28587302322204 588 +Bryn 36 28587302322204 1021 +Bryn 36 28587302322204 1767 +Bryn 36 28587302322204 1940 +Bryn 36 28587302322204 1995 +Bryn 36 28587302322204 2018 +Bryn 36 28587302322204 5174 +Bryn 36 28587302322204 6413 +Bryn 36 28587302322204 7328 +Bryn 36 28587302322204 9170 +Bryn 36 28587302322204 11695 +Bryn 36 28587302322204 12002 +Bryn 38 28587302322223 775 +Bryn 38 28587302322223 1938 +Bryn 39 30786325577731 196 +Bryn 39 30786325577731 1031 +Bryn 43 32985348833329 3 +Bryn 43 32985348833329 139 +Bryn 43 32985348833329 470 +Bryn 43 32985348833329 580 +Bryn 43 32985348833329 1985 +Bryn 43 32985348833329 2058 +Bryn 43 32985348833329 2777 +Bryn 43 32985348833329 2836 +Bryn 43 32985348833329 5114 +Bryn 45 35184372088850 804 +Bryn 45 35184372088850 973 +Bryn 45 35184372088850 1170 +Bryn 45 35184372088850 1185 +Bryn 45 35184372088850 1206 +Bryn 45 35184372088850 1749 +Bryn 45 35184372088850 1908 +Bryn 45 35184372088850 1954 +Bryn 45 35184372088850 2003 +Bryn 45 35184372088850 2786 +Bryn 45 35184372088850 2816 +Bryn 45 35184372088850 2969 +Bryn 45 35184372088850 2985 +Bryn 45 35184372088850 4865 +Bryn 45 35184372088850 6399 +Bryn 45 35184372088850 6815 +Bryn 45 35184372088850 7025 +Bryn 45 35184372088850 7142 +Bryn 45 35184372088850 7689 +Bryn 45 35184372088850 9929 + +query IIII +-FROM GRAPH_TABLE (snb + MATCH (a:Person WHERE a.id = 28587302322180)-[w:knows]-> {1,3}(b:Person)-[i:hasInterest]->(t:Tag WHERE t.id = 6) + COLUMNS (a.firstname as p_name, b.rowid as b_rowid, b.id as b_id, t.id as t_id) + ) tmp +ORDER BY b_id, t_id +---- +Bryn 36 28587302322204 6 + +statement error +-FROM GRAPH_TABLE (snb + MATCH (a:Person WHERE a.id = 28587302322180){3}) + COLUMNS (a.firstname as a_name) + ) tmp +---- +Parser Error: syntax error at or near "{" + +query III +-FROM GRAPH_TABLE (snb + MATCH p = (a:Person where a.id = 16)-[k:knows]->{1,3}(b:Person) + COLUMNS (element_id(p), a.id, b.id) + ) tmp; +---- +[1, 3, 5] 16 2199023255594 +[1, 3, 5, 16, 10] 16 8796093022244 +[1, 3, 5, 17, 12] 16 10995116277761 +[1, 3, 5, 18, 16] 16 13194139533342 +[1, 3, 5, 19, 17] 16 13194139533352 +[1, 3, 5, 16, 10, 32, 18] 16 13194139533355 +[1, 3, 5, 20, 19] 16 15393162788877 +[1, 3, 5, 17, 12, 39, 20] 16 17592186044443 +[1, 3, 5, 21, 21] 16 17592186044461 +[1, 3, 5, 19, 17, 48, 23] 16 19791209299987 +[1, 3, 5, 22, 26] 16 24189255811081 +[1, 3, 5, 22, 26, 61, 27] 16 24189255811109 +[1, 3, 5, 19, 17, 49, 29] 16 26388279066641 +[1, 4, 30] 16 26388279066655 +[1, 3, 5, 23, 31] 16 26388279066658 +[1, 3, 5, 24, 32] 16 26388279066668 +[1, 5, 33] 16 28587302322180 +[1, 3, 5, 26, 35] 16 28587302322196 +[1, 6, 36] 16 28587302322204 +[1, 5, 33, 78, 38] 16 28587302322223 +[1, 5, 33, 79, 39] 16 30786325577731 +[1, 3, 5, 27, 40] 16 30786325577740 +[1, 5, 33, 80, 43] 16 32985348833329 +[1, 3, 5, 22, 26, 66, 44] 16 35184372088834 +[1, 3, 5, 28, 45] 16 35184372088850 +[1, 3, 5, 23, 31, 74, 46] 16 35184372088856 diff --git a/test/sql/path-finding/shortest_path.test b/test/sql/path-finding/shortest_path.test index ce6035f6..a82e8ec1 100644 --- a/test/sql/path-finding/shortest_path.test +++ b/test/sql/path-finding/shortest_path.test @@ -47,7 +47,7 @@ query III -FROM GRAPH_TABLE (pg MATCH p = ANY SHORTEST (a:Person WHERE a.name = 'Daniel')-[k:knows]->{1,3}(b:Person) - COLUMNS (p, a.name as name, b.name as b_name) + COLUMNS (element_id(p), a.name as name, b.name as b_name) ) study; ---- [0, 0, 1] Daniel Tavneet @@ -58,7 +58,7 @@ query IIII -FROM GRAPH_TABLE (pg MATCH p = ANY SHORTEST (a:Person)-[k:knows]->{1,3}(b:Person) - COLUMNS (path_length(p), p, a.name as name, b.name as b_name) + COLUMNS (path_length(p), element_id(p), a.name as name, b.name as b_name) ) study order by study.name, study.b_name; ---- @@ -114,10 +114,9 @@ WITH cte1 AS ( FROM Know k JOIN student a on a.id = k.src JOIN student c on c.id = k.dst -) SELECT named_subpath.path as path, named_subpath.a_name as a_name, named_subpath.b_name as b_name -FROM (SELECT shortestpath(0, (select count(*) from student), a.rowid, b.rowid) as path, a.name as a_name, b.name as b_name +) SELECT shortestpath(0, (select count(*) from student), a.rowid, b.rowid) as path, a.name as a_name, b.name as b_name FROM student a, student b, (select count(cte1.temp) * 0 as temp from cte1) __x - WHERE a.name = 'Daniel' and __x.temp * 0 + iterativelength(0, (select count(*) from student), a.rowid, b.rowid) between 1 and 3) named_subpath + WHERE a.name = 'Daniel' and __x.temp * 0 + iterativelength(0, (select count(*) from student), a.rowid, b.rowid) between 1 and 3 ---- [0, 0, 1] Daniel Tavneet [0, 1, 2] Daniel Gabor diff --git a/test/sql/scalar/get_csr_w_type.test b/test/sql/scalar/get_csr_w_type.test index 47880d84..7fbc514d 100644 --- a/test/sql/scalar/get_csr_w_type.test +++ b/test/sql/scalar/get_csr_w_type.test @@ -1,8 +1,6 @@ # name: test/sql/sqlpgq/get_csr_w_type.test # group: [sqlpgq] - - require duckpgq statement ok diff --git a/test/sql/snb/snb.test b/test/sql/snb/snb.test index de45a93e..f04f2cba 100644 --- a/test/sql/snb/snb.test +++ b/test/sql/snb/snb.test @@ -160,7 +160,8 @@ query IIIIII MATCH (replyAuthor:person)<-[au2:hasAuthor]-(c:message where c.ParentMessageId is not null)-[r:replyOf]->(m:message where m.id = 618475290624)-[au:hasAuthor]->(messageAuthor:person), (replyAuthor:person)-[k:knows]-(messageAuthor:person) COLUMNS (c.id,c.content,c.creationDate, replyAuthor.id, replyAuthor.firstName, replyAuthor.lastName) - ) tmp; + ) tmp + ORDER BY tmp.content; ---- 962072674306 thanks 2012-07-08 20:32:03.239+00 24189255811081 Alim Guliyev 962072674305 yes 2012-07-08 23:48:41.63+00 24189255811081 Alim Guliyev