diff --git a/.github/workflows/package_all.yaml b/.github/workflows/package_all.yaml index b0ef18fde..7d225bac7 100644 --- a/.github/workflows/package_all.yaml +++ b/.github/workflows/package_all.yaml @@ -177,6 +177,23 @@ jobs: name: fedora-36 path: build/output/fedora-36/memgraph*.rpm + amzn-2: + runs-on: [self-hosted, DockerMgBuild, X64] + timeout-minutes: 60 + steps: + - name: "Set up repository" + uses: actions/checkout@v3 + with: + fetch-depth: 0 # Required because of release/get_version.py + - name: "Build package" + run: | + ./release/package/run.sh package amzn-2 + - name: "Upload package" + uses: actions/upload-artifact@v3 + with: + name: amzn-2 + path: build/output/amzn-2/memgraph*.rpm + debian-11-arm: runs-on: [self-hosted, DockerMgBuild, ARM64, strange] timeout-minutes: 60 diff --git a/.gitignore b/.gitignore index e1a4187b0..83b9a5dc7 100644 --- a/.gitignore +++ b/.gitignore @@ -34,9 +34,6 @@ TAGS *.fas *.fasl -# LCP generated C++ files -*.lcp.cpp - src/database/distributed/serialization.hpp src/database/single_node_ha/serialization.hpp src/distributed/bfs_rpc_messages.hpp @@ -50,15 +47,11 @@ src/distributed/pull_produce_rpc_messages.hpp src/distributed/storage_gc_rpc_messages.hpp src/distributed/token_sharing_rpc_messages.hpp src/distributed/updates_rpc_messages.hpp -src/query/frontend/ast/ast.hpp -src/query/distributed/frontend/ast/ast_serialization.hpp src/durability/distributed/state_delta.hpp src/durability/single_node/state_delta.hpp src/durability/single_node_ha/state_delta.hpp -src/query/frontend/semantic/symbol.hpp src/query/distributed/frontend/semantic/symbol_serialization.hpp src/query/distributed/plan/ops.hpp -src/query/plan/operator.hpp src/raft/log_entry.hpp src/raft/raft_rpc_messages.hpp src/raft/snapshot_metadata.hpp diff --git a/environment/os/amzn-2.sh b/environment/os/amzn-2.sh new file mode 100755 index 000000000..6df12312c --- /dev/null +++ b/environment/os/amzn-2.sh @@ -0,0 +1,156 @@ +#!/bin/bash + +set -Eeuo pipefail + +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +source "$DIR/../util.sh" + +check_operating_system "amzn-2" +check_architecture "x86_64" + +TOOLCHAIN_BUILD_DEPS=( + gcc gcc-c++ make # generic build tools + wget # used for archive download + gnupg2 # used for archive signature verification + tar gzip bzip2 xz unzip # used for archive unpacking + zlib-devel # zlib library used for all builds + expat-devel xz-devel python3-devel texinfo + curl libcurl-devel # for cmake + readline-devel # for cmake and llvm + libffi-devel libxml2-devel # for llvm + libedit-devel pcre-devel automake bison # for swig + file + openssl-devel + gmp-devel + gperf + diffutils + patch + libipt libipt-devel # intel + perl # for openssl +) + +TOOLCHAIN_RUN_DEPS=( + make # generic build tools + tar gzip bzip2 xz # used for archive unpacking + zlib # zlib library used for all builds + expat xz-libs python3 # for gdb + readline # for cmake and llvm + libffi libxml2 # for llvm + openssl-devel +) + +MEMGRAPH_BUILD_DEPS=( + git # source code control + make # build system + wget # for downloading libs + libuuid-devel java-11-openjdk # required by antlr + readline-devel # for memgraph console + python3-devel # for query modules + openssl-devel + libseccomp-devel + python3 python3-pip nmap-ncat # for tests + # + # IMPORTANT: python3-yaml does NOT exist on CentOS + # Install it using `pip3 install PyYAML` + # + PyYAML # Package name here does not correspond to the yum package! + libcurl-devel # mg-requests + rpm-build rpmlint # for RPM package building + doxygen graphviz # source documentation generators + which nodejs golang zip unzip java-11-openjdk-devel # for driver tests + autoconf # for jemalloc code generation + libtool # for protobuf code generation +) + +list() { + echo "$1" +} + +check() { + local missing="" + # On Fedora yum/dnf and python10 use newer glibc which is not compatible + # with ours, so we need to momentarely disable env + local OLD_LD_LIBRARY_PATH=${LD_LIBRARY_PATH:-""} + LD_LIBRARY_PATH="" + for pkg in $1; do + if [ "$pkg" == "PyYAML" ]; then + if ! python3 -c "import yaml" >/dev/null 2>/dev/null; then + missing="$pkg $missing" + fi + continue + fi + if ! yum list installed "$pkg" >/dev/null 2>/dev/null; then + missing="$pkg $missing" + fi + done + if [ "$missing" != "" ]; then + echo "MISSING PACKAGES: $missing" + exit 1 + fi + LD_LIBRARY_PATH=${OLD_LD_LIBRARY_PATH} +} + +install() { + cd "$DIR" + if [ "$EUID" -ne 0 ]; then + echo "Please run as root." + exit 1 + fi + # If GitHub Actions runner is installed, append LANG to the environment. + # Python related tests don't work without the LANG export. + if [ -d "/home/gh/actions-runner" ]; then + echo "LANG=en_US.utf8" >> /home/gh/actions-runner/.env + else + echo "NOTE: export LANG=en_US.utf8" + fi + yum update -y + for pkg in $1; do + if [ "$pkg" == libipt ]; then + if ! yum list installed libipt >/dev/null 2>/dev/null; then + yum install -y http://repo.okay.com.mx/centos/8/x86_64/release/libipt-1.6.1-8.el8.x86_64.rpm + fi + continue + fi + if [ "$pkg" == libipt-devel ]; then + if ! yum list installed libipt-devel >/dev/null 2>/dev/null; then + yum install -y http://repo.okay.com.mx/centos/8/x86_64/release/libipt-devel-1.6.1-8.el8.x86_64.rpm + fi + continue + fi + if [ "$pkg" == nodejs ]; then + curl -sL https://rpm.nodesource.com/setup_16.x | bash - + if ! yum list installed nodejs >/dev/null 2>/dev/null; then + yum install -y nodejs + fi + continue + fi + if [ "$pkg" == PyYAML ]; then + if [ -z ${SUDO_USER+x} ]; then # Running as root (e.g. Docker). + pip3 install --user PyYAML + else # Running using sudo. + sudo -H -u "$SUDO_USER" bash -c "pip3 install --user PyYAML" + fi + continue + fi + if [ "$pkg" == nodejs ]; then + curl -sL https://rpm.nodesource.com/setup_16.x | bash - + if ! yum list installed nodejs >/dev/null 2>/dev/null; then + yum install -y nodejs + fi + continue + fi + if [ "$pkg" == java-11-openjdk ]; then + amazon-linux-extras install -y java-openjdk11 + continue + fi + if [ "$pkg" == java-11-openjdk-devel ]; then + amazon-linux-extras install -y java-openjdk11 + yum install -y java-11-openjdk-devel + continue + fi + yum install -y "$pkg" + done +} + +deps=$2"[*]" +"$1" "${!deps}" diff --git a/environment/toolchain/v4.sh b/environment/toolchain/v4.sh index e3fddaa1f..2ac92441f 100755 --- a/environment/toolchain/v4.sh +++ b/environment/toolchain/v4.sh @@ -415,6 +415,34 @@ if [ ! -f $PREFIX/bin/gdb ]; then --with-intel-pt \ --enable-tui \ --with-python=python3 + elif [[ "${DISTRO}" == "amzn-2" ]]; then + # Remove readline, gdb does not compile + env \ + CC=gcc \ + CXX=g++ \ + CFLAGS="-g -O2 -fstack-protector-strong -Wformat -Werror=format-security" \ + CXXFLAGS="-g -O2 -fstack-protector-strong -Wformat -Werror=format-security" \ + CPPFLAGS="-Wdate-time -D_FORTIFY_SOURCE=2 -fPIC" \ + LDFLAGS="-Wl,-z,relro" \ + PYTHON="" \ + ../configure \ + --build=x86_64-linux-gnu \ + --host=x86_64-linux-gnu \ + --prefix=$PREFIX \ + --disable-maintainer-mode \ + --disable-dependency-tracking \ + --disable-silent-rules \ + --disable-gdbtk \ + --disable-shared \ + --without-guile \ + --with-system-gdbinit=$PREFIX/etc/gdb/gdbinit \ + --with-expat \ + --with-system-zlib \ + --with-lzma \ + --with-babeltrace \ + --with-intel-pt \ + --enable-tui \ + --with-python=python3 else # https://buildd.debian.org/status/fetch.php?pkg=gdb&arch=amd64&ver=8.2.1-2&stamp=1550831554&raw=0 env \ @@ -1143,119 +1171,121 @@ if [ ! -f $PREFIX/include/libaio.h ]; then popd fi -log_tool_name "folly $FBLIBS_VERSION" -if [ ! -d $PREFIX/include/folly ]; then - if [ -d folly-$FBLIBS_VERSION ]; then - rm -rf folly-$FBLIBS_VERSION +if [[ "${DISTRO}" != "amzn-2" ]]; then + log_tool_name "folly $FBLIBS_VERSION" + if [ ! -d $PREFIX/include/folly ]; then + if [ -d folly-$FBLIBS_VERSION ]; then + rm -rf folly-$FBLIBS_VERSION + fi + mkdir folly-$FBLIBS_VERSION + tar -xzf ../archives/folly-$FBLIBS_VERSION.tar.gz -C folly-$FBLIBS_VERSION + pushd folly-$FBLIBS_VERSION + patch -p1 < ../../folly.patch + # build is used by facebook builder + mkdir _build + pushd _build + cmake .. $COMMON_CMAKE_FLAGS \ + -DBOOST_LINK_STATIC=ON \ + -DBUILD_TESTS=OFF \ + -DGFLAGS_NOTHREADS=OFF \ + -DCXX_STD="c++20" + make -j$CPUS install + popd && popd fi - mkdir folly-$FBLIBS_VERSION - tar -xzf ../archives/folly-$FBLIBS_VERSION.tar.gz -C folly-$FBLIBS_VERSION - pushd folly-$FBLIBS_VERSION - patch -p1 < ../../folly.patch - # build is used by facebook builder - mkdir _build - pushd _build - cmake .. $COMMON_CMAKE_FLAGS \ - -DBOOST_LINK_STATIC=ON \ - -DBUILD_TESTS=OFF \ - -DGFLAGS_NOTHREADS=OFF \ - -DCXX_STD="c++20" - make -j$CPUS install - popd && popd -fi -log_tool_name "fizz $FBLIBS_VERSION" -if [ ! -d $PREFIX/include/fizz ]; then - if [ -d fizz-$FBLIBS_VERSION ]; then - rm -rf fizz-$FBLIBS_VERSION + log_tool_name "fizz $FBLIBS_VERSION" + if [ ! -d $PREFIX/include/fizz ]; then + if [ -d fizz-$FBLIBS_VERSION ]; then + rm -rf fizz-$FBLIBS_VERSION + fi + mkdir fizz-$FBLIBS_VERSION + tar -xzf ../archives/fizz-$FBLIBS_VERSION.tar.gz -C fizz-$FBLIBS_VERSION + pushd fizz-$FBLIBS_VERSION + # build is used by facebook builder + mkdir _build + pushd _build + cmake ../fizz $COMMON_CMAKE_FLAGS \ + -DBUILD_TESTS=OFF \ + -DBUILD_EXAMPLES=OFF \ + -DGFLAGS_NOTHREADS=OFF + make -j$CPUS install + popd && popd fi - mkdir fizz-$FBLIBS_VERSION - tar -xzf ../archives/fizz-$FBLIBS_VERSION.tar.gz -C fizz-$FBLIBS_VERSION - pushd fizz-$FBLIBS_VERSION - # build is used by facebook builder - mkdir _build - pushd _build - cmake ../fizz $COMMON_CMAKE_FLAGS \ - -DBUILD_TESTS=OFF \ - -DBUILD_EXAMPLES=OFF \ - -DGFLAGS_NOTHREADS=OFF - make -j$CPUS install - popd && popd -fi -log_tool_name "wangle FBLIBS_VERSION" -if [ ! -d $PREFIX/include/wangle ]; then - if [ -d wangle-$FBLIBS_VERSION ]; then - rm -rf wangle-$FBLIBS_VERSION + log_tool_name "wangle FBLIBS_VERSION" + if [ ! -d $PREFIX/include/wangle ]; then + if [ -d wangle-$FBLIBS_VERSION ]; then + rm -rf wangle-$FBLIBS_VERSION + fi + mkdir wangle-$FBLIBS_VERSION + tar -xzf ../archives/wangle-$FBLIBS_VERSION.tar.gz -C wangle-$FBLIBS_VERSION + pushd wangle-$FBLIBS_VERSION + # build is used by facebook builder + mkdir _build + pushd _build + cmake ../wangle $COMMON_CMAKE_FLAGS \ + -DBUILD_TESTS=OFF \ + -DBUILD_EXAMPLES=OFF \ + -DGFLAGS_NOTHREADS=OFF + make -j$CPUS install + popd && popd fi - mkdir wangle-$FBLIBS_VERSION - tar -xzf ../archives/wangle-$FBLIBS_VERSION.tar.gz -C wangle-$FBLIBS_VERSION - pushd wangle-$FBLIBS_VERSION - # build is used by facebook builder - mkdir _build - pushd _build - cmake ../wangle $COMMON_CMAKE_FLAGS \ - -DBUILD_TESTS=OFF \ - -DBUILD_EXAMPLES=OFF \ - -DGFLAGS_NOTHREADS=OFF - make -j$CPUS install - popd && popd -fi -log_tool_name "proxygen $FBLIBS_VERSION" -if [ ! -d $PREFIX/include/proxygen ]; then - if [ -d proxygen-$FBLIBS_VERSION ]; then - rm -rf proxygen-$FBLIBS_VERSION + log_tool_name "proxygen $FBLIBS_VERSION" + if [ ! -d $PREFIX/include/proxygen ]; then + if [ -d proxygen-$FBLIBS_VERSION ]; then + rm -rf proxygen-$FBLIBS_VERSION + fi + mkdir proxygen-$FBLIBS_VERSION + tar -xzf ../archives/proxygen-$FBLIBS_VERSION.tar.gz -C proxygen-$FBLIBS_VERSION + pushd proxygen-$FBLIBS_VERSION + patch -p1 < ../../proxygen.patch + # build is used by facebook builder + mkdir _build + pushd _build + cmake .. $COMMON_CMAKE_FLAGS \ + -DBUILD_TESTS=OFF \ + -DBUILD_SAMPLES=OFF \ + -DGFLAGS_NOTHREADS=OFF \ + -DBUILD_QUIC=OFF + make -j$CPUS install + popd && popd fi - mkdir proxygen-$FBLIBS_VERSION - tar -xzf ../archives/proxygen-$FBLIBS_VERSION.tar.gz -C proxygen-$FBLIBS_VERSION - pushd proxygen-$FBLIBS_VERSION - patch -p1 < ../../proxygen.patch - # build is used by facebook builder - mkdir _build - pushd _build - cmake .. $COMMON_CMAKE_FLAGS \ - -DBUILD_TESTS=OFF \ - -DBUILD_SAMPLES=OFF \ - -DGFLAGS_NOTHREADS=OFF \ - -DBUILD_QUIC=OFF - make -j$CPUS install - popd && popd -fi -log_tool_name "flex $FBLIBS_VERSION" -if [ ! -f $PREFIX/include/FlexLexer.h ]; then - if [ -d flex-$FLEX_VERSION ]; then - rm -rf flex-$FLEX_VERSION + log_tool_name "flex $FBLIBS_VERSION" + if [ ! -f $PREFIX/include/FlexLexer.h ]; then + if [ -d flex-$FLEX_VERSION ]; then + rm -rf flex-$FLEX_VERSION + fi + tar -xzf ../archives/flex-$FLEX_VERSION.tar.gz + pushd flex-$FLEX_VERSION + ./configure $COMMON_CONFIGURE_FLAGS + make -j$CPUS install + popd fi - tar -xzf ../archives/flex-$FLEX_VERSION.tar.gz - pushd flex-$FLEX_VERSION - ./configure $COMMON_CONFIGURE_FLAGS - make -j$CPUS install - popd -fi -log_tool_name "fbthrift $FBLIBS_VERSION" -if [ ! -d $PREFIX/include/thrift ]; then - if [ -d fbthrift-$FBLIBS_VERSION ]; then - rm -rf fbthrift-$FBLIBS_VERSION + log_tool_name "fbthrift $FBLIBS_VERSION" + if [ ! -d $PREFIX/include/thrift ]; then + if [ -d fbthrift-$FBLIBS_VERSION ]; then + rm -rf fbthrift-$FBLIBS_VERSION + fi + git clone --depth 1 --branch v$FBLIBS_VERSION https://github.com/facebook/fbthrift.git fbthrift-$FBLIBS_VERSION + pushd fbthrift-$FBLIBS_VERSION + # build is used by facebook builder + mkdir _build + pushd _build + if [ "$TOOLCHAIN_STDCXX" = "libstdc++" ]; then + CMAKE_CXX_FLAGS="-fsized-deallocation" + else + CMAKE_CXX_FLAGS="-fsized-deallocation -stdlib=libc++" + fi + cmake .. $COMMON_CMAKE_FLAGS \ + -Denable_tests=OFF \ + -DGFLAGS_NOTHREADS=OFF \ + -DCMAKE_CXX_FLAGS="$CMAKE_CXX_FLAGS" + make -j$CPUS install + popd fi - git clone --depth 1 --branch v$FBLIBS_VERSION https://github.com/facebook/fbthrift.git fbthrift-$FBLIBS_VERSION - pushd fbthrift-$FBLIBS_VERSION - # build is used by facebook builder - mkdir _build - pushd _build - if [ "$TOOLCHAIN_STDCXX" = "libstdc++" ]; then - CMAKE_CXX_FLAGS="-fsized-deallocation" - else - CMAKE_CXX_FLAGS="-fsized-deallocation -stdlib=libc++" - fi - cmake .. $COMMON_CMAKE_FLAGS \ - -Denable_tests=OFF \ - -DGFLAGS_NOTHREADS=OFF \ - -DCMAKE_CXX_FLAGS="$CMAKE_CXX_FLAGS" - make -j$CPUS install - popd fi popd diff --git a/init b/init index a4754fb3e..95a2438eb 100755 --- a/init +++ b/init @@ -14,7 +14,6 @@ function print_help () { echo "Optional arguments:" echo -e " -h\tdisplay this help and exit" echo -e " --without-libs-setup\tskip the step for setting up libs" - echo -e " --wsl-quicklisp-proxy \"host:port\"\tquicklist HTTP proxy (this flag + HTTP proxy are required on WSL)" } function setup_virtualenv () { @@ -35,7 +34,6 @@ function setup_virtualenv () { popd > /dev/null } -wsl_quicklisp_proxy="" setup_libs=true if [[ $# -eq 1 && "$1" == "-h" ]]; then print_help @@ -43,16 +41,6 @@ if [[ $# -eq 1 && "$1" == "-h" ]]; then else while(($#)); do case "$1" in - --wsl-quicklisp-proxy) - shift - if [[ $# -eq 0 ]]; then - echo "Missing proxy URL" - print_help - exit 1 - fi - wsl_quicklisp_proxy=":proxy \"http://$1/\"" - shift - ;; --without-libs-setup) shift setup_libs=false @@ -79,41 +67,16 @@ echo "All packages are in-place..." # create a default build directory mkdir -p ./build -# quicklisp package manager for Common Lisp -quicklisp_install_dir="$HOME/quicklisp" -if [[ -v QUICKLISP_HOME ]]; then - quicklisp_install_dir="${QUICKLISP_HOME}" -fi - -if [[ ! -f "${quicklisp_install_dir}/setup.lisp" ]]; then - wget -nv https://beta.quicklisp.org/quicklisp.lisp -O quicklisp.lisp || exit 1 - echo \ - " - (load \"${DIR}/quicklisp.lisp\") - (quicklisp-quickstart:install $wsl_quicklisp_proxy :path \"${quicklisp_install_dir}\") - " | sbcl --script || exit 1 - rm -rf quicklisp.lisp || exit 1 -fi -ln -Tfs "$DIR/src/lisp" "${quicklisp_install_dir}/local-projects/lcp" -# Install LCP dependencies -# TODO: We should at some point cache or have a mirror of packages we use. -# TODO: move the installation of LCP's dependencies into ./setup.sh -echo \ - " - (load \"${quicklisp_install_dir}/setup.lisp\") - (ql:quickload '(:lcp :lcp/test) :silent t) - " | sbcl --script - if [[ "$setup_libs" == "true" ]]; then - # Setup libs (download). - cd libs - ./cleanup.sh - ./setup.sh - cd .. + # Setup libs (download). + cd libs + ./cleanup.sh + ./setup.sh + cd .. fi # Fix for centos 7 during release -if [ "${DISTRO}" = "centos-7" ] || [ "${DISTRO}" = "debian-11" ]; then +if [ "${DISTRO}" = "centos-7" ] || [ "${DISTRO}" = "debian-11" ] || [ "${DISTRO}" = "amzn-2" ]; then python3 -m pip uninstall -y virtualenv python3 -m pip install virtualenv fi diff --git a/release/CMakeLists.txt b/release/CMakeLists.txt index 489aea989..4bdb4bf69 100644 --- a/release/CMakeLists.txt +++ b/release/CMakeLists.txt @@ -1,6 +1,10 @@ # Install systemd service (must use absolute path). install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/memgraph.service - DESTINATION /lib/systemd/system) + DESTINATION /lib/systemd/system) + +# Set parameters to recognize the host distro +cmake_host_system_information(RESULT DISTRO QUERY DISTRIB_NAME) +cmake_host_system_information(RESULT DISTRO_VERSION QUERY DISTRIB_VERSION) # ---- Setup CPack -------- @@ -12,10 +16,11 @@ set(CPACK_PACKAGE_DESCRIPTION_SUMMARY # Setting arhitecture extension for deb packages set(MG_ARCH_EXTENSION_DEB "all") -if (${MG_ARCH} STREQUAL "x86_64") + +if(${MG_ARCH} STREQUAL "x86_64") set(MG_ARCH_EXTENSION_DEB "amd64") -elseif (${MG_ARCH} STREQUAL "ARM64") - set(MG_ARCH_EXTENSION_DEB "arm64") +elseif(${MG_ARCH} STREQUAL "ARM64") + set(MG_ARCH_EXTENSION_DEB "arm64") endif() # DEB specific @@ -34,21 +39,24 @@ set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_CURRENT_SOURCE_DIR}/debian/postrm;" "${CMAKE_CURRENT_SOURCE_DIR}/debian/postinst;") set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) + # Description formatting is important, summary must be followed with a newline and 1 space. set(CPACK_DEBIAN_PACKAGE_DESCRIPTION "${CPACK_PACKAGE_DESCRIPTION_SUMMARY} Contains Memgraph, the graph database. It aims to deliver developers the speed, simplicity and scale required to build the next generation of applications driver by real-time connected data.") + # Add `openssl` package to dependencies list. Used to generate SSL certificates. # We also depend on `python3` because we embed it in Memgraph. set(CPACK_DEBIAN_PACKAGE_DEPENDS "openssl (>= 1.1.0), python3 (>= 3.5.0), libstdc++6") # Setting arhitecture extension for rpm packages set(MG_ARCH_EXTENSION_RPM "noarch") -if (${MG_ARCH} STREQUAL "x86_64") + +if(${MG_ARCH} STREQUAL "x86_64") set(MG_ARCH_EXTENSION_RPM "x86_64") -elseif (${MG_ARCH} STREQUAL "ARM64") - set(MG_ARCH_EXTENSION_RPM "aarch64") +elseif(${MG_ARCH} STREQUAL "ARM64") + set(MG_ARCH_EXTENSION_RPM "aarch64") endif() # RPM specific @@ -56,18 +64,26 @@ set(CPACK_RPM_PACKAGE_URL https://memgraph.com) set(CPACK_RPM_PACKAGE_VERSION "${MEMGRAPH_VERSION_RPM}") set(CPACK_RPM_FILE_NAME "memgraph-${MEMGRAPH_VERSION_RPM}-1.${MG_ARCH_EXTENSION_RPM}.rpm") set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION - /var /var/lib /var/log /etc/logrotate.d - /lib /lib/systemd /lib/systemd/system /lib/systemd/system/memgraph.service) + /var /var/lib /var/log /etc/logrotate.d + /lib /lib/systemd /lib/systemd/system /lib/systemd/system/memgraph.service) set(CPACK_RPM_PACKAGE_REQUIRES_PRE "shadow-utils") set(CPACK_RPM_USER_BINARY_SPECFILE "${CMAKE_CURRENT_SOURCE_DIR}/rpm/memgraph.spec.in") set(CPACK_RPM_PACKAGE_LICENSE "Memgraph License") + # Description formatting is important, no line must be greater than 80 characters. set(CPACK_RPM_PACKAGE_DESCRIPTION "Contains Memgraph, the graph database. It aims to deliver developers the speed, simplicity and scale required to build the next generation of applications driver by real-time connected data.") + # Add `openssl` package to dependencies list. Used to generate SSL certificates. # We also depend on `python3` because we embed it in Memgraph. -set(CPACK_RPM_PACKAGE_REQUIRES "openssl >= 1.0.0, curl >= 7.29.0, python3 >= 3.5.0, libstdc++ >= 6, logrotate") +set(CPACK_RPM_PACKAGE_REQUIRES "openssl >= 1.0.0, curl >= 7.29.0, python3 >= 3.5.0, libstdc++ >= 3.4.29, logrotate") + +# If amzn-2 +if(DISTRO STREQUAL "Amazon Linux" AND DISTRO_VERSION STREQUAL "2") + # It causes issues with glibcxx 2.4 + set(CPACK_RPM_PACKAGE_AUTOREQ " no") +endif() # All variables must be set before including. include(CPack) diff --git a/release/package/amzn-2/Dockerfile b/release/package/amzn-2/Dockerfile new file mode 100644 index 000000000..3bcc8ad72 --- /dev/null +++ b/release/package/amzn-2/Dockerfile @@ -0,0 +1,14 @@ +FROM amazonlinux:2 + +ARG TOOLCHAIN_VERSION + +RUN yum -y update \ + && yum install -y wget git tar +# Do NOT be smart here and clean the cache because the container is used in the +# stateful context. + +RUN wget -q https://s3-eu-west-1.amazonaws.com/deps.memgraph.io/${TOOLCHAIN_VERSION}/${TOOLCHAIN_VERSION}-binaries-amzn-2-x86_64.tar.gz \ + -O ${TOOLCHAIN_VERSION}-binaries-amzn-2-x86_64.tar.gz \ + && tar xzvf ${TOOLCHAIN_VERSION}-binaries-amzn-2-x86_64.tar.gz -C /opt + +ENTRYPOINT ["sleep", "infinity"] diff --git a/release/package/docker-compose.yml b/release/package/docker-compose.yml index 1f285bf84..4da0526ba 100644 --- a/release/package/docker-compose.yml +++ b/release/package/docker-compose.yml @@ -32,3 +32,7 @@ services: build: context: fedora-36 container_name: "mgbuild_fedora-36" + mgbuild_amzn-2: + build: + context: amzn-2 + container_name: "mgbuild_amzn-2" diff --git a/release/package/run.sh b/release/package/run.sh index 7d068eaa9..cdf95466a 100755 --- a/release/package/run.sh +++ b/release/package/run.sh @@ -3,7 +3,14 @@ set -Eeuo pipefail SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -SUPPORTED_OS=(centos-7 centos-9 debian-10 debian-11 ubuntu-18.04 ubuntu-20.04 ubuntu-22.04 debian-11-arm fedora-36 ubuntu-22.04-arm) +SUPPORTED_OS=( + centos-7 centos-9 + debian-10 debian-11 debian-11-arm + ubuntu-18.04 ubuntu-20.04 ubuntu-22.04 ubuntu-22.04-arm + fedora-36 + amzn-2 +) + PROJECT_ROOT="$SCRIPT_DIR/../.." TOOLCHAIN_VERSION="toolchain-v4" ACTIVATE_TOOLCHAIN="source /opt/${TOOLCHAIN_VERSION}/activate" @@ -23,7 +30,7 @@ make_package () { echo "Building Memgraph for $os on $build_container..." package_command="" - if [[ "$os" =~ ^"centos".* ]] || [[ "$os" =~ ^"fedora".* ]]; then + if [[ "$os" =~ ^"centos".* ]] || [[ "$os" =~ ^"fedora".* ]] || [[ "$os" =~ ^"amzn".* ]]; then docker exec "$build_container" bash -c "yum -y update" package_command=" cpack -G RPM --config ../CPackConfig.cmake && rpmlint --file='../../release/rpm/rpmlintrc' memgraph*.rpm " fi diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d6f58c642..ad1cfd711 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,6 @@ # CMake configuration for the main memgraph library and executable # add memgraph sub libraries, ordered by dependency -add_subdirectory(lisp) add_subdirectory(utils) add_subdirectory(requests) add_subdirectory(io) diff --git a/src/query/CMakeLists.txt b/src/query/CMakeLists.txt index 77a12a430..e7e2bd66e 100644 --- a/src/query/CMakeLists.txt +++ b/src/query/CMakeLists.txt @@ -1,13 +1,7 @@ -define_add_lcp(add_lcp_query lcp_query_cpp_files generated_lcp_query_files) - -add_lcp_query(frontend/ast/ast.lcp) -add_lcp_query(frontend/semantic/symbol.lcp) -add_lcp_query(plan/operator.lcp) - -add_custom_target(generate_lcp_query DEPENDS ${generated_lcp_query_files}) - set(mg_query_sources - ${lcp_query_cpp_files} + frontend/ast/ast.cpp + frontend/semantic/symbol.cpp + plan/operator_type_info.cpp common.cpp cypher_query_interpreter.cpp dump.cpp @@ -46,7 +40,6 @@ set(mg_query_sources find_package(Boost REQUIRED) add_library(mg-query STATIC ${mg_query_sources}) -add_dependencies(mg-query generate_lcp_query) target_include_directories(mg-query PUBLIC ${CMAKE_SOURCE_DIR}/include) target_link_libraries(mg-query dl cppitertools Boost::headers) target_link_libraries(mg-query mg-integrations-pulsar mg-integrations-kafka mg-storage-v2 mg-license mg-utils mg-kvstore mg-memory) diff --git a/src/query/frontend/ast/ast.cpp b/src/query/frontend/ast/ast.cpp new file mode 100644 index 000000000..6dfd4f85c --- /dev/null +++ b/src/query/frontend/ast/ast.cpp @@ -0,0 +1,263 @@ +// Copyright 2023 Memgraph Ltd. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source +// License, and you may not use this file except in compliance with the Business Source License. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +#include "query/frontend/ast/ast.hpp" +#include "utils/typeinfo.hpp" + +namespace memgraph { + +constexpr utils::TypeInfo query::LabelIx::kType{utils::TypeId::AST_LABELIX, "LabelIx", nullptr}; + +constexpr utils::TypeInfo query::PropertyIx::kType{utils::TypeId::AST_PROPERTYIX, "PropertyIx", nullptr}; + +constexpr utils::TypeInfo query::EdgeTypeIx::kType{utils::TypeId::AST_EDGETYPEIX, "EdgeTypeIx", nullptr}; + +constexpr utils::TypeInfo query::Tree::kType{utils::TypeId::AST_TREE, "Tree", nullptr}; + +constexpr utils::TypeInfo query::Expression::kType{utils::TypeId::AST_EXPRESSION, "Expression", &query::Tree::kType}; + +constexpr utils::TypeInfo query::Where::kType{utils::TypeId::AST_WHERE, "Where", &query::Tree::kType}; + +constexpr utils::TypeInfo query::BinaryOperator::kType{utils::TypeId::AST_BINARY_OPERATOR, "BinaryOperator", + &query::Expression::kType}; + +constexpr utils::TypeInfo query::UnaryOperator::kType{utils::TypeId::AST_UNARY_OPERATOR, "UnaryOperator", + &query::Expression::kType}; + +constexpr utils::TypeInfo query::OrOperator::kType{utils::TypeId::AST_OR_OPERATOR, "OrOperator", + &query::BinaryOperator::kType}; + +constexpr utils::TypeInfo query::XorOperator::kType{utils::TypeId::AST_XOR_OPERATOR, "XorOperator", + &query::BinaryOperator::kType}; + +constexpr utils::TypeInfo query::AndOperator::kType{utils::TypeId::AST_AND_OPERATOR, "AndOperator", + &query::BinaryOperator::kType}; + +constexpr utils::TypeInfo query::AdditionOperator::kType{utils::TypeId::AST_ADDITION_OPERATOR, "AdditionOperator", + &query::BinaryOperator::kType}; + +constexpr utils::TypeInfo query::SubtractionOperator::kType{utils::TypeId::AST_SUBTRACTION_OPERATOR, + "SubtractionOperator", &query::BinaryOperator::kType}; + +constexpr utils::TypeInfo query::MultiplicationOperator::kType{utils::TypeId::AST_MULTIPLICATION_OPERATOR, + "MultiplicationOperator", &query::BinaryOperator::kType}; + +constexpr utils::TypeInfo query::DivisionOperator::kType{utils::TypeId::AST_DIVISION_OPERATOR, "DivisionOperator", + &query::BinaryOperator::kType}; + +constexpr utils::TypeInfo query::ModOperator::kType{utils::TypeId::AST_MOD_OPERATOR, "ModOperator", + &query::BinaryOperator::kType}; + +constexpr utils::TypeInfo query::NotEqualOperator::kType{utils::TypeId::AST_NOT_EQUAL_OPERATOR, "NotEqualOperator", + &query::BinaryOperator::kType}; + +constexpr utils::TypeInfo query::EqualOperator::kType{utils::TypeId::AST_EQUAL_OPERATOR, "EqualOperator", + &query::BinaryOperator::kType}; + +constexpr utils::TypeInfo query::LessOperator::kType{utils::TypeId::AST_LESS_OPERATOR, "LessOperator", + &query::BinaryOperator::kType}; + +constexpr utils::TypeInfo query::GreaterOperator::kType{utils::TypeId::AST_GREATER_OPERATOR, "GreaterOperator", + &query::BinaryOperator::kType}; + +constexpr utils::TypeInfo query::LessEqualOperator::kType{utils::TypeId::AST_LESS_EQUAL_OPERATOR, "LessEqualOperator", + &query::BinaryOperator::kType}; + +constexpr utils::TypeInfo query::GreaterEqualOperator::kType{utils::TypeId::AST_GREATER_EQUAL_OPERATOR, + "GreaterEqualOperator", &query::BinaryOperator::kType}; + +constexpr utils::TypeInfo query::InListOperator::kType{utils::TypeId::AST_IN_LIST_OPERATOR, "InListOperator", + &query::BinaryOperator::kType}; + +constexpr utils::TypeInfo query::SubscriptOperator::kType{utils::TypeId::AST_SUBSCRIPT_OPERATOR, "SubscriptOperator", + &query::BinaryOperator::kType}; + +constexpr utils::TypeInfo query::NotOperator::kType{utils::TypeId::AST_NOT_OPERATOR, "NotOperator", + &query::UnaryOperator::kType}; + +constexpr utils::TypeInfo query::UnaryPlusOperator::kType{utils::TypeId::AST_UNARY_PLUS_OPERATOR, "UnaryPlusOperator", + &query::UnaryOperator::kType}; + +constexpr utils::TypeInfo query::UnaryMinusOperator::kType{utils::TypeId::AST_UNARY_MINUS_OPERATOR, + "UnaryMinusOperator", &query::UnaryOperator::kType}; + +constexpr utils::TypeInfo query::IsNullOperator::kType{utils::TypeId::AST_IS_NULL_OPERATOR, "IsNullOperator", + &query::UnaryOperator::kType}; + +constexpr utils::TypeInfo query::Aggregation::kType{utils::TypeId::AST_AGGREGATION, "Aggregation", + &query::BinaryOperator::kType}; + +constexpr utils::TypeInfo query::ListSlicingOperator::kType{utils::TypeId::AST_LIST_SLICING_OPERATOR, + "ListSlicingOperator", &query::Expression::kType}; + +constexpr utils::TypeInfo query::IfOperator::kType{utils::TypeId::AST_IF_OPERATOR, "IfOperator", + &query::Expression::kType}; + +constexpr utils::TypeInfo query::BaseLiteral::kType{utils::TypeId::AST_BASE_LITERAL, "BaseLiteral", + &query::Expression::kType}; + +constexpr utils::TypeInfo query::PrimitiveLiteral::kType{utils::TypeId::AST_PRIMITIVE_LITERAL, "PrimitiveLiteral", + &query::BaseLiteral::kType}; + +constexpr utils::TypeInfo query::ListLiteral::kType{utils::TypeId::AST_LIST_LITERAL, "ListLiteral", + &query::BaseLiteral::kType}; + +constexpr utils::TypeInfo query::MapLiteral::kType{utils::TypeId::AST_MAP_LITERAL, "MapLiteral", + &query::BaseLiteral::kType}; + +constexpr utils::TypeInfo query::Identifier::kType{utils::TypeId::AST_IDENTIFIER, "Identifier", + &query::Expression::kType}; + +constexpr utils::TypeInfo query::PropertyLookup::kType{utils::TypeId::AST_PROPERTY_LOOKUP, "PropertyLookup", + &query::Expression::kType}; + +constexpr utils::TypeInfo query::LabelsTest::kType{utils::TypeId::AST_LABELS_TEST, "LabelsTest", + &query::Expression::kType}; + +constexpr utils::TypeInfo query::Function::kType{utils::TypeId::AST_FUNCTION, "Function", &query::Expression::kType}; + +constexpr utils::TypeInfo query::Reduce::kType{utils::TypeId::AST_REDUCE, "Reduce", &query::Expression::kType}; + +constexpr utils::TypeInfo query::Coalesce::kType{utils::TypeId::AST_COALESCE, "Coalesce", &query::Expression::kType}; + +constexpr utils::TypeInfo query::Extract::kType{utils::TypeId::AST_EXTRACT, "Extract", &query::Expression::kType}; + +constexpr utils::TypeInfo query::All::kType{utils::TypeId::AST_ALL, "All", &query::Expression::kType}; + +constexpr utils::TypeInfo query::Single::kType{utils::TypeId::AST_SINGLE, "Single", &query::Expression::kType}; + +constexpr utils::TypeInfo query::Any::kType{utils::TypeId::AST_ANY, "Any", &query::Expression::kType}; + +constexpr utils::TypeInfo query::None::kType{utils::TypeId::AST_NONE, "None", &query::Expression::kType}; + +constexpr utils::TypeInfo query::ParameterLookup::kType{utils::TypeId::AST_PARAMETER_LOOKUP, "ParameterLookup", + &query::Expression::kType}; + +constexpr utils::TypeInfo query::RegexMatch::kType{utils::TypeId::AST_REGEX_MATCH, "RegexMatch", + &query::Expression::kType}; + +constexpr utils::TypeInfo query::NamedExpression::kType{utils::TypeId::AST_NAMED_EXPRESSION, "NamedExpression", + &query::Tree::kType}; + +constexpr utils::TypeInfo query::PatternAtom::kType{utils::TypeId::AST_PATTERN_ATOM, "PatternAtom", + &query::Tree::kType}; + +constexpr utils::TypeInfo query::NodeAtom::kType{utils::TypeId::AST_NODE_ATOM, "NodeAtom", &query::PatternAtom::kType}; + +constexpr utils::TypeInfo query::EdgeAtom::Lambda::kType{utils::TypeId::AST_EDGE_ATOM_LAMBDA, "Lambda", nullptr}; + +constexpr utils::TypeInfo query::EdgeAtom::kType{utils::TypeId::AST_EDGE_ATOM, "EdgeAtom", &query::PatternAtom::kType}; + +constexpr utils::TypeInfo query::Pattern::kType{utils::TypeId::AST_PATTERN, "Pattern", &query::Tree::kType}; + +constexpr utils::TypeInfo query::Clause::kType{utils::TypeId::AST_CLAUSE, "Clause", &query::Tree::kType}; + +constexpr utils::TypeInfo query::SingleQuery::kType{utils::TypeId::AST_SINGLE_QUERY, "SingleQuery", + &query::Tree::kType}; + +constexpr utils::TypeInfo query::CypherUnion::kType{utils::TypeId::AST_CYPHER_UNION, "CypherUnion", + &query::Tree::kType}; + +constexpr utils::TypeInfo query::Query::kType{utils::TypeId::AST_QUERY, "Query", &query::Tree::kType}; + +constexpr utils::TypeInfo query::CypherQuery::kType{utils::TypeId::AST_CYPHER_QUERY, "CypherQuery", + &query::Query::kType}; + +constexpr utils::TypeInfo query::ExplainQuery::kType{utils::TypeId::AST_EXPLAIN_QUERY, "ExplainQuery", + &query::Query::kType}; + +constexpr utils::TypeInfo query::ProfileQuery::kType{utils::TypeId::AST_PROFILE_QUERY, "ProfileQuery", + &query::Query::kType}; + +constexpr utils::TypeInfo query::IndexQuery::kType{utils::TypeId::AST_INDEX_QUERY, "IndexQuery", &query::Query::kType}; + +constexpr utils::TypeInfo query::Create::kType{utils::TypeId::AST_CREATE, "Create", &query::Clause::kType}; + +constexpr utils::TypeInfo query::CallProcedure::kType{utils::TypeId::AST_CALL_PROCEDURE, "CallProcedure", + &query::Clause::kType}; + +constexpr utils::TypeInfo query::Match::kType{utils::TypeId::AST_MATCH, "Match", &query::Clause::kType}; + +constexpr utils::TypeInfo query::SortItem::kType{utils::TypeId::AST_SORT_ITEM, "SortItem", nullptr}; + +constexpr utils::TypeInfo query::ReturnBody::kType{utils::TypeId::AST_RETURN_BODY, "ReturnBody", nullptr}; + +constexpr utils::TypeInfo query::Return::kType{utils::TypeId::AST_RETURN, "Return", &query::Clause::kType}; + +constexpr utils::TypeInfo query::With::kType{utils::TypeId::AST_WITH, "With", &query::Clause::kType}; + +constexpr utils::TypeInfo query::Delete::kType{utils::TypeId::AST_DELETE, "Delete", &query::Clause::kType}; + +constexpr utils::TypeInfo query::SetProperty::kType{utils::TypeId::AST_SET_PROPERTY, "SetProperty", + &query::Clause::kType}; + +constexpr utils::TypeInfo query::SetProperties::kType{utils::TypeId::AST_SET_PROPERTIES, "SetProperties", + &query::Clause::kType}; + +constexpr utils::TypeInfo query::SetLabels::kType{utils::TypeId::AST_SET_LABELS, "SetLabels", &query::Clause::kType}; + +constexpr utils::TypeInfo query::RemoveProperty::kType{utils::TypeId::AST_REMOVE_PROPERTY, "RemoveProperty", + &query::Clause::kType}; + +constexpr utils::TypeInfo query::RemoveLabels::kType{utils::TypeId::AST_REMOVE_LABELS, "RemoveLabels", + &query::Clause::kType}; + +constexpr utils::TypeInfo query::Merge::kType{utils::TypeId::AST_MERGE, "Merge", &query::Clause::kType}; + +constexpr utils::TypeInfo query::Unwind::kType{utils::TypeId::AST_UNWIND, "Unwind", &query::Clause::kType}; + +constexpr utils::TypeInfo query::AuthQuery::kType{utils::TypeId::AST_AUTH_QUERY, "AuthQuery", &query::Query::kType}; + +constexpr utils::TypeInfo query::InfoQuery::kType{utils::TypeId::AST_INFO_QUERY, "InfoQuery", &query::Query::kType}; + +constexpr utils::TypeInfo query::Constraint::kType{utils::TypeId::AST_CONSTRAINT, "Constraint", nullptr}; + +constexpr utils::TypeInfo query::ConstraintQuery::kType{utils::TypeId::AST_CONSTRAINT_QUERY, "ConstraintQuery", + &query::Query::kType}; + +constexpr utils::TypeInfo query::DumpQuery::kType{utils::TypeId::AST_DUMP_QUERY, "DumpQuery", &query::Query::kType}; + +constexpr utils::TypeInfo query::ReplicationQuery::kType{utils::TypeId::AST_REPLICATION_QUERY, "ReplicationQuery", + &query::Query::kType}; + +constexpr utils::TypeInfo query::LockPathQuery::kType{utils::TypeId::AST_LOCK_PATH_QUERY, "LockPathQuery", + &query::Query::kType}; + +constexpr utils::TypeInfo query::LoadCsv::kType{utils::TypeId::AST_LOAD_CSV, "LoadCsv", &query::Clause::kType}; + +constexpr utils::TypeInfo query::FreeMemoryQuery::kType{utils::TypeId::AST_FREE_MEMORY_QUERY, "FreeMemoryQuery", + &query::Query::kType}; + +constexpr utils::TypeInfo query::TriggerQuery::kType{utils::TypeId::AST_TRIGGER_QUERY, "TriggerQuery", + &query::Query::kType}; + +constexpr utils::TypeInfo query::IsolationLevelQuery::kType{utils::TypeId::AST_ISOLATION_LEVEL_QUERY, + "IsolationLevelQuery", &query::Query::kType}; + +constexpr utils::TypeInfo query::CreateSnapshotQuery::kType{utils::TypeId::AST_CREATE_SNAPSHOT_QUERY, + "CreateSnapshotQuery", &query::Query::kType}; + +constexpr utils::TypeInfo query::StreamQuery::kType{utils::TypeId::AST_STREAM_QUERY, "StreamQuery", + &query::Query::kType}; + +constexpr utils::TypeInfo query::SettingQuery::kType{utils::TypeId::AST_SETTING_QUERY, "SettingQuery", + &query::Query::kType}; + +constexpr utils::TypeInfo query::VersionQuery::kType{utils::TypeId::AST_VERSION_QUERY, "VersionQuery", + &query::Query::kType}; + +constexpr utils::TypeInfo query::Foreach::kType{utils::TypeId::AST_FOREACH, "Foreach", &query::Clause::kType}; + +constexpr utils::TypeInfo query::ShowConfigQuery::kType{utils::TypeId::AST_SHOW_CONFIG_QUERY, "ShowConfigQuery", + &query::Query::kType}; + +constexpr utils::TypeInfo query::Exists::kType{utils::TypeId::AST_EXISTS, "Exists", &query::Expression::kType}; +} // namespace memgraph diff --git a/src/query/frontend/ast/ast.hpp b/src/query/frontend/ast/ast.hpp new file mode 100644 index 000000000..e27717a2c --- /dev/null +++ b/src/query/frontend/ast/ast.hpp @@ -0,0 +1,3246 @@ +// Copyright 2023 Memgraph Ltd. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source +// License, and you may not use this file except in compliance with the Business Source License. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +#pragma once + +#include +#include +#include +#include + +#include "query/frontend/ast/ast_visitor.hpp" +#include "query/frontend/semantic/symbol.hpp" +#include "query/interpret/awesome_memgraph_functions.hpp" +#include "query/typed_value.hpp" +#include "storage/v2/property_value.hpp" +#include "utils/typeinfo.hpp" + +namespace memgraph { + +namespace query { + +struct LabelIx { + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const { return kType; } + + std::string name; + int64_t ix; +}; + +struct PropertyIx { + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const { return kType; } + + std::string name; + int64_t ix; +}; + +struct EdgeTypeIx { + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const { return kType; } + + std::string name; + int64_t ix; +}; + +inline bool operator==(const LabelIx &a, const LabelIx &b) { return a.ix == b.ix && a.name == b.name; } + +inline bool operator!=(const LabelIx &a, const LabelIx &b) { return !(a == b); } + +inline bool operator==(const PropertyIx &a, const PropertyIx &b) { return a.ix == b.ix && a.name == b.name; } + +inline bool operator!=(const PropertyIx &a, const PropertyIx &b) { return !(a == b); } + +inline bool operator==(const EdgeTypeIx &a, const EdgeTypeIx &b) { return a.ix == b.ix && a.name == b.name; } + +inline bool operator!=(const EdgeTypeIx &a, const EdgeTypeIx &b) { return !(a == b); } +} // namespace query +} // namespace memgraph +namespace std { + +template <> +struct hash { + size_t operator()(const memgraph::query::LabelIx &label) const { return label.ix; } +}; + +template <> +struct hash { + size_t operator()(const memgraph::query::PropertyIx &prop) const { return prop.ix; } +}; + +template <> +struct hash { + size_t operator()(const memgraph::query::EdgeTypeIx &edge_type) const { return edge_type.ix; } +}; + +} // namespace std + +namespace memgraph { + +namespace query { + +class Tree; + +// It would be better to call this AstTree, but we already have a class Tree, +// which could be renamed to Node or AstTreeNode, but we also have a class +// called NodeAtom... +class AstStorage { + public: + AstStorage() = default; + AstStorage(const AstStorage &) = delete; + AstStorage &operator=(const AstStorage &) = delete; + AstStorage(AstStorage &&) = default; + AstStorage &operator=(AstStorage &&) = default; + + template + T *Create(Args &&...args) { + T *ptr = new T(std::forward(args)...); + std::unique_ptr tmp(ptr); + storage_.emplace_back(std::move(tmp)); + return ptr; + } + + LabelIx GetLabelIx(const std::string &name) { return LabelIx{name, FindOrAddName(name, &labels_)}; } + + PropertyIx GetPropertyIx(const std::string &name) { return PropertyIx{name, FindOrAddName(name, &properties_)}; } + + EdgeTypeIx GetEdgeTypeIx(const std::string &name) { return EdgeTypeIx{name, FindOrAddName(name, &edge_types_)}; } + + std::vector labels_; + std::vector edge_types_; + std::vector properties_; + + // Public only for serialization access + std::vector> storage_; + + private: + int64_t FindOrAddName(const std::string &name, std::vector *names) { + for (int64_t i = 0; i < names->size(); ++i) { + if ((*names)[i] == name) { + return i; + } + } + names->push_back(name); + return names->size() - 1; + } +}; + +class Tree { + public: + static const utils::TypeInfo kType; + virtual const utils::TypeInfo &GetTypeInfo() const { return kType; } + + Tree() = default; + virtual ~Tree() {} + + virtual Tree *Clone(AstStorage *storage) const = 0; + + private: + friend class AstStorage; +}; + +class Expression : public memgraph::query::Tree, + public utils::Visitable, + public utils::Visitable>, + public utils::Visitable>, + public utils::Visitable> { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + using utils::Visitable::Accept; + using utils::Visitable>::Accept; + using utils::Visitable>::Accept; + using utils::Visitable>::Accept; + + Expression() = default; + + Expression *Clone(AstStorage *storage) const override = 0; + + private: + friend class AstStorage; +}; + +class Where : public memgraph::query::Tree, public utils::Visitable { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + using utils::Visitable::Accept; + + Where() = default; + + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + expression_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + memgraph::query::Expression *expression_{nullptr}; + + Where *Clone(AstStorage *storage) const override { + Where *object = storage->Create(); + object->expression_ = expression_ ? expression_->Clone(storage) : nullptr; + return object; + } + + protected: + explicit Where(Expression *expression) : expression_(expression) {} + + private: + friend class AstStorage; +}; + +class BinaryOperator : public memgraph::query::Expression { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + BinaryOperator() = default; + + memgraph::query::Expression *expression1_{nullptr}; + memgraph::query::Expression *expression2_{nullptr}; + + BinaryOperator *Clone(AstStorage *storage) const override = 0; + + protected: + BinaryOperator(Expression *expression1, Expression *expression2) + : expression1_(expression1), expression2_(expression2) {} + + private: + friend class AstStorage; +}; + +class UnaryOperator : public memgraph::query::Expression { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + UnaryOperator() = default; + + memgraph::query::Expression *expression_{nullptr}; + + UnaryOperator *Clone(AstStorage *storage) const override = 0; + + protected: + explicit UnaryOperator(Expression *expression) : expression_(expression) {} + + private: + friend class AstStorage; +}; + +class OrOperator : public memgraph::query::BinaryOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + expression1_->Accept(visitor) && expression2_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + OrOperator *Clone(AstStorage *storage) const override { + OrOperator *object = storage->Create(); + object->expression1_ = expression1_ ? expression1_->Clone(storage) : nullptr; + object->expression2_ = expression2_ ? expression2_->Clone(storage) : nullptr; + return object; + } + + protected: + using BinaryOperator::BinaryOperator; + + private: + friend class AstStorage; +}; + +class XorOperator : public memgraph::query::BinaryOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + expression1_->Accept(visitor) && expression2_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + XorOperator *Clone(AstStorage *storage) const override { + XorOperator *object = storage->Create(); + object->expression1_ = expression1_ ? expression1_->Clone(storage) : nullptr; + object->expression2_ = expression2_ ? expression2_->Clone(storage) : nullptr; + return object; + } + + protected: + using BinaryOperator::BinaryOperator; + + private: + friend class AstStorage; +}; + +class AndOperator : public memgraph::query::BinaryOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + expression1_->Accept(visitor) && expression2_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + AndOperator *Clone(AstStorage *storage) const override { + AndOperator *object = storage->Create(); + object->expression1_ = expression1_ ? expression1_->Clone(storage) : nullptr; + object->expression2_ = expression2_ ? expression2_->Clone(storage) : nullptr; + return object; + } + + protected: + using BinaryOperator::BinaryOperator; + + private: + friend class AstStorage; +}; + +class AdditionOperator : public memgraph::query::BinaryOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + expression1_->Accept(visitor) && expression2_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + AdditionOperator *Clone(AstStorage *storage) const override { + AdditionOperator *object = storage->Create(); + object->expression1_ = expression1_ ? expression1_->Clone(storage) : nullptr; + object->expression2_ = expression2_ ? expression2_->Clone(storage) : nullptr; + return object; + } + + protected: + using BinaryOperator::BinaryOperator; + + private: + friend class AstStorage; +}; + +class SubtractionOperator : public memgraph::query::BinaryOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + expression1_->Accept(visitor) && expression2_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + SubtractionOperator *Clone(AstStorage *storage) const override { + SubtractionOperator *object = storage->Create(); + object->expression1_ = expression1_ ? expression1_->Clone(storage) : nullptr; + object->expression2_ = expression2_ ? expression2_->Clone(storage) : nullptr; + return object; + } + + protected: + using BinaryOperator::BinaryOperator; + + private: + friend class AstStorage; +}; + +class MultiplicationOperator : public memgraph::query::BinaryOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + expression1_->Accept(visitor) && expression2_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + MultiplicationOperator *Clone(AstStorage *storage) const override { + MultiplicationOperator *object = storage->Create(); + object->expression1_ = expression1_ ? expression1_->Clone(storage) : nullptr; + object->expression2_ = expression2_ ? expression2_->Clone(storage) : nullptr; + return object; + } + + protected: + using BinaryOperator::BinaryOperator; + + private: + friend class AstStorage; +}; + +class DivisionOperator : public memgraph::query::BinaryOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + expression1_->Accept(visitor) && expression2_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + DivisionOperator *Clone(AstStorage *storage) const override { + DivisionOperator *object = storage->Create(); + object->expression1_ = expression1_ ? expression1_->Clone(storage) : nullptr; + object->expression2_ = expression2_ ? expression2_->Clone(storage) : nullptr; + return object; + } + + protected: + using BinaryOperator::BinaryOperator; + + private: + friend class AstStorage; +}; + +class ModOperator : public memgraph::query::BinaryOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + expression1_->Accept(visitor) && expression2_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + ModOperator *Clone(AstStorage *storage) const override { + ModOperator *object = storage->Create(); + object->expression1_ = expression1_ ? expression1_->Clone(storage) : nullptr; + object->expression2_ = expression2_ ? expression2_->Clone(storage) : nullptr; + return object; + } + + protected: + using BinaryOperator::BinaryOperator; + + private: + friend class AstStorage; +}; + +class NotEqualOperator : public memgraph::query::BinaryOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + expression1_->Accept(visitor) && expression2_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + NotEqualOperator *Clone(AstStorage *storage) const override { + NotEqualOperator *object = storage->Create(); + object->expression1_ = expression1_ ? expression1_->Clone(storage) : nullptr; + object->expression2_ = expression2_ ? expression2_->Clone(storage) : nullptr; + return object; + } + + protected: + using BinaryOperator::BinaryOperator; + + private: + friend class AstStorage; +}; + +class EqualOperator : public memgraph::query::BinaryOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + expression1_->Accept(visitor) && expression2_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + EqualOperator *Clone(AstStorage *storage) const override { + EqualOperator *object = storage->Create(); + object->expression1_ = expression1_ ? expression1_->Clone(storage) : nullptr; + object->expression2_ = expression2_ ? expression2_->Clone(storage) : nullptr; + return object; + } + + protected: + using BinaryOperator::BinaryOperator; + + private: + friend class AstStorage; +}; + +class LessOperator : public memgraph::query::BinaryOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + expression1_->Accept(visitor) && expression2_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + LessOperator *Clone(AstStorage *storage) const override { + LessOperator *object = storage->Create(); + object->expression1_ = expression1_ ? expression1_->Clone(storage) : nullptr; + object->expression2_ = expression2_ ? expression2_->Clone(storage) : nullptr; + return object; + } + + protected: + using BinaryOperator::BinaryOperator; + + private: + friend class AstStorage; +}; + +class GreaterOperator : public memgraph::query::BinaryOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + expression1_->Accept(visitor) && expression2_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + GreaterOperator *Clone(AstStorage *storage) const override { + GreaterOperator *object = storage->Create(); + object->expression1_ = expression1_ ? expression1_->Clone(storage) : nullptr; + object->expression2_ = expression2_ ? expression2_->Clone(storage) : nullptr; + return object; + } + + protected: + using BinaryOperator::BinaryOperator; + + private: + friend class AstStorage; +}; + +class LessEqualOperator : public memgraph::query::BinaryOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + expression1_->Accept(visitor) && expression2_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + LessEqualOperator *Clone(AstStorage *storage) const override { + LessEqualOperator *object = storage->Create(); + object->expression1_ = expression1_ ? expression1_->Clone(storage) : nullptr; + object->expression2_ = expression2_ ? expression2_->Clone(storage) : nullptr; + return object; + } + + protected: + using BinaryOperator::BinaryOperator; + + private: + friend class AstStorage; +}; + +class GreaterEqualOperator : public memgraph::query::BinaryOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + expression1_->Accept(visitor) && expression2_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + GreaterEqualOperator *Clone(AstStorage *storage) const override { + GreaterEqualOperator *object = storage->Create(); + object->expression1_ = expression1_ ? expression1_->Clone(storage) : nullptr; + object->expression2_ = expression2_ ? expression2_->Clone(storage) : nullptr; + return object; + } + + protected: + using BinaryOperator::BinaryOperator; + + private: + friend class AstStorage; +}; + +class InListOperator : public memgraph::query::BinaryOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + expression1_->Accept(visitor) && expression2_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + InListOperator *Clone(AstStorage *storage) const override { + InListOperator *object = storage->Create(); + object->expression1_ = expression1_ ? expression1_->Clone(storage) : nullptr; + object->expression2_ = expression2_ ? expression2_->Clone(storage) : nullptr; + return object; + } + + protected: + using BinaryOperator::BinaryOperator; + + private: + friend class AstStorage; +}; + +class SubscriptOperator : public memgraph::query::BinaryOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + expression1_->Accept(visitor) && expression2_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + SubscriptOperator *Clone(AstStorage *storage) const override { + SubscriptOperator *object = storage->Create(); + object->expression1_ = expression1_ ? expression1_->Clone(storage) : nullptr; + object->expression2_ = expression2_ ? expression2_->Clone(storage) : nullptr; + return object; + } + + protected: + using BinaryOperator::BinaryOperator; + + private: + friend class AstStorage; +}; + +class NotOperator : public memgraph::query::UnaryOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + expression_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + NotOperator *Clone(AstStorage *storage) const override { + NotOperator *object = storage->Create(); + object->expression_ = expression_ ? expression_->Clone(storage) : nullptr; + return object; + } + + protected: + using UnaryOperator::UnaryOperator; + + private: + friend class AstStorage; +}; + +class UnaryPlusOperator : public memgraph::query::UnaryOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + expression_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + UnaryPlusOperator *Clone(AstStorage *storage) const override { + UnaryPlusOperator *object = storage->Create(); + object->expression_ = expression_ ? expression_->Clone(storage) : nullptr; + return object; + } + + protected: + using UnaryOperator::UnaryOperator; + + private: + friend class AstStorage; +}; + +class UnaryMinusOperator : public memgraph::query::UnaryOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + expression_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + UnaryMinusOperator *Clone(AstStorage *storage) const override { + UnaryMinusOperator *object = storage->Create(); + object->expression_ = expression_ ? expression_->Clone(storage) : nullptr; + return object; + } + + protected: + using UnaryOperator::UnaryOperator; + + private: + friend class AstStorage; +}; + +class IsNullOperator : public memgraph::query::UnaryOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + expression_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + IsNullOperator *Clone(AstStorage *storage) const override { + IsNullOperator *object = storage->Create(); + object->expression_ = expression_ ? expression_->Clone(storage) : nullptr; + return object; + } + + protected: + using UnaryOperator::UnaryOperator; + + private: + friend class AstStorage; +}; + +class Aggregation : public memgraph::query::BinaryOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + enum class Op { COUNT, MIN, MAX, SUM, AVG, COLLECT_LIST, COLLECT_MAP, PROJECT }; + + Aggregation() = default; + + static const constexpr char *const kCount = "COUNT"; + static const constexpr char *const kMin = "MIN"; + static const constexpr char *const kMax = "MAX"; + static const constexpr char *const kSum = "SUM"; + static const constexpr char *const kAvg = "AVG"; + static const constexpr char *const kCollect = "COLLECT"; + static const constexpr char *const kProject = "PROJECT"; + + static std::string OpToString(Op op) { + const char *op_strings[] = {kCount, kMin, kMax, kSum, kAvg, kCollect, kCollect, kProject}; + return op_strings[static_cast(op)]; + } + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + if (expression1_) expression1_->Accept(visitor); + if (expression2_) expression2_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + Aggregation *MapTo(const Symbol &symbol) { + symbol_pos_ = symbol.position(); + return this; + } + + memgraph::query::Aggregation::Op op_; + /// Symbol table position of the symbol this Aggregation is mapped to. + int32_t symbol_pos_{-1}; + bool distinct_{false}; + + Aggregation *Clone(AstStorage *storage) const override { + Aggregation *object = storage->Create(); + object->expression1_ = expression1_ ? expression1_->Clone(storage) : nullptr; + object->expression2_ = expression2_ ? expression2_->Clone(storage) : nullptr; + object->op_ = op_; + object->symbol_pos_ = symbol_pos_; + object->distinct_ = distinct_; + return object; + } + + protected: + // Use only for serialization. + explicit Aggregation(Op op) : op_(op) {} + + /// Aggregation's first expression is the value being aggregated. The second + /// expression is the key used only in COLLECT_MAP. + Aggregation(Expression *expression1, Expression *expression2, Op op, bool distinct) + : BinaryOperator(expression1, expression2), op_(op), distinct_(distinct) { + // COUNT without expression denotes COUNT(*) in cypher. + DMG_ASSERT(expression1 || op == Aggregation::Op::COUNT, "All aggregations, except COUNT require expression"); + DMG_ASSERT((expression2 == nullptr) ^ (op == Aggregation::Op::COLLECT_MAP), + "The second expression is obligatory in COLLECT_MAP and " + "invalid otherwise"); + } + + private: + friend class AstStorage; +}; + +class ListSlicingOperator : public memgraph::query::Expression { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + ListSlicingOperator() = default; + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + bool cont = list_->Accept(visitor); + if (cont && lower_bound_) { + cont = lower_bound_->Accept(visitor); + } + if (cont && upper_bound_) { + upper_bound_->Accept(visitor); + } + } + return visitor.PostVisit(*this); + } + + memgraph::query::Expression *list_{nullptr}; + memgraph::query::Expression *lower_bound_{nullptr}; + memgraph::query::Expression *upper_bound_{nullptr}; + + ListSlicingOperator *Clone(AstStorage *storage) const override { + ListSlicingOperator *object = storage->Create(); + object->list_ = list_ ? list_->Clone(storage) : nullptr; + object->lower_bound_ = lower_bound_ ? lower_bound_->Clone(storage) : nullptr; + object->upper_bound_ = upper_bound_ ? upper_bound_->Clone(storage) : nullptr; + return object; + } + + protected: + ListSlicingOperator(Expression *list, Expression *lower_bound, Expression *upper_bound) + : list_(list), lower_bound_(lower_bound), upper_bound_(upper_bound) {} + + private: + friend class AstStorage; +}; + +class IfOperator : public memgraph::query::Expression { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + IfOperator() = default; + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + condition_->Accept(visitor) && then_expression_->Accept(visitor) && else_expression_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + /// None of the expressions should be nullptr. If there is no else_expression, you should make it null + /// PrimitiveLiteral. + memgraph::query::Expression *condition_; + memgraph::query::Expression *then_expression_; + memgraph::query::Expression *else_expression_; + + IfOperator *Clone(AstStorage *storage) const override { + IfOperator *object = storage->Create(); + object->condition_ = condition_ ? condition_->Clone(storage) : nullptr; + object->then_expression_ = then_expression_ ? then_expression_->Clone(storage) : nullptr; + object->else_expression_ = else_expression_ ? else_expression_->Clone(storage) : nullptr; + return object; + } + + protected: + IfOperator(Expression *condition, Expression *then_expression, Expression *else_expression) + : condition_(condition), then_expression_(then_expression), else_expression_(else_expression) {} + + private: + friend class AstStorage; +}; + +class BaseLiteral : public memgraph::query::Expression { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + BaseLiteral() = default; + + BaseLiteral *Clone(AstStorage *storage) const override = 0; + + private: + friend class AstStorage; +}; + +class PrimitiveLiteral : public memgraph::query::BaseLiteral { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + PrimitiveLiteral() = default; + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(HierarchicalTreeVisitor); + + storage::PropertyValue value_; + /// This field contains token position of literal used to create PrimitiveLiteral object. If PrimitiveLiteral object + /// is not created from query, leave its value at -1. + int32_t token_position_{-1}; + + PrimitiveLiteral *Clone(AstStorage *storage) const override { + PrimitiveLiteral *object = storage->Create(); + object->value_ = value_; + object->token_position_ = token_position_; + return object; + } + + protected: + template + explicit PrimitiveLiteral(T value) : value_(value) {} + template + PrimitiveLiteral(T value, int token_position) : value_(value), token_position_(token_position) {} + + private: + friend class AstStorage; +}; + +class ListLiteral : public memgraph::query::BaseLiteral { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + ListLiteral() = default; + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + for (auto expr_ptr : elements_) + if (!expr_ptr->Accept(visitor)) break; + } + return visitor.PostVisit(*this); + } + + std::vector elements_; + + ListLiteral *Clone(AstStorage *storage) const override { + ListLiteral *object = storage->Create(); + object->elements_.resize(elements_.size()); + for (auto i0 = 0; i0 < elements_.size(); ++i0) { + object->elements_[i0] = elements_[i0] ? elements_[i0]->Clone(storage) : nullptr; + } + return object; + } + + protected: + explicit ListLiteral(const std::vector &elements) : elements_(elements) {} + + private: + friend class AstStorage; +}; + +class MapLiteral : public memgraph::query::BaseLiteral { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + MapLiteral() = default; + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + for (auto pair : elements_) + if (!pair.second->Accept(visitor)) break; + } + return visitor.PostVisit(*this); + } + + std::unordered_map elements_; + + MapLiteral *Clone(AstStorage *storage) const override { + MapLiteral *object = storage->Create(); + for (const auto &entry : elements_) { + PropertyIx key = storage->GetPropertyIx(entry.first.name); + object->elements_[key] = entry.second->Clone(storage); + } + return object; + } + + protected: + explicit MapLiteral(const std::unordered_map &elements) : elements_(elements) {} + + private: + friend class AstStorage; +}; + +class Identifier : public memgraph::query::Expression { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + Identifier() = default; + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(HierarchicalTreeVisitor); + + Identifier *MapTo(const Symbol &symbol) { + symbol_pos_ = symbol.position(); + return this; + } + + explicit Identifier(const std::string &name) : name_(name) {} + Identifier(const std::string &name, bool user_declared) : name_(name), user_declared_(user_declared) {} + + std::string name_; + bool user_declared_{true}; + /// Symbol table position of the symbol this Identifier is mapped to. + int32_t symbol_pos_{-1}; + + Identifier *Clone(AstStorage *storage) const override { + Identifier *object = storage->Create(); + object->name_ = name_; + object->user_declared_ = user_declared_; + object->symbol_pos_ = symbol_pos_; + return object; + } + + private: + friend class AstStorage; +}; + +class PropertyLookup : public memgraph::query::Expression { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + PropertyLookup() = default; + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + expression_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + memgraph::query::Expression *expression_{nullptr}; + memgraph::query::PropertyIx property_; + + PropertyLookup *Clone(AstStorage *storage) const override { + PropertyLookup *object = storage->Create(); + object->expression_ = expression_ ? expression_->Clone(storage) : nullptr; + object->property_ = storage->GetPropertyIx(property_.name); + return object; + } + + protected: + PropertyLookup(Expression *expression, PropertyIx property) : expression_(expression), property_(property) {} + + private: + friend class AstStorage; +}; + +class LabelsTest : public memgraph::query::Expression { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + LabelsTest() = default; + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + expression_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + memgraph::query::Expression *expression_{nullptr}; + std::vector labels_; + + LabelsTest *Clone(AstStorage *storage) const override { + LabelsTest *object = storage->Create(); + object->expression_ = expression_ ? expression_->Clone(storage) : nullptr; + object->labels_.resize(labels_.size()); + for (auto i = 0; i < object->labels_.size(); ++i) { + object->labels_[i] = storage->GetLabelIx(labels_[i].name); + } + return object; + } + + protected: + LabelsTest(Expression *expression, const std::vector &labels) : expression_(expression), labels_(labels) {} + + private: + friend class AstStorage; +}; + +class Function : public memgraph::query::Expression { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + Function() = default; + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + for (auto *argument : arguments_) { + if (!argument->Accept(visitor)) break; + } + } + return visitor.PostVisit(*this); + } + + std::vector arguments_; + std::string function_name_; + std::function function_; + + Function *Clone(AstStorage *storage) const override { + Function *object = storage->Create(); + object->arguments_.resize(arguments_.size()); + for (auto i1 = 0; i1 < arguments_.size(); ++i1) { + object->arguments_[i1] = arguments_[i1] ? arguments_[i1]->Clone(storage) : nullptr; + } + object->function_name_ = function_name_; + object->function_ = function_; + return object; + } + + protected: + Function(const std::string &function_name, const std::vector &arguments) + : arguments_(arguments), function_name_(function_name), function_(NameToFunction(function_name_)) { + if (!function_) { + throw SemanticException("Function '{}' doesn't exist.", function_name); + } + } + + private: + friend class AstStorage; +}; + +class Reduce : public memgraph::query::Expression { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + Reduce() = default; + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + accumulator_->Accept(visitor) && initializer_->Accept(visitor) && identifier_->Accept(visitor) && + list_->Accept(visitor) && expression_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + /// Identifier for the accumulating variable + memgraph::query::Identifier *accumulator_{nullptr}; + /// Expression which produces the initial accumulator value. + memgraph::query::Expression *initializer_{nullptr}; + /// Identifier for the list element. + memgraph::query::Identifier *identifier_{nullptr}; + /// Expression which produces a list to be reduced. + memgraph::query::Expression *list_{nullptr}; + /// Expression which does the reduction, i.e. produces the new accumulator value. + memgraph::query::Expression *expression_{nullptr}; + + Reduce *Clone(AstStorage *storage) const override { + Reduce *object = storage->Create(); + object->accumulator_ = accumulator_ ? accumulator_->Clone(storage) : nullptr; + object->initializer_ = initializer_ ? initializer_->Clone(storage) : nullptr; + object->identifier_ = identifier_ ? identifier_->Clone(storage) : nullptr; + object->list_ = list_ ? list_->Clone(storage) : nullptr; + object->expression_ = expression_ ? expression_->Clone(storage) : nullptr; + return object; + } + + protected: + Reduce(Identifier *accumulator, Expression *initializer, Identifier *identifier, Expression *list, + Expression *expression) + : accumulator_(accumulator), + initializer_(initializer), + identifier_(identifier), + list_(list), + expression_(expression) {} + + private: + friend class AstStorage; +}; + +class Coalesce : public memgraph::query::Expression { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + Coalesce() = default; + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + for (auto *expr : expressions_) { + if (!expr->Accept(visitor)) break; + } + } + return visitor.PostVisit(*this); + } + + /// A list of expressions to evaluate. None of the expressions should be nullptr. + std::vector expressions_; + + Coalesce *Clone(AstStorage *storage) const override { + Coalesce *object = storage->Create(); + object->expressions_.resize(expressions_.size()); + for (auto i2 = 0; i2 < expressions_.size(); ++i2) { + object->expressions_[i2] = expressions_[i2] ? expressions_[i2]->Clone(storage) : nullptr; + } + return object; + } + + private: + explicit Coalesce(const std::vector &expressions) : expressions_(expressions) {} + + friend class AstStorage; +}; + +class Extract : public memgraph::query::Expression { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + Extract() = default; + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + identifier_->Accept(visitor) && list_->Accept(visitor) && expression_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + /// Identifier for the list element. + memgraph::query::Identifier *identifier_{nullptr}; + /// Expression which produces a list which will be extracted. + memgraph::query::Expression *list_{nullptr}; + /// Expression which produces the new value for list element. + memgraph::query::Expression *expression_{nullptr}; + + Extract *Clone(AstStorage *storage) const override { + Extract *object = storage->Create(); + object->identifier_ = identifier_ ? identifier_->Clone(storage) : nullptr; + object->list_ = list_ ? list_->Clone(storage) : nullptr; + object->expression_ = expression_ ? expression_->Clone(storage) : nullptr; + return object; + } + + protected: + Extract(Identifier *identifier, Expression *list, Expression *expression) + : identifier_(identifier), list_(list), expression_(expression) {} + + private: + friend class AstStorage; +}; + +class All : public memgraph::query::Expression { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + All() = default; + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + identifier_->Accept(visitor) && list_expression_->Accept(visitor) && where_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + memgraph::query::Identifier *identifier_{nullptr}; + memgraph::query::Expression *list_expression_{nullptr}; + memgraph::query::Where *where_{nullptr}; + + All *Clone(AstStorage *storage) const override { + All *object = storage->Create(); + object->identifier_ = identifier_ ? identifier_->Clone(storage) : nullptr; + object->list_expression_ = list_expression_ ? list_expression_->Clone(storage) : nullptr; + object->where_ = where_ ? where_->Clone(storage) : nullptr; + return object; + } + + protected: + All(Identifier *identifier, Expression *list_expression, Where *where) + : identifier_(identifier), list_expression_(list_expression), where_(where) {} + + private: + friend class AstStorage; +}; + +class Single : public memgraph::query::Expression { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + Single() = default; + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + identifier_->Accept(visitor) && list_expression_->Accept(visitor) && where_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + memgraph::query::Identifier *identifier_{nullptr}; + memgraph::query::Expression *list_expression_{nullptr}; + memgraph::query::Where *where_{nullptr}; + + Single *Clone(AstStorage *storage) const override { + Single *object = storage->Create(); + object->identifier_ = identifier_ ? identifier_->Clone(storage) : nullptr; + object->list_expression_ = list_expression_ ? list_expression_->Clone(storage) : nullptr; + object->where_ = where_ ? where_->Clone(storage) : nullptr; + return object; + } + + protected: + Single(Identifier *identifier, Expression *list_expression, Where *where) + : identifier_(identifier), list_expression_(list_expression), where_(where) {} + + private: + friend class AstStorage; +}; + +class Any : public memgraph::query::Expression { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + Any() = default; + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + identifier_->Accept(visitor) && list_expression_->Accept(visitor) && where_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + memgraph::query::Identifier *identifier_{nullptr}; + memgraph::query::Expression *list_expression_{nullptr}; + memgraph::query::Where *where_{nullptr}; + + Any *Clone(AstStorage *storage) const override { + Any *object = storage->Create(); + object->identifier_ = identifier_ ? identifier_->Clone(storage) : nullptr; + object->list_expression_ = list_expression_ ? list_expression_->Clone(storage) : nullptr; + object->where_ = where_ ? where_->Clone(storage) : nullptr; + return object; + } + + protected: + Any(Identifier *identifier, Expression *list_expression, Where *where) + : identifier_(identifier), list_expression_(list_expression), where_(where) {} + + private: + friend class AstStorage; +}; + +class None : public memgraph::query::Expression { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + None() = default; + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + identifier_->Accept(visitor) && list_expression_->Accept(visitor) && where_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + memgraph::query::Identifier *identifier_{nullptr}; + memgraph::query::Expression *list_expression_{nullptr}; + memgraph::query::Where *where_{nullptr}; + + None *Clone(AstStorage *storage) const override { + None *object = storage->Create(); + object->identifier_ = identifier_ ? identifier_->Clone(storage) : nullptr; + object->list_expression_ = list_expression_ ? list_expression_->Clone(storage) : nullptr; + object->where_ = where_ ? where_->Clone(storage) : nullptr; + return object; + } + + protected: + None(Identifier *identifier, Expression *list_expression, Where *where) + : identifier_(identifier), list_expression_(list_expression), where_(where) {} + + private: + friend class AstStorage; +}; + +class ParameterLookup : public memgraph::query::Expression { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + ParameterLookup() = default; + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(HierarchicalTreeVisitor); + + /// This field contains token position of *literal* used to create ParameterLookup object. If ParameterLookup object + /// is not created from a literal leave this value at -1. + int32_t token_position_{-1}; + + ParameterLookup *Clone(AstStorage *storage) const override { + ParameterLookup *object = storage->Create(); + object->token_position_ = token_position_; + return object; + } + + protected: + explicit ParameterLookup(int token_position) : token_position_(token_position) {} + + private: + friend class AstStorage; +}; + +class RegexMatch : public memgraph::query::Expression { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + RegexMatch() = default; + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + string_expr_->Accept(visitor) && regex_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + memgraph::query::Expression *string_expr_; + memgraph::query::Expression *regex_; + + RegexMatch *Clone(AstStorage *storage) const override { + RegexMatch *object = storage->Create(); + object->string_expr_ = string_expr_ ? string_expr_->Clone(storage) : nullptr; + object->regex_ = regex_ ? regex_->Clone(storage) : nullptr; + return object; + } + + private: + friend class AstStorage; + RegexMatch(Expression *string_expr, Expression *regex) : string_expr_(string_expr), regex_(regex) {} +}; + +class NamedExpression : public memgraph::query::Tree, + public utils::Visitable, + public utils::Visitable>, + public utils::Visitable>, + public utils::Visitable> { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + using utils::Visitable>::Accept; + using utils::Visitable>::Accept; + using utils::Visitable::Accept; + + NamedExpression() = default; + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + expression_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + NamedExpression *MapTo(const Symbol &symbol) { + symbol_pos_ = symbol.position(); + return this; + } + + std::string name_; + memgraph::query::Expression *expression_{nullptr}; + /// This field contains token position of first token in named expression used to create name_. If NamedExpression + /// object is not created from query or it is aliased leave this value at -1. + int32_t token_position_{-1}; + /// Symbol table position of the symbol this NamedExpression is mapped to. + int32_t symbol_pos_{-1}; + + NamedExpression *Clone(AstStorage *storage) const override { + NamedExpression *object = storage->Create(); + object->name_ = name_; + object->expression_ = expression_ ? expression_->Clone(storage) : nullptr; + object->token_position_ = token_position_; + object->symbol_pos_ = symbol_pos_; + return object; + } + + protected: + explicit NamedExpression(const std::string &name) : name_(name) {} + NamedExpression(const std::string &name, Expression *expression) : name_(name), expression_(expression) {} + NamedExpression(const std::string &name, Expression *expression, int token_position) + : name_(name), expression_(expression), token_position_(token_position) {} + + private: + friend class AstStorage; +}; + +class PatternAtom : public memgraph::query::Tree, public utils::Visitable { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + using utils::Visitable::Accept; + + PatternAtom() = default; + + memgraph::query::Identifier *identifier_{nullptr}; + + PatternAtom *Clone(AstStorage *storage) const override = 0; + + protected: + explicit PatternAtom(Identifier *identifier) : identifier_(identifier) {} + + private: + friend class AstStorage; +}; + +class NodeAtom : public memgraph::query::PatternAtom { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + if (auto *properties = std::get_if>(&properties_)) { + bool cont = identifier_->Accept(visitor); + for (auto &property : *properties) { + if (cont) { + cont = property.second->Accept(visitor); + } + } + } else { + std::get(properties_)->Accept(visitor); + } + } + return visitor.PostVisit(*this); + } + + std::vector labels_; + std::variant, + memgraph::query::ParameterLookup *> + properties_; + + NodeAtom *Clone(AstStorage *storage) const override { + NodeAtom *object = storage->Create(); + object->identifier_ = identifier_ ? identifier_->Clone(storage) : nullptr; + object->labels_.resize(labels_.size()); + for (auto i = 0; i < object->labels_.size(); ++i) { + object->labels_[i] = storage->GetLabelIx(labels_[i].name); + } + if (const auto *properties = std::get_if>(&properties_)) { + auto &new_obj_properties = std::get>(object->properties_); + for (const auto &[property, value_expression] : *properties) { + PropertyIx key = storage->GetPropertyIx(property.name); + new_obj_properties[key] = value_expression->Clone(storage); + } + } else { + object->properties_ = std::get(properties_)->Clone(storage); + } + return object; + } + + protected: + using PatternAtom::PatternAtom; + + private: + friend class AstStorage; +}; + +class EdgeAtom : public memgraph::query::PatternAtom { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + enum class Type { SINGLE, DEPTH_FIRST, BREADTH_FIRST, WEIGHTED_SHORTEST_PATH, ALL_SHORTEST_PATHS }; + + enum class Direction { IN, OUT, BOTH }; + + /// Lambda for use in filtering or weight calculation during variable expand. + struct Lambda { + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const { return kType; } + + /// Argument identifier for the edge currently being traversed. + memgraph::query::Identifier *inner_edge{nullptr}; + /// Argument identifier for the destination node of the edge. + memgraph::query::Identifier *inner_node{nullptr}; + /// Evaluates the result of the lambda. + memgraph::query::Expression *expression{nullptr}; + + Lambda Clone(AstStorage *storage) const { + Lambda object; + object.inner_edge = inner_edge ? inner_edge->Clone(storage) : nullptr; + object.inner_node = inner_node ? inner_node->Clone(storage) : nullptr; + object.expression = expression ? expression->Clone(storage) : nullptr; + return object; + } + }; + + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + bool cont = identifier_->Accept(visitor); + if (auto *properties = std::get_if>(&properties_)) { + for (auto &property : *properties) { + if (cont) { + cont = property.second->Accept(visitor); + } + } + } else { + std::get(properties_)->Accept(visitor); + } + if (cont && lower_bound_) { + cont = lower_bound_->Accept(visitor); + } + if (cont && upper_bound_) { + cont = upper_bound_->Accept(visitor); + } + if (cont && total_weight_) { + total_weight_->Accept(visitor); + } + } + return visitor.PostVisit(*this); + } + + bool IsVariable() const { + switch (type_) { + case Type::DEPTH_FIRST: + case Type::BREADTH_FIRST: + case Type::WEIGHTED_SHORTEST_PATH: + case Type::ALL_SHORTEST_PATHS: + return true; + case Type::SINGLE: + return false; + } + } + + memgraph::query::EdgeAtom::Type type_{Type::SINGLE}; + memgraph::query::EdgeAtom::Direction direction_{Direction::BOTH}; + std::vector edge_types_; + std::variant, + memgraph::query::ParameterLookup *> + properties_; + /// Evaluates to lower bound in variable length expands. + memgraph::query::Expression *lower_bound_{nullptr}; + /// Evaluated to upper bound in variable length expands. + memgraph::query::Expression *upper_bound_{nullptr}; + /// Filter lambda for variable length expands. Can have an empty expression, but identifiers must be valid, because an + /// optimization pass may inline other expressions into this lambda. + memgraph::query::EdgeAtom::Lambda filter_lambda_; + /// Used in weighted shortest path. It must have valid expressions and identifiers. In all other expand types, it is + /// empty. + memgraph::query::EdgeAtom::Lambda weight_lambda_; + /// Variable where the total weight for weighted shortest path will be stored. + memgraph::query::Identifier *total_weight_{nullptr}; + + EdgeAtom *Clone(AstStorage *storage) const override { + EdgeAtom *object = storage->Create(); + object->identifier_ = identifier_ ? identifier_->Clone(storage) : nullptr; + object->type_ = type_; + object->direction_ = direction_; + object->edge_types_.resize(edge_types_.size()); + for (auto i = 0; i < object->edge_types_.size(); ++i) { + object->edge_types_[i] = storage->GetEdgeTypeIx(edge_types_[i].name); + } + if (const auto *properties = std::get_if>(&properties_)) { + auto &new_obj_properties = std::get>(object->properties_); + for (const auto &[property, value_expression] : *properties) { + PropertyIx key = storage->GetPropertyIx(property.name); + new_obj_properties[key] = value_expression->Clone(storage); + } + } else { + object->properties_ = std::get(properties_)->Clone(storage); + } + object->lower_bound_ = lower_bound_ ? lower_bound_->Clone(storage) : nullptr; + object->upper_bound_ = upper_bound_ ? upper_bound_->Clone(storage) : nullptr; + object->filter_lambda_ = filter_lambda_.Clone(storage); + object->weight_lambda_ = weight_lambda_.Clone(storage); + object->total_weight_ = total_weight_ ? total_weight_->Clone(storage) : nullptr; + return object; + } + + protected: + using PatternAtom::PatternAtom; + EdgeAtom(Identifier *identifier, Type type, Direction direction) + : PatternAtom(identifier), type_(type), direction_(direction) {} + + // Creates an edge atom for a SINGLE expansion with the given . + EdgeAtom(Identifier *identifier, Type type, Direction direction, const std::vector &edge_types) + : PatternAtom(identifier), type_(type), direction_(direction), edge_types_(edge_types) {} + + private: + friend class AstStorage; +}; + +class Pattern : public memgraph::query::Tree, public utils::Visitable { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + using utils::Visitable::Accept; + + Pattern() = default; + + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + bool cont = identifier_->Accept(visitor); + for (auto &part : atoms_) { + if (cont) { + cont = part->Accept(visitor); + } + } + } + return visitor.PostVisit(*this); + } + + memgraph::query::Identifier *identifier_{nullptr}; + std::vector atoms_; + + Pattern *Clone(AstStorage *storage) const override { + Pattern *object = storage->Create(); + object->identifier_ = identifier_ ? identifier_->Clone(storage) : nullptr; + object->atoms_.resize(atoms_.size()); + for (auto i3 = 0; i3 < atoms_.size(); ++i3) { + object->atoms_[i3] = atoms_[i3] ? atoms_[i3]->Clone(storage) : nullptr; + } + return object; + } + + private: + friend class AstStorage; +}; + +class Clause : public memgraph::query::Tree, public utils::Visitable { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + using utils::Visitable::Accept; + + Clause() = default; + + Clause *Clone(AstStorage *storage) const override = 0; + + private: + friend class AstStorage; +}; + +class SingleQuery : public memgraph::query::Tree, public utils::Visitable { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + using utils::Visitable::Accept; + + SingleQuery() = default; + + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + for (auto &clause : clauses_) { + if (!clause->Accept(visitor)) break; + } + } + return visitor.PostVisit(*this); + } + + std::vector clauses_; + + SingleQuery *Clone(AstStorage *storage) const override { + SingleQuery *object = storage->Create(); + object->clauses_.resize(clauses_.size()); + for (auto i4 = 0; i4 < clauses_.size(); ++i4) { + object->clauses_[i4] = clauses_[i4] ? clauses_[i4]->Clone(storage) : nullptr; + } + return object; + } + + private: + friend class AstStorage; +}; + +class CypherUnion : public memgraph::query::Tree, public utils::Visitable { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + using utils::Visitable::Accept; + + CypherUnion() = default; + + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + single_query_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + memgraph::query::SingleQuery *single_query_{nullptr}; + bool distinct_{false}; + /// Holds symbols that are created during symbol generation phase. These symbols are used when UNION/UNION ALL + /// combines single query results. + std::vector union_symbols_; + + CypherUnion *Clone(AstStorage *storage) const override { + CypherUnion *object = storage->Create(); + object->single_query_ = single_query_ ? single_query_->Clone(storage) : nullptr; + object->distinct_ = distinct_; + object->union_symbols_ = union_symbols_; + return object; + } + + protected: + explicit CypherUnion(bool distinct) : distinct_(distinct) {} + CypherUnion(bool distinct, SingleQuery *single_query, std::vector union_symbols) + : single_query_(single_query), distinct_(distinct), union_symbols_(union_symbols) {} + + private: + friend class AstStorage; +}; + +class Query : public memgraph::query::Tree, public utils::Visitable> { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + using utils::Visitable>::Accept; + + Query() = default; + + Query *Clone(AstStorage *storage) const override = 0; + + private: + friend class AstStorage; +}; + +class CypherQuery : public memgraph::query::Query { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + CypherQuery() = default; + + DEFVISITABLE(QueryVisitor); + + /// First and potentially only query. + memgraph::query::SingleQuery *single_query_{nullptr}; + /// Contains remaining queries that should form and union with `single_query_`. + std::vector cypher_unions_; + memgraph::query::Expression *memory_limit_{nullptr}; + size_t memory_scale_{1024U}; + + CypherQuery *Clone(AstStorage *storage) const override { + CypherQuery *object = storage->Create(); + object->single_query_ = single_query_ ? single_query_->Clone(storage) : nullptr; + object->cypher_unions_.resize(cypher_unions_.size()); + for (auto i5 = 0; i5 < cypher_unions_.size(); ++i5) { + object->cypher_unions_[i5] = cypher_unions_[i5] ? cypher_unions_[i5]->Clone(storage) : nullptr; + } + object->memory_limit_ = memory_limit_ ? memory_limit_->Clone(storage) : nullptr; + object->memory_scale_ = memory_scale_; + return object; + } + + private: + friend class AstStorage; +}; + +class ExplainQuery : public memgraph::query::Query { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + ExplainQuery() = default; + + DEFVISITABLE(QueryVisitor); + + /// The CypherQuery to explain. + memgraph::query::CypherQuery *cypher_query_{nullptr}; + + ExplainQuery *Clone(AstStorage *storage) const override { + ExplainQuery *object = storage->Create(); + object->cypher_query_ = cypher_query_ ? cypher_query_->Clone(storage) : nullptr; + return object; + } + + private: + friend class AstStorage; +}; + +class ProfileQuery : public memgraph::query::Query { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + ProfileQuery() = default; + + DEFVISITABLE(QueryVisitor); + + /// The CypherQuery to profile. + memgraph::query::CypherQuery *cypher_query_{nullptr}; + + ProfileQuery *Clone(AstStorage *storage) const override { + ProfileQuery *object = storage->Create(); + object->cypher_query_ = cypher_query_ ? cypher_query_->Clone(storage) : nullptr; + return object; + } + + private: + friend class AstStorage; +}; + +class IndexQuery : public memgraph::query::Query { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + enum class Action { CREATE, DROP }; + + IndexQuery() = default; + + DEFVISITABLE(QueryVisitor); + + memgraph::query::IndexQuery::Action action_; + memgraph::query::LabelIx label_; + std::vector properties_; + + IndexQuery *Clone(AstStorage *storage) const override { + IndexQuery *object = storage->Create(); + object->action_ = action_; + object->label_ = storage->GetLabelIx(label_.name); + object->properties_.resize(properties_.size()); + for (auto i = 0; i < object->properties_.size(); ++i) { + object->properties_[i] = storage->GetPropertyIx(properties_[i].name); + } + return object; + } + + protected: + IndexQuery(Action action, LabelIx label, std::vector properties) + : action_(action), label_(label), properties_(properties) {} + + private: + friend class AstStorage; +}; + +class Create : public memgraph::query::Clause { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + Create() = default; + + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + for (auto &pattern : patterns_) { + if (!pattern->Accept(visitor)) break; + } + } + return visitor.PostVisit(*this); + } + + std::vector patterns_; + + Create *Clone(AstStorage *storage) const override { + Create *object = storage->Create(); + object->patterns_.resize(patterns_.size()); + for (auto i6 = 0; i6 < patterns_.size(); ++i6) { + object->patterns_[i6] = patterns_[i6] ? patterns_[i6]->Clone(storage) : nullptr; + } + return object; + } + + protected: + explicit Create(std::vector patterns) : patterns_(patterns) {} + + private: + friend class AstStorage; +}; + +class CallProcedure : public memgraph::query::Clause { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + CallProcedure() = default; + + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + bool cont = true; + for (auto &arg : arguments_) { + if (!arg->Accept(visitor)) { + cont = false; + break; + } + } + if (cont) { + for (auto &ident : result_identifiers_) { + if (!ident->Accept(visitor)) { + cont = false; + break; + } + } + } + } + return visitor.PostVisit(*this); + } + + std::string procedure_name_; + std::vector arguments_; + std::vector result_fields_; + std::vector result_identifiers_; + memgraph::query::Expression *memory_limit_{nullptr}; + size_t memory_scale_{1024U}; + bool is_write_; + + CallProcedure *Clone(AstStorage *storage) const override { + CallProcedure *object = storage->Create(); + object->procedure_name_ = procedure_name_; + object->arguments_.resize(arguments_.size()); + for (auto i7 = 0; i7 < arguments_.size(); ++i7) { + object->arguments_[i7] = arguments_[i7] ? arguments_[i7]->Clone(storage) : nullptr; + } + object->result_fields_ = result_fields_; + object->result_identifiers_.resize(result_identifiers_.size()); + for (auto i8 = 0; i8 < result_identifiers_.size(); ++i8) { + object->result_identifiers_[i8] = result_identifiers_[i8] ? result_identifiers_[i8]->Clone(storage) : nullptr; + } + object->memory_limit_ = memory_limit_ ? memory_limit_->Clone(storage) : nullptr; + object->memory_scale_ = memory_scale_; + object->is_write_ = is_write_; + return object; + } + + private: + friend class AstStorage; +}; + +class Match : public memgraph::query::Clause { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + Match() = default; + + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + bool cont = true; + for (auto &pattern : patterns_) { + if (!pattern->Accept(visitor)) { + cont = false; + break; + } + } + if (cont && where_) { + where_->Accept(visitor); + } + } + return visitor.PostVisit(*this); + } + + std::vector patterns_; + memgraph::query::Where *where_{nullptr}; + bool optional_{false}; + + Match *Clone(AstStorage *storage) const override { + Match *object = storage->Create(); + object->patterns_.resize(patterns_.size()); + for (auto i9 = 0; i9 < patterns_.size(); ++i9) { + object->patterns_[i9] = patterns_[i9] ? patterns_[i9]->Clone(storage) : nullptr; + } + object->where_ = where_ ? where_->Clone(storage) : nullptr; + object->optional_ = optional_; + return object; + } + + protected: + explicit Match(bool optional) : optional_(optional) {} + Match(bool optional, Where *where, std::vector patterns) + : patterns_(patterns), where_(where), optional_(optional) {} + + private: + friend class AstStorage; +}; + +/// Defines the order for sorting values (ascending or descending). +enum class Ordering { ASC, DESC }; + +struct SortItem { + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const { return kType; } + + memgraph::query::Ordering ordering; + memgraph::query::Expression *expression; + + SortItem Clone(AstStorage *storage) const { + SortItem object; + object.ordering = ordering; + object.expression = expression ? expression->Clone(storage) : nullptr; + return object; + } +}; + +/// Contents common to @c Return and @c With clauses. +struct ReturnBody { + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const { return kType; } + + /// True if distinct results should be produced. + bool distinct{false}; + /// True if asterisk was found in the return body. + bool all_identifiers{false}; + /// Expressions which are used to produce results. + std::vector named_expressions; + /// Expressions used for ordering the results. + std::vector order_by; + /// Optional expression on how many results to skip. + memgraph::query::Expression *skip{nullptr}; + /// Optional expression on how many results to produce. + memgraph::query::Expression *limit{nullptr}; + + ReturnBody Clone(AstStorage *storage) const { + ReturnBody object; + object.distinct = distinct; + object.all_identifiers = all_identifiers; + object.named_expressions.resize(named_expressions.size()); + for (auto i10 = 0; i10 < named_expressions.size(); ++i10) { + object.named_expressions[i10] = named_expressions[i10] ? named_expressions[i10]->Clone(storage) : nullptr; + } + object.order_by.resize(order_by.size()); + for (auto i11 = 0; i11 < order_by.size(); ++i11) { + object.order_by[i11] = order_by[i11].Clone(storage); + } + object.skip = skip ? skip->Clone(storage) : nullptr; + object.limit = limit ? limit->Clone(storage) : nullptr; + return object; + } +}; + +class Return : public memgraph::query::Clause { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + Return() = default; + + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + bool cont = true; + for (auto &expr : body_.named_expressions) { + if (!expr->Accept(visitor)) { + cont = false; + break; + } + } + if (cont) { + for (auto &order_by : body_.order_by) { + if (!order_by.expression->Accept(visitor)) { + cont = false; + break; + } + } + } + if (cont && body_.skip) cont = body_.skip->Accept(visitor); + if (cont && body_.limit) cont = body_.limit->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + memgraph::query::ReturnBody body_; + + Return *Clone(AstStorage *storage) const override { + Return *object = storage->Create(); + object->body_ = body_.Clone(storage); + return object; + } + + protected: + explicit Return(ReturnBody &body) : body_(body) {} + + private: + friend class AstStorage; +}; + +class With : public memgraph::query::Clause { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + With() = default; + + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + bool cont = true; + for (auto &expr : body_.named_expressions) { + if (!expr->Accept(visitor)) { + cont = false; + break; + } + } + if (cont) { + for (auto &order_by : body_.order_by) { + if (!order_by.expression->Accept(visitor)) { + cont = false; + break; + } + } + } + if (cont && where_) cont = where_->Accept(visitor); + if (cont && body_.skip) cont = body_.skip->Accept(visitor); + if (cont && body_.limit) cont = body_.limit->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + memgraph::query::ReturnBody body_; + memgraph::query::Where *where_{nullptr}; + + With *Clone(AstStorage *storage) const override { + With *object = storage->Create(); + object->body_ = body_.Clone(storage); + object->where_ = where_ ? where_->Clone(storage) : nullptr; + return object; + } + + protected: + With(ReturnBody &body, Where *where) : body_(body), where_(where) {} + + private: + friend class AstStorage; +}; + +class Delete : public memgraph::query::Clause { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + Delete() = default; + + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + for (auto &expr : expressions_) { + if (!expr->Accept(visitor)) break; + } + } + return visitor.PostVisit(*this); + } + + std::vector expressions_; + bool detach_{false}; + + Delete *Clone(AstStorage *storage) const override { + Delete *object = storage->Create(); + object->expressions_.resize(expressions_.size()); + for (auto i12 = 0; i12 < expressions_.size(); ++i12) { + object->expressions_[i12] = expressions_[i12] ? expressions_[i12]->Clone(storage) : nullptr; + } + object->detach_ = detach_; + return object; + } + + protected: + Delete(bool detach, std::vector expressions) : expressions_(expressions), detach_(detach) {} + + private: + friend class AstStorage; +}; + +class SetProperty : public memgraph::query::Clause { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + SetProperty() = default; + + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + property_lookup_->Accept(visitor) && expression_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + memgraph::query::PropertyLookup *property_lookup_{nullptr}; + memgraph::query::Expression *expression_{nullptr}; + + SetProperty *Clone(AstStorage *storage) const override { + SetProperty *object = storage->Create(); + object->property_lookup_ = property_lookup_ ? property_lookup_->Clone(storage) : nullptr; + object->expression_ = expression_ ? expression_->Clone(storage) : nullptr; + return object; + } + + protected: + SetProperty(PropertyLookup *property_lookup, Expression *expression) + : property_lookup_(property_lookup), expression_(expression) {} + + private: + friend class AstStorage; +}; + +class SetProperties : public memgraph::query::Clause { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + SetProperties() = default; + + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + identifier_->Accept(visitor) && expression_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + memgraph::query::Identifier *identifier_{nullptr}; + memgraph::query::Expression *expression_{nullptr}; + bool update_{false}; + + SetProperties *Clone(AstStorage *storage) const override { + SetProperties *object = storage->Create(); + object->identifier_ = identifier_ ? identifier_->Clone(storage) : nullptr; + object->expression_ = expression_ ? expression_->Clone(storage) : nullptr; + object->update_ = update_; + return object; + } + + protected: + SetProperties(Identifier *identifier, Expression *expression, bool update = false) + : identifier_(identifier), expression_(expression), update_(update) {} + + private: + friend class AstStorage; +}; + +class SetLabels : public memgraph::query::Clause { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + SetLabels() = default; + + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + identifier_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + memgraph::query::Identifier *identifier_{nullptr}; + std::vector labels_; + + SetLabels *Clone(AstStorage *storage) const override { + SetLabels *object = storage->Create(); + object->identifier_ = identifier_ ? identifier_->Clone(storage) : nullptr; + object->labels_.resize(labels_.size()); + for (auto i = 0; i < object->labels_.size(); ++i) { + object->labels_[i] = storage->GetLabelIx(labels_[i].name); + } + return object; + } + + protected: + SetLabels(Identifier *identifier, const std::vector &labels) : identifier_(identifier), labels_(labels) {} + + private: + friend class AstStorage; +}; + +class RemoveProperty : public memgraph::query::Clause { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + RemoveProperty() = default; + + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + property_lookup_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + memgraph::query::PropertyLookup *property_lookup_{nullptr}; + + RemoveProperty *Clone(AstStorage *storage) const override { + RemoveProperty *object = storage->Create(); + object->property_lookup_ = property_lookup_ ? property_lookup_->Clone(storage) : nullptr; + return object; + } + + protected: + explicit RemoveProperty(PropertyLookup *property_lookup) : property_lookup_(property_lookup) {} + + private: + friend class AstStorage; +}; + +class RemoveLabels : public memgraph::query::Clause { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + RemoveLabels() = default; + + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + identifier_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + memgraph::query::Identifier *identifier_{nullptr}; + std::vector labels_; + + RemoveLabels *Clone(AstStorage *storage) const override { + RemoveLabels *object = storage->Create(); + object->identifier_ = identifier_ ? identifier_->Clone(storage) : nullptr; + object->labels_.resize(labels_.size()); + for (auto i = 0; i < object->labels_.size(); ++i) { + object->labels_[i] = storage->GetLabelIx(labels_[i].name); + } + return object; + } + + protected: + RemoveLabels(Identifier *identifier, const std::vector &labels) : identifier_(identifier), labels_(labels) {} + + private: + friend class AstStorage; +}; + +class Merge : public memgraph::query::Clause { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + Merge() = default; + + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + bool cont = pattern_->Accept(visitor); + if (cont) { + for (auto &set : on_match_) { + if (!set->Accept(visitor)) { + cont = false; + break; + } + } + } + if (cont) { + for (auto &set : on_create_) { + if (!set->Accept(visitor)) { + cont = false; + break; + } + } + } + } + return visitor.PostVisit(*this); + } + + memgraph::query::Pattern *pattern_{nullptr}; + std::vector on_match_; + std::vector on_create_; + + Merge *Clone(AstStorage *storage) const override { + Merge *object = storage->Create(); + object->pattern_ = pattern_ ? pattern_->Clone(storage) : nullptr; + object->on_match_.resize(on_match_.size()); + for (auto i13 = 0; i13 < on_match_.size(); ++i13) { + object->on_match_[i13] = on_match_[i13] ? on_match_[i13]->Clone(storage) : nullptr; + } + object->on_create_.resize(on_create_.size()); + for (auto i14 = 0; i14 < on_create_.size(); ++i14) { + object->on_create_[i14] = on_create_[i14] ? on_create_[i14]->Clone(storage) : nullptr; + } + return object; + } + + protected: + Merge(Pattern *pattern, std::vector on_match, std::vector on_create) + : pattern_(pattern), on_match_(on_match), on_create_(on_create) {} + + private: + friend class AstStorage; +}; + +class Unwind : public memgraph::query::Clause { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + Unwind() = default; + + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + named_expression_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + memgraph::query::NamedExpression *named_expression_{nullptr}; + + Unwind *Clone(AstStorage *storage) const override { + Unwind *object = storage->Create(); + object->named_expression_ = named_expression_ ? named_expression_->Clone(storage) : nullptr; + return object; + } + + protected: + explicit Unwind(NamedExpression *named_expression) : named_expression_(named_expression) { + DMG_ASSERT(named_expression, "Unwind cannot take nullptr for named_expression"); + } + + private: + friend class AstStorage; +}; + +class AuthQuery : public memgraph::query::Query { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + enum class Action { + CREATE_ROLE, + DROP_ROLE, + SHOW_ROLES, + CREATE_USER, + SET_PASSWORD, + DROP_USER, + SHOW_USERS, + SET_ROLE, + CLEAR_ROLE, + GRANT_PRIVILEGE, + DENY_PRIVILEGE, + REVOKE_PRIVILEGE, + SHOW_PRIVILEGES, + SHOW_ROLE_FOR_USER, + SHOW_USERS_FOR_ROLE + }; + + enum class Privilege { + CREATE, + DELETE, + MATCH, + MERGE, + SET, + REMOVE, + INDEX, + STATS, + AUTH, + CONSTRAINT, + DUMP, + REPLICATION, + DURABILITY, + READ_FILE, + FREE_MEMORY, + TRIGGER, + CONFIG, + STREAM, + MODULE_READ, + MODULE_WRITE, + WEBSOCKET + }; + + enum class FineGrainedPrivilege { NOTHING, READ, UPDATE, CREATE_DELETE }; + + AuthQuery() = default; + + DEFVISITABLE(QueryVisitor); + + memgraph::query::AuthQuery::Action action_; + std::string user_; + std::string role_; + std::string user_or_role_; + memgraph::query::Expression *password_{nullptr}; + std::vector privileges_; + std::vector>> + label_privileges_; + std::vector>> + edge_type_privileges_; + + AuthQuery *Clone(AstStorage *storage) const override { + AuthQuery *object = storage->Create(); + object->action_ = action_; + object->user_ = user_; + object->role_ = role_; + object->user_or_role_ = user_or_role_; + object->password_ = password_ ? password_->Clone(storage) : nullptr; + object->privileges_ = privileges_; + object->label_privileges_ = label_privileges_; + object->edge_type_privileges_ = edge_type_privileges_; + return object; + } + + protected: + AuthQuery(Action action, std::string user, std::string role, std::string user_or_role, Expression *password, + std::vector privileges, + std::vector>> label_privileges, + std::vector>> edge_type_privileges) + : action_(action), + user_(user), + role_(role), + user_or_role_(user_or_role), + password_(password), + privileges_(privileges), + label_privileges_(label_privileges), + edge_type_privileges_(edge_type_privileges) {} + + private: + friend class AstStorage; +}; + +/// Constant that holds all available privileges. +const std::vector kPrivilegesAll = { + AuthQuery::Privilege::CREATE, AuthQuery::Privilege::DELETE, AuthQuery::Privilege::MATCH, + AuthQuery::Privilege::MERGE, AuthQuery::Privilege::SET, AuthQuery::Privilege::REMOVE, + AuthQuery::Privilege::INDEX, AuthQuery::Privilege::STATS, AuthQuery::Privilege::AUTH, + AuthQuery::Privilege::CONSTRAINT, AuthQuery::Privilege::DUMP, AuthQuery::Privilege::REPLICATION, + AuthQuery::Privilege::READ_FILE, AuthQuery::Privilege::DURABILITY, AuthQuery::Privilege::FREE_MEMORY, + AuthQuery::Privilege::TRIGGER, AuthQuery::Privilege::CONFIG, AuthQuery::Privilege::STREAM, + AuthQuery::Privilege::MODULE_READ, AuthQuery::Privilege::MODULE_WRITE, AuthQuery::Privilege::WEBSOCKET}; + +class InfoQuery : public memgraph::query::Query { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + enum class InfoType { STORAGE, INDEX, CONSTRAINT }; + + DEFVISITABLE(QueryVisitor); + + memgraph::query::InfoQuery::InfoType info_type_; + + InfoQuery *Clone(AstStorage *storage) const override { + InfoQuery *object = storage->Create(); + object->info_type_ = info_type_; + return object; + } +}; + +struct Constraint { + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const { return kType; } + + enum class Type { EXISTS, UNIQUE, NODE_KEY }; + + memgraph::query::Constraint::Type type; + memgraph::query::LabelIx label; + std::vector properties; + + Constraint Clone(AstStorage *storage) const { + Constraint object; + object.type = type; + object.label = storage->GetLabelIx(label.name); + object.properties.resize(properties.size()); + for (auto i = 0; i < object.properties.size(); ++i) { + object.properties[i] = storage->GetPropertyIx(properties[i].name); + } + return object; + } +}; + +class ConstraintQuery : public memgraph::query::Query { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + enum class ActionType { CREATE, DROP }; + + DEFVISITABLE(QueryVisitor); + + memgraph::query::ConstraintQuery::ActionType action_type_; + memgraph::query::Constraint constraint_; + + ConstraintQuery *Clone(AstStorage *storage) const override { + ConstraintQuery *object = storage->Create(); + object->action_type_ = action_type_; + object->constraint_ = constraint_.Clone(storage); + return object; + } +}; + +class DumpQuery : public memgraph::query::Query { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + DEFVISITABLE(QueryVisitor); + + DumpQuery *Clone(AstStorage *storage) const override { + DumpQuery *object = storage->Create(); + return object; + } +}; + +class ReplicationQuery : public memgraph::query::Query { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + enum class Action { SET_REPLICATION_ROLE, SHOW_REPLICATION_ROLE, REGISTER_REPLICA, DROP_REPLICA, SHOW_REPLICAS }; + + enum class ReplicationRole { MAIN, REPLICA }; + + enum class SyncMode { SYNC, ASYNC }; + + enum class ReplicaState { READY, REPLICATING, RECOVERY, INVALID }; + + ReplicationQuery() = default; + + DEFVISITABLE(QueryVisitor); + + memgraph::query::ReplicationQuery::Action action_; + memgraph::query::ReplicationQuery::ReplicationRole role_; + std::string replica_name_; + memgraph::query::Expression *socket_address_{nullptr}; + memgraph::query::Expression *port_{nullptr}; + memgraph::query::ReplicationQuery::SyncMode sync_mode_; + + ReplicationQuery *Clone(AstStorage *storage) const override { + ReplicationQuery *object = storage->Create(); + object->action_ = action_; + object->role_ = role_; + object->replica_name_ = replica_name_; + object->socket_address_ = socket_address_ ? socket_address_->Clone(storage) : nullptr; + object->port_ = port_ ? port_->Clone(storage) : nullptr; + object->sync_mode_ = sync_mode_; + return object; + } + + private: + friend class AstStorage; +}; + +class LockPathQuery : public memgraph::query::Query { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + enum class Action { LOCK_PATH, UNLOCK_PATH }; + + LockPathQuery() = default; + + DEFVISITABLE(QueryVisitor); + + memgraph::query::LockPathQuery::Action action_; + + LockPathQuery *Clone(AstStorage *storage) const override { + LockPathQuery *object = storage->Create(); + object->action_ = action_; + return object; + } + + private: + friend class AstStorage; +}; + +class LoadCsv : public memgraph::query::Clause { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + LoadCsv() = default; + + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + row_var_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + + memgraph::query::Expression *file_; + bool with_header_; + bool ignore_bad_; + memgraph::query::Expression *delimiter_{nullptr}; + memgraph::query::Expression *quote_{nullptr}; + memgraph::query::Identifier *row_var_{nullptr}; + + LoadCsv *Clone(AstStorage *storage) const override { + LoadCsv *object = storage->Create(); + object->file_ = file_ ? file_->Clone(storage) : nullptr; + object->with_header_ = with_header_; + object->ignore_bad_ = ignore_bad_; + object->delimiter_ = delimiter_ ? delimiter_->Clone(storage) : nullptr; + object->quote_ = quote_ ? quote_->Clone(storage) : nullptr; + object->row_var_ = row_var_ ? row_var_->Clone(storage) : nullptr; + return object; + } + + protected: + explicit LoadCsv(Expression *file, bool with_header, bool ignore_bad, Expression *delimiter, Expression *quote, + Identifier *row_var) + : file_(file), + with_header_(with_header), + ignore_bad_(ignore_bad), + delimiter_(delimiter), + quote_(quote), + row_var_(row_var) { + DMG_ASSERT(row_var, "LoadCsv cannot take nullptr for identifier"); + } + + private: + friend class AstStorage; +}; + +class FreeMemoryQuery : public memgraph::query::Query { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + DEFVISITABLE(QueryVisitor); + + FreeMemoryQuery *Clone(AstStorage *storage) const override { + FreeMemoryQuery *object = storage->Create(); + return object; + } +}; + +class TriggerQuery : public memgraph::query::Query { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + enum class Action { CREATE_TRIGGER, DROP_TRIGGER, SHOW_TRIGGERS }; + + enum class EventType { + ANY, + VERTEX_CREATE, + EDGE_CREATE, + CREATE, + VERTEX_DELETE, + EDGE_DELETE, + DELETE, + VERTEX_UPDATE, + EDGE_UPDATE, + UPDATE + }; + + TriggerQuery() = default; + + DEFVISITABLE(QueryVisitor); + + memgraph::query::TriggerQuery::Action action_; + memgraph::query::TriggerQuery::EventType event_type_; + std::string trigger_name_; + bool before_commit_; + std::string statement_; + + TriggerQuery *Clone(AstStorage *storage) const override { + TriggerQuery *object = storage->Create(); + object->action_ = action_; + object->event_type_ = event_type_; + object->trigger_name_ = trigger_name_; + object->before_commit_ = before_commit_; + object->statement_ = statement_; + return object; + } + + private: + friend class AstStorage; +}; + +class IsolationLevelQuery : public memgraph::query::Query { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + enum class IsolationLevel { SNAPSHOT_ISOLATION, READ_COMMITTED, READ_UNCOMMITTED }; + + enum class IsolationLevelScope { NEXT, SESSION, GLOBAL }; + + IsolationLevelQuery() = default; + + DEFVISITABLE(QueryVisitor); + + memgraph::query::IsolationLevelQuery::IsolationLevel isolation_level_; + memgraph::query::IsolationLevelQuery::IsolationLevelScope isolation_level_scope_; + + IsolationLevelQuery *Clone(AstStorage *storage) const override { + IsolationLevelQuery *object = storage->Create(); + object->isolation_level_ = isolation_level_; + object->isolation_level_scope_ = isolation_level_scope_; + return object; + } + + private: + friend class AstStorage; +}; + +class CreateSnapshotQuery : public memgraph::query::Query { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + DEFVISITABLE(QueryVisitor); + + CreateSnapshotQuery *Clone(AstStorage *storage) const override { + CreateSnapshotQuery *object = storage->Create(); + return object; + } +}; + +class StreamQuery : public memgraph::query::Query { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + enum class Action { + CREATE_STREAM, + DROP_STREAM, + START_STREAM, + STOP_STREAM, + START_ALL_STREAMS, + STOP_ALL_STREAMS, + SHOW_STREAMS, + CHECK_STREAM + }; + + enum class Type { KAFKA, PULSAR }; + + StreamQuery() = default; + + DEFVISITABLE(QueryVisitor); + + memgraph::query::StreamQuery::Action action_; + memgraph::query::StreamQuery::Type type_; + std::string stream_name_; + memgraph::query::Expression *batch_limit_{nullptr}; + memgraph::query::Expression *timeout_{nullptr}; + std::string transform_name_; + memgraph::query::Expression *batch_interval_{nullptr}; + memgraph::query::Expression *batch_size_{nullptr}; + std::variant> topic_names_{nullptr}; + std::string consumer_group_; + memgraph::query::Expression *bootstrap_servers_{nullptr}; + memgraph::query::Expression *service_url_{nullptr}; + std::unordered_map configs_; + std::unordered_map credentials_; + + StreamQuery *Clone(AstStorage *storage) const override { + StreamQuery *object = storage->Create(); + object->action_ = action_; + object->type_ = type_; + object->stream_name_ = stream_name_; + object->batch_limit_ = batch_limit_ ? batch_limit_->Clone(storage) : nullptr; + object->timeout_ = timeout_ ? timeout_->Clone(storage) : nullptr; + object->transform_name_ = transform_name_; + object->batch_interval_ = batch_interval_ ? batch_interval_->Clone(storage) : nullptr; + object->batch_size_ = batch_size_ ? batch_size_->Clone(storage) : nullptr; + if (auto *topic_expression = std::get_if(&topic_names_)) { + if (*topic_expression == nullptr) { + object->topic_names_ = nullptr; + } else { + object->topic_names_ = (*topic_expression)->Clone(storage); + } + } else { + object->topic_names_ = std::get>(topic_names_); + } + object->consumer_group_ = consumer_group_; + object->bootstrap_servers_ = bootstrap_servers_ ? bootstrap_servers_->Clone(storage) : nullptr; + object->service_url_ = service_url_ ? service_url_->Clone(storage) : nullptr; + for (const auto &[key, value] : configs_) { + object->configs_[key->Clone(storage)] = value->Clone(storage); + } + for (const auto &[key, value] : credentials_) { + object->credentials_[key->Clone(storage)] = value->Clone(storage); + } + return object; + } + + private: + friend class AstStorage; +}; + +class SettingQuery : public memgraph::query::Query { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + enum class Action { SHOW_SETTING, SHOW_ALL_SETTINGS, SET_SETTING }; + + SettingQuery() = default; + + DEFVISITABLE(QueryVisitor); + + memgraph::query::SettingQuery::Action action_; + memgraph::query::Expression *setting_name_{nullptr}; + memgraph::query::Expression *setting_value_{nullptr}; + + SettingQuery *Clone(AstStorage *storage) const override { + SettingQuery *object = storage->Create(); + object->action_ = action_; + object->setting_name_ = setting_name_ ? setting_name_->Clone(storage) : nullptr; + object->setting_value_ = setting_value_ ? setting_value_->Clone(storage) : nullptr; + return object; + } + + private: + friend class AstStorage; +}; + +class VersionQuery : public memgraph::query::Query { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + DEFVISITABLE(QueryVisitor); + + VersionQuery *Clone(AstStorage *storage) const override { + VersionQuery *object = storage->Create(); + return object; + } +}; + +class Foreach : public memgraph::query::Clause { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + Foreach() = default; + + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + named_expression_->Accept(visitor); + for (auto &clause : clauses_) { + clause->Accept(visitor); + } + } + return visitor.PostVisit(*this); + } + + memgraph::query::NamedExpression *named_expression_{nullptr}; + std::vector clauses_; + + Foreach *Clone(AstStorage *storage) const override { + Foreach *object = storage->Create(); + object->named_expression_ = named_expression_ ? named_expression_->Clone(storage) : nullptr; + object->clauses_.resize(clauses_.size()); + for (auto i15 = 0; i15 < clauses_.size(); ++i15) { + object->clauses_[i15] = clauses_[i15] ? clauses_[i15]->Clone(storage) : nullptr; + } + return object; + } + + protected: + Foreach(NamedExpression *expression, std::vector clauses) + : named_expression_(expression), clauses_(clauses) {} + + private: + friend class AstStorage; +}; + +class ShowConfigQuery : public memgraph::query::Query { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + DEFVISITABLE(QueryVisitor); + + ShowConfigQuery *Clone(AstStorage *storage) const override { + ShowConfigQuery *object = storage->Create(); + return object; + } +}; + +class Exists : public memgraph::query::Expression { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + Exists() = default; + + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + DEFVISITABLE(ExpressionVisitor); + bool Accept(HierarchicalTreeVisitor &visitor) override { + if (visitor.PreVisit(*this)) { + pattern_->Accept(visitor); + } + return visitor.PostVisit(*this); + } + Exists *MapTo(const Symbol &symbol) { + symbol_pos_ = symbol.position(); + return this; + } + + memgraph::query::Pattern *pattern_{nullptr}; + /// Symbol table position of the symbol this Aggregation is mapped to. + int32_t symbol_pos_{-1}; + + Exists *Clone(AstStorage *storage) const override { + Exists *object = storage->Create(); + object->pattern_ = pattern_ ? pattern_->Clone(storage) : nullptr; + object->symbol_pos_ = symbol_pos_; + return object; + } + + protected: + Exists(Pattern *pattern) : pattern_(pattern) {} + + private: + friend class AstStorage; +}; + +} // namespace query +} // namespace memgraph diff --git a/src/query/frontend/semantic/symbol.cpp b/src/query/frontend/semantic/symbol.cpp new file mode 100644 index 000000000..57d19b25d --- /dev/null +++ b/src/query/frontend/semantic/symbol.cpp @@ -0,0 +1,18 @@ +// Copyright 2023 Memgraph Ltd. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source +// License, and you may not use this file except in compliance with the Business Source License. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +#include "query/frontend/semantic/symbol.hpp" +#include "utils/typeinfo.hpp" + +namespace memgraph { + +constexpr utils::TypeInfo query::Symbol::kType{utils::TypeId::SYMBOL, "Symbol", nullptr}; +} // namespace memgraph diff --git a/src/query/frontend/semantic/symbol.hpp b/src/query/frontend/semantic/symbol.hpp new file mode 100644 index 000000000..5381cb48d --- /dev/null +++ b/src/query/frontend/semantic/symbol.hpp @@ -0,0 +1,75 @@ +// Copyright 2023 Memgraph Ltd. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source +// License, and you may not use this file except in compliance with the Business Source License. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +#pragma once + +#include + +#include "utils/typeinfo.hpp" + +namespace memgraph { + +namespace query { + +class Symbol { + public: + static const utils::TypeInfo kType; + static const utils::TypeInfo &GetTypeInfo() { return kType; } + + enum class Type { ANY, VERTEX, EDGE, PATH, NUMBER, EDGE_LIST }; + + // TODO: Generate enum to string conversion from LCP. Note, that this is + // displayed to the end user, so we may want to have a pretty name of each + // value. + static std::string TypeToString(Type type) { + const char *enum_string[] = {"Any", "Vertex", "Edge", "Path", "Number", "EdgeList"}; + return enum_string[static_cast(type)]; + } + + Symbol() {} + Symbol(const std::string &name, int position, bool user_declared, Type type = Type::ANY, int token_position = -1) + : name_(name), position_(position), user_declared_(user_declared), type_(type), token_position_(token_position) {} + + bool operator==(const Symbol &other) const { + return position_ == other.position_ && name_ == other.name_ && type_ == other.type_; + } + bool operator!=(const Symbol &other) const { return !operator==(other); } + + // TODO: Remove these since members are public + const auto &name() const { return name_; } + int position() const { return position_; } + Type type() const { return type_; } + bool user_declared() const { return user_declared_; } + int token_position() const { return token_position_; } + + std::string name_; + int64_t position_; + bool user_declared_{true}; + memgraph::query::Symbol::Type type_{Type::ANY}; + int64_t token_position_{-1}; +}; + +} // namespace query +} // namespace memgraph +namespace std { + +template <> +struct hash { + size_t operator()(const memgraph::query::Symbol &symbol) const { + size_t prime = 265443599u; + size_t hash = std::hash{}(symbol.position()); + hash ^= prime * std::hash{}(symbol.name()); + hash ^= prime * std::hash{}(static_cast(symbol.type())); + return hash; + } +}; + +} // namespace std diff --git a/src/query/plan/operator.hpp b/src/query/plan/operator.hpp new file mode 100644 index 000000000..08ced64aa --- /dev/null +++ b/src/query/plan/operator.hpp @@ -0,0 +1,2296 @@ +// Copyright 2023 Memgraph Ltd. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source +// License, and you may not use this file except in compliance with the Business Source License. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include "query/common.hpp" +#include "query/frontend/ast/ast.hpp" +#include "query/frontend/semantic/symbol.hpp" +#include "query/typed_value.hpp" +#include "storage/v2/id_types.hpp" +#include "utils/bound.hpp" +#include "utils/fnv.hpp" +#include "utils/logging.hpp" +#include "utils/memory.hpp" +#include "utils/visitor.hpp" + +namespace memgraph { + +namespace query { + +struct ExecutionContext; +class ExpressionEvaluator; +class Frame; +class SymbolTable; + +namespace plan { + +/// Base class for iteration cursors of @c LogicalOperator classes. +/// +/// Each @c LogicalOperator must produce a concrete @c Cursor, which provides +/// the iteration mechanism. +class Cursor { + public: + /// Run an iteration of a @c LogicalOperator. + /// + /// Since operators may be chained, the iteration may pull results from + /// multiple operators. + /// + /// @param Frame May be read from or written to while performing the + /// iteration. + /// @param ExecutionContext Used to get the position of symbols in frame and + /// other information. + /// + /// @throws QueryRuntimeException if something went wrong with execution + virtual bool Pull(Frame &, ExecutionContext &) = 0; + + /// Resets the Cursor to its initial state. + virtual void Reset() = 0; + + /// Perform cleanup which may throw an exception + virtual void Shutdown() = 0; + + virtual ~Cursor() {} +}; + +/// unique_ptr to Cursor managed with a custom deleter. +/// This allows us to use utils::MemoryResource for allocation. +using UniqueCursorPtr = std::unique_ptr>; + +template +std::unique_ptr> MakeUniqueCursorPtr(utils::Allocator allocator, + TArgs &&...args) { + auto *ptr = allocator.allocate(1); + try { + auto *cursor = new (ptr) TCursor(std::forward(args)...); + return std::unique_ptr>(cursor, [allocator](Cursor *base_ptr) mutable { + auto *p = static_cast(base_ptr); + p->~TCursor(); + allocator.deallocate(p, 1); + }); + } catch (...) { + allocator.deallocate(ptr, 1); + throw; + } +} + +class Once; +class CreateNode; +class CreateExpand; +class ScanAll; +class ScanAllByLabel; +class ScanAllByLabelPropertyRange; +class ScanAllByLabelPropertyValue; +class ScanAllByLabelProperty; +class ScanAllById; +class Expand; +class ExpandVariable; +class ConstructNamedPath; +class Filter; +class Produce; +class Delete; +class SetProperty; +class SetProperties; +class SetLabels; +class RemoveProperty; +class RemoveLabels; +class EdgeUniquenessFilter; +class Accumulate; +class Aggregate; +class Skip; +class Limit; +class OrderBy; +class Merge; +class Optional; +class Unwind; +class Distinct; +class Union; +class Cartesian; +class CallProcedure; +class LoadCsv; +class Foreach; +class EmptyResult; +class EvaluatePatternFilter; + +using LogicalOperatorCompositeVisitor = + utils::CompositeVisitor; + +using LogicalOperatorLeafVisitor = utils::LeafVisitor; + +/** + * @brief Base class for hierarchical visitors of @c LogicalOperator class + * hierarchy. + */ +class HierarchicalLogicalOperatorVisitor : public LogicalOperatorCompositeVisitor, public LogicalOperatorLeafVisitor { + public: + using LogicalOperatorCompositeVisitor::PostVisit; + using LogicalOperatorCompositeVisitor::PreVisit; + using LogicalOperatorLeafVisitor::Visit; + using typename LogicalOperatorLeafVisitor::ReturnType; +}; + +/// Base class for logical operators. +/// +/// Each operator describes an operation, which is to be performed on the +/// database. Operators are iterated over using a @c Cursor. Various operators +/// can serve as inputs to others and thus a sequence of operations is formed. +class LogicalOperator : public utils::Visitable { + public: + static const utils::TypeInfo kType; + virtual const utils::TypeInfo &GetTypeInfo() const { return kType; } + + virtual ~LogicalOperator() {} + + /** Construct a @c Cursor which is used to run this operator. + * + * @param utils::MemoryResource Memory resource used for allocations during + * the lifetime of the returned Cursor. + */ + virtual UniqueCursorPtr MakeCursor(utils::MemoryResource *) const = 0; + + /** Return @c Symbol vector where the query results will be stored. + * + * Currently, output symbols are generated in @c Produce @c Union and + * @c CallProcedure operators. @c Skip, @c Limit, @c OrderBy and @c Distinct + * propagate the symbols from @c Produce (if it exists as input operator). + * + * @param SymbolTable used to find symbols for expressions. + * @return std::vector used for results. + */ + virtual std::vector OutputSymbols(const SymbolTable &) const { return std::vector(); } + + /** + * Symbol vector whose values are modified by this operator sub-tree. + * + * This is different than @c OutputSymbols, because it returns all of the + * modified symbols, including those that may not be returned as the + * result of the query. Note that the modified symbols will not contain + * those that should not be read after the operator is processed. + * + * For example, `MATCH (n)-[e]-(m) RETURN n AS l` will generate `ScanAll (n) > + * Expand (e, m) > Produce (l)`. The modified symbols on Produce sub-tree will + * be `l`, the same as output symbols, because it isn't valid to read `n`, `e` + * nor `m` after Produce. On the other hand, modified symbols from Expand + * contain `e` and `m`, as well as `n`, while output symbols are empty. + * Modified symbols from ScanAll contain only `n`, while output symbols are + * also empty. + */ + virtual std::vector ModifiedSymbols(const SymbolTable &) const = 0; + + /** + * Returns true if the operator takes only one input operator. + * NOTE: When this method returns true, you may use `input` and `set_input` + * methods. + */ + virtual bool HasSingleInput() const = 0; + + /** + * Returns the input operator if it has any. + * NOTE: This should only be called if `HasSingleInput() == true`. + */ + virtual std::shared_ptr input() const = 0; + /** + * Set a different input on this operator. + * NOTE: This should only be called if `HasSingleInput() == true`. + */ + virtual void set_input(std::shared_ptr) = 0; + + struct SaveHelper { + std::vector saved_ops; + }; + + struct LoadHelper { + AstStorage ast_storage; + std::vector>> loaded_ops; + }; + + struct SlkLoadHelper { + AstStorage ast_storage; + std::vector> loaded_ops; + }; + + virtual std::unique_ptr Clone(AstStorage *storage) const = 0; +}; + +/// A logical operator whose Cursor returns true on the first Pull +/// and false on every following Pull. +class Once : public memgraph::query::plan::LogicalOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + Once(std::vector symbols = {}) : symbols_{std::move(symbols)} {} + DEFVISITABLE(HierarchicalLogicalOperatorVisitor); + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + std::vector ModifiedSymbols(const SymbolTable &) const override { return symbols_; } + + bool HasSingleInput() const override; + std::shared_ptr input() const override; + void set_input(std::shared_ptr) override; + + std::vector symbols_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->symbols_ = symbols_; + return object; + } + + private: + class OnceCursor : public Cursor { + public: + OnceCursor() {} + bool Pull(Frame &, ExecutionContext &) override; + void Shutdown() override; + void Reset() override; + + private: + bool did_pull_{false}; + }; +}; + +using PropertiesMapList = std::vector>; + +struct NodeCreationInfo { + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const { return kType; } + + NodeCreationInfo() = default; + + NodeCreationInfo(Symbol symbol, std::vector labels, + std::variant properties) + : symbol{std::move(symbol)}, labels{std::move(labels)}, properties{std::move(properties)} {}; + + NodeCreationInfo(Symbol symbol, std::vector labels, PropertiesMapList properties) + : symbol{std::move(symbol)}, labels{std::move(labels)}, properties{std::move(properties)} {}; + + NodeCreationInfo(Symbol symbol, std::vector labels, ParameterLookup *properties) + : symbol{std::move(symbol)}, labels{std::move(labels)}, properties{properties} {}; + + Symbol symbol; + std::vector labels; + std::variant properties; + + NodeCreationInfo Clone(AstStorage *storage) const { + NodeCreationInfo object; + object.symbol = symbol; + object.labels = labels; + if (const auto *props = std::get_if(&properties)) { + auto &destination_props = std::get(object.properties); + destination_props.resize(props->size()); + for (auto i0 = 0; i0 < props->size(); ++i0) { + { + storage::PropertyId first1 = (*props)[i0].first; + Expression *second2; + second2 = (*props)[i0].second ? (*props)[i0].second->Clone(storage) : nullptr; + destination_props[i0] = std::make_pair(std::move(first1), std::move(second2)); + } + } + } else { + object.properties = std::get(properties)->Clone(storage); + } + return object; + } +}; + +/// Operator for creating a node. +/// +/// This op is used both for creating a single node (`CREATE` statement without +/// a preceding `MATCH`), or multiple nodes (`MATCH ... CREATE` or +/// `CREATE (), () ...`). +/// +/// @sa CreateExpand +class CreateNode : public memgraph::query::plan::LogicalOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + CreateNode() {} + + /** + * @param input Optional. If @c nullptr, then a single node will be + * created (a single successful @c Cursor::Pull from this op's @c Cursor). + * If a valid input, then a node will be created for each + * successful pull from the given input. + * @param node_info @c NodeCreationInfo + */ + CreateNode(const std::shared_ptr &input, const NodeCreationInfo &node_info); + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + std::vector ModifiedSymbols(const SymbolTable &) const override; + + bool HasSingleInput() const override { return true; } + std::shared_ptr input() const override { return input_; } + void set_input(std::shared_ptr input) override { input_ = input; } + + std::shared_ptr input_; + memgraph::query::plan::NodeCreationInfo node_info_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->input_ = input_ ? input_->Clone(storage) : nullptr; + object->node_info_ = node_info_.Clone(storage); + return object; + } + + private: + class CreateNodeCursor : public Cursor { + public: + CreateNodeCursor(const CreateNode &, utils::MemoryResource *); + bool Pull(Frame &, ExecutionContext &) override; + void Shutdown() override; + void Reset() override; + + private: + const CreateNode &self_; + const UniqueCursorPtr input_cursor_; + }; +}; + +struct EdgeCreationInfo { + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const { return kType; } + + EdgeCreationInfo() = default; + + EdgeCreationInfo(Symbol symbol, std::variant properties, + storage::EdgeTypeId edge_type, EdgeAtom::Direction direction) + : symbol{std::move(symbol)}, properties{std::move(properties)}, edge_type{edge_type}, direction{direction} {}; + + EdgeCreationInfo(Symbol symbol, PropertiesMapList properties, storage::EdgeTypeId edge_type, + EdgeAtom::Direction direction) + : symbol{std::move(symbol)}, properties{std::move(properties)}, edge_type{edge_type}, direction{direction} {}; + + EdgeCreationInfo(Symbol symbol, ParameterLookup *properties, storage::EdgeTypeId edge_type, + EdgeAtom::Direction direction) + : symbol{std::move(symbol)}, properties{properties}, edge_type{edge_type}, direction{direction} {}; + + Symbol symbol; + std::variant properties; + storage::EdgeTypeId edge_type; + EdgeAtom::Direction direction{EdgeAtom::Direction::BOTH}; + + EdgeCreationInfo Clone(AstStorage *storage) const { + EdgeCreationInfo object; + object.symbol = symbol; + if (const auto *props = std::get_if(&properties)) { + auto &destination_props = std::get(object.properties); + destination_props.resize(props->size()); + for (auto i0 = 0; i0 < props->size(); ++i0) { + { + storage::PropertyId first1 = (*props)[i0].first; + Expression *second2; + second2 = (*props)[i0].second ? (*props)[i0].second->Clone(storage) : nullptr; + destination_props[i0] = std::make_pair(std::move(first1), std::move(second2)); + } + } + } else { + object.properties = std::get(properties)->Clone(storage); + } + object.edge_type = edge_type; + object.direction = direction; + return object; + } +}; + +/// Operator for creating edges and destination nodes. +/// +/// This operator extends already created nodes with an edge. If the other node +/// on the edge does not exist, it will be created. For example, in `MATCH (n) +/// CREATE (n) -[r:r]-> (n)` query, this operator will create just the edge `r`. +/// In `MATCH (n) CREATE (n) -[r:r]-> (m)` query, the operator will create both +/// the edge `r` and the node `m`. In case of `CREATE (n) -[r:r]-> (m)` the +/// first node `n` is created by @c CreateNode operator, while @c CreateExpand +/// will create the edge `r` and `m`. Similarly, multiple @c CreateExpand are +/// chained in cases when longer paths need creating. +/// +/// @sa CreateNode +class CreateExpand : public memgraph::query::plan::LogicalOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + CreateExpand() {} + + /** @brief Construct @c CreateExpand. + * + * @param node_info @c NodeCreationInfo at the end of the edge. + * Used to create a node, unless it refers to an existing one. + * @param edge_info @c EdgeCreationInfo for the edge to be created. + * @param input Optional. Previous @c LogicalOperator which will be pulled. + * For each successful @c Cursor::Pull, this operator will create an + * expansion. + * @param input_symbol @c Symbol for the node at the start of the edge. + * @param existing_node @c bool indicating whether the @c node_atom refers to + * an existing node. If @c false, the operator will also create the node. + */ + CreateExpand(const NodeCreationInfo &node_info, const EdgeCreationInfo &edge_info, + const std::shared_ptr &input, Symbol input_symbol, bool existing_node); + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + std::vector ModifiedSymbols(const SymbolTable &) const override; + + bool HasSingleInput() const override { return true; } + std::shared_ptr input() const override { return input_; } + void set_input(std::shared_ptr input) override { input_ = input; } + + memgraph::query::plan::NodeCreationInfo node_info_; + memgraph::query::plan::EdgeCreationInfo edge_info_; + std::shared_ptr input_; + Symbol input_symbol_; + /// if the given node atom refers to an existing node (either matched or created) + bool existing_node_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->node_info_ = node_info_.Clone(storage); + object->edge_info_ = edge_info_.Clone(storage); + object->input_ = input_ ? input_->Clone(storage) : nullptr; + object->input_symbol_ = input_symbol_; + object->existing_node_ = existing_node_; + return object; + } + + private: + class CreateExpandCursor : public Cursor { + public: + CreateExpandCursor(const CreateExpand &, utils::MemoryResource *); + bool Pull(Frame &, ExecutionContext &) override; + void Shutdown() override; + void Reset() override; + + private: + const CreateExpand &self_; + const UniqueCursorPtr input_cursor_; + + // Get the existing node (if existing_node_ == true), or create a new node + VertexAccessor &OtherVertex(Frame &frame, ExecutionContext &context); + }; +}; + +/// Operator which iterates over all the nodes currently in the database. +/// When given an input (optional), does a cartesian product. +/// +/// It accepts an optional input. If provided then this op scans all the nodes +/// currently in the database for each successful Pull from it's input, thereby +/// producing a cartesian product of input Pulls and database elements. +/// +/// ScanAll can either iterate over the previous graph state (state before +/// the current transacton+command) or over current state. This is controlled +/// with a constructor argument. +/// +/// @sa ScanAllByLabel +/// @sa ScanAllByLabelPropertyRange +/// @sa ScanAllByLabelPropertyValue +class ScanAll : public memgraph::query::plan::LogicalOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + ScanAll() {} + ScanAll(const std::shared_ptr &input, Symbol output_symbol, storage::View view = storage::View::OLD); + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + std::vector ModifiedSymbols(const SymbolTable &) const override; + + bool HasSingleInput() const override { return true; } + std::shared_ptr input() const override { return input_; } + void set_input(std::shared_ptr input) override { input_ = input; } + + std::shared_ptr input_; + Symbol output_symbol_; + /// Controls which graph state is used to produce vertices. + /// + /// If @c storage::View::OLD, @c ScanAll will produce vertices visible in the + /// previous graph state, before modifications done by current transaction & + /// command. With @c storage::View::NEW, all vertices will be produced the current + /// transaction sees along with their modifications. + storage::View view_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->input_ = input_ ? input_->Clone(storage) : nullptr; + object->output_symbol_ = output_symbol_; + object->view_ = view_; + return object; + } +}; + +/// Behaves like @c ScanAll, but this operator produces only vertices with +/// given label. +/// +/// @sa ScanAll +/// @sa ScanAllByLabelPropertyRange +/// @sa ScanAllByLabelPropertyValue +class ScanAllByLabel : public memgraph::query::plan::ScanAll { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + ScanAllByLabel() {} + ScanAllByLabel(const std::shared_ptr &input, Symbol output_symbol, storage::LabelId label, + storage::View view = storage::View::OLD); + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + + storage::LabelId label_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->input_ = input_ ? input_->Clone(storage) : nullptr; + object->output_symbol_ = output_symbol_; + object->view_ = view_; + object->label_ = label_; + return object; + } +}; + +/// Behaves like @c ScanAll, but produces only vertices with given label and +/// property value which is inside a range (inclusive or exlusive). +/// +/// @sa ScanAll +/// @sa ScanAllByLabel +/// @sa ScanAllByLabelPropertyValue +class ScanAllByLabelPropertyRange : public memgraph::query::plan::ScanAll { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + /** Bound with expression which when evaluated produces the bound value. */ + using Bound = utils::Bound; + ScanAllByLabelPropertyRange() {} + /** + * Constructs the operator for given label and property value in range + * (inclusive). + * + * Range bounds are optional, but only one bound can be left out. + * + * @param input Preceding operator which will serve as the input. + * @param output_symbol Symbol where the vertices will be stored. + * @param label Label which the vertex must have. + * @param property Property from which the value will be looked up from. + * @param lower_bound Optional lower @c Bound. + * @param upper_bound Optional upper @c Bound. + * @param view storage::View used when obtaining vertices. + */ + ScanAllByLabelPropertyRange(const std::shared_ptr &input, Symbol output_symbol, + storage::LabelId label, storage::PropertyId property, const std::string &property_name, + std::optional lower_bound, std::optional upper_bound, + storage::View view = storage::View::OLD); + + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + + storage::LabelId label_; + storage::PropertyId property_; + std::string property_name_; + std::optional lower_bound_; + std::optional upper_bound_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->input_ = input_ ? input_->Clone(storage) : nullptr; + object->output_symbol_ = output_symbol_; + object->view_ = view_; + object->label_ = label_; + object->property_ = property_; + object->property_name_ = property_name_; + if (lower_bound_) { + object->lower_bound_.emplace( + utils::Bound(lower_bound_->value()->Clone(storage), lower_bound_->type())); + } else { + object->lower_bound_ = std::nullopt; + } + if (upper_bound_) { + object->upper_bound_.emplace( + utils::Bound(upper_bound_->value()->Clone(storage), upper_bound_->type())); + } else { + object->upper_bound_ = std::nullopt; + } + return object; + } +}; + +/// Behaves like @c ScanAll, but produces only vertices with given label and +/// property value. +/// +/// @sa ScanAll +/// @sa ScanAllByLabel +/// @sa ScanAllByLabelPropertyRange +class ScanAllByLabelPropertyValue : public memgraph::query::plan::ScanAll { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + ScanAllByLabelPropertyValue() {} + /** + * Constructs the operator for given label and property value. + * + * @param input Preceding operator which will serve as the input. + * @param output_symbol Symbol where the vertices will be stored. + * @param label Label which the vertex must have. + * @param property Property from which the value will be looked up from. + * @param expression Expression producing the value of the vertex property. + * @param view storage::View used when obtaining vertices. + */ + ScanAllByLabelPropertyValue(const std::shared_ptr &input, Symbol output_symbol, + storage::LabelId label, storage::PropertyId property, const std::string &property_name, + Expression *expression, storage::View view = storage::View::OLD); + + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + + storage::LabelId label_; + storage::PropertyId property_; + std::string property_name_; + Expression *expression_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->input_ = input_ ? input_->Clone(storage) : nullptr; + object->output_symbol_ = output_symbol_; + object->view_ = view_; + object->label_ = label_; + object->property_ = property_; + object->property_name_ = property_name_; + object->expression_ = expression_ ? expression_->Clone(storage) : nullptr; + return object; + } +}; + +/// Behaves like @c ScanAll, but this operator produces only vertices with +/// given label and property. +/// +/// @sa ScanAll +/// @sa ScanAllByLabelPropertyRange +/// @sa ScanAllByLabelPropertyValue +class ScanAllByLabelProperty : public memgraph::query::plan::ScanAll { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + ScanAllByLabelProperty() {} + ScanAllByLabelProperty(const std::shared_ptr &input, Symbol output_symbol, storage::LabelId label, + storage::PropertyId property, const std::string &property_name, + storage::View view = storage::View::OLD); + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + + storage::LabelId label_; + storage::PropertyId property_; + std::string property_name_; + Expression *expression_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->input_ = input_ ? input_->Clone(storage) : nullptr; + object->output_symbol_ = output_symbol_; + object->view_ = view_; + object->label_ = label_; + object->property_ = property_; + object->property_name_ = property_name_; + object->expression_ = expression_ ? expression_->Clone(storage) : nullptr; + return object; + } +}; + +/// ScanAll producing a single node with ID equal to evaluated expression +class ScanAllById : public memgraph::query::plan::ScanAll { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + ScanAllById() {} + ScanAllById(const std::shared_ptr &input, Symbol output_symbol, Expression *expression, + storage::View view = storage::View::OLD); + + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + + Expression *expression_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->input_ = input_ ? input_->Clone(storage) : nullptr; + object->output_symbol_ = output_symbol_; + object->view_ = view_; + object->expression_ = expression_ ? expression_->Clone(storage) : nullptr; + return object; + } +}; + +struct ExpandCommon { + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const { return kType; } + + /// Symbol pointing to the node to be expanded. + /// This is where the new node will be stored. + Symbol node_symbol; + /// Symbol for the edges to be expanded. + /// This is where a TypedValue containing a list of expanded edges will be stored. + Symbol edge_symbol; + /// EdgeAtom::Direction determining the direction of edge + /// expansion. The direction is relative to the starting vertex for each expansion. + EdgeAtom::Direction direction; + /// storage::EdgeTypeId specifying which edges we want + /// to expand. If empty, all edges are valid. If not empty, only edges with one of + /// the given types are valid. + std::vector edge_types; + /// If the given node atom refer to a symbol + /// that has already been expanded and should be just validated in the frame. + bool existing_node; +}; + +/// Expansion operator. For a node existing in the frame it +/// expands one edge and one node and places them on the frame. +/// +/// This class does not handle node/edge filtering based on +/// properties, labels and edge types. However, it does handle +/// filtering on existing node / edge. +/// +/// Filtering on existing means that for a pattern that references +/// an already declared node or edge (for example in +/// MATCH (a) MATCH (a)--(b)), +/// only expansions that match defined equalities are successfully +/// pulled. +class Expand : public memgraph::query::plan::LogicalOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + /** + * Creates an expansion. All parameters except input and input_symbol are + * forwarded to @c ExpandCommon and are documented there. + * + * @param input Optional logical operator that preceeds this one. + * @param input_symbol Symbol that points to a VertexAccessor in the frame + * that expansion should emanate from. + */ + Expand(const std::shared_ptr &input, Symbol input_symbol, Symbol node_symbol, Symbol edge_symbol, + EdgeAtom::Direction direction, const std::vector &edge_types, bool existing_node, + storage::View view); + + Expand() {} + + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + std::vector ModifiedSymbols(const SymbolTable &) const override; + + bool HasSingleInput() const override { return true; } + std::shared_ptr input() const override { return input_; } + void set_input(std::shared_ptr input) override { input_ = input; } + + class ExpandCursor : public Cursor { + public: + ExpandCursor(const Expand &, utils::MemoryResource *); + bool Pull(Frame &, ExecutionContext &) override; + void Shutdown() override; + void Reset() override; + + private: + using InEdgeT = std::remove_reference_t().InEdges(storage::View::OLD))>; + using InEdgeIteratorT = decltype(std::declval().begin()); + using OutEdgeT = std::remove_reference_t().OutEdges(storage::View::OLD))>; + using OutEdgeIteratorT = decltype(std::declval().begin()); + + const Expand &self_; + const UniqueCursorPtr input_cursor_; + + // The iterable over edges and the current edge iterator are referenced via + // optional because they can not be initialized in the constructor of + // this class. They are initialized once for each pull from the input. + std::optional in_edges_; + std::optional in_edges_it_; + std::optional out_edges_; + std::optional out_edges_it_; + + bool InitEdges(Frame &, ExecutionContext &); + }; + + std::shared_ptr input_; + Symbol input_symbol_; + memgraph::query::plan::ExpandCommon common_; + /// State from which the input node should get expanded. + storage::View view_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->input_ = input_ ? input_->Clone(storage) : nullptr; + object->input_symbol_ = input_symbol_; + object->common_ = common_; + object->view_ = view_; + return object; + } +}; + +struct ExpansionLambda { + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const { return kType; } + + /// Currently expanded edge symbol. + Symbol inner_edge_symbol; + /// Currently expanded node symbol. + Symbol inner_node_symbol; + /// Expression used in lambda during expansion. + Expression *expression; + + ExpansionLambda Clone(AstStorage *storage) const { + ExpansionLambda object; + object.inner_edge_symbol = inner_edge_symbol; + object.inner_node_symbol = inner_node_symbol; + object.expression = expression ? expression->Clone(storage) : nullptr; + return object; + } +}; + +/// Variable-length expansion operator. For a node existing in +/// the frame it expands a variable number of edges and places them +/// (in a list-type TypedValue), as well as the final destination node, +/// on the frame. +/// +/// This class does not handle node/edge filtering based on +/// properties, labels and edge types. However, it does handle +/// filtering on existing node / edge. Additionally it handles's +/// edge-uniquess (cyphermorphism) because it's not feasable to do +/// later. +/// +/// Filtering on existing means that for a pattern that references +/// an already declared node or edge (for example in +/// MATCH (a) MATCH (a)--(b)), +/// only expansions that match defined equalities are succesfully +/// pulled. +class ExpandVariable : public memgraph::query::plan::LogicalOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + ExpandVariable() {} + + /** + * Creates a variable-length expansion. Most params are forwarded + * to the @c ExpandCommon constructor, and are documented there. + * + * Expansion length bounds are both inclusive (as in Neo's Cypher + * implementation). + * + * @param input Optional logical operator that preceeds this one. + * @param input_symbol Symbol that points to a VertexAccessor in the frame + * that expansion should emanate from. + * @param type - Either Type::DEPTH_FIRST (default variable-length expansion), + * or Type::BREADTH_FIRST. + * @param is_reverse Set to `true` if the edges written on frame should expand + * from `node_symbol` to `input_symbol`. Opposed to the usual expanding + * from `input_symbol` to `node_symbol`. + * @param lower_bound An optional indicator of the minimum number of edges + * that get expanded (inclusive). + * @param upper_bound An optional indicator of the maximum number of edges + * that get expanded (inclusive). + * @param inner_edge_symbol Like `inner_node_symbol` + * @param inner_node_symbol For each expansion the node expanded into is + * assigned to this symbol so it can be evaulated by the 'where' + * expression. + * @param filter_ The filter that must be satisfied for an expansion to + * succeed. Can use inner(node/edge) symbols. If nullptr, it is ignored. + */ + ExpandVariable(const std::shared_ptr &input, Symbol input_symbol, Symbol node_symbol, + Symbol edge_symbol, EdgeAtom::Type type, EdgeAtom::Direction direction, + const std::vector &edge_types, bool is_reverse, Expression *lower_bound, + Expression *upper_bound, bool existing_node, ExpansionLambda filter_lambda, + std::optional weight_lambda, std::optional total_weight); + + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + std::vector ModifiedSymbols(const SymbolTable &) const override; + + bool HasSingleInput() const override { return true; } + std::shared_ptr input() const override { return input_; } + void set_input(std::shared_ptr input) override { input_ = input; } + + std::shared_ptr input_; + Symbol input_symbol_; + memgraph::query::plan::ExpandCommon common_; + EdgeAtom::Type type_; + /// True if the path should be written as expanding from node_symbol to input_symbol. + bool is_reverse_; + /// Optional lower bound of the variable length expansion, defaults are (1, inf) + Expression *lower_bound_; + /// Optional upper bound of the variable length expansion, defaults are (1, inf) + Expression *upper_bound_; + memgraph::query::plan::ExpansionLambda filter_lambda_; + std::optional weight_lambda_; + std::optional total_weight_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->input_ = input_ ? input_->Clone(storage) : nullptr; + object->input_symbol_ = input_symbol_; + object->common_ = common_; + object->type_ = type_; + object->is_reverse_ = is_reverse_; + object->lower_bound_ = lower_bound_ ? lower_bound_->Clone(storage) : nullptr; + object->upper_bound_ = upper_bound_ ? upper_bound_->Clone(storage) : nullptr; + object->filter_lambda_ = filter_lambda_.Clone(storage); + if (weight_lambda_) { + memgraph::query::plan::ExpansionLambda value0; + value0 = (*weight_lambda_).Clone(storage); + object->weight_lambda_.emplace(std::move(value0)); + } else { + object->weight_lambda_ = std::nullopt; + } + object->total_weight_ = total_weight_; + return object; + } + + private: + // the Cursors are not declared in the header because + // it's edges_ and edges_it_ are decltyped using a helper function + // that should be inaccessible (private class function won't compile) + friend class ExpandVariableCursor; + friend class ExpandWeightedShortestPathCursor; + friend class ExpandAllShortestPathCursor; +}; + +/// Constructs a named path from its elements and places it on the frame. +class ConstructNamedPath : public memgraph::query::plan::LogicalOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + ConstructNamedPath() {} + ConstructNamedPath(const std::shared_ptr &input, Symbol path_symbol, + const std::vector &path_elements) + : input_(input), path_symbol_(path_symbol), path_elements_(path_elements) {} + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + std::vector ModifiedSymbols(const SymbolTable &) const override; + + bool HasSingleInput() const override { return true; } + std::shared_ptr input() const override { return input_; } + void set_input(std::shared_ptr input) override { input_ = input; } + + std::shared_ptr input_; + Symbol path_symbol_; + std::vector path_elements_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->input_ = input_ ? input_->Clone(storage) : nullptr; + object->path_symbol_ = path_symbol_; + object->path_elements_ = path_elements_; + return object; + } +}; + +/// Filter whose Pull returns true only when the given expression +/// evaluates into true. +/// +/// The given expression is assumed to return either NULL (treated as false) or +/// a boolean value. +class Filter : public memgraph::query::plan::LogicalOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + Filter() {} + + Filter(const std::shared_ptr &input_, + const std::vector> &pattern_filters_, Expression *expression_); + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + std::vector ModifiedSymbols(const SymbolTable &) const override; + + bool HasSingleInput() const override { return true; } + std::shared_ptr input() const override { return input_; } + void set_input(std::shared_ptr input) override { input_ = input; } + + std::shared_ptr input_; + std::vector> pattern_filters_; + Expression *expression_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->input_ = input_ ? input_->Clone(storage) : nullptr; + object->pattern_filters_.resize(pattern_filters_.size()); + for (auto i1 = 0; i1 < pattern_filters_.size(); ++i1) { + object->pattern_filters_[i1] = pattern_filters_[i1] ? pattern_filters_[i1]->Clone(storage) : nullptr; + } + object->expression_ = expression_ ? expression_->Clone(storage) : nullptr; + return object; + } + + private: + class FilterCursor : public Cursor { + public: + FilterCursor(const Filter &, utils::MemoryResource *); + bool Pull(Frame &, ExecutionContext &) override; + void Shutdown() override; + void Reset() override; + + private: + const Filter &self_; + const UniqueCursorPtr input_cursor_; + const std::vector pattern_filter_cursors_; + }; +}; + +/// A logical operator that places an arbitrary number +/// of named expressions on the frame (the logical operator +/// for the RETURN clause). +/// +/// Supports optional input. When the input is provided, +/// it is Pulled from and the Produce succeeds once for +/// every input Pull (typically a MATCH/RETURN query). +/// When the input is not provided (typically a standalone +/// RETURN clause) the Produce's pull succeeds exactly once. +class Produce : public memgraph::query::plan::LogicalOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + Produce() {} + + Produce(const std::shared_ptr &input, const std::vector &named_expressions); + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + std::vector OutputSymbols(const SymbolTable &) const override; + std::vector ModifiedSymbols(const SymbolTable &) const override; + + bool HasSingleInput() const override { return true; } + std::shared_ptr input() const override { return input_; } + void set_input(std::shared_ptr input) override { input_ = input; } + + std::shared_ptr input_; + std::vector named_expressions_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->input_ = input_ ? input_->Clone(storage) : nullptr; + object->named_expressions_.resize(named_expressions_.size()); + for (auto i1 = 0; i1 < named_expressions_.size(); ++i1) { + object->named_expressions_[i1] = named_expressions_[i1] ? named_expressions_[i1]->Clone(storage) : nullptr; + } + return object; + } + + private: + class ProduceCursor : public Cursor { + public: + ProduceCursor(const Produce &, utils::MemoryResource *); + bool Pull(Frame &, ExecutionContext &) override; + void Shutdown() override; + void Reset() override; + + private: + const Produce &self_; + const UniqueCursorPtr input_cursor_; + }; +}; + +/// Operator for deleting vertices and edges. +/// +/// Has a flag for using DETACH DELETE when deleting vertices. +class Delete : public memgraph::query::plan::LogicalOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + Delete() {} + + Delete(const std::shared_ptr &input_, const std::vector &expressions, bool detach_); + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + std::vector ModifiedSymbols(const SymbolTable &) const override; + + bool HasSingleInput() const override { return true; } + std::shared_ptr input() const override { return input_; } + void set_input(std::shared_ptr input) override { input_ = input; } + + std::shared_ptr input_; + std::vector expressions_; + /// Whether the vertex should be detached before deletion. If not detached, + /// and has connections, an error is raised when deleting edges. + bool detach_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->input_ = input_ ? input_->Clone(storage) : nullptr; + object->expressions_.resize(expressions_.size()); + for (auto i2 = 0; i2 < expressions_.size(); ++i2) { + object->expressions_[i2] = expressions_[i2] ? expressions_[i2]->Clone(storage) : nullptr; + } + object->detach_ = detach_; + return object; + } + + private: + class DeleteCursor : public Cursor { + public: + DeleteCursor(const Delete &, utils::MemoryResource *); + bool Pull(Frame &, ExecutionContext &) override; + void Shutdown() override; + void Reset() override; + + private: + const Delete &self_; + const UniqueCursorPtr input_cursor_; + }; +}; + +/// Logical operator for setting a single property on a single vertex or edge. +/// +/// The property value is an expression that must evaluate to some type that +/// can be stored (a TypedValue that can be converted to PropertyValue). +class SetProperty : public memgraph::query::plan::LogicalOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + SetProperty() {} + + SetProperty(const std::shared_ptr &input, storage::PropertyId property, PropertyLookup *lhs, + Expression *rhs); + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + std::vector ModifiedSymbols(const SymbolTable &) const override; + + bool HasSingleInput() const override { return true; } + std::shared_ptr input() const override { return input_; } + void set_input(std::shared_ptr input) override { input_ = input; } + + std::shared_ptr input_; + storage::PropertyId property_; + PropertyLookup *lhs_; + Expression *rhs_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->input_ = input_ ? input_->Clone(storage) : nullptr; + object->property_ = property_; + object->lhs_ = lhs_ ? lhs_->Clone(storage) : nullptr; + object->rhs_ = rhs_ ? rhs_->Clone(storage) : nullptr; + return object; + } + + private: + class SetPropertyCursor : public Cursor { + public: + SetPropertyCursor(const SetProperty &, utils::MemoryResource *); + bool Pull(Frame &, ExecutionContext &) override; + void Shutdown() override; + void Reset() override; + + private: + const SetProperty &self_; + const UniqueCursorPtr input_cursor_; + }; +}; + +/// Logical operator for setting the whole property set on a vertex or an edge. +/// +/// The value being set is an expression that must evaluate to a vertex, edge or +/// map (literal or parameter). +/// +/// Supports setting (replacing the whole properties set with another) and +/// updating. +class SetProperties : public memgraph::query::plan::LogicalOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + /// Defines how setting the properties works. + /// + /// @c UPDATE means that the current property set is augmented with additional + /// ones (existing props of the same name are replaced), while @c REPLACE means + /// that the old properties are discarded and replaced with new ones. + enum class Op { UPDATE, REPLACE }; + + SetProperties() {} + + SetProperties(const std::shared_ptr &input, Symbol input_symbol, Expression *rhs, Op op); + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + std::vector ModifiedSymbols(const SymbolTable &) const override; + + bool HasSingleInput() const override { return true; } + std::shared_ptr input() const override { return input_; } + void set_input(std::shared_ptr input) override { input_ = input; } + + std::shared_ptr input_; + Symbol input_symbol_; + Expression *rhs_; + memgraph::query::plan::SetProperties::Op op_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->input_ = input_ ? input_->Clone(storage) : nullptr; + object->input_symbol_ = input_symbol_; + object->rhs_ = rhs_ ? rhs_->Clone(storage) : nullptr; + object->op_ = op_; + return object; + } + + private: + class SetPropertiesCursor : public Cursor { + public: + SetPropertiesCursor(const SetProperties &, utils::MemoryResource *); + bool Pull(Frame &, ExecutionContext &) override; + void Shutdown() override; + void Reset() override; + + private: + const SetProperties &self_; + const UniqueCursorPtr input_cursor_; + }; +}; + +/// Logical operator for setting an arbitrary number of labels on a Vertex. +/// +/// It does NOT remove labels that are already set on that Vertex. +class SetLabels : public memgraph::query::plan::LogicalOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + SetLabels() {} + + SetLabels(const std::shared_ptr &input, Symbol input_symbol, + const std::vector &labels); + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + std::vector ModifiedSymbols(const SymbolTable &) const override; + + bool HasSingleInput() const override { return true; } + std::shared_ptr input() const override { return input_; } + void set_input(std::shared_ptr input) override { input_ = input; } + + std::shared_ptr input_; + Symbol input_symbol_; + std::vector labels_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->input_ = input_ ? input_->Clone(storage) : nullptr; + object->input_symbol_ = input_symbol_; + object->labels_ = labels_; + return object; + } + + private: + class SetLabelsCursor : public Cursor { + public: + SetLabelsCursor(const SetLabels &, utils::MemoryResource *); + bool Pull(Frame &, ExecutionContext &) override; + void Shutdown() override; + void Reset() override; + + private: + const SetLabels &self_; + const UniqueCursorPtr input_cursor_; + }; +}; + +/// Logical operator for removing a property from an edge or a vertex. +class RemoveProperty : public memgraph::query::plan::LogicalOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + RemoveProperty() {} + + RemoveProperty(const std::shared_ptr &input, storage::PropertyId property, PropertyLookup *lhs); + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + std::vector ModifiedSymbols(const SymbolTable &) const override; + + bool HasSingleInput() const override { return true; } + std::shared_ptr input() const override { return input_; } + void set_input(std::shared_ptr input) override { input_ = input; } + + std::shared_ptr input_; + storage::PropertyId property_; + PropertyLookup *lhs_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->input_ = input_ ? input_->Clone(storage) : nullptr; + object->property_ = property_; + object->lhs_ = lhs_ ? lhs_->Clone(storage) : nullptr; + return object; + } + + private: + class RemovePropertyCursor : public Cursor { + public: + RemovePropertyCursor(const RemoveProperty &, utils::MemoryResource *); + bool Pull(Frame &, ExecutionContext &) override; + void Shutdown() override; + void Reset() override; + + private: + const RemoveProperty &self_; + const UniqueCursorPtr input_cursor_; + }; +}; + +/// Logical operator for removing an arbitrary number of labels on a Vertex. +/// +/// If a label does not exist on a Vertex, nothing happens. +class RemoveLabels : public memgraph::query::plan::LogicalOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + RemoveLabels() {} + + RemoveLabels(const std::shared_ptr &input, Symbol input_symbol, + const std::vector &labels); + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + std::vector ModifiedSymbols(const SymbolTable &) const override; + + bool HasSingleInput() const override { return true; } + std::shared_ptr input() const override { return input_; } + void set_input(std::shared_ptr input) override { input_ = input; } + + std::shared_ptr input_; + Symbol input_symbol_; + std::vector labels_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->input_ = input_ ? input_->Clone(storage) : nullptr; + object->input_symbol_ = input_symbol_; + object->labels_ = labels_; + return object; + } + + private: + class RemoveLabelsCursor : public Cursor { + public: + RemoveLabelsCursor(const RemoveLabels &, utils::MemoryResource *); + bool Pull(Frame &, ExecutionContext &) override; + void Shutdown() override; + void Reset() override; + + private: + const RemoveLabels &self_; + const UniqueCursorPtr input_cursor_; + }; +}; + +/// Filter whose Pull returns true only when the given expand_symbol frame +/// value (the latest expansion) is not equal to any of the previous_symbols frame +/// values. +/// +/// Used for implementing Cyphermorphism. +/// Isomorphism is vertex-uniqueness. It means that two different vertices in a +/// pattern can not map to the same data vertex. +/// Cyphermorphism is edge-uniqueness (the above explanation applies). By default +/// Neo4j uses Cyphermorphism (that's where the name stems from, it is not a valid +/// graph-theory term). +/// +/// Supports variable-length-edges (uniqueness comparisons between edges and an +/// edge lists). +class EdgeUniquenessFilter : public memgraph::query::plan::LogicalOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + EdgeUniquenessFilter() {} + + EdgeUniquenessFilter(const std::shared_ptr &input, Symbol expand_symbol, + const std::vector &previous_symbols); + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + std::vector ModifiedSymbols(const SymbolTable &) const override; + + bool HasSingleInput() const override { return true; } + std::shared_ptr input() const override { return input_; } + void set_input(std::shared_ptr input) override { input_ = input; } + + std::shared_ptr input_; + Symbol expand_symbol_; + std::vector previous_symbols_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->input_ = input_ ? input_->Clone(storage) : nullptr; + object->expand_symbol_ = expand_symbol_; + object->previous_symbols_ = previous_symbols_; + return object; + } + + private: + class EdgeUniquenessFilterCursor : public Cursor { + public: + EdgeUniquenessFilterCursor(const EdgeUniquenessFilter &, utils::MemoryResource *); + bool Pull(Frame &, ExecutionContext &) override; + void Shutdown() override; + void Reset() override; + + private: + const EdgeUniquenessFilter &self_; + const UniqueCursorPtr input_cursor_; + }; +}; + +/// Pulls everything from the input and discards it. +/// +/// On the first Pull from this operator's Cursor the input Cursor will be Pulled +/// until it is empty. The results won't be accumulated in the temporary cache. +/// +/// This technique is used for ensuring that the cursor has been exhausted after +/// a WriteHandleClause. A typical use case is a `MATCH--SET` query with RETURN statement +/// missing. +/// @param input Input @c LogicalOperator. +class EmptyResult : public memgraph::query::plan::LogicalOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + EmptyResult() {} + + EmptyResult(const std::shared_ptr &input); + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + std::vector OutputSymbols(const SymbolTable &) const override; + std::vector ModifiedSymbols(const SymbolTable &) const override; + + bool HasSingleInput() const override { return true; } + std::shared_ptr input() const override { return input_; } + void set_input(std::shared_ptr input) override { input_ = input; } + + std::shared_ptr input_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->input_ = input_ ? input_->Clone(storage) : nullptr; + return object; + } +}; + +/// Pulls everything from the input before passing it through. +/// Optionally advances the command after accumulation and before emitting. +/// +/// On the first Pull from this operator's Cursor the input Cursor will be Pulled +/// until it is empty. The results will be accumulated in the temporary cache. Once +/// the input Cursor is empty, this operator's Cursor will start returning cached +/// stuff from its Pull. +/// +/// This technique is used for ensuring all the operations from the +/// previous logical operator have been performed before exposing data +/// to the next. A typical use case is a `MATCH--SET--RETURN` +/// query in which every SET iteration must be performed before +/// RETURN starts iterating (see Memgraph Wiki for detailed reasoning). +/// +/// IMPORTANT: This operator does not cache all the results but only those +/// elements from the frame whose symbols (frame positions) it was given. +/// All other frame positions will contain undefined junk after this +/// operator has executed, and should not be used. +/// +/// This operator can also advance the command after the accumulation and +/// before emitting. If the command gets advanced, every value that +/// has been cached will be reconstructed before Pull returns. +/// +/// @param input Input @c LogicalOperator. +/// @param symbols A vector of Symbols that need to be accumulated +/// and exposed to the next op. +class Accumulate : public memgraph::query::plan::LogicalOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + Accumulate() {} + + Accumulate(const std::shared_ptr &input, const std::vector &symbols, + bool advance_command = false); + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + std::vector ModifiedSymbols(const SymbolTable &) const override; + + bool HasSingleInput() const override { return true; } + std::shared_ptr input() const override { return input_; } + void set_input(std::shared_ptr input) override { input_ = input; } + + std::shared_ptr input_; + std::vector symbols_; + bool advance_command_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->input_ = input_ ? input_->Clone(storage) : nullptr; + object->symbols_ = symbols_; + object->advance_command_ = advance_command_; + return object; + } +}; + +/// Performs an arbitrary number of aggregations of data +/// from the given input grouped by the given criteria. +/// +/// Aggregations are defined by triples that define +/// (input data expression, type of aggregation, output symbol). +/// Input data is grouped based on the given set of named +/// expressions. Grouping is done on unique values. +/// +/// IMPORTANT: +/// Operators taking their input from an aggregation are only +/// allowed to use frame values that are either aggregation +/// outputs or group-by named-expressions. All other frame +/// elements are in an undefined state after aggregation. +class Aggregate : public memgraph::query::plan::LogicalOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + /// An aggregation element, contains: + /// (input data expression, key expression - only used in COLLECT_MAP, type of + /// aggregation, output symbol). + struct Element { + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const { return kType; } + + Expression *value; + Expression *key; + Aggregation::Op op; + Symbol output_sym; + bool distinct{false}; + + Element Clone(AstStorage *storage) const { + Element object; + object.value = value ? value->Clone(storage) : nullptr; + object.key = key ? key->Clone(storage) : nullptr; + object.op = op; + object.output_sym = output_sym; + object.distinct = distinct; + return object; + } + }; + + Aggregate() = default; + Aggregate(const std::shared_ptr &input, const std::vector &aggregations, + const std::vector &group_by, const std::vector &remember); + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + std::vector ModifiedSymbols(const SymbolTable &) const override; + + bool HasSingleInput() const override { return true; } + std::shared_ptr input() const override { return input_; } + void set_input(std::shared_ptr input) override { input_ = input; } + + std::shared_ptr input_; + std::vector aggregations_; + std::vector group_by_; + std::vector remember_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->input_ = input_ ? input_->Clone(storage) : nullptr; + object->aggregations_.resize(aggregations_.size()); + for (auto i3 = 0; i3 < aggregations_.size(); ++i3) { + object->aggregations_[i3] = aggregations_[i3].Clone(storage); + } + object->group_by_.resize(group_by_.size()); + for (auto i4 = 0; i4 < group_by_.size(); ++i4) { + object->group_by_[i4] = group_by_[i4] ? group_by_[i4]->Clone(storage) : nullptr; + } + object->remember_ = remember_; + return object; + } +}; + +/// Skips a number of Pulls from the input op. +/// +/// The given expression determines how many Pulls from the input +/// should be skipped (ignored). +/// All other successful Pulls from the +/// input are simply passed through. +/// +/// The given expression is evaluated after the first Pull from +/// the input, and only once. Neo does not allow this expression +/// to contain identifiers, and neither does Memgraph, but this +/// operator's implementation does not expect this. +class Skip : public memgraph::query::plan::LogicalOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + Skip() {} + + Skip(const std::shared_ptr &input, Expression *expression); + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + std::vector OutputSymbols(const SymbolTable &) const override; + std::vector ModifiedSymbols(const SymbolTable &) const override; + + bool HasSingleInput() const override { return true; } + std::shared_ptr input() const override { return input_; } + void set_input(std::shared_ptr input) override { input_ = input; } + + std::shared_ptr input_; + Expression *expression_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->input_ = input_ ? input_->Clone(storage) : nullptr; + object->expression_ = expression_ ? expression_->Clone(storage) : nullptr; + return object; + } + + private: + class SkipCursor : public Cursor { + public: + SkipCursor(const Skip &, utils::MemoryResource *); + bool Pull(Frame &, ExecutionContext &) override; + void Shutdown() override; + void Reset() override; + + private: + const Skip &self_; + const UniqueCursorPtr input_cursor_; + // init to_skip_ to -1, indicating + // that it's still unknown (input has not been Pulled yet) + int64_t to_skip_{-1}; + int64_t skipped_{0}; + }; +}; + +/// Applies the pattern filter by putting the value of the input cursor to the frame. +class EvaluatePatternFilter : public memgraph::query::plan::LogicalOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + EvaluatePatternFilter() {} + + EvaluatePatternFilter(const std::shared_ptr &input, Symbol output_symbol); + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + std::vector ModifiedSymbols(const SymbolTable &) const override; + + bool HasSingleInput() const override { return true; } + std::shared_ptr input() const override { return input_; } + void set_input(std::shared_ptr input) override { input_ = input; } + + std::shared_ptr input_; + Symbol output_symbol_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->input_ = input_ ? input_->Clone(storage) : nullptr; + object->output_symbol_ = output_symbol_; + return object; + } + + private: + class EvaluatePatternFilterCursor : public Cursor { + public: + EvaluatePatternFilterCursor(const EvaluatePatternFilter &, utils::MemoryResource *); + bool Pull(Frame &, ExecutionContext &) override; + void Shutdown() override; + void Reset() override; + + private: + const EvaluatePatternFilter &self_; + UniqueCursorPtr input_cursor_; + }; +}; + +/// Limits the number of Pulls from the input op. +/// +/// The given expression determines how many +/// input Pulls should be passed through. The input is not +/// Pulled once this limit is reached. Note that this has +/// implications: the out-of-bounds input Pulls are never +/// evaluated. +/// +/// The limit expression must NOT use anything from the +/// Frame. It is evaluated before the first Pull from the +/// input. This is consistent with Neo (they don't allow +/// identifiers in limit expressions), and it's necessary +/// when limit evaluates to 0 (because 0 Pulls from the +/// input should be performed). +class Limit : public memgraph::query::plan::LogicalOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + Limit() {} + + Limit(const std::shared_ptr &input, Expression *expression); + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + std::vector OutputSymbols(const SymbolTable &) const override; + std::vector ModifiedSymbols(const SymbolTable &) const override; + + bool HasSingleInput() const override { return true; } + std::shared_ptr input() const override { return input_; } + void set_input(std::shared_ptr input) override { input_ = input; } + + std::shared_ptr input_; + Expression *expression_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->input_ = input_ ? input_->Clone(storage) : nullptr; + object->expression_ = expression_ ? expression_->Clone(storage) : nullptr; + return object; + } + + private: + class LimitCursor : public Cursor { + public: + LimitCursor(const Limit &, utils::MemoryResource *); + bool Pull(Frame &, ExecutionContext &) override; + void Shutdown() override; + void Reset() override; + + private: + const Limit &self_; + UniqueCursorPtr input_cursor_; + // init limit_ to -1, indicating + // that it's still unknown (Cursor has not been Pulled yet) + int64_t limit_{-1}; + int64_t pulled_{0}; + }; +}; + +/// Logical operator for ordering (sorting) results. +/// +/// Sorts the input rows based on an arbitrary number of +/// Expressions. Ascending or descending ordering can be chosen +/// for each independently (not providing enough orderings +/// results in a runtime error). +/// +/// For each row an arbitrary number of Frame elements can be +/// remembered. Only these elements (defined by their Symbols) +/// are valid for usage after the OrderBy operator. +class OrderBy : public memgraph::query::plan::LogicalOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + OrderBy() {} + + OrderBy(const std::shared_ptr &input, const std::vector &order_by, + const std::vector &output_symbols); + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + std::vector OutputSymbols(const SymbolTable &) const override; + std::vector ModifiedSymbols(const SymbolTable &) const override; + + bool HasSingleInput() const override { return true; } + std::shared_ptr input() const override { return input_; } + void set_input(std::shared_ptr input) override { input_ = input; } + + std::shared_ptr input_; + TypedValueVectorCompare compare_; + std::vector order_by_; + std::vector output_symbols_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->input_ = input_ ? input_->Clone(storage) : nullptr; + object->compare_ = compare_; + object->order_by_.resize(order_by_.size()); + for (auto i5 = 0; i5 < order_by_.size(); ++i5) { + object->order_by_[i5] = order_by_[i5] ? order_by_[i5]->Clone(storage) : nullptr; + } + object->output_symbols_ = output_symbols_; + return object; + } +}; + +/// Merge operator. For every sucessful Pull from the +/// input operator a Pull from the merge_match is attempted. All +/// successfull Pulls from the merge_match are passed on as output. +/// If merge_match Pull does not yield any elements, a single Pull +/// from the merge_create op is performed. +/// +/// The input logical op is optional. If false (nullptr) +/// it will be replaced by a Once op. +/// +/// For an argumentation of this implementation see the wiki +/// documentation. +class Merge : public memgraph::query::plan::LogicalOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + Merge() {} + + Merge(const std::shared_ptr &input, const std::shared_ptr &merge_match, + const std::shared_ptr &merge_create); + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + std::vector ModifiedSymbols(const SymbolTable &) const override; + + // TODO: Consider whether we want to treat Merge as having single input. It + // makes sense that we do, because other branches are executed depending on + // the input. + bool HasSingleInput() const override { return true; } + std::shared_ptr input() const override { return input_; } + void set_input(std::shared_ptr input) override { input_ = input; } + + std::shared_ptr input_; + std::shared_ptr merge_match_; + std::shared_ptr merge_create_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->input_ = input_ ? input_->Clone(storage) : nullptr; + object->merge_match_ = merge_match_ ? merge_match_->Clone(storage) : nullptr; + object->merge_create_ = merge_create_ ? merge_create_->Clone(storage) : nullptr; + return object; + } + + private: + class MergeCursor : public Cursor { + public: + MergeCursor(const Merge &, utils::MemoryResource *); + bool Pull(Frame &, ExecutionContext &) override; + void Shutdown() override; + void Reset() override; + + private: + const UniqueCursorPtr input_cursor_; + const UniqueCursorPtr merge_match_cursor_; + const UniqueCursorPtr merge_create_cursor_; + + // indicates if the next Pull from this cursor + // should perform a pull from input_cursor_ + // this is true when: + // - first Pulling from this cursor + // - previous Pull from this cursor exhausted the merge_match_cursor + bool pull_input_{true}; + }; +}; + +/// Optional operator. Used for optional match. For every +/// successful Pull from the input branch a Pull from the optional +/// branch is attempted (and Pulled from till exhausted). If zero +/// Pulls succeed from the optional branch, the Optional operator +/// sets the optional symbols to TypedValue::Null on the Frame +/// and returns true, once. +class Optional : public memgraph::query::plan::LogicalOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + Optional() {} + + Optional(const std::shared_ptr &input, const std::shared_ptr &optional, + const std::vector &optional_symbols); + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + std::vector ModifiedSymbols(const SymbolTable &) const override; + + bool HasSingleInput() const override { return true; } + std::shared_ptr input() const override { return input_; } + void set_input(std::shared_ptr input) override { input_ = input; } + + std::shared_ptr input_; + std::shared_ptr optional_; + std::vector optional_symbols_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->input_ = input_ ? input_->Clone(storage) : nullptr; + object->optional_ = optional_ ? optional_->Clone(storage) : nullptr; + object->optional_symbols_ = optional_symbols_; + return object; + } + + private: + class OptionalCursor : public Cursor { + public: + OptionalCursor(const Optional &, utils::MemoryResource *); + bool Pull(Frame &, ExecutionContext &) override; + void Shutdown() override; + void Reset() override; + + private: + const Optional &self_; + const UniqueCursorPtr input_cursor_; + const UniqueCursorPtr optional_cursor_; + // indicates if the next Pull from this cursor should + // perform a Pull from the input_cursor_ + // this is true when: + // - first pulling from this Cursor + // - previous Pull from this cursor exhausted the optional_cursor_ + bool pull_input_{true}; + }; +}; + +/// Takes a list TypedValue as it's input and yields each +/// element as it's output. +/// +/// Input is optional (unwind can be the first clause in a query). +class Unwind : public memgraph::query::plan::LogicalOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + Unwind() {} + + Unwind(const std::shared_ptr &input, Expression *input_expression_, Symbol output_symbol); + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + std::vector ModifiedSymbols(const SymbolTable &) const override; + + bool HasSingleInput() const override { return true; } + std::shared_ptr input() const override { return input_; } + void set_input(std::shared_ptr input) override { input_ = input; } + + std::shared_ptr input_; + Expression *input_expression_; + Symbol output_symbol_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->input_ = input_ ? input_->Clone(storage) : nullptr; + object->input_expression_ = input_expression_ ? input_expression_->Clone(storage) : nullptr; + object->output_symbol_ = output_symbol_; + return object; + } +}; + +/// Ensures that only distinct rows are yielded. +/// This implementation accepts a vector of Symbols +/// which define a row. Only those Symbols are valid +/// for use in operators following Distinct. +/// +/// This implementation maintains input ordering. +class Distinct : public memgraph::query::plan::LogicalOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + Distinct() {} + + Distinct(const std::shared_ptr &input, const std::vector &value_symbols); + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + std::vector OutputSymbols(const SymbolTable &) const override; + std::vector ModifiedSymbols(const SymbolTable &) const override; + + bool HasSingleInput() const override { return true; } + std::shared_ptr input() const override { return input_; } + void set_input(std::shared_ptr input) override { input_ = input; } + + std::shared_ptr input_; + std::vector value_symbols_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->input_ = input_ ? input_->Clone(storage) : nullptr; + object->value_symbols_ = value_symbols_; + return object; + } +}; + +/// A logical operator that applies UNION operator on inputs and places the +/// result on the frame. +/// +/// This operator takes two inputs, a vector of symbols for the result, and vectors +/// of symbols used by each of the inputs. +class Union : public memgraph::query::plan::LogicalOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + Union() {} + + Union(const std::shared_ptr &left_op, const std::shared_ptr &right_op, + const std::vector &union_symbols, const std::vector &left_symbols, + const std::vector &right_symbols); + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + std::vector OutputSymbols(const SymbolTable &) const override; + std::vector ModifiedSymbols(const SymbolTable &) const override; + + bool HasSingleInput() const override; + std::shared_ptr input() const override; + void set_input(std::shared_ptr) override; + + std::shared_ptr left_op_; + std::shared_ptr right_op_; + std::vector union_symbols_; + std::vector left_symbols_; + std::vector right_symbols_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->left_op_ = left_op_ ? left_op_->Clone(storage) : nullptr; + object->right_op_ = right_op_ ? right_op_->Clone(storage) : nullptr; + object->union_symbols_ = union_symbols_; + object->left_symbols_ = left_symbols_; + object->right_symbols_ = right_symbols_; + return object; + } + + private: + class UnionCursor : public Cursor { + public: + UnionCursor(const Union &, utils::MemoryResource *); + bool Pull(Frame &, ExecutionContext &) override; + void Shutdown() override; + void Reset() override; + + private: + const Union &self_; + const UniqueCursorPtr left_cursor_, right_cursor_; + }; +}; + +/// Operator for producing a Cartesian product from 2 input branches +class Cartesian : public memgraph::query::plan::LogicalOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + Cartesian() {} + /** Construct the operator with left input branch and right input branch. */ + Cartesian(const std::shared_ptr &left_op, const std::vector &left_symbols, + const std::shared_ptr &right_op, const std::vector &right_symbols) + : left_op_(left_op), left_symbols_(left_symbols), right_op_(right_op), right_symbols_(right_symbols) {} + + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + std::vector ModifiedSymbols(const SymbolTable &) const override; + + bool HasSingleInput() const override; + std::shared_ptr input() const override; + void set_input(std::shared_ptr) override; + + std::shared_ptr left_op_; + std::vector left_symbols_; + std::shared_ptr right_op_; + std::vector right_symbols_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->left_op_ = left_op_ ? left_op_->Clone(storage) : nullptr; + object->left_symbols_ = left_symbols_; + object->right_op_ = right_op_ ? right_op_->Clone(storage) : nullptr; + object->right_symbols_ = right_symbols_; + return object; + } +}; + +/// An operator that outputs a table, producing a single row on each pull +class OutputTable : public memgraph::query::plan::LogicalOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + OutputTable() {} + OutputTable(std::vector output_symbols, + std::function>(Frame *, ExecutionContext *)> callback); + OutputTable(std::vector output_symbols, std::vector> rows); + + bool Accept(HierarchicalLogicalOperatorVisitor &) override { + LOG_FATAL("OutputTable operator should not be visited!"); + } + + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + std::vector OutputSymbols(const SymbolTable &) const override { return output_symbols_; } + std::vector ModifiedSymbols(const SymbolTable &) const override { return output_symbols_; } + + bool HasSingleInput() const override; + std::shared_ptr input() const override; + void set_input(std::shared_ptr input) override; + + std::vector output_symbols_; + std::function>(Frame *, ExecutionContext *)> callback_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->output_symbols_ = output_symbols_; + object->callback_ = callback_; + return object; + } +}; + +/// An operator that outputs a table, producing a single row on each pull. +/// This class is different from @c OutputTable in that its callback doesn't fetch all rows +/// at once. Instead, each call of the callback should return a single row of the table. +class OutputTableStream : public memgraph::query::plan::LogicalOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + OutputTableStream() {} + OutputTableStream(std::vector output_symbols, + std::function>(Frame *, ExecutionContext *)> callback); + + bool Accept(HierarchicalLogicalOperatorVisitor &) override { + LOG_FATAL("OutputTableStream operator should not be visited!"); + } + + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + std::vector OutputSymbols(const SymbolTable &) const override { return output_symbols_; } + std::vector ModifiedSymbols(const SymbolTable &) const override { return output_symbols_; } + + bool HasSingleInput() const override; + std::shared_ptr input() const override; + void set_input(std::shared_ptr input) override; + + std::vector output_symbols_; + std::function>(Frame *, ExecutionContext *)> callback_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->output_symbols_ = output_symbols_; + object->callback_ = callback_; + return object; + } +}; + +class CallProcedure : public memgraph::query::plan::LogicalOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + CallProcedure() = default; + CallProcedure(std::shared_ptr input, std::string name, std::vector arguments, + std::vector fields, std::vector symbols, Expression *memory_limit, + size_t memory_scale, bool is_write); + + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + std::vector OutputSymbols(const SymbolTable &) const override; + std::vector ModifiedSymbols(const SymbolTable &) const override; + + bool HasSingleInput() const override { return true; } + std::shared_ptr input() const override { return input_; } + void set_input(std::shared_ptr input) override { input_ = input; } + + static void IncrementCounter(const std::string &procedure_name); + static std::unordered_map GetAndResetCounters(); + + std::shared_ptr input_; + std::string procedure_name_; + std::vector arguments_; + std::vector result_fields_; + std::vector result_symbols_; + Expression *memory_limit_{nullptr}; + size_t memory_scale_{1024U}; + bool is_write_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->input_ = input_ ? input_->Clone(storage) : nullptr; + object->procedure_name_ = procedure_name_; + object->arguments_.resize(arguments_.size()); + for (auto i6 = 0; i6 < arguments_.size(); ++i6) { + object->arguments_[i6] = arguments_[i6] ? arguments_[i6]->Clone(storage) : nullptr; + } + object->result_fields_ = result_fields_; + object->result_symbols_ = result_symbols_; + object->memory_limit_ = memory_limit_ ? memory_limit_->Clone(storage) : nullptr; + object->memory_scale_ = memory_scale_; + object->is_write_ = is_write_; + return object; + } + + private: + inline static utils::Synchronized, utils::SpinLock> procedure_counters_; +}; + +class LoadCsv : public memgraph::query::plan::LogicalOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + LoadCsv() = default; + LoadCsv(std::shared_ptr input, Expression *file, bool with_header, bool ignore_bad, + Expression *delimiter, Expression *quote, Symbol row_var); + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + std::vector OutputSymbols(const SymbolTable &) const override; + std::vector ModifiedSymbols(const SymbolTable &) const override; + + bool HasSingleInput() const override { return true; } + std::shared_ptr input() const override { return input_; } + void set_input(std::shared_ptr input) override { input_ = input; } + + std::shared_ptr input_; + Expression *file_; + bool with_header_; + bool ignore_bad_; + Expression *delimiter_{nullptr}; + Expression *quote_{nullptr}; + Symbol row_var_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->input_ = input_ ? input_->Clone(storage) : nullptr; + object->file_ = file_ ? file_->Clone(storage) : nullptr; + object->with_header_ = with_header_; + object->ignore_bad_ = ignore_bad_; + object->delimiter_ = delimiter_ ? delimiter_->Clone(storage) : nullptr; + object->quote_ = quote_ ? quote_->Clone(storage) : nullptr; + object->row_var_ = row_var_; + return object; + } +}; + +/// Iterates over a collection of elements and applies one or more update +/// clauses. +/// +class Foreach : public memgraph::query::plan::LogicalOperator { + public: + static const utils::TypeInfo kType; + const utils::TypeInfo &GetTypeInfo() const override { return kType; } + + Foreach() = default; + Foreach(std::shared_ptr input, std::shared_ptr updates, Expression *named_expr, + Symbol loop_variable_symbol); + + bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override; + UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override; + std::vector ModifiedSymbols(const SymbolTable &) const override; + bool HasSingleInput() const override { return true; } + std::shared_ptr input() const override { return input_; } + void set_input(std::shared_ptr input) override { input_ = std::move(input); } + + std::shared_ptr input_; + std::shared_ptr update_clauses_; + Expression *expression_; + Symbol loop_variable_symbol_; + + std::unique_ptr Clone(AstStorage *storage) const override { + auto object = std::make_unique(); + object->input_ = input_ ? input_->Clone(storage) : nullptr; + object->update_clauses_ = update_clauses_ ? update_clauses_->Clone(storage) : nullptr; + object->expression_ = expression_ ? expression_->Clone(storage) : nullptr; + object->loop_variable_symbol_ = loop_variable_symbol_; + return object; + } +}; + +} // namespace plan +} // namespace query +} // namespace memgraph diff --git a/src/query/plan/operator_type_info.cpp b/src/query/plan/operator_type_info.cpp new file mode 100644 index 000000000..c20dd1e77 --- /dev/null +++ b/src/query/plan/operator_type_info.cpp @@ -0,0 +1,148 @@ +// Copyright 2023 Memgraph Ltd. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source +// License, and you may not use this file except in compliance with the Business Source License. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +#include + +#include "query/plan/operator.hpp" + +namespace memgraph { + +constexpr utils::TypeInfo query::plan::LogicalOperator::kType{utils::TypeId::LOGICAL_OPERATOR, "LogicalOperator", + nullptr}; + +constexpr utils::TypeInfo query::plan::Once::kType{utils::TypeId::ONCE, "Once", &query::plan::LogicalOperator::kType}; + +constexpr utils::TypeInfo query::plan::NodeCreationInfo::kType{utils::TypeId::NODE_CREATION_INFO, "NodeCreationInfo", + nullptr}; + +constexpr utils::TypeInfo query::plan::CreateNode::kType{utils::TypeId::CREATE_NODE, "CreateNode", + &query::plan::LogicalOperator::kType}; + +constexpr utils::TypeInfo query::plan::EdgeCreationInfo::kType{utils::TypeId::EDGE_CREATION_INFO, "EdgeCreationInfo", + nullptr}; + +constexpr utils::TypeInfo query::plan::CreateExpand::kType{utils::TypeId::CREATE_EXPAND, "CreateExpand", + &query::plan::LogicalOperator::kType}; + +constexpr utils::TypeInfo query::plan::ScanAll::kType{utils::TypeId::SCAN_ALL, "ScanAll", + &query::plan::LogicalOperator::kType}; + +constexpr utils::TypeInfo query::plan::ScanAllByLabel::kType{utils::TypeId::SCAN_ALL_BY_LABEL, "ScanAllByLabel", + &query::plan::ScanAll::kType}; + +constexpr utils::TypeInfo query::plan::ScanAllByLabelPropertyRange::kType{ + utils::TypeId::SCAN_ALL_BY_LABEL_PROPERTY_RANGE, "ScanAllByLabelPropertyRange", &query::plan::ScanAll::kType}; + +constexpr utils::TypeInfo query::plan::ScanAllByLabelPropertyValue::kType{ + utils::TypeId::SCAN_ALL_BY_LABEL_PROPERTY_VALUE, "ScanAllByLabelPropertyValue", &query::plan::ScanAll::kType}; + +constexpr utils::TypeInfo query::plan::ScanAllByLabelProperty::kType{ + utils::TypeId::SCAN_ALL_BY_LABEL_PROPERTY, "ScanAllByLabelProperty", &query::plan::ScanAll::kType}; + +constexpr utils::TypeInfo query::plan::ScanAllById::kType{utils::TypeId::SCAN_ALL_BY_ID, "ScanAllById", + &query::plan::ScanAll::kType}; + +constexpr utils::TypeInfo query::plan::ExpandCommon::kType{utils::TypeId::EXPAND_COMMON, "ExpandCommon", nullptr}; + +constexpr utils::TypeInfo query::plan::Expand::kType{utils::TypeId::EXPAND, "Expand", + &query::plan::LogicalOperator::kType}; + +constexpr utils::TypeInfo query::plan::ExpansionLambda::kType{utils::TypeId::EXPANSION_LAMBDA, "ExpansionLambda", + nullptr}; + +constexpr utils::TypeInfo query::plan::ExpandVariable::kType{utils::TypeId::EXPAND_VARIABLE, "ExpandVariable", + &query::plan::LogicalOperator::kType}; + +constexpr utils::TypeInfo query::plan::ConstructNamedPath::kType{ + utils::TypeId::CONSTRUCT_NAMED_PATH, "ConstructNamedPath", &query::plan::LogicalOperator::kType}; + +constexpr utils::TypeInfo query::plan::Filter::kType{utils::TypeId::FILTER, "Filter", + &query::plan::LogicalOperator::kType}; + +constexpr utils::TypeInfo query::plan::Produce::kType{utils::TypeId::PRODUCE, "Produce", + &query::plan::LogicalOperator::kType}; + +constexpr utils::TypeInfo query::plan::Delete::kType{utils::TypeId::DELETE, "Delete", + &query::plan::LogicalOperator::kType}; + +constexpr utils::TypeInfo query::plan::SetProperty::kType{utils::TypeId::SET_PROPERTY, "SetProperty", + &query::plan::LogicalOperator::kType}; + +constexpr utils::TypeInfo query::plan::SetProperties::kType{utils::TypeId::SET_PROPERTIES, "SetProperties", + &query::plan::LogicalOperator::kType}; + +constexpr utils::TypeInfo query::plan::SetLabels::kType{utils::TypeId::SET_LABELS, "SetLabels", + &query::plan::LogicalOperator::kType}; + +constexpr utils::TypeInfo query::plan::RemoveProperty::kType{utils::TypeId::REMOVE_PROPERTY, "RemoveProperty", + &query::plan::LogicalOperator::kType}; + +constexpr utils::TypeInfo query::plan::RemoveLabels::kType{utils::TypeId::REMOVE_LABELS, "RemoveLabels", + &query::plan::LogicalOperator::kType}; + +constexpr utils::TypeInfo query::plan::EdgeUniquenessFilter::kType{ + utils::TypeId::EDGE_UNIQUENESS_FILTER, "EdgeUniquenessFilter", &query::plan::LogicalOperator::kType}; + +constexpr utils::TypeInfo query::plan::EmptyResult::kType{utils::TypeId::EMPTY_RESULT, "EmptyResult", + &query::plan::LogicalOperator::kType}; + +constexpr utils::TypeInfo query::plan::Accumulate::kType{utils::TypeId::ACCUMULATE, "Accumulate", + &query::plan::LogicalOperator::kType}; + +constexpr utils::TypeInfo query::plan::Aggregate::Element::kType{utils::TypeId::AGGREGATE_ELEMENT, "Element", nullptr}; + +constexpr utils::TypeInfo query::plan::Aggregate::kType{utils::TypeId::AGGREGATE, "Aggregate", + &query::plan::LogicalOperator::kType}; + +constexpr utils::TypeInfo query::plan::Skip::kType{utils::TypeId::SKIP, "Skip", &query::plan::LogicalOperator::kType}; + +constexpr utils::TypeInfo query::plan::EvaluatePatternFilter::kType{ + utils::TypeId::EVALUATE_PATTERN_FILTER, "EvaluatePatternFilter", &query::plan::LogicalOperator::kType}; + +constexpr utils::TypeInfo query::plan::Limit::kType{utils::TypeId::LIMIT, "Limit", + &query::plan::LogicalOperator::kType}; + +constexpr utils::TypeInfo query::plan::OrderBy::kType{utils::TypeId::ORDERBY, "OrderBy", + &query::plan::LogicalOperator::kType}; + +constexpr utils::TypeInfo query::plan::Merge::kType{utils::TypeId::MERGE, "Merge", + &query::plan::LogicalOperator::kType}; + +constexpr utils::TypeInfo query::plan::Optional::kType{utils::TypeId::OPTIONAL, "Optional", + &query::plan::LogicalOperator::kType}; + +constexpr utils::TypeInfo query::plan::Unwind::kType{utils::TypeId::UNWIND, "Unwind", + &query::plan::LogicalOperator::kType}; + +constexpr utils::TypeInfo query::plan::Distinct::kType{utils::TypeId::DISTINCT, "Distinct", + &query::plan::LogicalOperator::kType}; + +constexpr utils::TypeInfo query::plan::Union::kType{utils::TypeId::UNION, "Union", + &query::plan::LogicalOperator::kType}; + +constexpr utils::TypeInfo query::plan::Cartesian::kType{utils::TypeId::CARTESIAN, "Cartesian", + &query::plan::LogicalOperator::kType}; + +constexpr utils::TypeInfo query::plan::OutputTable::kType{utils::TypeId::OUTPUT_TABLE, "OutputTable", + &query::plan::LogicalOperator::kType}; + +constexpr utils::TypeInfo query::plan::OutputTableStream::kType{utils::TypeId::OUTPUT_TABLE_STREAM, "OutputTableStream", + &query::plan::LogicalOperator::kType}; + +constexpr utils::TypeInfo query::plan::CallProcedure::kType{utils::TypeId::CALL_PROCEDURE, "CallProcedure", + &query::plan::LogicalOperator::kType}; + +constexpr utils::TypeInfo query::plan::LoadCsv::kType{utils::TypeId::LOAD_CSV, "LoadCsv", + &query::plan::LogicalOperator::kType}; + +constexpr utils::TypeInfo query::plan::Foreach::kType{utils::TypeId::FOREACH, "Foreach", + &query::plan::LogicalOperator::kType}; +} // namespace memgraph diff --git a/src/rpc/client.hpp b/src/rpc/client.hpp index 5c9d2ad41..4756cd6a5 100644 --- a/src/rpc/client.hpp +++ b/src/rpc/client.hpp @@ -1,4 +1,4 @@ -// Copyright 2022 Memgraph Ltd. +// Copyright 2023 Memgraph Ltd. // // Use of this software is governed by the Business Source License // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source @@ -23,6 +23,7 @@ #include "slk/streams.hpp" #include "utils/logging.hpp" #include "utils/on_scope_exit.hpp" +#include "utils/typeinfo.hpp" namespace memgraph::rpc { @@ -84,11 +85,11 @@ class Client { slk::Reader res_reader(self_->client_->GetData(), response_data_size); utils::OnScopeExit res_cleanup([&, response_data_size] { self_->client_->ShiftData(response_data_size); }); - uint64_t res_id = 0; + utils::TypeId res_id{utils::TypeId::UNKNOWN}; slk::Load(&res_id, &res_reader); // Check the response ID. - if (res_id != res_type.id) { + if (res_id != res_type.id && res_id != utils::TypeId::UNKNOWN) { spdlog::error("Message response was of unexpected type"); self_->client_ = std::nullopt; throw RpcFailedException(self_->endpoint_); diff --git a/src/rpc/protocol.cpp b/src/rpc/protocol.cpp index 63ac58760..ac74d754b 100644 --- a/src/rpc/protocol.cpp +++ b/src/rpc/protocol.cpp @@ -1,4 +1,4 @@ -// Copyright 2022 Memgraph Ltd. +// Copyright 2023 Memgraph Ltd. // // Use of this software is governed by the Business Source License // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source @@ -16,6 +16,7 @@ #include "slk/serialization.hpp" #include "slk/streams.hpp" #include "utils/on_scope_exit.hpp" +#include "utils/typeinfo.hpp" namespace memgraph::rpc { @@ -41,7 +42,7 @@ void Session::Execute() { [&](const uint8_t *data, size_t size, bool have_more) { output_stream_->Write(data, size, have_more); }); // Load the request ID. - uint64_t req_id = 0; + utils::TypeId req_id{utils::TypeId::UNKNOWN}; slk::Load(&req_id, &req_reader); // Access to `callbacks_` and `extended_callbacks_` is done here without diff --git a/src/rpc/server.hpp b/src/rpc/server.hpp index af0c60dde..877420381 100644 --- a/src/rpc/server.hpp +++ b/src/rpc/server.hpp @@ -1,4 +1,4 @@ -// Copyright 2022 Memgraph Ltd. +// Copyright 2023 Memgraph Ltd. // // Use of this software is governed by the Business Source License // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source @@ -86,8 +86,8 @@ class Server { }; std::mutex lock_; - std::map callbacks_; - std::map extended_callbacks_; + std::map callbacks_; + std::map extended_callbacks_; communication::Server server_; }; diff --git a/src/slk/serialization.hpp b/src/slk/serialization.hpp index f7961368f..2b3dab796 100644 --- a/src/slk/serialization.hpp +++ b/src/slk/serialization.hpp @@ -1,4 +1,4 @@ -// Copyright 2022 Memgraph Ltd. +// Copyright 2023 Memgraph Ltd. // // Use of this software is governed by the Business Source License // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source @@ -29,8 +29,10 @@ #include "slk/streams.hpp" #include "utils/cast.hpp" +#include "utils/concepts.hpp" #include "utils/endian.hpp" #include "utils/exceptions.hpp" +#include "utils/typeinfo.hpp" // The namespace name stands for SaveLoadKit. It should be not mistaken for the // Mercedes car model line. @@ -308,6 +310,10 @@ inline void Save(const std::optional &obj, Builder *builder) { } } +inline void Save(const utils::TypeId &obj, Builder *builder) { + Save(static_cast>(obj), builder); +} + template inline void Load(std::optional *obj, Reader *reader) { bool exists = false; @@ -471,4 +477,12 @@ inline void Load(std::optional *obj, Reader *reader, std::function; + enum_type obj_encoded; + slk::Load(&obj_encoded, reader); + *obj = utils::TypeId(utils::MemcpyCast(obj_encoded)); +} + } // namespace memgraph::slk diff --git a/src/storage/v2/CMakeLists.txt b/src/storage/v2/CMakeLists.txt index d46563183..505ae45ec 100644 --- a/src/storage/v2/CMakeLists.txt +++ b/src/storage/v2/CMakeLists.txt @@ -12,12 +12,6 @@ set(storage_v2_src_files vertex_accessor.cpp storage.cpp) -##### Replication ##### -define_add_lcp(add_lcp_storage lcp_storage_cpp_files generated_lcp_storage_files) - -add_lcp_storage(replication/rpc.lcp SLK_SERIALIZE) - -add_custom_target(generate_lcp_storage DEPENDS ${generated_lcp_storage_files}) set(storage_v2_src_files ${storage_v2_src_files} @@ -26,7 +20,7 @@ set(storage_v2_src_files replication/serialization.cpp replication/slk.cpp replication/replication_persistence_helper.cpp - ${lcp_storage_cpp_files}) + replication/rpc.cpp) ####################### find_package(gflags REQUIRED) @@ -35,5 +29,4 @@ find_package(Threads REQUIRED) add_library(mg-storage-v2 STATIC ${storage_v2_src_files}) target_link_libraries(mg-storage-v2 Threads::Threads mg-utils gflags) -add_dependencies(mg-storage-v2 generate_lcp_storage) target_link_libraries(mg-storage-v2 mg-rpc mg-slk) diff --git a/src/storage/v2/replication/.gitignore b/src/storage/v2/replication/.gitignore deleted file mode 100644 index 8fb0c720c..000000000 --- a/src/storage/v2/replication/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# autogenerated files -rpc.hpp diff --git a/src/storage/v2/replication/rpc.cpp b/src/storage/v2/replication/rpc.cpp new file mode 100644 index 000000000..783e3b4f5 --- /dev/null +++ b/src/storage/v2/replication/rpc.cpp @@ -0,0 +1,263 @@ +// Copyright 2023 Memgraph Ltd. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source +// License, and you may not use this file except in compliance with the Business Source License. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +#include "storage/v2/replication/rpc.hpp" +#include "utils/typeinfo.hpp" + +namespace memgraph { + +namespace storage { + +namespace replication { + +void AppendDeltasReq::Save(const AppendDeltasReq &self, memgraph::slk::Builder *builder) { + memgraph::slk::Save(self, builder); +} +void AppendDeltasReq::Load(AppendDeltasReq *self, memgraph::slk::Reader *reader) { memgraph::slk::Load(self, reader); } +void AppendDeltasRes::Save(const AppendDeltasRes &self, memgraph::slk::Builder *builder) { + memgraph::slk::Save(self, builder); +} +void AppendDeltasRes::Load(AppendDeltasRes *self, memgraph::slk::Reader *reader) { memgraph::slk::Load(self, reader); } +void HeartbeatReq::Save(const HeartbeatReq &self, memgraph::slk::Builder *builder) { + memgraph::slk::Save(self, builder); +} +void HeartbeatReq::Load(HeartbeatReq *self, memgraph::slk::Reader *reader) { memgraph::slk::Load(self, reader); } +void HeartbeatRes::Save(const HeartbeatRes &self, memgraph::slk::Builder *builder) { + memgraph::slk::Save(self, builder); +} +void HeartbeatRes::Load(HeartbeatRes *self, memgraph::slk::Reader *reader) { memgraph::slk::Load(self, reader); } +void FrequentHeartbeatReq::Save(const FrequentHeartbeatReq &self, memgraph::slk::Builder *builder) { + memgraph::slk::Save(self, builder); +} +void FrequentHeartbeatReq::Load(FrequentHeartbeatReq *self, memgraph::slk::Reader *reader) { + memgraph::slk::Load(self, reader); +} +void FrequentHeartbeatRes::Save(const FrequentHeartbeatRes &self, memgraph::slk::Builder *builder) { + memgraph::slk::Save(self, builder); +} +void FrequentHeartbeatRes::Load(FrequentHeartbeatRes *self, memgraph::slk::Reader *reader) { + memgraph::slk::Load(self, reader); +} +void SnapshotReq::Save(const SnapshotReq &self, memgraph::slk::Builder *builder) { memgraph::slk::Save(self, builder); } +void SnapshotReq::Load(SnapshotReq *self, memgraph::slk::Reader *reader) { memgraph::slk::Load(self, reader); } +void SnapshotRes::Save(const SnapshotRes &self, memgraph::slk::Builder *builder) { memgraph::slk::Save(self, builder); } +void SnapshotRes::Load(SnapshotRes *self, memgraph::slk::Reader *reader) { memgraph::slk::Load(self, reader); } +void WalFilesReq::Save(const WalFilesReq &self, memgraph::slk::Builder *builder) { memgraph::slk::Save(self, builder); } +void WalFilesReq::Load(WalFilesReq *self, memgraph::slk::Reader *reader) { memgraph::slk::Load(self, reader); } +void WalFilesRes::Save(const WalFilesRes &self, memgraph::slk::Builder *builder) { memgraph::slk::Save(self, builder); } +void WalFilesRes::Load(WalFilesRes *self, memgraph::slk::Reader *reader) { memgraph::slk::Load(self, reader); } +void CurrentWalReq::Save(const CurrentWalReq &self, memgraph::slk::Builder *builder) { + memgraph::slk::Save(self, builder); +} +void CurrentWalReq::Load(CurrentWalReq *self, memgraph::slk::Reader *reader) { memgraph::slk::Load(self, reader); } +void CurrentWalRes::Save(const CurrentWalRes &self, memgraph::slk::Builder *builder) { + memgraph::slk::Save(self, builder); +} +void CurrentWalRes::Load(CurrentWalRes *self, memgraph::slk::Reader *reader) { memgraph::slk::Load(self, reader); } +void TimestampReq::Save(const TimestampReq &self, memgraph::slk::Builder *builder) { + memgraph::slk::Save(self, builder); +} +void TimestampReq::Load(TimestampReq *self, memgraph::slk::Reader *reader) { memgraph::slk::Load(self, reader); } +void TimestampRes::Save(const TimestampRes &self, memgraph::slk::Builder *builder) { + memgraph::slk::Save(self, builder); +} +void TimestampRes::Load(TimestampRes *self, memgraph::slk::Reader *reader) { memgraph::slk::Load(self, reader); } + +} // namespace replication +} // namespace storage + +constexpr utils::TypeInfo storage::replication::AppendDeltasReq::kType{utils::TypeId::REP_APPEND_DELTAS_REQ, + "AppendDeltasReq", nullptr}; + +constexpr utils::TypeInfo storage::replication::AppendDeltasRes::kType{utils::TypeId::REP_APPEND_DELTAS_RES, + "AppendDeltasRes", nullptr}; + +constexpr utils::TypeInfo storage::replication::HeartbeatReq::kType{utils::TypeId::REP_HEARTBEAT_REQ, "HeartbeatReq", + nullptr}; + +constexpr utils::TypeInfo storage::replication::HeartbeatRes::kType{utils::TypeId::REP_HEARTBEAT_RES, "HeartbeatRes", + nullptr}; + +constexpr utils::TypeInfo storage::replication::FrequentHeartbeatReq::kType{utils::TypeId::REP_FREQUENT_HEARTBEAT_REQ, + "FrequentHeartbeatReq", nullptr}; + +constexpr utils::TypeInfo storage::replication::FrequentHeartbeatRes::kType{utils::TypeId::REP_FREQUENT_HEARTBEAT_RES, + "FrequentHeartbeatRes", nullptr}; + +constexpr utils::TypeInfo storage::replication::SnapshotReq::kType{utils::TypeId::REP_SNAPSHOT_REQ, "SnapshotReq", + nullptr}; + +constexpr utils::TypeInfo storage::replication::SnapshotRes::kType{utils::TypeId::REP_SNAPSHOT_RES, "SnapshotRes", + nullptr}; + +constexpr utils::TypeInfo storage::replication::WalFilesReq::kType{utils::TypeId::REP_WALFILES_REQ, "WalFilesReq", + nullptr}; + +constexpr utils::TypeInfo storage::replication::WalFilesRes::kType{utils::TypeId::REP_WALFILES_RES, "WalFilesRes", + nullptr}; + +constexpr utils::TypeInfo storage::replication::CurrentWalReq::kType{utils::TypeId::REP_CURRENT_WAL_REQ, + "CurrentWalReq", nullptr}; + +constexpr utils::TypeInfo storage::replication::CurrentWalRes::kType{utils::TypeId::REP_CURRENT_WAL_RES, + "CurrentWalRes", nullptr}; + +constexpr utils::TypeInfo storage::replication::TimestampReq::kType{utils::TypeId::REP_TIMESTAMP_REQ, "TimestampReq", + nullptr}; + +constexpr utils::TypeInfo storage::replication::TimestampRes::kType{utils::TypeId::REP_TIMESTAMP_RES, "TimestampRes", + nullptr}; + +// Autogenerated SLK serialization code +namespace slk { +// Serialize code for TimestampRes + +void Save(const memgraph::storage::replication::TimestampRes &self, memgraph::slk::Builder *builder) { + memgraph::slk::Save(self.success, builder); + memgraph::slk::Save(self.current_commit_timestamp, builder); +} + +void Load(memgraph::storage::replication::TimestampRes *self, memgraph::slk::Reader *reader) { + memgraph::slk::Load(&self->success, reader); + memgraph::slk::Load(&self->current_commit_timestamp, reader); +} + +// Serialize code for TimestampReq + +void Save(const memgraph::storage::replication::TimestampReq &self, memgraph::slk::Builder *builder) {} + +void Load(memgraph::storage::replication::TimestampReq *self, memgraph::slk::Reader *reader) {} + +// Serialize code for CurrentWalRes + +void Save(const memgraph::storage::replication::CurrentWalRes &self, memgraph::slk::Builder *builder) { + memgraph::slk::Save(self.success, builder); + memgraph::slk::Save(self.current_commit_timestamp, builder); +} + +void Load(memgraph::storage::replication::CurrentWalRes *self, memgraph::slk::Reader *reader) { + memgraph::slk::Load(&self->success, reader); + memgraph::slk::Load(&self->current_commit_timestamp, reader); +} + +// Serialize code for CurrentWalReq + +void Save(const memgraph::storage::replication::CurrentWalReq &self, memgraph::slk::Builder *builder) {} + +void Load(memgraph::storage::replication::CurrentWalReq *self, memgraph::slk::Reader *reader) {} + +// Serialize code for WalFilesRes + +void Save(const memgraph::storage::replication::WalFilesRes &self, memgraph::slk::Builder *builder) { + memgraph::slk::Save(self.success, builder); + memgraph::slk::Save(self.current_commit_timestamp, builder); +} + +void Load(memgraph::storage::replication::WalFilesRes *self, memgraph::slk::Reader *reader) { + memgraph::slk::Load(&self->success, reader); + memgraph::slk::Load(&self->current_commit_timestamp, reader); +} + +// Serialize code for WalFilesReq + +void Save(const memgraph::storage::replication::WalFilesReq &self, memgraph::slk::Builder *builder) { + memgraph::slk::Save(self.file_number, builder); +} + +void Load(memgraph::storage::replication::WalFilesReq *self, memgraph::slk::Reader *reader) { + memgraph::slk::Load(&self->file_number, reader); +} + +// Serialize code for SnapshotRes + +void Save(const memgraph::storage::replication::SnapshotRes &self, memgraph::slk::Builder *builder) { + memgraph::slk::Save(self.success, builder); + memgraph::slk::Save(self.current_commit_timestamp, builder); +} + +void Load(memgraph::storage::replication::SnapshotRes *self, memgraph::slk::Reader *reader) { + memgraph::slk::Load(&self->success, reader); + memgraph::slk::Load(&self->current_commit_timestamp, reader); +} + +// Serialize code for SnapshotReq + +void Save(const memgraph::storage::replication::SnapshotReq &self, memgraph::slk::Builder *builder) {} + +void Load(memgraph::storage::replication::SnapshotReq *self, memgraph::slk::Reader *reader) {} + +// Serialize code for FrequentHeartbeatRes + +void Save(const memgraph::storage::replication::FrequentHeartbeatRes &self, memgraph::slk::Builder *builder) { + memgraph::slk::Save(self.success, builder); +} + +void Load(memgraph::storage::replication::FrequentHeartbeatRes *self, memgraph::slk::Reader *reader) { + memgraph::slk::Load(&self->success, reader); +} + +// Serialize code for FrequentHeartbeatReq + +void Save(const memgraph::storage::replication::FrequentHeartbeatReq &self, memgraph::slk::Builder *builder) {} + +void Load(memgraph::storage::replication::FrequentHeartbeatReq *self, memgraph::slk::Reader *reader) {} + +// Serialize code for HeartbeatRes + +void Save(const memgraph::storage::replication::HeartbeatRes &self, memgraph::slk::Builder *builder) { + memgraph::slk::Save(self.success, builder); + memgraph::slk::Save(self.current_commit_timestamp, builder); + memgraph::slk::Save(self.epoch_id, builder); +} + +void Load(memgraph::storage::replication::HeartbeatRes *self, memgraph::slk::Reader *reader) { + memgraph::slk::Load(&self->success, reader); + memgraph::slk::Load(&self->current_commit_timestamp, reader); + memgraph::slk::Load(&self->epoch_id, reader); +} + +// Serialize code for HeartbeatReq + +void Save(const memgraph::storage::replication::HeartbeatReq &self, memgraph::slk::Builder *builder) { + memgraph::slk::Save(self.main_commit_timestamp, builder); + memgraph::slk::Save(self.epoch_id, builder); +} + +void Load(memgraph::storage::replication::HeartbeatReq *self, memgraph::slk::Reader *reader) { + memgraph::slk::Load(&self->main_commit_timestamp, reader); + memgraph::slk::Load(&self->epoch_id, reader); +} + +// Serialize code for AppendDeltasRes + +void Save(const memgraph::storage::replication::AppendDeltasRes &self, memgraph::slk::Builder *builder) { + memgraph::slk::Save(self.success, builder); + memgraph::slk::Save(self.current_commit_timestamp, builder); +} + +void Load(memgraph::storage::replication::AppendDeltasRes *self, memgraph::slk::Reader *reader) { + memgraph::slk::Load(&self->success, reader); + memgraph::slk::Load(&self->current_commit_timestamp, reader); +} + +// Serialize code for AppendDeltasReq + +void Save(const memgraph::storage::replication::AppendDeltasReq &self, memgraph::slk::Builder *builder) { + memgraph::slk::Save(self.previous_commit_timestamp, builder); + memgraph::slk::Save(self.seq_num, builder); +} + +void Load(memgraph::storage::replication::AppendDeltasReq *self, memgraph::slk::Reader *reader) { + memgraph::slk::Load(&self->previous_commit_timestamp, reader); + memgraph::slk::Load(&self->seq_num, reader); +} +} // namespace slk +} // namespace memgraph diff --git a/src/storage/v2/replication/rpc.hpp b/src/storage/v2/replication/rpc.hpp new file mode 100644 index 000000000..f466b1880 --- /dev/null +++ b/src/storage/v2/replication/rpc.hpp @@ -0,0 +1,278 @@ +// Copyright 2023 Memgraph Ltd. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source +// License, and you may not use this file except in compliance with the Business Source License. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +#pragma once + +#include +#include +#include + +#include "rpc/messages.hpp" +#include "slk/serialization.hpp" +#include "slk/streams.hpp" + +namespace memgraph { + +namespace storage { + +namespace replication { + +struct AppendDeltasReq { + static const utils::TypeInfo kType; + static const utils::TypeInfo &GetTypeInfo() { return kType; } + + static void Load(AppendDeltasReq *self, memgraph::slk::Reader *reader); + static void Save(const AppendDeltasReq &self, memgraph::slk::Builder *builder); + AppendDeltasReq() {} + AppendDeltasReq(uint64_t previous_commit_timestamp, uint64_t seq_num) + : previous_commit_timestamp(previous_commit_timestamp), seq_num(seq_num) {} + + uint64_t previous_commit_timestamp; + uint64_t seq_num; +}; + +struct AppendDeltasRes { + static const utils::TypeInfo kType; + static const utils::TypeInfo &GetTypeInfo() { return kType; } + + static void Load(AppendDeltasRes *self, memgraph::slk::Reader *reader); + static void Save(const AppendDeltasRes &self, memgraph::slk::Builder *builder); + AppendDeltasRes() {} + AppendDeltasRes(bool success, uint64_t current_commit_timestamp) + : success(success), current_commit_timestamp(current_commit_timestamp) {} + + bool success; + uint64_t current_commit_timestamp; +}; + +using AppendDeltasRpc = rpc::RequestResponse; + +struct HeartbeatReq { + static const utils::TypeInfo kType; + static const utils::TypeInfo &GetTypeInfo() { return kType; } + + static void Load(HeartbeatReq *self, memgraph::slk::Reader *reader); + static void Save(const HeartbeatReq &self, memgraph::slk::Builder *builder); + HeartbeatReq() {} + HeartbeatReq(uint64_t main_commit_timestamp, std::string epoch_id) + : main_commit_timestamp(main_commit_timestamp), epoch_id(epoch_id) {} + + uint64_t main_commit_timestamp; + std::string epoch_id; +}; + +struct HeartbeatRes { + static const utils::TypeInfo kType; + static const utils::TypeInfo &GetTypeInfo() { return kType; } + + static void Load(HeartbeatRes *self, memgraph::slk::Reader *reader); + static void Save(const HeartbeatRes &self, memgraph::slk::Builder *builder); + HeartbeatRes() {} + HeartbeatRes(bool success, uint64_t current_commit_timestamp, std::string epoch_id) + : success(success), current_commit_timestamp(current_commit_timestamp), epoch_id(epoch_id) {} + + bool success; + uint64_t current_commit_timestamp; + std::string epoch_id; +}; + +using HeartbeatRpc = rpc::RequestResponse; + +struct FrequentHeartbeatReq { + static const utils::TypeInfo kType; + static const utils::TypeInfo &GetTypeInfo() { return kType; } + + static void Load(FrequentHeartbeatReq *self, memgraph::slk::Reader *reader); + static void Save(const FrequentHeartbeatReq &self, memgraph::slk::Builder *builder); + FrequentHeartbeatReq() {} +}; + +struct FrequentHeartbeatRes { + static const utils::TypeInfo kType; + static const utils::TypeInfo &GetTypeInfo() { return kType; } + + static void Load(FrequentHeartbeatRes *self, memgraph::slk::Reader *reader); + static void Save(const FrequentHeartbeatRes &self, memgraph::slk::Builder *builder); + FrequentHeartbeatRes() {} + explicit FrequentHeartbeatRes(bool success) : success(success) {} + + bool success; +}; + +using FrequentHeartbeatRpc = rpc::RequestResponse; + +struct SnapshotReq { + static const utils::TypeInfo kType; + static const utils::TypeInfo &GetTypeInfo() { return kType; } + + static void Load(SnapshotReq *self, memgraph::slk::Reader *reader); + static void Save(const SnapshotReq &self, memgraph::slk::Builder *builder); + SnapshotReq() {} +}; + +struct SnapshotRes { + static const utils::TypeInfo kType; + static const utils::TypeInfo &GetTypeInfo() { return kType; } + + static void Load(SnapshotRes *self, memgraph::slk::Reader *reader); + static void Save(const SnapshotRes &self, memgraph::slk::Builder *builder); + SnapshotRes() {} + SnapshotRes(bool success, uint64_t current_commit_timestamp) + : success(success), current_commit_timestamp(current_commit_timestamp) {} + + bool success; + uint64_t current_commit_timestamp; +}; + +using SnapshotRpc = rpc::RequestResponse; + +struct WalFilesReq { + static const utils::TypeInfo kType; + static const utils::TypeInfo &GetTypeInfo() { return kType; } + + static void Load(WalFilesReq *self, memgraph::slk::Reader *reader); + static void Save(const WalFilesReq &self, memgraph::slk::Builder *builder); + WalFilesReq() {} + explicit WalFilesReq(uint64_t file_number) : file_number(file_number) {} + + uint64_t file_number; +}; + +struct WalFilesRes { + static const utils::TypeInfo kType; + static const utils::TypeInfo &GetTypeInfo() { return kType; } + + static void Load(WalFilesRes *self, memgraph::slk::Reader *reader); + static void Save(const WalFilesRes &self, memgraph::slk::Builder *builder); + WalFilesRes() {} + WalFilesRes(bool success, uint64_t current_commit_timestamp) + : success(success), current_commit_timestamp(current_commit_timestamp) {} + + bool success; + uint64_t current_commit_timestamp; +}; + +using WalFilesRpc = rpc::RequestResponse; + +struct CurrentWalReq { + static const utils::TypeInfo kType; + static const utils::TypeInfo &GetTypeInfo() { return kType; } + + static void Load(CurrentWalReq *self, memgraph::slk::Reader *reader); + static void Save(const CurrentWalReq &self, memgraph::slk::Builder *builder); + CurrentWalReq() {} +}; + +struct CurrentWalRes { + static const utils::TypeInfo kType; + static const utils::TypeInfo &GetTypeInfo() { return kType; } + + static void Load(CurrentWalRes *self, memgraph::slk::Reader *reader); + static void Save(const CurrentWalRes &self, memgraph::slk::Builder *builder); + CurrentWalRes() {} + CurrentWalRes(bool success, uint64_t current_commit_timestamp) + : success(success), current_commit_timestamp(current_commit_timestamp) {} + + bool success; + uint64_t current_commit_timestamp; +}; + +using CurrentWalRpc = rpc::RequestResponse; + +struct TimestampReq { + static const utils::TypeInfo kType; + static const utils::TypeInfo &GetTypeInfo() { return kType; } + + static void Load(TimestampReq *self, memgraph::slk::Reader *reader); + static void Save(const TimestampReq &self, memgraph::slk::Builder *builder); + TimestampReq() {} +}; + +struct TimestampRes { + static const utils::TypeInfo kType; + static const utils::TypeInfo &GetTypeInfo() { return kType; } + + static void Load(TimestampRes *self, memgraph::slk::Reader *reader); + static void Save(const TimestampRes &self, memgraph::slk::Builder *builder); + TimestampRes() {} + TimestampRes(bool success, uint64_t current_commit_timestamp) + : success(success), current_commit_timestamp(current_commit_timestamp) {} + + bool success; + uint64_t current_commit_timestamp; +}; + +using TimestampRpc = rpc::RequestResponse; +} // namespace replication +} // namespace storage +} // namespace memgraph + +// SLK serialization declarations +#include "slk/serialization.hpp" +namespace memgraph::slk { + +void Save(const memgraph::storage::replication::TimestampRes &self, memgraph::slk::Builder *builder); + +void Load(memgraph::storage::replication::TimestampRes *self, memgraph::slk::Reader *reader); + +void Save(const memgraph::storage::replication::TimestampReq &self, memgraph::slk::Builder *builder); + +void Load(memgraph::storage::replication::TimestampReq *self, memgraph::slk::Reader *reader); + +void Save(const memgraph::storage::replication::CurrentWalRes &self, memgraph::slk::Builder *builder); + +void Load(memgraph::storage::replication::CurrentWalRes *self, memgraph::slk::Reader *reader); + +void Save(const memgraph::storage::replication::CurrentWalReq &self, memgraph::slk::Builder *builder); + +void Load(memgraph::storage::replication::CurrentWalReq *self, memgraph::slk::Reader *reader); + +void Save(const memgraph::storage::replication::WalFilesRes &self, memgraph::slk::Builder *builder); + +void Load(memgraph::storage::replication::WalFilesRes *self, memgraph::slk::Reader *reader); + +void Save(const memgraph::storage::replication::WalFilesReq &self, memgraph::slk::Builder *builder); + +void Load(memgraph::storage::replication::WalFilesReq *self, memgraph::slk::Reader *reader); + +void Save(const memgraph::storage::replication::SnapshotRes &self, memgraph::slk::Builder *builder); + +void Load(memgraph::storage::replication::SnapshotRes *self, memgraph::slk::Reader *reader); + +void Save(const memgraph::storage::replication::SnapshotReq &self, memgraph::slk::Builder *builder); + +void Load(memgraph::storage::replication::SnapshotReq *self, memgraph::slk::Reader *reader); + +void Save(const memgraph::storage::replication::FrequentHeartbeatRes &self, memgraph::slk::Builder *builder); + +void Load(memgraph::storage::replication::FrequentHeartbeatRes *self, memgraph::slk::Reader *reader); + +void Save(const memgraph::storage::replication::FrequentHeartbeatReq &self, memgraph::slk::Builder *builder); + +void Load(memgraph::storage::replication::FrequentHeartbeatReq *self, memgraph::slk::Reader *reader); + +void Save(const memgraph::storage::replication::HeartbeatRes &self, memgraph::slk::Builder *builder); + +void Load(memgraph::storage::replication::HeartbeatRes *self, memgraph::slk::Reader *reader); + +void Save(const memgraph::storage::replication::HeartbeatReq &self, memgraph::slk::Builder *builder); + +void Load(memgraph::storage::replication::HeartbeatReq *self, memgraph::slk::Reader *reader); + +void Save(const memgraph::storage::replication::AppendDeltasRes &self, memgraph::slk::Builder *builder); + +void Load(memgraph::storage::replication::AppendDeltasRes *self, memgraph::slk::Reader *reader); + +void Save(const memgraph::storage::replication::AppendDeltasReq &self, memgraph::slk::Builder *builder); + +void Load(memgraph::storage::replication::AppendDeltasReq *self, memgraph::slk::Reader *reader); + +} // namespace memgraph::slk diff --git a/src/utils/typeinfo.hpp b/src/utils/typeinfo.hpp index 7d8085bce..ca0cbe39d 100644 --- a/src/utils/typeinfo.hpp +++ b/src/utils/typeinfo.hpp @@ -1,4 +1,4 @@ -// Copyright 2022 Memgraph Ltd. +// Copyright 2023 Memgraph Ltd. // // Use of this software is governed by the Business Source License // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source @@ -16,6 +16,172 @@ namespace memgraph::utils { +enum class TypeId : uint64_t { + // Operators + UNKNOWN, + LOGICAL_OPERATOR, + ONCE, + NODE_CREATION_INFO, + CREATE_NODE, + EDGE_CREATION_INFO, + CREATE_EXPAND, + SCAN_ALL, + SCAN_ALL_BY_LABEL, + SCAN_ALL_BY_LABEL_PROPERTY_RANGE, + SCAN_ALL_BY_LABEL_PROPERTY_VALUE, + SCAN_ALL_BY_LABEL_PROPERTY, + SCAN_ALL_BY_ID, + EXPAND_COMMON, + EXPAND, + EXPANSION_LAMBDA, + EXPAND_VARIABLE, + CONSTRUCT_NAMED_PATH, + FILTER, + PRODUCE, + DELETE, + SET_PROPERTY, + SET_PROPERTIES, + SET_LABELS, + REMOVE_PROPERTY, + REMOVE_LABELS, + EDGE_UNIQUENESS_FILTER, + EMPTY_RESULT, + ACCUMULATE, + AGGREGATE, + AGGREGATE_ELEMENT, + SKIP, + EVALUATE_PATTERN_FILTER, + LIMIT, + ORDERBY, + MERGE, + OPTIONAL, + UNWIND, + DISTINCT, + UNION, + CARTESIAN, + OUTPUT_TABLE, + OUTPUT_TABLE_STREAM, + CALL_PROCEDURE, + LOAD_CSV, + FOREACH, + + // Replication + REP_APPEND_DELTAS_REQ, + REP_APPEND_DELTAS_RES, + REP_HEARTBEAT_REQ, + REP_HEARTBEAT_RES, + REP_FREQUENT_HEARTBEAT_REQ, + REP_FREQUENT_HEARTBEAT_RES, + REP_SNAPSHOT_REQ, + REP_SNAPSHOT_RES, + REP_WALFILES_REQ, + REP_WALFILES_RES, + REP_CURRENT_WAL_REQ, + REP_CURRENT_WAL_RES, + REP_TIMESTAMP_REQ, + REP_TIMESTAMP_RES, + + // AST + AST_LABELIX, + AST_PROPERTYIX, + AST_EDGETYPEIX, + AST_TREE, + AST_EXPRESSION, + AST_WHERE, + AST_BINARY_OPERATOR, + AST_UNARY_OPERATOR, + AST_OR_OPERATOR, + AST_XOR_OPERATOR, + AST_AND_OPERATOR, + AST_ADDITION_OPERATOR, + AST_SUBTRACTION_OPERATOR, + AST_MULTIPLICATION_OPERATOR, + AST_DIVISION_OPERATOR, + AST_MOD_OPERATOR, + AST_NOT_EQUAL_OPERATOR, + AST_EQUAL_OPERATOR, + AST_LESS_OPERATOR, + AST_GREATER_OPERATOR, + AST_LESS_EQUAL_OPERATOR, + AST_GREATER_EQUAL_OPERATOR, + AST_IN_LIST_OPERATOR, + AST_SUBSCRIPT_OPERATOR, + AST_NOT_OPERATOR, + AST_UNARY_PLUS_OPERATOR, + AST_UNARY_MINUS_OPERATOR, + AST_IS_NULL_OPERATOR, + AST_AGGREGATION, + AST_LIST_SLICING_OPERATOR, + AST_IF_OPERATOR, + AST_BASE_LITERAL, + AST_PRIMITIVE_LITERAL, + AST_LIST_LITERAL, + AST_MAP_LITERAL, + AST_IDENTIFIER, + AST_PROPERTY_LOOKUP, + AST_LABELS_TEST, + AST_FUNCTION, + AST_REDUCE, + AST_COALESCE, + AST_EXTRACT, + AST_ALL, + AST_SINGLE, + AST_ANY, + AST_NONE, + AST_PARAMETER_LOOKUP, + AST_REGEX_MATCH, + AST_NAMED_EXPRESSION, + AST_PATTERN_ATOM, + AST_NODE_ATOM, + AST_EDGE_ATOM_LAMBDA, + AST_EDGE_ATOM, + AST_PATTERN, + AST_CLAUSE, + AST_SINGLE_QUERY, + AST_CYPHER_UNION, + AST_QUERY, + AST_CYPHER_QUERY, + AST_EXPLAIN_QUERY, + AST_PROFILE_QUERY, + AST_INDEX_QUERY, + AST_CREATE, + AST_CALL_PROCEDURE, + AST_MATCH, + AST_SORT_ITEM, + AST_RETURN_BODY, + AST_RETURN, + AST_WITH, + AST_DELETE, + AST_SET_PROPERTY, + AST_SET_PROPERTIES, + AST_SET_LABELS, + AST_REMOVE_PROPERTY, + AST_REMOVE_LABELS, + AST_MERGE, + AST_UNWIND, + AST_AUTH_QUERY, + AST_INFO_QUERY, + AST_CONSTRAINT, + AST_CONSTRAINT_QUERY, + AST_DUMP_QUERY, + AST_REPLICATION_QUERY, + AST_LOCK_PATH_QUERY, + AST_LOAD_CSV, + AST_FREE_MEMORY_QUERY, + AST_TRIGGER_QUERY, + AST_ISOLATION_LEVEL_QUERY, + AST_CREATE_SNAPSHOT_QUERY, + AST_STREAM_QUERY, + AST_SETTING_QUERY, + AST_VERSION_QUERY, + AST_FOREACH, + AST_SHOW_CONFIG_QUERY, + AST_EXISTS, + + // Symbol + SYMBOL, +}; + /// Type information on a C++ type. /// /// You should embed this structure as a static constant member `kType` and make @@ -24,7 +190,7 @@ namespace memgraph::utils { /// runtime type. struct TypeInfo { /// Unique ID for the type. - uint64_t id; + TypeId id; /// Pretty name of the type. const char *name; /// `TypeInfo *` for superclass of this type. diff --git a/tests/benchmark/rpc.cpp b/tests/benchmark/rpc.cpp index fc60b76b1..3dace0531 100644 --- a/tests/benchmark/rpc.cpp +++ b/tests/benchmark/rpc.cpp @@ -1,4 +1,4 @@ -// Copyright 2022 Memgraph Ltd. +// Copyright 2023 Memgraph Ltd. // // Use of this software is governed by the Business Source License // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source @@ -25,7 +25,7 @@ struct EchoMessage { static const memgraph::utils::TypeInfo kType; EchoMessage() {} // Needed for serialization. - EchoMessage(const std::string &data) : data(data) {} + explicit EchoMessage(const std::string &data) : data(data) {} static void Load(EchoMessage *obj, memgraph::slk::Reader *reader); static void Save(const EchoMessage &obj, memgraph::slk::Builder *builder); @@ -41,7 +41,7 @@ void Load(EchoMessage *echo, Reader *reader) { Load(&echo->data, reader); } void EchoMessage::Load(EchoMessage *obj, memgraph::slk::Reader *reader) { memgraph::slk::Load(obj, reader); } void EchoMessage::Save(const EchoMessage &obj, memgraph::slk::Builder *builder) { memgraph::slk::Save(obj, builder); } -const memgraph::utils::TypeInfo EchoMessage::kType{2, "EchoMessage"}; +const memgraph::utils::TypeInfo EchoMessage::kType{memgraph::utils::TypeId::UNKNOWN, "EchoMessage"}; using Echo = memgraph::rpc::RequestResponse; diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index fe3cea930..dfcbc9697 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -360,15 +360,6 @@ if(MG_ENTERPRISE) target_link_libraries(${test_prefix}rpc mg-rpc) endif() -# Test LCP -add_custom_command( - OUTPUT test_lcp - DEPENDS ${lcp_src_files} lcp test_lcp.lisp - COMMAND sbcl --script ${CMAKE_CURRENT_SOURCE_DIR}/test_lcp.lisp) -add_custom_target(test_lcp ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/test_lcp) -add_test(test_lcp ${CMAKE_CURRENT_BINARY_DIR}/test_lcp) -add_dependencies(memgraph__unit test_lcp) - # Test websocket find_package(Boost REQUIRED) diff --git a/tests/unit/rpc_messages.hpp b/tests/unit/rpc_messages.hpp index aa8b89fe3..6058c37cf 100644 --- a/tests/unit/rpc_messages.hpp +++ b/tests/unit/rpc_messages.hpp @@ -1,4 +1,4 @@ -// Copyright 2022 Memgraph Ltd. +// Copyright 2023 Memgraph Ltd. // // Use of this software is governed by the Business Source License // included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source @@ -28,7 +28,7 @@ struct SumReq { int y; }; -const memgraph::utils::TypeInfo SumReq::kType{0, "SumReq"}; +const memgraph::utils::TypeInfo SumReq::kType{memgraph::utils::TypeId::UNKNOWN, "SumReq"}; struct SumRes { static const memgraph::utils::TypeInfo kType; @@ -42,7 +42,7 @@ struct SumRes { int sum; }; -const memgraph::utils::TypeInfo SumRes::kType{1, "SumRes"}; +const memgraph::utils::TypeInfo SumRes::kType{memgraph::utils::TypeId::UNKNOWN, "SumRes"}; namespace memgraph::slk { void Save(const SumReq &sum, Builder *builder); @@ -66,7 +66,7 @@ struct EchoMessage { std::string data; }; -const memgraph::utils::TypeInfo EchoMessage::kType{2, "EchoMessage"}; +const memgraph::utils::TypeInfo EchoMessage::kType{memgraph::utils::TypeId::UNKNOWN, "EchoMessage"}; namespace memgraph::slk { void Save(const EchoMessage &echo, Builder *builder);