diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..ba558c0 --- /dev/null +++ b/.clang-format @@ -0,0 +1,16 @@ +--- + BasedOnStyle: Google + AccessModifierOffset: '-2' + AlignTrailingComments: 'true' + AllowAllParametersOfDeclarationOnNextLine: 'false' + AlwaysBreakTemplateDeclarations: 'No' + BreakBeforeBraces: Attach + ColumnLimit: '100' + ConstructorInitializerAllOnOneLineOrOnePerLine: 'true' + IncludeBlocks: Preserve + IndentPPDirectives: AfterHash + IndentWidth: '2' + NamespaceIndentation: None + BreakBeforeBinaryOperators: All + BreakBeforeTernaryOperators: 'true' +... diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b5c418b --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +/.cache/ +/build/ +/CMakeFiles/ +**/codegen/ +/build-sanitizers/ +/build-release/ +FlameGraph/ +/.vscode/ +/perf.data +/perf.data.old +**/.auctex-auto/ +**/build/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..96a5572 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,50 @@ +cmake_minimum_required(VERSION 3.15..3.29) + +project( + sql-compiler + VERSION 0.0.1 + LANGUAGES CXX +) + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") +list(APPEND CMAKE_PREFIX_PATH "${CMAKE_BINARY_DIR}") + +option(SANITIZE_ADDRESS "Enable AddressSanitizer" OFF) +option(SANITIZE_UNDEFINED "Enable UndefinedBehaviorSanitizer" OFF) +option(SANITIZE_THREADS "Enable ThreadSanitizer" OFF) + +add_compile_options(-Wno-deprecated-declarations) + +if (SANITIZE_ADDRESS) + add_compile_options(-fsanitize=address -fno-omit-frame-pointer -g) + add_link_options(-fsanitize=address) +endif() + +if (SANITIZE_UNDEFINED) + add_compile_options(-fsanitize=undefined -fno-omit-frame-pointer -g) + add_link_options(-fsanitize=undefined) +endif() + +if (SANITIZE_THREADS) + add_compile_options(-fsanitize=thread -fno-omit-frame-pointer -g) + add_link_options(-fsanitize=thread) +endif() + +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib) + +set(FETCHCONTENT_QUIET OFF) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +add_subdirectory(src/stewkk/sql) + +if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) + add_subdirectory(benchmarks) + + include(CTest) + if(BUILD_TESTING) + add_subdirectory(test) + endif() +endif() diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b7b89d1 --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +CURRENT_DIR := $(shell pwd) +CODEGEN_DIR := $(CURRENT_DIR)/src/stewkk/sql/logic/parser/codegen +PARSER_SOURCE_DIR := $(CURRENT_DIR)/src/stewkk/sql/logic/parser + +build: + cmake --build build -- -j 6 + +codegen: + @antlr -Dlanguage=Cpp -visitor -o $(CODEGEN_DIR) -package stewkk::sql::codegen $(PARSER_SOURCE_DIR)/PostgreSQLParser.g4 $(PARSER_SOURCE_DIR)/PostgreSQLLexer.g4 + +.PHONY: codegen build diff --git a/README.md b/README.md index e69de29..111b8f3 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,16 @@ +```sh +docker run --rm -it --name some-postgres -e POSTGRES_PASSWORD=mysecretpassword postgres +docker exec -it some-postgres psql -U postgres +``` + + +```sh +git clone https://github.com/brendangregg/FlameGraph.git + +sed -i 's|#!/usr/bin/perl -w|#!/usr/bin/env perl|' FlameGraph/stackcollapse-perf.pl +sed -i 's|#!/usr/bin/perl -w|#!/usr/bin/env perl|' FlameGraph/flamegraph.pl + +perf record -F 99 -g ./build-release/bin/benchmarks --benchmark_filter="BM_SQL benchmarks/flamegraph-jit.svg +``` diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt new file mode 100644 index 0000000..8cfaea0 --- /dev/null +++ b/benchmarks/CMakeLists.txt @@ -0,0 +1,16 @@ +include(FetchGBenchmark) + +add_executable(benchmarks main.cpp) +target_compile_features(benchmarks PRIVATE cxx_std_23) +set_target_properties(benchmarks PROPERTIES + CXX_STANDART 23 + CXX_STANDART_REQUIRED YES + CXX_EXTENSIONS YES +) +target_compile_options(benchmarks PRIVATE ${BASE_COMPILE_FLAGS}) +target_link_options(benchmarks PRIVATE ${BASE_LINK_FLAGS}) +target_link_libraries(benchmarks PRIVATE stewkk::libsql benchmark::benchmark + Boost::asio + Boost::thread + Boost::filesystem +) diff --git a/benchmarks/analysis.ipynb b/benchmarks/analysis.ipynb new file mode 100644 index 0000000..63464fc --- /dev/null +++ b/benchmarks/analysis.ipynb @@ -0,0 +1,1409 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 2, + "id": "999ec94f", + "metadata": {}, + "outputs": [], + "source": [ + "data = \"\"\"\n", + "{\n", + " \"context\": {\n", + " \"date\": \"2026-01-10T22:17:41+03:00\",\n", + " \"host_name\": \"nixos\",\n", + " \"executable\": \"./build-release/bin/benchmarks\",\n", + " \"num_cpus\": 8,\n", + " \"mhz_per_cpu\": 4200,\n", + " \"cpu_scaling_enabled\": true,\n", + " \"caches\": [\n", + " {\n", + " \"type\": \"Data\",\n", + " \"level\": 1,\n", + " \"size\": 49152,\n", + " \"num_sharing\": 2\n", + " },\n", + " {\n", + " \"type\": \"Instruction\",\n", + " \"level\": 1,\n", + " \"size\": 32768,\n", + " \"num_sharing\": 2\n", + " },\n", + " {\n", + " \"type\": \"Unified\",\n", + " \"level\": 2,\n", + " \"size\": 1310720,\n", + " \"num_sharing\": 2\n", + " },\n", + " {\n", + " \"type\": \"Unified\",\n", + " \"level\": 3,\n", + " \"size\": 8388608,\n", + " \"num_sharing\": 8\n", + " }\n", + " ],\n", + " \"load_avg\": [0.936523,0.910156,0.82959],\n", + " \"library_version\": \"v1.9.0\",\n", + " \"library_build_type\": \"release\",\n", + " \"json_schema_version\": 1\n", + " },\n", + " \"benchmarks\": [\n", + " {\n", + " \"name\": \"BM_SQL\",\n", + " \"family_index\": 0,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 37973,\n", + " \"real_time\": 1.8439718747488580e+04,\n", + " \"cpu_time\": 1.8393154688857870e+04,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL\",\n", + " \"family_index\": 1,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 37635,\n", + " \"real_time\": 1.8646254444011862e+04,\n", + " \"cpu_time\": 1.8605846924405472e+04,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL\",\n", + " \"family_index\": 2,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 11616,\n", + " \"real_time\": 6.1504978047441888e+04,\n", + " \"cpu_time\": 6.1064501205234126e+04,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL\",\n", + " \"family_index\": 3,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 11736,\n", + " \"real_time\": 5.8408048312897139e+04,\n", + " \"cpu_time\": 5.8085960889570553e+04,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL\",\n", + " \"family_index\": 4,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 9930,\n", + " \"real_time\": 7.0793681671783255e+04,\n", + " \"cpu_time\": 7.0392283987915405e+04,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL\",\n", + " \"family_index\": 5,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 10340,\n", + " \"real_time\": 6.7845838684643837e+04,\n", + " \"cpu_time\": 6.7519644680851081e+04,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL\",\n", + " \"family_index\": 6,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 959,\n", + " \"real_time\": 7.3587727215961309e+05,\n", + " \"cpu_time\": 7.3293833785192831e+05,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL\",\n", + " \"family_index\": 7,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 1324,\n", + " \"real_time\": 5.3172040483321249e+05,\n", + " \"cpu_time\": 5.2990015785498510e+05,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL\",\n", + " \"family_index\": 8,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 959,\n", + " \"real_time\": 7.3307096767407400e+05,\n", + " \"cpu_time\": 7.3027849426485947e+05,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL\",\n", + " \"family_index\": 9,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 1283,\n", + " \"real_time\": 5.3211894699760526e+05,\n", + " \"cpu_time\": 5.3048981060015631e+05,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL\",\n", + " \"family_index\": 10,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 615,\n", + " \"real_time\": 1.1423289658545756e+06,\n", + " \"cpu_time\": 1.1391460959349603e+06,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL\",\n", + " \"family_index\": 11,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 764,\n", + " \"real_time\": 9.1461425262047106e+05,\n", + " \"cpu_time\": 9.1169844371727761e+05,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL\",\n", + " \"family_index\": 12,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 359,\n", + " \"real_time\": 1.9482222869099684e+06,\n", + " \"cpu_time\": 1.9423905626740968e+06,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL\",\n", + " \"family_index\": 13,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 417,\n", + " \"real_time\": 1.6953180815330239e+06,\n", + " \"cpu_time\": 1.6724347146282962e+06,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL\",\n", + " \"family_index\": 14,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 198,\n", + " \"real_time\": 3.5503262929110364e+06,\n", + " \"cpu_time\": 3.5421274595959657e+06,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL\",\n", + " \"family_index\": 15,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 220,\n", + " \"real_time\": 3.1995414954508306e+06,\n", + " \"cpu_time\": 3.1910090772727318e+06,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL\",\n", + " \"family_index\": 16,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 104,\n", + " \"real_time\": 6.7452504230669336e+06,\n", + " \"cpu_time\": 6.7309672692307681e+06,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL\",\n", + " \"family_index\": 17,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 113,\n", + " \"real_time\": 6.2372058495609770e+06,\n", + " \"cpu_time\": 6.2177674513274478e+06,\n", + " \"time_unit\": \"ns\"\n", + " }\n", + " ]\n", + "}\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "39950eb9", + "metadata": {}, + "outputs": [], + "source": [ + "import json\n", + "\n", + "data = json.loads(data) " + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "eb39d9d9", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
executorqueryreal_timecpu_time
0InterpretedExpressionExecutorkSimpleSelectSmall1.843972e+041.839315e+04
1CachedJitCompiledExpressionExecutorkSimpleSelectSmall1.864625e+041.860585e+04
2InterpretedExpressionExecutorkJoinSmall6.150498e+046.106450e+04
3CachedJitCompiledExpressionExecutorkJoinSmall5.840805e+045.808596e+04
4InterpretedExpressionExecutorkComplex57.079368e+047.039228e+04
5CachedJitCompiledExpressionExecutorkComplex56.784584e+046.751964e+04
6InterpretedExpressionExecutorkComplex5007.358773e+057.329383e+05
7CachedJitCompiledExpressionExecutorkComplex5005.317204e+055.299002e+05
8InterpretedExpressionExecutorkComplex10007.330710e+057.302785e+05
9CachedJitCompiledExpressionExecutorkComplex10005.321189e+055.304898e+05
10InterpretedExpressionExecutorkComplex20001.142329e+061.139146e+06
11CachedJitCompiledExpressionExecutorkComplex20009.146143e+059.116984e+05
12InterpretedExpressionExecutorkComplex40001.948222e+061.942391e+06
13CachedJitCompiledExpressionExecutorkComplex40001.695318e+061.672435e+06
14InterpretedExpressionExecutorkComplex80003.550326e+063.542127e+06
15CachedJitCompiledExpressionExecutorkComplex80003.199541e+063.191009e+06
16InterpretedExpressionExecutorkComplex160006.745250e+066.730967e+06
17CachedJitCompiledExpressionExecutorkComplex160006.237206e+066.217767e+06
\n", + "
" + ], + "text/plain": [ + " executor query real_time \\\n", + "0 InterpretedExpressionExecutor kSimpleSelectSmall 1.843972e+04 \n", + "1 CachedJitCompiledExpressionExecutor kSimpleSelectSmall 1.864625e+04 \n", + "2 InterpretedExpressionExecutor kJoinSmall 6.150498e+04 \n", + "3 CachedJitCompiledExpressionExecutor kJoinSmall 5.840805e+04 \n", + "4 InterpretedExpressionExecutor kComplex5 7.079368e+04 \n", + "5 CachedJitCompiledExpressionExecutor kComplex5 6.784584e+04 \n", + "6 InterpretedExpressionExecutor kComplex500 7.358773e+05 \n", + "7 CachedJitCompiledExpressionExecutor kComplex500 5.317204e+05 \n", + "8 InterpretedExpressionExecutor kComplex1000 7.330710e+05 \n", + "9 CachedJitCompiledExpressionExecutor kComplex1000 5.321189e+05 \n", + "10 InterpretedExpressionExecutor kComplex2000 1.142329e+06 \n", + "11 CachedJitCompiledExpressionExecutor kComplex2000 9.146143e+05 \n", + "12 InterpretedExpressionExecutor kComplex4000 1.948222e+06 \n", + "13 CachedJitCompiledExpressionExecutor kComplex4000 1.695318e+06 \n", + "14 InterpretedExpressionExecutor kComplex8000 3.550326e+06 \n", + "15 CachedJitCompiledExpressionExecutor kComplex8000 3.199541e+06 \n", + "16 InterpretedExpressionExecutor kComplex16000 6.745250e+06 \n", + "17 CachedJitCompiledExpressionExecutor kComplex16000 6.237206e+06 \n", + "\n", + " cpu_time \n", + "0 1.839315e+04 \n", + "1 1.860585e+04 \n", + "2 6.106450e+04 \n", + "3 5.808596e+04 \n", + "4 7.039228e+04 \n", + "5 6.751964e+04 \n", + "6 7.329383e+05 \n", + "7 5.299002e+05 \n", + "8 7.302785e+05 \n", + "9 5.304898e+05 \n", + "10 1.139146e+06 \n", + "11 9.116984e+05 \n", + "12 1.942391e+06 \n", + "13 1.672435e+06 \n", + "14 3.542127e+06 \n", + "15 3.191009e+06 \n", + "16 6.730967e+06 \n", + "17 6.217767e+06 " + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import re\n", + "from typing import Any\n", + "\n", + "benchmarks: list[dict[str, Any]] = list()\n", + "\n", + "for benchmark in data['benchmarks']:\n", + " match = re.match('BM_SQL<(.*), (.*)>', benchmark['name'])\n", + " if match is None:\n", + " raise ValueError(\"invalid benchmark name\")\n", + " executor, query = match.group(1), match.group(2)\n", + " real_time, cpu_time = benchmark['real_time'], benchmark['cpu_time']\n", + " time_unit = benchmark['time_unit']\n", + " if time_unit != 'ns':\n", + " raise ValueError(\"time_unit is not ns\")\n", + " benchmarks.append({\n", + " 'executor': executor,\n", + " 'query': query,\n", + " 'real_time': real_time,\n", + " 'cpu_time': cpu_time,\n", + " })\n", + " \n", + "import pandas as pd\n", + "\n", + "benchmarks = pd.DataFrame(benchmarks)\n", + "\n", + "benchmarks\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "b31f03cf", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
executorqueryreal_timecpu_time
0InterpretedExpressionExecutor57.079368e+047.039228e+04
1CachedJitCompiledExpressionExecutor56.784584e+046.751964e+04
2InterpretedExpressionExecutor5007.358773e+057.329383e+05
3CachedJitCompiledExpressionExecutor5005.317204e+055.299002e+05
4InterpretedExpressionExecutor10007.330710e+057.302785e+05
5CachedJitCompiledExpressionExecutor10005.321189e+055.304898e+05
6InterpretedExpressionExecutor20001.142329e+061.139146e+06
7CachedJitCompiledExpressionExecutor20009.146143e+059.116984e+05
8InterpretedExpressionExecutor40001.948222e+061.942391e+06
9CachedJitCompiledExpressionExecutor40001.695318e+061.672435e+06
10InterpretedExpressionExecutor80003.550326e+063.542127e+06
11CachedJitCompiledExpressionExecutor80003.199541e+063.191009e+06
12InterpretedExpressionExecutor160006.745250e+066.730967e+06
13CachedJitCompiledExpressionExecutor160006.237206e+066.217767e+06
\n", + "
" + ], + "text/plain": [ + " executor query real_time cpu_time\n", + "0 InterpretedExpressionExecutor 5 7.079368e+04 7.039228e+04\n", + "1 CachedJitCompiledExpressionExecutor 5 6.784584e+04 6.751964e+04\n", + "2 InterpretedExpressionExecutor 500 7.358773e+05 7.329383e+05\n", + "3 CachedJitCompiledExpressionExecutor 500 5.317204e+05 5.299002e+05\n", + "4 InterpretedExpressionExecutor 1000 7.330710e+05 7.302785e+05\n", + "5 CachedJitCompiledExpressionExecutor 1000 5.321189e+05 5.304898e+05\n", + "6 InterpretedExpressionExecutor 2000 1.142329e+06 1.139146e+06\n", + "7 CachedJitCompiledExpressionExecutor 2000 9.146143e+05 9.116984e+05\n", + "8 InterpretedExpressionExecutor 4000 1.948222e+06 1.942391e+06\n", + "9 CachedJitCompiledExpressionExecutor 4000 1.695318e+06 1.672435e+06\n", + "10 InterpretedExpressionExecutor 8000 3.550326e+06 3.542127e+06\n", + "11 CachedJitCompiledExpressionExecutor 8000 3.199541e+06 3.191009e+06\n", + "12 InterpretedExpressionExecutor 16000 6.745250e+06 6.730967e+06\n", + "13 CachedJitCompiledExpressionExecutor 16000 6.237206e+06 6.217767e+06" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "benchmarks = benchmarks[benchmarks['query'].str.contains('Complex')].copy()\n", + "benchmarks['query'] = benchmarks['query'].str.extract(r'(\\d+)').astype(int)\n", + "benchmarks.sort_values(by='query', inplace=True)\n", + "benchmarks.reset_index(drop=True, inplace=True)\n", + "benchmarks" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "deac9830", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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M1Olp65Qamoqb/dFREREpEElDnbvvfce1q9fLz1XKBRQKpVYuHAhOnTooNbiiIiIiKj4SjwUu3DhQnTq1AmnT59Gbm4upkyZggsXLiA1NRVRUVGlUSMRERERFUOJe+waNWqEK1euoF27dujZsycyMzPRu3dvnD17FrVr1y6NGomIiIioGN7olmKmpqaYMWOGumshIiIiorfwRsEuOzsbsbGxSE5OhlKpVJn30UcfqaUwIiIiIiqZEge7vXv3YvDgwfjnn3+KzFMoFCgoKFBLYURERERUMiU+xu6rr75Cv379kJSUBKVSqfJgqCMiIiLSnBIHuwcPHmDChAmoVq1aadRDRERERG+oxMGub9++iIyMLIVSiIiIiOhtlPgYuxUrVqBfv344evQoXFxcoKOjozJ/zJgxaiuOiIiIiIqvxMHuhx9+wP79+1G5cmVERkZCoVBI8xQKBYMdERHRuxJgWgrbTFP/NumdKXGwmzFjBgIDAzFt2jRoaZV4JJeIiIiISkmJk1lubi769+/PUEdERERUxpQ4nfn6+mLr1q2lUQsRERERvYUSD8UWFBRg4cKF2LdvH1xdXYucPLFkyRK1FUdERERExVfiYHf+/Hm4ubkBAOLi4lTmPXsiBRERERG9WyUOdocOHSqNOoiIiIjoLfEMCCIiIiKZKFaPXe/evREREQETExP07t37lctu27ZNLYURERERUckUK9iZmppKx8+ZmJjwWDoiIiKiMqhYwS48PFz6OSIiorRqISIiIqK3UOJj7Dp27IhHjx4VmZ6eno6OHTuqoyYiIiIiegMlDnaRkZHIzc0tMj07OxtHjx5VS1FEREREVHLFvtxJbGys9PPFixdx//596XlBQQH27t0LOzs79VZHRERERMVW7GDXpEkTKBQKKBSKFw656uvrY/ny5WotjoiIiIiKr9jB7saNGxBCoFatWjh58iQsLS2lebq6urCysoK2tnapFElEREREr1fsYFejRg0AgFKpLLViiIiIiOjN8c4TRERERDJR4nvFEhER0ZtxnLZLrdtLrKzWzZEMsMeOiIiISCYY7IiIiIhkothDsenp6S+cbmhoyLNhiYiIiMqAYvfYmZmZoUqVKkUe+vr6qFu3LtasWVOadRIRERHRaxS7x+7QoUMvnP7o0SNER0dj8uTJqFSpEoYOHVrsFw8JCUFISAgSExMBAA0b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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "\n", + "benchmarks.pivot(index='query', columns='executor', values='cpu_time').plot(kind='bar')\n", + "plt.ylabel('CPU time (ns)')\n", + "plt.xticks(rotation=45, ha='right')\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "1d432ac6", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
executorCachedJitCompiledExpressionExecutorInterpretedExpressionExecutorspeedup
query
56.751964e+047.039228e+044.080901
5005.299002e+057.329383e+0527.701946
10005.304898e+057.302785e+0527.357876
20009.116984e+051.139146e+0619.966504
40001.672435e+061.942391e+0613.898124
80003.191009e+063.542127e+069.912641
160006.217767e+066.730967e+067.624459
\n", + "
" + ], + "text/plain": [ + "executor CachedJitCompiledExpressionExecutor InterpretedExpressionExecutor \\\n", + "query \n", + "5 6.751964e+04 7.039228e+04 \n", + "500 5.299002e+05 7.329383e+05 \n", + "1000 5.304898e+05 7.302785e+05 \n", + "2000 9.116984e+05 1.139146e+06 \n", + "4000 1.672435e+06 1.942391e+06 \n", + "8000 3.191009e+06 3.542127e+06 \n", + "16000 6.217767e+06 6.730967e+06 \n", + "\n", + "executor speedup \n", + "query \n", + "5 4.080901 \n", + "500 27.701946 \n", + "1000 27.357876 \n", + "2000 19.966504 \n", + "4000 13.898124 \n", + "8000 9.912641 \n", + "16000 7.624459 " + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pivoted = benchmarks.pivot(index='query', columns='executor', values='cpu_time')\n", + "pivoted['speedup'] = (1.0 - pivoted['CachedJitCompiledExpressionExecutor'] / pivoted['InterpretedExpressionExecutor']) * 100\n", + "pivoted" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "f5af9c1a", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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19euXavMzEz5+PhIkpKSktS+ffuynxAAAAAlUuITFP/xj39U7969dfLkSUlSmzZtNHz4cK1Zs0afffaZxo8fr3bt2pXboAAAALi3EofdZ599pgEDBqhLly569913tWDBAoWEhGjixImaNGmSYmNjtWTJkvKcFQAAAPfg1mfs+vXrp6SkJI0fP15JSUmaP3++Zs2aVV6zAQAAwA1u/63YsLAwLViwQDNnztTzzz+vcePG6erVq+UxGwAAANxQ4rA7fvy4nnvuOTVv3lwDBw5Uw4YNtXPnTgUFBally5b64osvynNOAAAAFKPEYff888+rUqVKmjlzpiIjI/XrX/9a/v7+mjp1qlauXKn09HQ999xz5TkrAAAA7qHEn7HbsWOH9u7dq/r16yspKUlxcXHO25o2bapNmzZpwYIF5TIkAAAAilfisGvbtq0mT56sQYMG6auvvlLz5s1v2+fFF18s0+EAAABQciV+K3bx4sUqKCjQ6NGj9eOPP+r9998vz7kAAADgphIfsatTp47+/Oc/l+csAAAAKIUSHbHLz89360Hd3R8AAAClV6Kwa9CggaZPn67s7Oy77mOM0bp165ScnKw5c+aU2YAAAAAomRK9FZuRkaHf/OY3evPNN9WyZUs9/vjjiomJUeXKlXX+/Hl9//332rp1q3x9fTVhwgT9+te/Lu+5AQAA8C9KFHaNGzfWX/7yFx0/flyffvqpNm/erG+//VZXrlxRRESEWrdurQ8++EDJycny8fEp75kBAABwB279rdjatWtrzJgxGjNmTHnNAwAAgPvk9t+KBQAAgHci7AAAACxB2AEAAFiCsAMAALAEYQcAAGAJt34r9qbz58/rww8/1IEDByRJTZs21QsvvKDw8PAyHQ4AAAAl5/YRu02bNikuLk5z5szR+fPndf78eb377ruKi4vTpk2bymNGAAAAlIDbR+xSU1P13HPPad68ec6TEd+4cUMvv/yyUlNT9d1335X5kAAAACie20fssrKyNGbMGJe/MOHj46O0tDRlZWW59VibNm1Sz549FRMTI4fDoZUrV7rcPnjwYDkcDpdLt27d3B0ZAADgoeB22LVp08b52bpbHThwQC1btnTrsfLz89WyZUvNnTv3rvt069ZN2dnZzsvSpUvdHRkAAOCh4PZbsa+++qpGjhyprKwstW/fXpK0bds2zZ07V9OnT9e+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vn7729+6/Akpvo//qbifeZJ04MABPfvsswoNDVWVKlXUrl07HT9+3Hm7ta9JA4+YMmWKeeyxx0x2drbzcubMGU+P5TWKW5/hw4eb2NhYs379erNjxw7Tvn178+STTzpvv379umnWrJlJTEw0u3fvNn/9619NRESEmTBhgieeTrn761//aiZOnGiWL19uJJkVK1a43D59+nQTGhpqVq5cafbu3WueffZZExcXZ65cueLcp1u3bqZly5Zm27ZtZvPmzaZBgwZmwIABztsvXrxooqKizMCBA83+/fvN0qVLTWBgoHn//fcr6mmWm6SkJLNw4UKzf/9+s2fPHtO9e3dTu3Ztk5eX59ynLF5z//d//2eCgoJMWlqa+f777827775rfHx8zJo1ayr0+Zanv/3tb6Zu3bqmRYsWZuTIkc7trN+9vf3226Z69epm9erV5siRI+bTTz81VatWNb/73e+c+/B9/E/F/czLysoy4eHhZty4cWbXrl0mKyvLrFq1ypw6dcq5j62vScLOQ6ZMmWJatmzp6TG81r3W58KFC8bPz898+umnzm0HDhwwkszWrVuNMT9901eqVMnk5OQ495k3b54JCQkxBQUF5Tq7p/3rD7mioiITHR1tZs6c6dx24cIFExAQYJYuXWqMMeb77783kszf//535z5ffPGFcTgc5scffzTGGPPee++ZatWquazfa6+9Zho3blzOz6jinT592kgyGzduNMaU3Wtu/Pjx5rHHHnP5Wv369TNJSUnl/ZQqxKVLl0zDhg3NunXrzNNPP+0MO9aveD169DAvvPCCy7aUlBQzcOBAYwzfx/dyp7Dr16+f+eUvf3nX+9j8muStWA86dOiQYmJiVK9ePQ0cONDlEDHuvj47d+5UYWGhEhMTnfs2adJEtWvX1tatWyVJW7duVfPmzV1OZJ2UlKTc3Fz94x//qNgn4mFHjhxRTk6Oy3qFhoYqPj7eZb3CwsL0+OOPO/dJTExUpUqVtH37duc+nTt3lr+/v3OfpKQkZWZm6vz58xX0bCrGxYsXJUnh4eGSyu41t3XrVpfHuLnPzcd40KWmpqpHjx63PUfWr3hPPvmk1q9fr4MHD0qS9u7dqy1btig5OVkS38fuKCoq0ueff65GjRopKSlJkZGRio+Pd3m71ubXJGHnIfHx8Vq0aJHWrFmjefPm6ciRI+rUqZMuXbrk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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "pivoted['speedup'].plot(kind='bar')\n", + "plt.ylabel('speedup (%)')\n", + "plt.xlabel('query')\n", + "plt.xticks(rotation=0, ha='center')\n", + "plt.tight_layout()\n", + "plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "25a5fe61", + "metadata": {}, + "outputs": [], + "source": [ + "data_mt = \"\"\"\n", + "{\n", + " \"context\": {\n", + " \"date\": \"2026-01-10T23:38:31+03:00\",\n", + " \"host_name\": \"nixos\",\n", + " \"executable\": \"./build-release/bin/benchmarks\",\n", + " \"num_cpus\": 8,\n", + " \"mhz_per_cpu\": 4200,\n", + " \"cpu_scaling_enabled\": true,\n", + " \"caches\": [\n", + " {\n", + " \"type\": \"Data\",\n", + " \"level\": 1,\n", + " \"size\": 49152,\n", + " \"num_sharing\": 2\n", + " },\n", + " {\n", + " \"type\": \"Instruction\",\n", + " \"level\": 1,\n", + " \"size\": 32768,\n", + " \"num_sharing\": 2\n", + " },\n", + " {\n", + " \"type\": \"Unified\",\n", + " \"level\": 2,\n", + " \"size\": 1310720,\n", + " \"num_sharing\": 2\n", + " },\n", + " {\n", + " \"type\": \"Unified\",\n", + " \"level\": 3,\n", + " \"size\": 8388608,\n", + " \"num_sharing\": 8\n", + " }\n", + " ],\n", + " \"load_avg\": [0.419922,0.788574,0.725586],\n", + " \"library_version\": \"v1.9.0\",\n", + " \"library_build_type\": \"release\",\n", + " \"json_schema_version\": 1\n", + " },\n", + " \"benchmarks\": [\n", + " {\n", + " \"name\": \"BM_SQL/real_time\",\n", + " \"family_index\": 0,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL/real_time\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 39131,\n", + " \"real_time\": 1.7763904934746992e+04,\n", + " \"cpu_time\": 1.7715753596892489e+04,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL/real_time\",\n", + " \"family_index\": 1,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL/real_time\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 38563,\n", + " \"real_time\": 1.8130024764634931e+04,\n", + " \"cpu_time\": 1.8088057438477295e+04,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL/real_time\",\n", + " \"family_index\": 2,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL/real_time\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 12373,\n", + " \"real_time\": 5.7384221530711082e+04,\n", + " \"cpu_time\": 5.7042944718338294e+04,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL/real_time\",\n", + " \"family_index\": 3,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL/real_time\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 12308,\n", + " \"real_time\": 5.6059255443637892e+04,\n", + " \"cpu_time\": 5.5761686545336357e+04,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL/real_time\",\n", + " \"family_index\": 4,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL/real_time\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 10318,\n", + " \"real_time\": 6.7906289300143544e+04,\n", + " \"cpu_time\": 6.7580570653227391e+04,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL/real_time\",\n", + " \"family_index\": 5,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL/real_time\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 10710,\n", + " \"real_time\": 6.5059496918799705e+04,\n", + " \"cpu_time\": 6.4733736414565828e+04,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL/real_time\",\n", + " \"family_index\": 6,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL/real_time\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 916,\n", + " \"real_time\": 6.8747337554748205e+05,\n", + " \"cpu_time\": 6.8549197270742385e+05,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL/real_time\",\n", + " \"family_index\": 7,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL/real_time\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 1368,\n", + " \"real_time\": 5.1371013011559722e+05,\n", + " \"cpu_time\": 5.0669114400584786e+05,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL/real_time\",\n", + " \"family_index\": 8,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL/real_time\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 1016,\n", + " \"real_time\": 6.8965960629676247e+05,\n", + " \"cpu_time\": 6.8773966338582651e+05,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL/real_time\",\n", + " \"family_index\": 9,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL/real_time\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 1376,\n", + " \"real_time\": 5.0798636846138834e+05,\n", + " \"cpu_time\": 5.0643320566860412e+05,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL/real_time\",\n", + " \"family_index\": 10,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL/real_time\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 646,\n", + " \"real_time\": 1.0864569783272836e+06,\n", + " \"cpu_time\": 1.0833641873065040e+06,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL/real_time\",\n", + " \"family_index\": 11,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL/real_time\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 796,\n", + " \"real_time\": 8.7479362060439051e+05,\n", + " \"cpu_time\": 8.7213186055276426e+05,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL/real_time\",\n", + " \"family_index\": 12,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL/real_time\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 378,\n", + " \"real_time\": 1.8729881534425891e+06,\n", + " \"cpu_time\": 1.8523415952380972e+06,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL/real_time\",\n", + " \"family_index\": 13,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL/real_time\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 440,\n", + " \"real_time\": 1.6120009977302372e+06,\n", + " \"cpu_time\": 1.5915791840909088e+06,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL/real_time\",\n", + " \"family_index\": 14,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL/real_time\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 206,\n", + " \"real_time\": 3.3982538106746450e+06,\n", + " \"cpu_time\": 3.3882851407766948e+06,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL/real_time\",\n", + " \"family_index\": 15,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL/real_time\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 231,\n", + " \"real_time\": 3.0235657922004336e+06,\n", + " \"cpu_time\": 3.0163061558441538e+06,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL/real_time\",\n", + " \"family_index\": 16,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL/real_time\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 108,\n", + " \"real_time\": 6.4594497962725991e+06,\n", + " \"cpu_time\": 6.4458291388888815e+06,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL/real_time\",\n", + " \"family_index\": 17,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL/real_time\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 117,\n", + " \"real_time\": 5.9735239316131240e+06,\n", + " \"cpu_time\": 5.8960350598290535e+06,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL_Multithreaded/real_time\",\n", + " \"family_index\": 18,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL_Multithreaded/real_time\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 5314,\n", + " \"real_time\": 1.3457497459533918e+05,\n", + " \"cpu_time\": 6.7566829130599754e+03,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL_Multithreaded/real_time\",\n", + " \"family_index\": 19,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL_Multithreaded/real_time\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 5168,\n", + " \"real_time\": 1.3406582294902750e+05,\n", + " \"cpu_time\": 7.0243527476779418e+03,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL_Multithreaded/real_time\",\n", + " \"family_index\": 20,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL_Multithreaded/real_time\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 607,\n", + " \"real_time\": 1.1404998929171630e+06,\n", + " \"cpu_time\": 5.1917100494251117e+03,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL_Multithreaded/real_time\",\n", + " \"family_index\": 21,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL_Multithreaded/real_time\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 706,\n", + " \"real_time\": 9.3259300000174274e+05,\n", + " \"cpu_time\": 4.6985750708203832e+03,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL_Multithreaded/real_time\",\n", + " \"family_index\": 22,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL_Multithreaded/real_time\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 630,\n", + " \"real_time\": 1.1420491063507230e+06,\n", + " \"cpu_time\": 6.7041952380945313e+03,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL_Multithreaded/real_time\",\n", + " \"family_index\": 23,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL_Multithreaded/real_time\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 756,\n", + " \"real_time\": 1.0241538029106023e+06,\n", + " \"cpu_time\": 7.8318994708982927e+03,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL_Multithreaded/real_time\",\n", + " \"family_index\": 24,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL_Multithreaded/real_time\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 381,\n", + " \"real_time\": 1.8506752703352764e+06,\n", + " \"cpu_time\": 4.9503858267712976e+03,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL_Multithreaded/real_time\",\n", + " \"family_index\": 25,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL_Multithreaded/real_time\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 406,\n", + " \"real_time\": 1.6802704630580470e+06,\n", + " \"cpu_time\": 5.1671182266014257e+03,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL_Multithreaded/real_time\",\n", + " \"family_index\": 26,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL_Multithreaded/real_time\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 214,\n", + " \"real_time\": 3.3278060280315354e+06,\n", + " \"cpu_time\": 6.8044112149555713e+03,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL_Multithreaded/real_time\",\n", + " \"family_index\": 27,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL_Multithreaded/real_time\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 215,\n", + " \"real_time\": 3.2163211860596528e+06,\n", + " \"cpu_time\": 6.8673441860502680e+03,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL_Multithreaded/real_time\",\n", + " \"family_index\": 28,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL_Multithreaded/real_time\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 114,\n", + " \"real_time\": 6.1605299473612504e+06,\n", + " \"cpu_time\": 5.7971666666632946e+03,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL_Multithreaded/real_time\",\n", + " \"family_index\": 29,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL_Multithreaded/real_time\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 113,\n", + " \"real_time\": 5.8682074159150943e+06,\n", + " \"cpu_time\": 5.4813097345176830e+03,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL_Multithreaded/real_time\",\n", + " \"family_index\": 30,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL_Multithreaded/real_time\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 61,\n", + " \"real_time\": 1.1749900573734328e+07,\n", + " \"cpu_time\": 6.1474918032748528e+03,\n", + " \"time_unit\": \"ns\"\n", + " },\n", + " {\n", + " \"name\": \"BM_SQL_Multithreaded/real_time\",\n", + " \"family_index\": 31,\n", + " \"per_family_instance_index\": 0,\n", + " \"run_name\": \"BM_SQL_Multithreaded/real_time\",\n", + " \"run_type\": \"iteration\",\n", + " \"repetitions\": 1,\n", + " \"repetition_index\": 0,\n", + " \"threads\": 1,\n", + " \"iterations\": 61,\n", + " \"real_time\": 1.1562019360650590e+07,\n", + " \"cpu_time\": 7.6402295082020755e+03,\n", + " \"time_unit\": \"ns\"\n", + " }\n", + " ]\n", + "}\n", + "\"\"\"" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/benchmarks/flamegraph-jit.svg b/benchmarks/flamegraph-jit.svg new file mode 100644 index 0000000..c42206e --- /dev/null +++ b/benchmarks/flamegraph-jit.svg @@ -0,0 +1,3206 @@ + + + + + + + + + + + + + + +Flame Graph + +Reset Zoom +Search +ic + + + +pthread_cond_signal@@GLIBC_2.3.2 (12,413,973 samples, 0.23%) + + + +void boost::asio::experimental::detail::channel_service<boost::asio::detail::posix_mutex>::async_receive<boost::asio::experimental::channel_traits<>, void (41,284,771 samples, 0.77%) + + + +cfree@GLIBC_2.2.5 (20,221,764 samples, 0.38%) + + + +boost_asio_detail_posix_thread_function (5,097,584,863 samples, 94.65%) +boost_asio_detail_posix_thread_function + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +boost::asio::detail::executor_op<boost::asio::detail::executor_function, std::allocator<void>, boost::asio::detail::scheduler_operation>::do_complete (4,253,950,191 samples, 78.98%) +boost::asio::detail::executor_op<boost::asio::detail::executor_function, std::allocator<void>, boost::asio::detail::scheduler_ope.. + + +boost::asio::detail::awaitable_thread<boost::asio::any_io_executor>::pump (1,330,290,316 samples, 24.70%) +boost::asio::detail::awaitable_thread<b.. + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +void boost::asio::execution::detail::any_executor_base::copy_object<boost::asio::thread_pool::basic_executor_type<std::allocator<void>, 8u> > (7,806,326 samples, 0.14%) + + + +_int_free (44,735,347 samples, 0.83%) + + + +antlr4::atn::ParserATNSimulator::closure_ (24,508,665 samples, 0.46%) + + + +void boost::asio::execution::detail::any_executor_base::execute<boost::asio::detail::work_dispatcher<boost::asio::detail::empty_work_function, boost::asio::detail::completion_payload_handler<boost::asio::detail::completion_payload<void (26,209,776 samples, 0.49%) + + + +void boost::asio::detail::executor_function::complete<boost::asio::detail::binder0<boost::asio::detail::binder1<boost::asio::detail::awaitable_handler<boost::asio::any_io_executor, boost::system::error_code>, boost::system::error_code> >, std::allocator<void> > (1,378,912,689 samples, 25.60%) +void boost::asio::detail::executor_funct.. + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +void boost::asio::execution::detail::any_executor_base::execute<boost::asio::detail::work_dispatcher<boost::asio::detail::empty_work_function, boost::asio::detail::completion_payload_handler<boost::asio::detail::completion_payload<void (26,937,911 samples, 0.50%) + + + +void boost::asio::detail::initiate_post_with_executor<boost::asio::any_io_executor>::operator (26,209,776 samples, 0.49%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +void boost::asio::execution::detail::any_executor_base::destroy_object<boost::asio::thread_pool::basic_executor_type<std::allocator<void>, 8u> > (69,759,531 samples, 1.30%) + + + +stewkk::sql::ReceiveTuples (42,963,583 samples, 0.80%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +_int_free (50,763,113 samples, 0.94%) + + + +boost::asio::detail::executor_function::impl<boost::asio::detail::binder0<boost::asio::detail::completion_payload_handler<boost::asio::detail::completion_payload<void (20,782,792 samples, 0.39%) + + + +std::unique_ptr<(anonymous namespace)::PostgreSQLLexerStaticData, std::default_delete<(anonymous namespace)::PostgreSQLLexerStaticData> >::~unique_ptr (29,421,778 samples, 0.55%) + + + +_int_malloc (17,249,947 samples, 0.32%) + + + +boost::asio::experimental::detail::channel_operation::handler_work<boost::asio::detail::awaitable_handler<boost::asio::any_io_executor, boost::system::error_code>, boost::asio::any_io_executor, void>::handler_work (29,672,186 samples, 0.55%) + + + +stewkk::sql::codegen::PostgreSQLParser::target_list_ (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +__pthread_mutex_cond_lock (25,449,055 samples, 0.47%) + + + +__GI___lll_lock_wait (41,186,819 samples, 0.76%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +antlr4::Lexer::nextToken (14,786,529 samples, 0.27%) + + + +void boost::asio::execution::detail::any_executor_base::destroy_object<boost::asio::thread_pool::basic_executor_type<std::allocator<void>, 8u> > (73,960,902 samples, 1.37%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +_ZZZN6stewkk3sql20BM_SQL_MultithreadedINS0_29InterpretedExpressionExecutorEXadsoKcL_ZNS0_L12kComplex2000EEEEEEvRN9benchmark5StateEENKUlvE_clEvENKUlvE_clEv.resume (63,815,507 samples, 1.18%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +void boost::asio::thread_pool::basic_executor_type<std::allocator<void>, 8u>::do_execute<boost::asio::detail::executor_function> (2,612,697,086 samples, 48.51%) +void boost::asio::thread_pool::basic_executor_type<std::allocator<void>, 8u>::.. + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +stewkk::sql::codegen::PostgreSQLParser::a_expr_between (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +__condvar_confirm_wakeup (21,216,559 samples, 0.39%) + + + +std::enable_if<call_traits<boost_asio_prefer_fn::impl, boost::asio::any_io_executor const&, void (25,825,382 samples, 0.48%) + + + +stewkk::sql::Executor<stewkk::sql::InterpretedExpressionExecutor>::ExecuteProjection (28,645,678 samples, 0.53%) + + + +_ZN5boost4asio8co_spawnINS0_15any_io_executorES2_TkNS0_20completion_token_forIFvNSt15__exception_ptr13exception_ptrEEEERKNS0_10detached_tEEEDaRKT_NS0_9awaitableIvT0_EEOT1_NS0_10constraintIXaaoosr11is_executorISA_EE5valuesr9execution11is_executorISA_EE5valuesr14is_convertibleISA_SE_EE5valueEiE4typeE (43,166,371 samples, 0.80%) + + + +boost::asio::detail::scheduler::work_finished (21,270,699 samples, 0.39%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +std::enable_if<call_traits<boost_asio_require_fn::impl, boost::asio::any_io_executor const&, void (47,436,972 samples, 0.88%) + + + +antlr4::atn::ParserATNSimulator::adaptivePredict (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +void* boost::asio::detail::thread_info_base::allocate<boost::asio::detail::thread_info_base::awaitable_frame_tag> (19,405,153 samples, 0.36%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +std::_Hashtable<std::shared_ptr<antlr4::atn::ATNConfig>, std::shared_ptr<antlr4::atn::ATNConfig>, std::allocator<std::shared_ptr<antlr4::atn::ATNConfig> >, std::__detail::_Identity, antlr4::atn::ATNConfig::Comparer, antlr4::atn::ATNConfig::Hasher, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<true, true, true> >::count (31,901,449 samples, 0.59%) + + + +std::_Sp_counted_ptr_inplace<antlr4::atn::SingletonPredictionContext, std::allocator<void>, (29,421,778 samples, 0.55%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +stewkk::sql::codegen::PostgreSQLParser::a_expr_or (37,424,238 samples, 0.69%) + + + +stewkk::sql::codegen::PostgreSQLParser::a_expr_typecast (24,508,665 samples, 0.46%) + + + +stewkk::sql::codegen::PostgreSQLParser::simple_select_intersect (61,932,903 samples, 1.15%) + + + +antlr4::atn::PredictionContextMergeCache::Entry::~Entry (37,424,238 samples, 0.69%) + + + +boost::asio::detail::scheduler::work_finished (81,354,602 samples, 1.51%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +__memmove_evex_unaligned_erms (9,485,663 samples, 0.18%) + + + +void boost::asio::detail::executor_function::complete<boost::asio::detail::work_dispatcher<boost::asio::detail::empty_work_function, boost::asio::detail::completion_payload_handler<boost::asio::detail::completion_payload<void (2,715,823,435 samples, 50.43%) +void boost::asio::detail::executor_function::complete<boost::asio::detail::work_di.. + + +boost::asio::experimental::detail::channel_receive_op<boost::asio::detail::completion_payload<void (86,917,634 samples, 1.61%) + + + +boost::asio::detail::awaitable_frame_base<boost::asio::any_io_executor>::await_transform<boost::asio::async_result<boost::asio::use_awaitable_t<boost::asio::any_io_executor>, void (627,608,615 samples, 11.65%) +boost::asio::deta.. + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +void boost::asio::thread_pool::basic_executor_type<std::allocator<void>, 0u>::do_execute<boost::asio::detail::executor_function> (43,166,371 samples, 0.80%) + + + +std::_Deque_base<boost::asio::detail::completion_payload<void (23,984,314 samples, 0.45%) + + + +benchmark::RunSpecifiedBenchmarks (100,364,807 samples, 1.86%) +b.. + + +std::enable_if<call_traits<boost_asio_prefer_fn::impl, boost::asio::any_io_executor const&, void (24,917,780 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +non-virtual thunk to antlr4::Lexer::nextToken (14,786,529 samples, 0.27%) + + + +operator new (17,249,947 samples, 0.32%) + + + +_ZN5boost4asio8co_spawnINS0_15any_io_executorES2_TkNS0_20completion_token_forIFvNSt15__exception_ptr13exception_ptrEEEERKNS0_10detached_tEEEDaRKT_NS0_9awaitableIvT0_EEOT1_NS0_10constraintIXaaoosr11is_executorISA_EE5valuesr9execution11is_executorISA_EE5valuesr14is_convertibleISA_SE_EE5valueEiE4typeE (43,166,371 samples, 0.80%) + + + +void boost::asio::execution::detail::any_executor_base::execute<boost::asio::detail::binder0<boost::asio::detail::binder1<boost::asio::detail::awaitable_handler<boost::asio::any_io_executor, boost::system::error_code>, boost::system::error_code> > > (1,429,901,377 samples, 26.55%) +void boost::asio::execution::detail::any_e.. + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +void boost::asio::experimental::detail::channel_operation::handler_work_base<boost::asio::any_io_executor, boost::asio::any_io_executor, void>::post<boost::asio::any_io_executor, boost::asio::detail::binder1<boost::asio::detail::awaitable_handler<boost::asio::any_io_executor, boost::system::error_code>, boost::system::error_code>, boost::asio::detail::awaitable_handler<boost::asio::any_io_executor, boost::system::error_code> > (188,525,570 samples, 3.50%) +voi.. + + +void boost::asio::thread_pool::basic_executor_type<std::allocator<void>, 8u>::do_execute<boost::asio::detail::executor_function> (19,129,396 samples, 0.36%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +stewkk::sql::codegen::PostgreSQLParser::colid (24,508,665 samples, 0.46%) + + + +void boost::asio::execution::detail::any_executor_base::execute<boost::asio::detail::binder0<boost::asio::detail::completion_payload_handler<boost::asio::detail::completion_payload<void (2,664,225,604 samples, 49.47%) +void boost::asio::execution::detail::any_executor_base::execute<boost::asio::det.. + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +boost::asio::detail::awaitable_thread<boost::asio::any_io_executor>::pump (2,500,706,936 samples, 46.43%) +boost::asio::detail::awaitable_thread<boost::asio::any_io_executor>::pump + + +std::enable_if<call_traits<boost_asio_prefer_fn::impl, boost::asio::any_io_executor const&, void (16,513,150 samples, 0.31%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +stewkk::sql::MaterializeChannel (16,892,604 samples, 0.31%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::adaptivePredict (37,424,238 samples, 0.69%) + + + +void boost::asio::thread_pool::basic_executor_type<std::allocator<void>, 8u>::do_execute<boost::asio::detail::executor_function> (26,209,776 samples, 0.49%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +void* boost::asio::detail::thread_info_base::allocate<boost::asio::detail::thread_info_base::default_tag> (12,637,984 samples, 0.23%) + + + +benchmark::internal::BenchmarkInstance::Run (91,907,772 samples, 1.71%) + + + +[unknown] (20,125,463 samples, 0.37%) + + + +void boost::asio::execution::detail::any_executor_base::destroy_object<boost::asio::thread_pool::basic_executor_type<std::allocator<void>, 8u> > (48,185,083 samples, 0.89%) + + + +stewkk::sql::codegen::PostgreSQLParser::target_el (24,508,665 samples, 0.46%) + + + +void boost::asio::execution::detail::any_executor_base::destroy_object<boost::asio::thread_pool::basic_executor_type<std::allocator<void>, 8u> > (12,490,400 samples, 0.23%) + + + +__GI___lll_lock_wait (5,050,505 samples, 0.09%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +_ZN6stewkk3sql20BM_SQL_MultithreadedINS0_29InterpretedExpressionExecutorEXadsoKcL_ZNS0_L12kComplex2000EEEEEEvRN9benchmark5StateE (91,907,772 samples, 1.71%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +antlr4::atn::ATNConfig::~ATNConfig (29,421,778 samples, 0.55%) + + + +void boost::asio::experimental::detail::channel_operation::handler_work_base<boost::asio::any_io_executor, boost::asio::any_io_executor, void>::post<boost::asio::any_io_executor, boost::asio::detail::completion_payload_handler<boost::asio::detail::completion_payload<void (26,937,911 samples, 0.50%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +void boost::asio::detail::initiate_post_with_executor<boost::asio::any_io_executor>::operator (230,596,188 samples, 4.28%) +void .. + + +stewkk::sql::codegen::PostgreSQLParser::a_expr_unary_qualop (24,508,665 samples, 0.46%) + + + +_int_free (45,110,211 samples, 0.84%) + + + +boost::asio::detail::executor_op<boost::asio::detail::executor_function, std::allocator<void>, boost::asio::detail::scheduler_operation>::do_complete (91,907,772 samples, 1.71%) + + + +stewkk::sql::codegen::PostgreSQLParser::a_expr_lessless (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +malloc (15,188,340 samples, 0.28%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +stewkk::sql::codegen::PostgreSQLParser::identifier (24,508,665 samples, 0.46%) + + + +pthread_mutex_lock@@GLIBC_2.2.5 (15,169,748 samples, 0.28%) + + + +benchmark::internal::BenchmarkFamilies::FindBenchmarks (8,457,035 samples, 0.16%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +boost::asio::detail::awaitable_async_op<void (43,166,371 samples, 0.80%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +stewkk::sql::codegen::PostgreSQLParser::stmtblock (61,932,903 samples, 1.15%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +boost::asio::detail::scheduler::work_finished (29,261,323 samples, 0.54%) + + + +void boost::asio::execution::detail::any_executor_base::destroy_object<boost::asio::thread_pool::basic_executor_type<std::allocator<void>, 8u> > (22,304,436 samples, 0.41%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +stewkk::sql::codegen::PostgreSQLParser::selectstmt (61,932,903 samples, 1.15%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +void boost::asio::execution::detail::any_executor_base::destroy_object<boost::asio::thread_pool::basic_executor_type<std::allocator<void>, 0u> > (20,879,359 samples, 0.39%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +void boost::asio::thread_pool::basic_executor_type<std::allocator<void>, 0u>::do_execute<boost::asio::detail::executor_function> (43,166,371 samples, 0.80%) + + + +stewkk::sql::codegen::PostgreSQLParser::stmt (61,932,903 samples, 1.15%) + + + +pthread_cond_signal@@GLIBC_2.3.2 (41,261,557 samples, 0.77%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +_int_free (37,424,238 samples, 0.69%) + + + +std::enable_if<call_traits<boost_asio_prefer_fn::impl, boost::asio::any_io_executor const&, void (21,531,340 samples, 0.40%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +stewkk::sql::codegen::PostgreSQLParser::PostgreSQLParser (15,188,340 samples, 0.28%) + + + +malloc (25,168,871 samples, 0.47%) + + + +antlr4::atn::OrderedATNConfigSet::~OrderedATNConfigSet (29,421,778 samples, 0.55%) + + + +stewkk::sql::CalcExpression (47,573,615 samples, 0.88%) + + + +cfree@GLIBC_2.2.5 (8,183,224 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +stewkk::sql::Executor<stewkk::sql::InterpretedExpressionExecutor>::ExecuteJoin (863,671,399 samples, 16.04%) +stewkk::sql::Executor<st.. + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +boost::asio::detail::executor_function::executor_function<boost::asio::detail::work_dispatcher<boost::asio::detail::empty_work_function, boost::asio::detail::completion_payload_handler<boost::asio::detail::completion_payload<void (24,108,290 samples, 0.45%) + + + +boost::asio::detail::scheduler::do_run_one (91,907,772 samples, 1.71%) + + + +pthread_mutex_lock@plt (8,018,740 samples, 0.15%) + + + +stewkk::sql::ReceiveTuples (45,343,074 samples, 0.84%) + + + +pthread_cond_signal@@GLIBC_2.3.2 (29,271,007 samples, 0.54%) + + + +stewkk::sql::codegen::PostgreSQLParser::a_expr_at_time_zone (24,508,665 samples, 0.46%) + + + +void boost::asio::experimental::detail::channel_service<boost::asio::detail::posix_mutex>::async_send<boost::asio::experimental::channel_traits<>, void (573,768,071 samples, 10.65%) +void boost::asi.. + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +boost::asio::detail::scheduler::post_immediate_completion (22,757,469 samples, 0.42%) + + + +malloc (92,078,600 samples, 1.71%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +stewkk::sql::CalcExpression (282,042,305 samples, 5.24%) +stewkk.. + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +boost::asio::execution::any_executor<boost::asio::execution::context_as_t<boost::asio::execution_context&>, boost::asio::execution::detail::blocking::never_t<0>, boost::asio::execution::prefer_only<boost::asio::execution::detail::blocking::possibly_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::tracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::untracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::fork_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::continuation_t<0> > > boost::asio::execution::detail::any_executor_base::prefer_fn<boost::asio::execution::any_executor<boost::asio::execution::context_as_t<boost::asio::execution_context&>, boost::asio::execution::detail::blocking::never_t<0>, boost::asio::execution::prefer_only<boost::asio::execution::detail::blocking::possibly_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::tracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::untracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::fork_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::continuation_t<0> > >, boost::asio::thread_pool::basic_executor_type<std::allocator<void>, 0u>, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::tracked_t<0> > > (9,314,054 samples, 0.17%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +boost::asio::experimental::detail::channel_receive_op<boost::asio::detail::completion_payload<void (19,129,396 samples, 0.36%) + + + +stewkk::sql::codegen::PostgreSQLParser::stmtmulti (61,932,903 samples, 1.15%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +_int_malloc (92,078,600 samples, 1.71%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +antlr4::dfa::DFA::~DFA (29,421,778 samples, 0.55%) + + + +uw_update_context_1 (25,467,846 samples, 0.47%) + + + +stewkk::sql::ApplyProjection (282,042,305 samples, 5.24%) +stewkk.. + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +malloc_consolidate (12,089,111 samples, 0.22%) + + + +antlr4::atn::LexerATNSimulator::match (14,786,529 samples, 0.27%) + + + +antlr4::atn::ATNState::addTransition (15,188,340 samples, 0.28%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +antlr4::atn::LexerATNSimulator::computeTargetState (14,786,529 samples, 0.27%) + + + +boost::asio::detail::awaitable_thread<boost::asio::any_io_executor>::~awaitable_thread (16,186,366 samples, 0.30%) + + + +void boost::asio::detail::awaitable_handler<boost::asio::any_io_executor, boost::system::error_code, std::vector<stewkk::sql::AttributeInfo, std::allocator<stewkk::sql::AttributeInfo> > >::operator (26,937,911 samples, 0.50%) + + + +stewkk::sql::codegen::PostgreSQLParser::c_expr (24,508,665 samples, 0.46%) + + + +void boost::asio::detail::initiate_co_spawn<boost::asio::any_io_executor>::operator (43,166,371 samples, 0.80%) + + + +void boost::asio::execution::detail::any_executor_base::destroy_object<boost::asio::thread_pool::basic_executor_type<std::allocator<void>, 8u> > (23,872,024 samples, 0.44%) + + + +boost::asio::detail::awaitable_thread<boost::asio::any_io_executor>::~awaitable_thread (54,188,585 samples, 1.01%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closure_ (24,508,665 samples, 0.46%) + + + +void boost::asio::execution::detail::any_executor_base::execute<boost::asio::detail::work_dispatcher<boost::asio::detail::empty_work_function, boost::asio::detail::binder1<boost::asio::detail::awaitable_handler<boost::asio::any_io_executor, boost::system::error_code>, boost::system::error_code>, boost::asio::any_io_executor, void> > (38,234,974 samples, 0.71%) + + + +stewkk::sql::GetChannels (23,984,314 samples, 0.45%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (24,508,665 samples, 0.46%) + + + +boost::asio::detail::awaitable_thread<boost::asio::any_io_executor>::pump (26,937,911 samples, 0.50%) + + + +boost::asio::experimental::detail::channel_operation::handler_work<boost::asio::detail::awaitable_handler<boost::asio::any_io_executor, boost::system::error_code>, boost::asio::any_io_executor, void>::handler_work (24,917,780 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +void boost::asio::experimental::detail::channel_service<boost::asio::detail::posix_mutex>::async_send<boost::asio::experimental::channel_traits<>, void (26,937,911 samples, 0.50%) + + + +antlr4::atn::ParserATNSimulator::closure_ (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +malloc_consolidate (16,892,604 samples, 0.31%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +stewkk::sql::CalcExpression (201,925,159 samples, 3.75%) +stew.. + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +void boost::asio::detail::executor_function::complete<boost::asio::detail::binder0<boost::asio::detail::awaitable_async_op_handler<void (43,166,371 samples, 0.80%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +boost::asio::experimental::detail::channel_send_op<boost::asio::detail::completion_payload<void (12,841,321 samples, 0.24%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +pthread_cond_signal@@GLIBC_2.3.2 (17,896,964 samples, 0.33%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +__GI___pthread_mutex_unlock_usercnt (111,861,054 samples, 2.08%) +_.. + + +malloc (255,483,021 samples, 4.74%) +malloc + + +_int_malloc (16,892,604 samples, 0.31%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +stewkk::sql::CsvDirSequentialScanner::operator (294,581,404 samples, 5.47%) +stewkk:.. + + +boost::asio::experimental::detail::channel_receive_op<boost::asio::detail::completion_payload<void (238,402,514 samples, 4.43%) +boost.. + + +[unknown] (25,467,846 samples, 0.47%) + + + +benchmarks (5,385,823,897 samples, 100.00%) +benchmarks + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +stewkk::sql::codegen::PostgreSQLParser::from_list (37,424,238 samples, 0.69%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +_int_free (32,503,682 samples, 0.60%) + + + +stewkk::sql::Executor<stewkk::sql::InterpretedExpressionExecutor>::Execute (19,182,057 samples, 0.36%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +boost::asio::execution::any_executor<boost::asio::execution::context_as_t<boost::asio::execution_context&>, boost::asio::execution::detail::blocking::never_t<0>, boost::asio::execution::prefer_only<boost::asio::execution::detail::blocking::possibly_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::tracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::untracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::fork_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::continuation_t<0> > > boost::asio::execution::detail::any_executor_base::prefer_fn<boost::asio::execution::any_executor<boost::asio::execution::context_as_t<boost::asio::execution_context&>, boost::asio::execution::detail::blocking::never_t<0>, boost::asio::execution::prefer_only<boost::asio::execution::detail::blocking::possibly_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::tracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::untracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::fork_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::continuation_t<0> > >, boost::asio::thread_pool::basic_executor_type<std::allocator<void>, 0u>, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::tracked_t<0> > > (25,825,382 samples, 0.48%) + + + +antlr4::atn::PredictionContextMergeCache::get (24,508,665 samples, 0.46%) + + + +boost::asio::detail::awaitable_thread<boost::asio::any_io_executor>::pump (43,166,371 samples, 0.80%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +boost::asio::detail::scheduler::work_finished (28,112,100 samples, 0.52%) + + + +antlr4::atn::ParserATNSimulator::closure_ (24,508,665 samples, 0.46%) + + + +void boost::asio::execution::detail::any_executor_base::move_object<boost::asio::thread_pool::basic_executor_type<std::allocator<void>, 8u> > (20,184,606 samples, 0.37%) + + + +_int_free (8,438,753 samples, 0.16%) + + + +stewkk::sql::MaterializeChannel (45,068,730 samples, 0.84%) + + + +_ZNSt6ranges14__copy_or_moveILb0ETkSt14input_iteratorPKN6stewkk3sql5ValueETkSt12sentinel_forIT0_ES5_TkSt20weakly_incrementableSt20back_insert_iteratorISt6vectorIS3_SaIS3_EEEQquT_18indirectly_movableIS7_T2_E19indirectly_copyableIS7_SD_EEENSt13__conditionalIXT_EE4typeINS_13in_out_resultIS7_SD_EESI_EES7_T1_SD_ (82,005,608 samples, 1.52%) + + + +operator new (23,984,314 samples, 0.45%) + + + +stewkk::sql::codegen::PostgreSQLParser::a_expr_collate (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +stewkk::sql::codegen::PostgreSQLParser::root (61,932,903 samples, 1.15%) + + + +stewkk::sql::codegen::PostgreSQLParser::a_expr_is_not (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +_int_free (18,818,159 samples, 0.35%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +operator new (118,326,047 samples, 2.20%) +o.. + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +void boost::asio::detail::executor_function::complete<boost::asio::detail::work_dispatcher<boost::asio::detail::empty_work_function, boost::asio::detail::binder1<boost::asio::detail::awaitable_handler<boost::asio::any_io_executor, boost::system::error_code>, boost::system::error_code>, boost::asio::any_io_executor, void>, std::allocator<void> > (26,133,025 samples, 0.49%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +_ZZN6stewkk3sql20BM_SQL_MultithreadedINS0_29InterpretedExpressionExecutorEXadsoKcL_ZNS0_L12kComplex2000EEEEEEvRN9benchmark5StateEENKUlvE_clEv.resume (91,907,772 samples, 1.71%) + + + +antlr4::atn::ParserATNSimulator::computeStartState (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +__pthread_once_slow.isra.0 (15,188,340 samples, 0.28%) + + + +benchmark::internal::(anonymous namespace)::RunInThread (91,907,772 samples, 1.71%) + + + +void boost::asio::experimental::detail::channel_operation::handler_work<boost::asio::detail::awaitable_handler<boost::asio::any_io_executor, boost::system::error_code, std::vector<std::vector<stewkk::sql::Value, std::allocator<stewkk::sql::Value> >, std::allocator<std::vector<stewkk::sql::Value, std::allocator<stewkk::sql::Value> > > > >, boost::asio::any_io_executor, void>::immediate<boost::asio::detail::completion_payload_handler<boost::asio::detail::completion_payload<void (19,129,396 samples, 0.36%) + + + +boost::asio::detail::scheduler::work_finished (23,872,024 samples, 0.44%) + + + +void boost::asio::experimental::detail::channel_service<boost::asio::detail::posix_mutex>::start_receive_op<boost::asio::experimental::channel_traits<>, void (31,970,717 samples, 0.59%) + + + +void boost::asio::detail::initiate_post_with_executor<boost::asio::any_io_executor>::operator (19,129,396 samples, 0.36%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +stewkk::sql::codegen::PostgreSQLParser::a_expr_qual (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +operator new (54,664,255 samples, 1.01%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +void boost::asio::thread_pool::basic_executor_type<std::allocator<void>, 8u>::do_execute<boost::asio::detail::executor_function> (12,016,681 samples, 0.22%) + + + +antlr4::atn::ParserATNSimulator::closure_ (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closure_ (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closure_ (24,508,665 samples, 0.46%) + + + +void boost::asio::experimental::detail::channel_operation::handler_work<boost::asio::detail::awaitable_handler<boost::asio::any_io_executor, boost::system::error_code>, boost::asio::any_io_executor, void>::immediate<boost::asio::detail::binder1<boost::asio::detail::awaitable_handler<boost::asio::any_io_executor, boost::system::error_code>, boost::system::error_code> > (308,370,936 samples, 5.73%) +void bo.. + + +std::enable_if<call_traits<boost_asio_prefer_fn::impl, boost::asio::any_io_executor, void (39,830,937 samples, 0.74%) + + + +__GI___pthread_mutex_unlock_usercnt (23,992,394 samples, 0.45%) + + + +_int_free (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +void boost::asio::thread_pool::basic_executor_type<std::allocator<void>, 8u>::do_execute<boost::asio::detail::executor_function> (1,378,912,689 samples, 25.60%) +void boost::asio::thread_pool::basic_exe.. + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +void boost::asio::detail::initiate_post_with_executor<boost::asio::any_io_executor>::operator (12,841,321 samples, 0.24%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +__run_exit_handlers (29,421,778 samples, 0.55%) + + + +boost::asio::detail::awaitable_async_op<void (43,166,371 samples, 0.80%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +__libc_start_main@@GLIBC_2.34 (129,786,585 samples, 2.41%) +__.. + + +std::istream::sentry::sentry (22,556,793 samples, 0.42%) + + + +void* boost::asio::detail::thread_info_base::allocate<boost::asio::detail::thread_info_base::executor_function_tag> (12,442,960 samples, 0.23%) + + + +antlr4::atn::LexerATNSimulator::getReachableConfigSet (14,786,529 samples, 0.27%) + + + +stewkk::sql::Executor<stewkk::sql::InterpretedExpressionExecutor>::Execute (107,095,505 samples, 1.99%) +s.. + + +__memcmp_evex_movbe (49,134,744 samples, 0.91%) + + + +std::basic_istream<char, std::char_traits<char> >& std::getline<char, std::char_traits<char>, std::allocator<char> > (22,407,757 samples, 0.42%) + + + +cfree@GLIBC_2.2.5 (30,709,462 samples, 0.57%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +boost::asio::execution::any_executor<boost::asio::execution::context_as_t<boost::asio::execution_context&>, boost::asio::execution::detail::blocking::never_t<0>, boost::asio::execution::prefer_only<boost::asio::execution::detail::blocking::possibly_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::tracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::untracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::fork_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::continuation_t<0> > > boost::asio::execution::detail::any_executor_base::prefer_fn<boost::asio::execution::any_executor<boost::asio::execution::context_as_t<boost::asio::execution_context&>, boost::asio::execution::detail::blocking::never_t<0>, boost::asio::execution::prefer_only<boost::asio::execution::detail::blocking::possibly_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::tracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::untracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::fork_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::continuation_t<0> > >, boost::asio::thread_pool::basic_executor_type<std::allocator<void>, 0u>, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::tracked_t<0> > > (27,364,608 samples, 0.51%) + + + +void* boost::asio::detail::thread_info_base::allocate<boost::asio::detail::thread_info_base::executor_function_tag> (23,578,020 samples, 0.44%) + + + +boost::asio::detail::scheduler::work_finished (21,134,143 samples, 0.39%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +stewkk::sql::codegen::PostgreSQLParser::table_ref (37,424,238 samples, 0.69%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +antlr4::atn::ArrayPredictionContext::hashCodeImpl (24,508,665 samples, 0.46%) + + + +stewkk::sql::codegen::PostgreSQLParser::select_clause (61,932,903 samples, 1.15%) + + + +void boost::asio::execution::detail::any_executor_base::move_object<boost::asio::thread_pool::basic_executor_type<std::allocator<void>, 8u> > (19,495,844 samples, 0.36%) + + + +void boost::asio::experimental::detail::channel_service<boost::asio::detail::posix_mutex>::start_send_op<boost::asio::experimental::channel_traits<>, void (26,209,776 samples, 0.49%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +operator new (15,188,340 samples, 0.28%) + + + +void boost::asio::execution::detail::any_executor_base::destroy_object<boost::asio::thread_pool::basic_executor_type<std::allocator<void>, 8u> > (21,134,143 samples, 0.39%) + + + +_int_free_maybe_consolidate.part.0 (12,089,111 samples, 0.22%) + + + +auto boost::asio::detail::awaitable_frame_base<boost::asio::any_io_executor>::await_transform<void> (38,357,846 samples, 0.71%) + + + +void boost::asio::thread_pool::basic_executor_type<std::allocator<void>, 8u>::do_execute<boost::asio::detail::executor_function> (15,477,505 samples, 0.29%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +stewkk::sql::codegen::PostgreSQLParser::a_expr_add (24,508,665 samples, 0.46%) + + + +void boost::asio::detail::executor_function::complete<boost::asio::detail::binder0<boost::asio::detail::completion_payload_handler<boost::asio::detail::completion_payload<void (2,612,697,086 samples, 48.51%) +void boost::asio::detail::executor_function::complete<boost::asio::detail::bin.. + + +[unknown] (17,932,534 samples, 0.33%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +stewkk::sql::codegen::PostgreSQLParser::a_expr_and (24,508,665 samples, 0.46%) + + + +void boost::asio::thread_pool::basic_executor_type<std::allocator<void>, 8u>::do_execute<boost::asio::detail::executor_function> (61,465,075 samples, 1.14%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +void boost::asio::experimental::detail::channel_operation::handler_work_base<boost::asio::any_io_executor, boost::asio::any_io_executor, void>::post<boost::asio::any_io_executor, boost::asio::detail::completion_payload_handler<boost::asio::detail::completion_payload<void (26,209,776 samples, 0.49%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +stewkk::sql::CalcExpression (201,925,159 samples, 3.75%) +stew.. + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +_int_malloc (161,090,161 samples, 2.99%) +_i.. + + +void boost::asio::detail::initiate_post_with_executor<boost::asio::any_io_executor>::operator (57,656,311 samples, 1.07%) + + + +_int_free (44,410,066 samples, 0.82%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (24,508,665 samples, 0.46%) + + + +pthread_mutex_lock@@GLIBC_2.2.5 (15,477,505 samples, 0.29%) + + + +void* boost::asio::detail::thread_info_base::allocate<boost::asio::detail::thread_info_base::default_tag> (24,903,038 samples, 0.46%) + + + +_int_malloc (19,182,057 samples, 0.36%) + + + +boost::asio::detail::awaitable_thread<boost::asio::any_io_executor>::pump (43,166,371 samples, 0.80%) + + + +antlr4::atn::PredictionContext::mergeArrays (24,508,665 samples, 0.46%) + + + +stewkk::sql::codegen::PostgreSQLParser::a_expr_qual (37,424,238 samples, 0.69%) + + + +std::basic_filebuf<char, std::char_traits<char> >::_M_destroy_internal_buffer (12,089,111 samples, 0.22%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +void boost::asio::execution::detail::any_executor_base::execute_ex<boost::asio::thread_pool::basic_executor_type<std::allocator<void>, 8u> > (21,272,303 samples, 0.39%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closure_ (24,508,665 samples, 0.46%) + + + +boost::asio::detail::scheduler::work_finished (12,490,400 samples, 0.23%) + + + +void boost::asio::detail::executor_function::complete<boost::asio::detail::work_dispatcher<boost::asio::detail::empty_work_function, boost::asio::detail::binder1<boost::asio::detail::awaitable_handler<boost::asio::any_io_executor, boost::system::error_code>, boost::system::error_code>, boost::asio::any_io_executor, void>, std::allocator<void> > (1,451,172,076 samples, 26.94%) +void boost::asio::detail::executor_functio.. + + +__libc_start_call_main (129,786,585 samples, 2.41%) +__.. + + +antlr4::atn::ParserATNSimulator::closure_ (24,508,665 samples, 0.46%) + + + +all (5,385,823,897 samples, 100%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closure_ (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +boost::asio::detail::awaitable_thread<boost::asio::any_io_executor>::~awaitable_thread (11,823,152 samples, 0.22%) + + + +boost::asio::detail::scheduler::work_finished (69,759,531 samples, 1.30%) + + + +antlr4::atn::ATNDeserializer::deserialize (15,188,340 samples, 0.28%) + + + +void boost::asio::execution::detail::any_executor_base::execute<boost::asio::detail::work_dispatcher<boost::asio::detail::empty_work_function, boost::asio::detail::binder1<boost::asio::detail::awaitable_handler<boost::asio::any_io_executor, boost::system::error_code>, boost::system::error_code>, boost::asio::any_io_executor, void> > (174,285,447 samples, 3.24%) +voi.. + + +_int_malloc (7,068,924 samples, 0.13%) + + + +void boost::asio::detail::initiate_post_with_executor<boost::asio::any_io_executor>::operator (26,937,911 samples, 0.50%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +stewkk::sql::codegen::PostgreSQLParser::a_expr_compare (24,508,665 samples, 0.46%) + + + +boost::asio::detail::scheduler::work_finished (22,304,436 samples, 0.41%) + + + +cfree@GLIBC_2.2.5 (77,205,009 samples, 1.43%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +stewkk::sql::codegen::PostgreSQLParser::a_expr_or (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +benchmark::internal::FindBenchmarksInternal (8,457,035 samples, 0.16%) + + + +benchmark::internal::BenchmarkRunner::DoOneRepetition (91,907,772 samples, 1.71%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closure_ (24,508,665 samples, 0.46%) + + + +malloc_consolidate (19,182,057 samples, 0.36%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +stewkk::sql::CalcExpression (55,369,899 samples, 1.03%) + + + +stewkk::sql::Executor<stewkk::sql::InterpretedExpressionExecutor>::ExecuteJoin (44,011,107 samples, 0.82%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (24,508,665 samples, 0.46%) + + + +auto boost::asio::detail::awaitable_frame_base<boost::asio::any_io_executor>::await_transform<void> (53,916,274 samples, 1.00%) + + + +antlr4::atn::ParserATNSimulator::closure (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +malloc (23,578,020 samples, 0.44%) + + + +boost::asio::experimental::detail::channel_operation::handler_work<boost::asio::detail::awaitable_handler<boost::asio::any_io_executor, boost::system::error_code, std::vector<std::vector<stewkk::sql::Value, std::allocator<stewkk::sql::Value> >, std::allocator<std::vector<stewkk::sql::Value, std::allocator<stewkk::sql::Value> > > > >, boost::asio::any_io_executor, void>::handler_work (9,314,054 samples, 0.17%) + + + +operator new (50,536,679 samples, 0.94%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +[unknown] (5,050,505 samples, 0.09%) + + + +void boost::asio::experimental::detail::channel_operation::handler_work_base<boost::asio::any_io_executor, boost::asio::any_io_executor, void>::post<boost::asio::any_io_executor, boost::asio::detail::binder1<boost::asio::detail::awaitable_handler<boost::asio::any_io_executor, boost::system::error_code>, boost::system::error_code>, boost::asio::detail::awaitable_handler<boost::asio::any_io_executor, boost::system::error_code> > (12,841,321 samples, 0.24%) + + + +void boost::asio::detail::initiate_dispatch::operator (43,166,371 samples, 0.80%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +void* boost::asio::detail::thread_info_base::allocate<boost::asio::detail::thread_info_base::awaitable_frame_tag> (16,892,604 samples, 0.31%) + + + +stewkk::sql::DiskFileWriter::Write (20,168,759 samples, 0.37%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +void* boost::asio::detail::thread_info_base::allocate<boost::asio::detail::thread_info_base::executor_function_tag> (50,988,688 samples, 0.95%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +void boost::asio::detail::executor_function::complete<boost::asio::detail::binder0<boost::asio::detail::awaitable_async_op_handler<void (43,166,371 samples, 0.80%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +stewkk::sql::codegen::PostgreSQLParser::a_expr_qual_op (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +boost::asio::experimental::detail::channel_receive_op<boost::asio::detail::completion_payload<void (26,209,776 samples, 0.49%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +antlr4::BufferedTokenStream::fetch (14,786,529 samples, 0.27%) + + + +antlr4::atn::ParserATNSimulator::closure_ (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +void boost::asio::execution::detail::any_executor_base::destroy_object<boost::asio::thread_pool::basic_executor_type<std::allocator<void>, 8u> > (29,261,323 samples, 0.54%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +stewkk::sql::ReceiveTuples (6,054,643 samples, 0.11%) + + + +cfree@GLIBC_2.2.5 (44,735,347 samples, 0.83%) + + + +antlr4::atn::ParserATNSimulator::closure_ (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +stewkk::sql::codegen::PostgreSQLParser::a_expr_mul (24,508,665 samples, 0.46%) + + + +std::deque<boost::asio::detail::completion_payload<void (20,221,764 samples, 0.38%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +void boost::asio::experimental::detail::channel_service<boost::asio::detail::posix_mutex>::start_send_op<boost::asio::experimental::channel_traits<>, void (26,937,911 samples, 0.50%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +std::type_info const& boost::asio::execution::detail::any_executor_base::target_type_ex<boost::asio::thread_pool::basic_executor_type<std::allocator<void>, 8u> > (26,937,911 samples, 0.50%) + + + +__GI_____strtoll_l_internal (74,846,533 samples, 1.39%) + + + +cfree@GLIBC_2.2.5 (12,089,111 samples, 0.22%) + + + +std::enable_if<call_traits<boost_asio_prefer_fn::impl, boost::asio::any_io_executor const&, void (27,364,608 samples, 0.51%) + + + +void boost::asio::execution::detail::any_executor_base::execute<boost::asio::detail::binder0<boost::asio::detail::awaitable_async_op_handler<void (43,166,371 samples, 0.80%) + + + +void boost::asio::execution::detail::any_executor_base::execute<boost::asio::detail::work_dispatcher<boost::asio::detail::empty_work_function, boost::asio::detail::completion_payload_handler<boost::asio::detail::completion_payload<void (36,124,971 samples, 0.67%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +stewkk::sql::CalcExpression (129,995,096 samples, 2.41%) +st.. + + +__GI___lll_lock_wait (17,932,534 samples, 0.33%) + + + +antlr4::atn::ParserATNSimulator::closure_ (24,508,665 samples, 0.46%) + + + +malloc (7,068,924 samples, 0.13%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (24,508,665 samples, 0.46%) + + + +boost::asio::detail::posix_thread::func<boost::asio::thread_pool::thread_function, boost::asio::execution_context::allocator<void> >::run (5,097,584,863 samples, 94.65%) +boost::asio::detail::posix_thread::func<boost::asio::thread_pool::thread_function, boost::asio::execution_context::allocator<void> >::run + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +std::vector<stewkk::sql::Value, std::allocator<stewkk::sql::Value> >* std::__do_uninit_copy<std::ranges::transform_view<std::ranges::ref_view<std::vector<std::vector<stewkk::sql::Value, std::allocator<stewkk::sql::Value> >, std::allocator<std::vector<stewkk::sql::Value, std::allocator<stewkk::sql::Value> > > > >, stewkk::sql::Executor<stewkk::sql::InterpretedExpressionExecutor>::ExecuteProjection (360,235,704 samples, 6.69%) +std::vect.. + + +boost::asio::detail::awaitable_thread<boost::asio::any_io_executor>::~awaitable_thread (26,477,355 samples, 0.49%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +stewkk::sql::codegen::PostgreSQLParser::a_expr_isnull (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +void boost::asio::detail::initiate_co_spawn<boost::asio::any_io_executor>::operator (43,166,371 samples, 0.80%) + + + +void const* boost::asio::execution::detail::any_executor_base::target_object<boost::asio::thread_pool::basic_executor_type<std::allocator<void>, 8u> > (12,128,983 samples, 0.23%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +void boost::asio::detail::initiate_post_with_executor<boost::asio::any_io_executor>::operator (176,035,170 samples, 3.27%) +voi.. + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +void boost::asio::execution::detail::any_executor_base::move_object<boost::asio::thread_pool::basic_executor_type<std::allocator<void>, 8u> > (24,345,703 samples, 0.45%) + + + +void boost::asio::execution::detail::any_executor_base::execute<boost::asio::detail::work_dispatcher<boost::asio::detail::empty_work_function, boost::asio::detail::completion_payload_handler<boost::asio::detail::completion_payload<void (95,180,338 samples, 1.77%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (24,508,665 samples, 0.46%) + + + +cfree@GLIBC_2.2.5 (147,744,567 samples, 2.74%) +cf.. + + +stewkk::sql::GetExpressionTypeUnchecked (17,360,474 samples, 0.32%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +boost::asio::detail::scheduler::post_immediate_completion (49,051,102 samples, 0.91%) + + + +antlr4::atn::ATNConfigSet::~ATNConfigSet (29,421,778 samples, 0.55%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +boost::asio::detail::scheduler::do_run_one (5,014,939,460 samples, 93.11%) +boost::asio::detail::scheduler::do_run_one + + +std::enable_if<call_traits<boost_asio_prefer_fn::impl, boost::asio::any_io_executor const&, void (12,841,321 samples, 0.24%) + + + +boost::asio::detail::awaitable_thread<boost::asio::any_io_executor>::pump (43,166,371 samples, 0.80%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +bcmp@plt (52,396,970 samples, 0.97%) + + + +boost::asio::detail::executor_function::executor_function<boost::asio::detail::work_dispatcher<boost::asio::detail::empty_work_function, boost::asio::detail::completion_payload_handler<boost::asio::detail::completion_payload<void (12,442,960 samples, 0.23%) + + + +benchmark::RunSpecifiedBenchmarks (100,364,807 samples, 1.86%) +b.. + + +stewkk::sql::codegen::PostgreSQLParser::a_expr_unary_not (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (24,508,665 samples, 0.46%) + + + +stewkk::sql::codegen::PostgreSQLParser::a_expr_caret (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +malloc@plt (31,818,749 samples, 0.59%) + + + +boost::asio::experimental::detail::channel_send_op<boost::asio::detail::completion_payload<void (372,428,037 samples, 6.91%) +boost::as.. + + +_int_free (24,899,971 samples, 0.46%) + + + +boost::asio::detail::scheduler::run (91,907,772 samples, 1.71%) + + + +std::enable_if<call_traits<boost_asio_prefer_fn::impl, boost::asio::any_io_executor const&, void (9,314,054 samples, 0.17%) + + + +boost::asio::detail::scheduler::post_immediate_completion (23,412,377 samples, 0.43%) + + + +stewkk::sql::codegen::PostgreSQLParser::simple_select_pramary (61,932,903 samples, 1.15%) + + + +void boost::asio::detail::awaitable_handler<boost::asio::any_io_executor, boost::system::error_code, std::vector<std::vector<stewkk::sql::Value, std::allocator<stewkk::sql::Value> >, std::allocator<std::vector<stewkk::sql::Value, std::allocator<stewkk::sql::Value> > > > >::operator (2,560,910,854 samples, 47.55%) +void boost::asio::detail::awaitable_handler<boost::asio::any_io_executor, boo.. + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +void* boost::asio::detail::thread_info_base::allocate<boost::asio::detail::thread_info_base::awaitable_frame_tag> (19,182,057 samples, 0.36%) + + + +boost::asio::experimental::basic_concurrent_channel<boost::asio::any_io_executor, boost::asio::experimental::channel_traits<>, void (23,984,314 samples, 0.45%) + + + +stewkk::sql::codegen::PostgreSQLParser::PostgreSQLParser (15,188,340 samples, 0.28%) + + + +malloc (19,182,057 samples, 0.36%) + + + +boost::asio::detail::scheduler::work_cleanup::~work_cleanup (97,273,190 samples, 1.81%) +b.. + + +stewkk::sql::Executor<stewkk::sql::InterpretedExpressionExecutor>::SpawnExecutor (43,166,371 samples, 0.80%) + + + +std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_append (22,419,907 samples, 0.42%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +boost::asio::awaitable<void, boost::asio::any_io_executor> boost::asio::async_result<boost::asio::use_awaitable_t<boost::asio::any_io_executor>, void (18,935,279 samples, 0.35%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +boost::asio::detail::awaitable_thread<boost::asio::any_io_executor>::pump (43,166,371 samples, 0.80%) + + + +cfree@GLIBC_2.2.5 (8,320,762 samples, 0.15%) + + + +boost::asio::detail::awaitable_thread<boost::asio::any_io_executor>::pump (91,907,772 samples, 1.71%) + + + +void boost::asio::experimental::detail::channel_service<boost::asio::detail::posix_mutex>::start_send_op<boost::asio::experimental::channel_traits<>, void (544,095,885 samples, 10.10%) +void boost::as.. + + +void boost::asio::execution::detail::any_executor_base::execute<boost::asio::detail::work_dispatcher<boost::asio::detail::empty_work_function, boost::asio::detail::completion_payload_handler<boost::asio::detail::completion_payload<void (19,129,396 samples, 0.36%) + + + +antlr4::atn::PredictionContextMergeCache::clear (37,424,238 samples, 0.69%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +malloc (17,249,947 samples, 0.32%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +antlr4::atn::SemanticContext::Predicate::equals (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +stewkk::sql::codegen::PostgreSQLParser::a_expr_in (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +stewkk::sql::Executor<stewkk::sql::InterpretedExpressionExecutor>::ExecuteProjection (523,860,669 samples, 9.73%) +stewkk::sql::E.. + + +_int_free (12,089,111 samples, 0.22%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +pthread_cond_wait@@GLIBC_2.3.2 (86,512,120 samples, 1.61%) + + + +bool std::__detail::__regex_algo_impl<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::__cxx11::sub_match<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, char, std::__cxx11::regex_traits<char> > (8,457,035 samples, 0.16%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (24,508,665 samples, 0.46%) + + + +stewkk::sql::codegen::PostgreSQLParser::a_expr_lessless (37,424,238 samples, 0.69%) + + + +start_thread (5,097,584,863 samples, 94.65%) +start_thread + + +boost::asio::detail::scheduler::post_immediate_completion (19,129,396 samples, 0.36%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +malloc (50,536,679 samples, 0.94%) + + + +[unknown] (29,271,007 samples, 0.54%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +void boost::asio::execution::detail::any_executor_base::destroy_object<boost::asio::thread_pool::basic_executor_type<std::allocator<void>, 8u> > (21,270,699 samples, 0.39%) + + + +boost::asio::detail::work_dispatcher<boost::asio::detail::empty_work_function, boost::asio::detail::completion_payload_handler<boost::asio::detail::completion_payload<void (2,691,951,411 samples, 49.98%) +boost::asio::detail::work_dispatcher<boost::asio::detail::empty_work_function, bo.. + + +stewkk::sql::codegen::PostgreSQLParser::a_expr_and (37,424,238 samples, 0.69%) + + + +_int_malloc (42,978,854 samples, 0.80%) + + + +__isoc23_strtol (21,467,623 samples, 0.40%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +boost::asio::detail::executor_function::impl<boost::asio::detail::binder0<boost::asio::detail::completion_payload_handler<boost::asio::detail::completion_payload<void (24,848,321 samples, 0.46%) + + + +cfree@GLIBC_2.2.5 (42,409,786 samples, 0.79%) + + + +void boost::asio::thread_pool::basic_executor_type<std::allocator<void>, 8u>::do_execute<boost::asio::detail::executor_function> (100,817,695 samples, 1.87%) +v.. + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +boost::asio::detail::scheduler::post_immediate_completion (15,477,505 samples, 0.29%) + + + +_start (129,786,585 samples, 2.41%) +_s.. + + +[libc.so.6] (29,421,778 samples, 0.55%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +boost::asio::detail::scheduler::post_immediate_completion (59,556,138 samples, 1.11%) + + + +void boost::asio::experimental::detail::channel_service<boost::asio::detail::posix_mutex>::async_receive<boost::asio::experimental::channel_traits<>, void (514,987,329 samples, 9.56%) +void boost::a.. + + +stewkk::sql::CalcExpression (47,573,615 samples, 0.88%) + + + +stewkk::sql::codegen::PostgreSQLParser::columnref (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +boost::asio::experimental::detail::channel_receive_op<boost::asio::detail::completion_payload<void (26,937,911 samples, 0.50%) + + + +stewkk::sql::codegen::PostgreSQLParser::a_expr_like (24,508,665 samples, 0.46%) + + + +void boost::asio::detail::executor_function::complete<boost::asio::detail::binder0<boost::asio::detail::awaitable_async_op_handler<void (43,166,371 samples, 0.80%) + + + +antlr4::atn::ParserATNSimulator::closure_ (24,508,665 samples, 0.46%) + + + +void boost::asio::detail::awaitable_handler<boost::asio::any_io_executor, boost::system::error_code>::operator (1,378,912,689 samples, 25.60%) +void boost::asio::detail::awaitable_hand.. + + +antlr4::dfa::DFAState::~DFAState (29,421,778 samples, 0.55%) + + + +void boost::asio::detail::executor_function::complete<boost::asio::detail::binder0<boost::asio::detail::awaitable_async_op_handler<void (91,907,772 samples, 1.71%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +boost::asio::detail::scheduler::run (5,089,566,123 samples, 94.50%) +boost::asio::detail::scheduler::run + + +stewkk::sql::ConcatTuples (82,005,608 samples, 1.52%) + + + +std::__detail::_Executor<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::__cxx11::sub_match<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, std::__cxx11::regex_traits<char>, true>::_M_dfs (8,457,035 samples, 0.16%) + + + +void boost::asio::execution::detail::any_executor_base::execute<boost::asio::detail::binder0<boost::asio::detail::awaitable_async_op_handler<void (43,166,371 samples, 0.80%) + + + +boost::asio::detail::awaitable_thread<boost::asio::any_io_executor>::pump (43,166,371 samples, 0.80%) + + + +benchmark::internal::BenchmarkRunner::DoNIterations (91,907,772 samples, 1.71%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +cfree@GLIBC_2.2.5 (45,617,961 samples, 0.85%) + + + +void boost::asio::experimental::detail::channel_service<boost::asio::detail::posix_mutex>::async_send<boost::asio::experimental::channel_traits<>, void (93,040,213 samples, 1.73%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +stewkk::sql::codegen::PostgreSQLParser::a_expr (37,424,238 samples, 0.69%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +boost::asio::experimental::detail::channel_send_op<boost::asio::detail::completion_payload<void (210,580,654 samples, 3.91%) +boos.. + + +antlr4::atn::ParserATNSimulator::closure_ (24,508,665 samples, 0.46%) + + + +void std::vector<std::vector<stewkk::sql::Value, std::allocator<stewkk::sql::Value> >, std::allocator<std::vector<stewkk::sql::Value, std::allocator<stewkk::sql::Value> > > >::_M_realloc_append<std::vector<stewkk::sql::Value, std::allocator<stewkk::sql::Value> > > (44,735,347 samples, 0.83%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +__memcmp_evex_movbe (39,055,049 samples, 0.73%) + + + +antlr4::atn::ParserATNSimulator::closure_ (24,508,665 samples, 0.46%) + + + +operator new (7,068,924 samples, 0.13%) + + + +boost::asio::detail::awaitable_frame_base<boost::asio::any_io_executor>::await_transform<boost::asio::async_result<boost::asio::use_awaitable_t<boost::asio::any_io_executor>, void (652,420,885 samples, 12.11%) +boost::asio::detai.. + + +pthread_once@GLIBC_2.2.5 (15,188,340 samples, 0.28%) + + + +antlr4::atn::PredictionContext::merge (24,508,665 samples, 0.46%) + + + +stewkk::sql::CalcExpression (282,042,305 samples, 5.24%) +stewkk.. + + +void boost::asio::detail::executor_function::complete<boost::asio::detail::work_dispatcher<boost::asio::detail::empty_work_function, boost::asio::detail::completion_payload_handler<boost::asio::detail::completion_payload<void (84,026,690 samples, 1.56%) + + + +cfree@GLIBC_2.2.5 (24,899,971 samples, 0.46%) + + + +void const* boost::asio::execution::detail::any_executor_base::target_object<boost::asio::thread_pool::basic_executor_type<std::allocator<void>, 0u> > (12,841,321 samples, 0.24%) + + + +boost::asio::detail::scheduler::work_finished (44,889,674 samples, 0.83%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +std::default_delete<(anonymous namespace)::PostgreSQLLexerStaticData>::operator (29,421,778 samples, 0.55%) + + + +__GI___pthread_mutex_unlock_usercnt (19,129,396 samples, 0.36%) + + + +void boost::asio::experimental::detail::channel_operation::handler_work_base<boost::asio::any_io_executor, boost::asio::any_io_executor, void>::post<boost::asio::any_io_executor, boost::asio::detail::completion_payload_handler<boost::asio::detail::completion_payload<void (86,917,634 samples, 1.61%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +stewkk::sql::codegen::PostgreSQLParser::a_expr_unary_sign (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +main (100,364,807 samples, 1.86%) +m.. + + +antlr4::atn::ParserATNSimulator::closure_ (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +stewkk::sql::CalcExpression (150,374,277 samples, 2.79%) +st.. + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (24,508,665 samples, 0.46%) + + + +malloc (54,664,255 samples, 1.01%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +cfree@GLIBC_2.2.5 (37,424,238 samples, 0.69%) + + + +antlr4::BufferedTokenStream::fill (14,786,529 samples, 0.27%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +_int_free (21,405,721 samples, 0.40%) + + + +malloc_consolidate (17,249,947 samples, 0.32%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +boost::asio::detail::awaitable_frame_base<boost::asio::any_io_executor>::await_transform<boost::asio::async_result<boost::asio::use_awaitable_t<boost::asio::any_io_executor>, void (26,937,911 samples, 0.50%) + + + +[unknown] (51,827,800 samples, 0.96%) + + + +stewkk::sql::codegen::PostgreSQLParser::select_no_parens (61,932,903 samples, 1.15%) + + + +antlr4::atn::ATNConfigSet::add (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +antlr4::atn::LexerATNSimulator::execATN (14,786,529 samples, 0.27%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +void boost::asio::detail::initiate_dispatch::operator (43,166,371 samples, 0.80%) + + + +std::_Hashtable<std::pair<antlr4::atn::PredictionContext const*, antlr4::atn::PredictionContext const*>, std::pair<std::pair<antlr4::atn::PredictionContext const*, antlr4::atn::PredictionContext const*> const, std::unique_ptr<antlr4::atn::PredictionContextMergeCache::Entry, std::default_delete<antlr4::atn::PredictionContextMergeCache::Entry> > >, std::allocator<std::pair<std::pair<antlr4::atn::PredictionContext const*, antlr4::atn::PredictionContext const*> const, std::unique_ptr<antlr4::atn::PredictionContextMergeCache::Entry, std::default_delete<antlr4::atn::PredictionContextMergeCache::Entry> > > >, std::__detail::_Select1st, antlr4::atn::PredictionContextMergeCache::PredictionContextComparer, antlr4::atn::PredictionContextMergeCache::PredictionContextHasher, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<true, false, true> >::find (24,508,665 samples, 0.46%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +stewkk::sql::codegen::PostgreSQLParser::from_clause (37,424,238 samples, 0.69%) + + + +malloc (16,892,604 samples, 0.31%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +stewkk::sql::codegen::PostgreSQLParser::target_list (24,508,665 samples, 0.46%) + + + +stewkk::sql::CalcExpression (150,374,277 samples, 2.79%) +st.. + + +stewkk::sql::codegen::PostgreSQLParser::a_expr (24,508,665 samples, 0.46%) + + + +malloc@plt (23,399,734 samples, 0.43%) + + + +__GI___clone3 (5,097,584,863 samples, 94.65%) +__GI___clone3 + + +stewkk::sql::codegen::PostgreSQLParser::join_qual (37,424,238 samples, 0.69%) + + + +__GI___lll_lock_wake (64,037,564 samples, 1.19%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closure_ (24,508,665 samples, 0.46%) + + + +void boost::asio::experimental::detail::channel_operation::handler_work<boost::asio::detail::awaitable_handler<boost::asio::any_io_executor, boost::system::error_code, std::vector<std::vector<stewkk::sql::Value, std::allocator<stewkk::sql::Value> >, std::allocator<std::vector<stewkk::sql::Value, std::allocator<stewkk::sql::Value> > > > >, boost::asio::any_io_executor, void>::immediate<boost::asio::detail::completion_payload_handler<boost::asio::detail::completion_payload<void (238,402,514 samples, 4.43%) +void .. + + +operator new (282,249,956 samples, 5.24%) +operat.. + + +stewkk::sql::GetAST (91,907,772 samples, 1.71%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +std::_Sp_counted_ptr_inplace<antlr4::atn::ArrayPredictionContext, std::allocator<void>, (37,424,238 samples, 0.69%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +stewkk::sql::Executor<stewkk::sql::InterpretedExpressionExecutor>::SpawnExecutor (43,166,371 samples, 0.80%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +antlr4::atn::ParserATNSimulator::closure_ (8,320,762 samples, 0.15%) + + + +void boost::asio::detail::initiate_post_with_executor<boost::asio::any_io_executor>::operator (286,066,500 samples, 5.31%) +void b.. + + +stewkk::sql::DiskFileReader::Read (47,121,918 samples, 0.87%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (31,901,449 samples, 0.59%) + + + +malloc (12,442,960 samples, 0.23%) + + + +stewkk::sql::ReceiveTuples (24,434,585 samples, 0.45%) + + + +_int_malloc (11,953,581 samples, 0.22%) + + + +antlr4::atn::ParserATNSimulator::closure_ (31,901,449 samples, 0.59%) + + + +void boost::asio::experimental::detail::channel_service<boost::asio::detail::posix_mutex>::start_receive_op<boost::asio::experimental::channel_traits<>, void (469,204,932 samples, 8.71%) +void boost::.. + + +boost::asio::detail::scheduler::post_immediate_completion (12,016,681 samples, 0.22%) + + + +cfree@GLIBC_2.2.5 (45,110,211 samples, 0.84%) + + + +antlr4::atn::ParserATNSimulator::closureCheckingStopState (8,320,762 samples, 0.15%) + + + + diff --git a/benchmarks/main.cpp b/benchmarks/main.cpp new file mode 100644 index 0000000..4356209 --- /dev/null +++ b/benchmarks/main.cpp @@ -0,0 +1,133 @@ +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +namespace stewkk::sql { + +const static std::string kProjectDir = std::getenv("PWD"); + +static constexpr char kSimpleSelectSmall[]{"SELECT users.id FROM users;"}; +static constexpr char kJoinSmall[]{"SELECT * FROM employees RIGHT JOIN departments ON employees.department_id = departments.id;"}; +static constexpr char kComplex5[]{"SELECT departments.id*2, employees.id+1 FROM employees RIGHT JOIN departments ON employees.department_id = departments.id AND departments.id > 3 AND departments.id*2*2/2/2*2 < 30;"}; +static constexpr char kComplex500[]{"SELECT departments_500.id*2, employees_200.id+1 FROM employees_200 RIGHT JOIN departments_500 ON employees_200.department_id = departments_500.id AND departments_500.id > 3 AND departments_500.id*2*2/2/2*2 < 30;"}; +static constexpr char kComplex1000[]{"SELECT departments_1000.id*2, employees_200.id+1 FROM employees_200 RIGHT JOIN departments_1000 ON employees_200.department_id = departments_1000.id AND departments_1000.id > 3 AND departments_1000.id*2*2/2/2*2 < 30;"}; +static constexpr char kComplex2000[]{"SELECT departments_2000.id*2, employees_200.id+1 FROM employees_200 RIGHT JOIN departments_2000 ON employees_200.department_id = departments_2000.id AND departments_2000.id > 3 AND departments_2000.id*2*2/2/2*2 < 30;"}; +static constexpr char kComplex4000[]{"SELECT departments_4000.id*2, employees_200.id+1 FROM employees_200 RIGHT JOIN departments_4000 ON employees_200.department_id = departments_4000.id AND departments_4000.id > 3 AND departments_4000.id*2*2/2/2*2 < 30;"}; +static constexpr char kComplex8000[]{"SELECT departments_8000.id*2, employees_200.id+1 FROM employees_200 RIGHT JOIN departments_8000 ON employees_200.department_id = departments_8000.id AND departments_8000.id > 3 AND departments_8000.id*2*2/2/2*2 < 30;"}; +static constexpr char kComplex16000[]{"SELECT departments_16000.id*2, employees_200.id+1 FROM employees_200 RIGHT JOIN departments_16000 ON employees_200.department_id = departments_16000.id AND departments_16000.id > 3 AND departments_16000.id*2*2/2/2*2 < 30;"}; + +template +void BM_SQL(benchmark::State& state) { + std::ofstream nullstream("/dev/null"); + std::clog.rdbuf(nullstream.rdbuf()); + boost::asio::io_context ctx; + boost::asio::co_spawn( + ctx, + [&state]() -> boost::asio::awaitable { + std::stringstream s{Query}; + Operator op = GetAST(s).value(); + CsvDirSequentialScanner seq_scan{kProjectDir + "/test/static/executor/test_data"}; + Executor executor(std::move(seq_scan), + co_await boost::asio::this_coro::executor); + + benchmark::DoNotOptimize(co_await executor.Execute(op)); + + for (auto _ : state) { + benchmark::DoNotOptimize(co_await executor.Execute(op)); + } + }(), + [](std::exception_ptr p) {}); + + ctx.run(); +} + +BENCHMARK(BM_SQL)->UseRealTime(); +BENCHMARK(BM_SQL)->UseRealTime(); + +BENCHMARK(BM_SQL)->UseRealTime(); +BENCHMARK(BM_SQL)->UseRealTime(); + +BENCHMARK(BM_SQL)->UseRealTime(); +BENCHMARK(BM_SQL)->UseRealTime(); + +BENCHMARK(BM_SQL)->UseRealTime(); +BENCHMARK(BM_SQL)->UseRealTime(); + +BENCHMARK(BM_SQL)->UseRealTime(); +BENCHMARK(BM_SQL)->UseRealTime(); + +BENCHMARK(BM_SQL)->UseRealTime(); +BENCHMARK(BM_SQL)->UseRealTime(); + +BENCHMARK(BM_SQL)->UseRealTime(); +BENCHMARK(BM_SQL)->UseRealTime(); + +BENCHMARK(BM_SQL)->UseRealTime(); +BENCHMARK(BM_SQL)->UseRealTime(); + +BENCHMARK(BM_SQL)->UseRealTime(); +BENCHMARK(BM_SQL)->UseRealTime(); + +template +void BM_SQL_Multithreaded(benchmark::State& state) { + std::ofstream nullstream("/dev/null"); + std::clog.rdbuf(nullstream.rdbuf()); + boost::asio::io_context ctx; + boost::asio::co_spawn( + ctx, + [&state]() -> boost::asio::awaitable { + boost::asio::thread_pool pool{4}; + std::stringstream s{Query}; + Operator op = GetAST(s).value(); + CsvDirSequentialScanner seq_scan{kProjectDir + "/test/static/executor/test_data"}; + Executor executor(std::move(seq_scan), + pool.executor()); + + // NOTE: precompile query + benchmark::DoNotOptimize(co_await executor.Execute(op)); + + for (auto _ : state) { + co_await boost::asio::co_spawn(pool, [&]() -> boost::asio::awaitable { + benchmark::DoNotOptimize(co_await executor.Execute(op)); + }, boost::asio::use_awaitable); + } + }(), + [](std::exception_ptr p) {}); + + ctx.run(); +} + +BENCHMARK(BM_SQL_Multithreaded)->UseRealTime(); +BENCHMARK(BM_SQL_Multithreaded)->UseRealTime(); + +BENCHMARK(BM_SQL_Multithreaded)->UseRealTime(); +BENCHMARK(BM_SQL_Multithreaded)->UseRealTime(); + +BENCHMARK(BM_SQL_Multithreaded)->UseRealTime(); +BENCHMARK(BM_SQL_Multithreaded)->UseRealTime(); + +BENCHMARK(BM_SQL_Multithreaded)->UseRealTime(); +BENCHMARK(BM_SQL_Multithreaded)->UseRealTime(); + +BENCHMARK(BM_SQL_Multithreaded)->UseRealTime(); +BENCHMARK(BM_SQL_Multithreaded)->UseRealTime(); + +BENCHMARK(BM_SQL_Multithreaded)->UseRealTime(); +BENCHMARK(BM_SQL_Multithreaded)->UseRealTime(); + +BENCHMARK(BM_SQL_Multithreaded)->UseRealTime(); +BENCHMARK(BM_SQL_Multithreaded)->UseRealTime(); + +} // namespace stewkk::sql + +BENCHMARK_MAIN(); diff --git a/benchmarks/results-01.json b/benchmarks/results-01.json new file mode 100644 index 0000000..70f9e5f --- /dev/null +++ b/benchmarks/results-01.json @@ -0,0 +1,294 @@ +{ + "context": { + "date": "2026-01-10T22:17:41+03:00", + "host_name": "nixos", + "executable": "./build-release/bin/benchmarks", + "num_cpus": 8, + "mhz_per_cpu": 4200, + "cpu_scaling_enabled": true, + "caches": [ + { + "type": "Data", + "level": 1, + "size": 49152, + "num_sharing": 2 + }, + { + "type": "Instruction", + "level": 1, + "size": 32768, + "num_sharing": 2 + }, + { + "type": "Unified", + "level": 2, + "size": 1310720, + "num_sharing": 2 + }, + { + "type": "Unified", + "level": 3, + "size": 8388608, + "num_sharing": 8 + } + ], + "load_avg": [0.936523,0.910156,0.82959], + "library_version": "v1.9.0", + "library_build_type": "release", + "json_schema_version": 1 + }, + "benchmarks": [ + { + "name": "BM_SQL", + "family_index": 0, + "per_family_instance_index": 0, + "run_name": "BM_SQL", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 37973, + "real_time": 1.8439718747488580e+04, + "cpu_time": 1.8393154688857870e+04, + "time_unit": "ns" + }, + { + "name": "BM_SQL", + "family_index": 1, + "per_family_instance_index": 0, + "run_name": "BM_SQL", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 37635, + "real_time": 1.8646254444011862e+04, + "cpu_time": 1.8605846924405472e+04, + "time_unit": "ns" + }, + { + "name": "BM_SQL", + "family_index": 2, + "per_family_instance_index": 0, + "run_name": "BM_SQL", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 11616, + "real_time": 6.1504978047441888e+04, + "cpu_time": 6.1064501205234126e+04, + "time_unit": "ns" + }, + { + "name": "BM_SQL", + "family_index": 3, + "per_family_instance_index": 0, + "run_name": "BM_SQL", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 11736, + "real_time": 5.8408048312897139e+04, + "cpu_time": 5.8085960889570553e+04, + "time_unit": "ns" + }, + { + "name": "BM_SQL", + "family_index": 4, + "per_family_instance_index": 0, + "run_name": "BM_SQL", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 9930, + "real_time": 7.0793681671783255e+04, + "cpu_time": 7.0392283987915405e+04, + "time_unit": "ns" + }, + { + "name": "BM_SQL", + "family_index": 5, + "per_family_instance_index": 0, + "run_name": "BM_SQL", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 10340, + "real_time": 6.7845838684643837e+04, + "cpu_time": 6.7519644680851081e+04, + "time_unit": "ns" + }, + { + "name": "BM_SQL", + "family_index": 6, + "per_family_instance_index": 0, + "run_name": "BM_SQL", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 959, + "real_time": 7.3587727215961309e+05, + "cpu_time": 7.3293833785192831e+05, + "time_unit": "ns" + }, + { + "name": "BM_SQL", + "family_index": 7, + "per_family_instance_index": 0, + "run_name": "BM_SQL", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 1324, + "real_time": 5.3172040483321249e+05, + "cpu_time": 5.2990015785498510e+05, + "time_unit": "ns" + }, + { + "name": "BM_SQL", + "family_index": 8, + "per_family_instance_index": 0, + "run_name": "BM_SQL", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 959, + "real_time": 7.3307096767407400e+05, + "cpu_time": 7.3027849426485947e+05, + "time_unit": "ns" + }, + { + "name": "BM_SQL", + "family_index": 9, + "per_family_instance_index": 0, + "run_name": "BM_SQL", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 1283, + "real_time": 5.3211894699760526e+05, + "cpu_time": 5.3048981060015631e+05, + "time_unit": "ns" + }, + { + "name": "BM_SQL", + "family_index": 10, + "per_family_instance_index": 0, + "run_name": "BM_SQL", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 615, + "real_time": 1.1423289658545756e+06, + "cpu_time": 1.1391460959349603e+06, + "time_unit": "ns" + }, + { + "name": "BM_SQL", + "family_index": 11, + "per_family_instance_index": 0, + "run_name": "BM_SQL", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 764, + "real_time": 9.1461425262047106e+05, + "cpu_time": 9.1169844371727761e+05, + "time_unit": "ns" + }, + { + "name": "BM_SQL", + "family_index": 12, + "per_family_instance_index": 0, + "run_name": "BM_SQL", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 359, + "real_time": 1.9482222869099684e+06, + "cpu_time": 1.9423905626740968e+06, + "time_unit": "ns" + }, + { + "name": "BM_SQL", + "family_index": 13, + "per_family_instance_index": 0, + "run_name": "BM_SQL", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 417, + "real_time": 1.6953180815330239e+06, + "cpu_time": 1.6724347146282962e+06, + "time_unit": "ns" + }, + { + "name": "BM_SQL", + "family_index": 14, + "per_family_instance_index": 0, + "run_name": "BM_SQL", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 198, + "real_time": 3.5503262929110364e+06, + "cpu_time": 3.5421274595959657e+06, + "time_unit": "ns" + }, + { + "name": "BM_SQL", + "family_index": 15, + "per_family_instance_index": 0, + "run_name": "BM_SQL", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 220, + "real_time": 3.1995414954508306e+06, + "cpu_time": 3.1910090772727318e+06, + "time_unit": "ns" + }, + { + "name": "BM_SQL", + "family_index": 16, + "per_family_instance_index": 0, + "run_name": "BM_SQL", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 104, + "real_time": 6.7452504230669336e+06, + "cpu_time": 6.7309672692307681e+06, + "time_unit": "ns" + }, + { + "name": "BM_SQL", + "family_index": 17, + "per_family_instance_index": 0, + "run_name": "BM_SQL", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 113, + "real_time": 6.2372058495609770e+06, + "cpu_time": 6.2177674513274478e+06, + "time_unit": "ns" + } + ] +} diff --git a/benchmarks/results-02.json b/benchmarks/results-02.json new file mode 100644 index 0000000..d89cf9a --- /dev/null +++ b/benchmarks/results-02.json @@ -0,0 +1,490 @@ +{ + "context": { + "date": "2026-01-10T23:38:31+03:00", + "host_name": "nixos", + "executable": "./build-release/bin/benchmarks", + "num_cpus": 8, + "mhz_per_cpu": 4200, + "cpu_scaling_enabled": true, + "caches": [ + { + "type": "Data", + "level": 1, + "size": 49152, + "num_sharing": 2 + }, + { + "type": "Instruction", + "level": 1, + "size": 32768, + "num_sharing": 2 + }, + { + "type": "Unified", + "level": 2, + "size": 1310720, + "num_sharing": 2 + }, + { + "type": "Unified", + "level": 3, + "size": 8388608, + "num_sharing": 8 + } + ], + "load_avg": [0.419922,0.788574,0.725586], + "library_version": "v1.9.0", + "library_build_type": "release", + "json_schema_version": 1 + }, + "benchmarks": [ + { + "name": "BM_SQL/real_time", + "family_index": 0, + "per_family_instance_index": 0, + "run_name": "BM_SQL/real_time", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 39131, + "real_time": 1.7763904934746992e+04, + "cpu_time": 1.7715753596892489e+04, + "time_unit": "ns" + }, + { + "name": "BM_SQL/real_time", + "family_index": 1, + "per_family_instance_index": 0, + "run_name": "BM_SQL/real_time", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 38563, + "real_time": 1.8130024764634931e+04, + "cpu_time": 1.8088057438477295e+04, + "time_unit": "ns" + }, + { + "name": "BM_SQL/real_time", + "family_index": 2, + "per_family_instance_index": 0, + "run_name": "BM_SQL/real_time", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 12373, + "real_time": 5.7384221530711082e+04, + "cpu_time": 5.7042944718338294e+04, + "time_unit": "ns" + }, + { + "name": "BM_SQL/real_time", + "family_index": 3, + "per_family_instance_index": 0, + "run_name": "BM_SQL/real_time", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 12308, + "real_time": 5.6059255443637892e+04, + "cpu_time": 5.5761686545336357e+04, + "time_unit": "ns" + }, + { + "name": "BM_SQL/real_time", + "family_index": 4, + "per_family_instance_index": 0, + "run_name": "BM_SQL/real_time", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 10318, + "real_time": 6.7906289300143544e+04, + "cpu_time": 6.7580570653227391e+04, + "time_unit": "ns" + }, + { + "name": "BM_SQL/real_time", + "family_index": 5, + "per_family_instance_index": 0, + "run_name": "BM_SQL/real_time", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 10710, + "real_time": 6.5059496918799705e+04, + "cpu_time": 6.4733736414565828e+04, + "time_unit": "ns" + }, + { + "name": "BM_SQL/real_time", + "family_index": 6, + "per_family_instance_index": 0, + "run_name": "BM_SQL/real_time", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 916, + "real_time": 6.8747337554748205e+05, + "cpu_time": 6.8549197270742385e+05, + "time_unit": "ns" + }, + { + "name": "BM_SQL/real_time", + "family_index": 7, + "per_family_instance_index": 0, + "run_name": "BM_SQL/real_time", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 1368, + "real_time": 5.1371013011559722e+05, + "cpu_time": 5.0669114400584786e+05, + "time_unit": "ns" + }, + { + "name": "BM_SQL/real_time", + "family_index": 8, + "per_family_instance_index": 0, + "run_name": "BM_SQL/real_time", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 1016, + "real_time": 6.8965960629676247e+05, + "cpu_time": 6.8773966338582651e+05, + "time_unit": "ns" + }, + { + "name": "BM_SQL/real_time", + "family_index": 9, + "per_family_instance_index": 0, + "run_name": "BM_SQL/real_time", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 1376, + "real_time": 5.0798636846138834e+05, + "cpu_time": 5.0643320566860412e+05, + "time_unit": "ns" + }, + { + "name": "BM_SQL/real_time", + "family_index": 10, + "per_family_instance_index": 0, + "run_name": "BM_SQL/real_time", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 646, + "real_time": 1.0864569783272836e+06, + "cpu_time": 1.0833641873065040e+06, + "time_unit": "ns" + }, + { + "name": "BM_SQL/real_time", + "family_index": 11, + "per_family_instance_index": 0, + "run_name": "BM_SQL/real_time", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 796, + "real_time": 8.7479362060439051e+05, + "cpu_time": 8.7213186055276426e+05, + "time_unit": "ns" + }, + { + "name": "BM_SQL/real_time", + "family_index": 12, + "per_family_instance_index": 0, + "run_name": "BM_SQL/real_time", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 378, + "real_time": 1.8729881534425891e+06, + "cpu_time": 1.8523415952380972e+06, + "time_unit": "ns" + }, + { + "name": "BM_SQL/real_time", + "family_index": 13, + "per_family_instance_index": 0, + "run_name": "BM_SQL/real_time", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 440, + "real_time": 1.6120009977302372e+06, + "cpu_time": 1.5915791840909088e+06, + "time_unit": "ns" + }, + { + "name": "BM_SQL/real_time", + "family_index": 14, + "per_family_instance_index": 0, + "run_name": "BM_SQL/real_time", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 206, + "real_time": 3.3982538106746450e+06, + "cpu_time": 3.3882851407766948e+06, + "time_unit": "ns" + }, + { + "name": "BM_SQL/real_time", + "family_index": 15, + "per_family_instance_index": 0, + "run_name": "BM_SQL/real_time", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 231, + "real_time": 3.0235657922004336e+06, + "cpu_time": 3.0163061558441538e+06, + "time_unit": "ns" + }, + { + "name": "BM_SQL/real_time", + "family_index": 16, + "per_family_instance_index": 0, + "run_name": "BM_SQL/real_time", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 108, + "real_time": 6.4594497962725991e+06, + "cpu_time": 6.4458291388888815e+06, + "time_unit": "ns" + }, + { + "name": "BM_SQL/real_time", + "family_index": 17, + "per_family_instance_index": 0, + "run_name": "BM_SQL/real_time", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 117, + "real_time": 5.9735239316131240e+06, + "cpu_time": 5.8960350598290535e+06, + "time_unit": "ns" + }, + { + "name": "BM_SQL_Multithreaded/real_time", + "family_index": 18, + "per_family_instance_index": 0, + "run_name": "BM_SQL_Multithreaded/real_time", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 5314, + "real_time": 1.3457497459533918e+05, + "cpu_time": 6.7566829130599754e+03, + "time_unit": "ns" + }, + { + "name": "BM_SQL_Multithreaded/real_time", + "family_index": 19, + "per_family_instance_index": 0, + "run_name": "BM_SQL_Multithreaded/real_time", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 5168, + "real_time": 1.3406582294902750e+05, + "cpu_time": 7.0243527476779418e+03, + "time_unit": "ns" + }, + { + "name": "BM_SQL_Multithreaded/real_time", + "family_index": 20, + "per_family_instance_index": 0, + "run_name": "BM_SQL_Multithreaded/real_time", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 607, + "real_time": 1.1404998929171630e+06, + "cpu_time": 5.1917100494251117e+03, + "time_unit": "ns" + }, + { + "name": "BM_SQL_Multithreaded/real_time", + "family_index": 21, + "per_family_instance_index": 0, + "run_name": "BM_SQL_Multithreaded/real_time", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 706, + "real_time": 9.3259300000174274e+05, + "cpu_time": 4.6985750708203832e+03, + "time_unit": "ns" + }, + { + "name": "BM_SQL_Multithreaded/real_time", + "family_index": 22, + "per_family_instance_index": 0, + "run_name": "BM_SQL_Multithreaded/real_time", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 630, + "real_time": 1.1420491063507230e+06, + "cpu_time": 6.7041952380945313e+03, + "time_unit": "ns" + }, + { + "name": "BM_SQL_Multithreaded/real_time", + "family_index": 23, + "per_family_instance_index": 0, + "run_name": "BM_SQL_Multithreaded/real_time", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 756, + "real_time": 1.0241538029106023e+06, + "cpu_time": 7.8318994708982927e+03, + "time_unit": "ns" + }, + { + "name": "BM_SQL_Multithreaded/real_time", + "family_index": 24, + "per_family_instance_index": 0, + "run_name": "BM_SQL_Multithreaded/real_time", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 381, + "real_time": 1.8506752703352764e+06, + "cpu_time": 4.9503858267712976e+03, + "time_unit": "ns" + }, + { + "name": "BM_SQL_Multithreaded/real_time", + "family_index": 25, + "per_family_instance_index": 0, + "run_name": "BM_SQL_Multithreaded/real_time", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 406, + "real_time": 1.6802704630580470e+06, + "cpu_time": 5.1671182266014257e+03, + "time_unit": "ns" + }, + { + "name": "BM_SQL_Multithreaded/real_time", + "family_index": 26, + "per_family_instance_index": 0, + "run_name": "BM_SQL_Multithreaded/real_time", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 214, + "real_time": 3.3278060280315354e+06, + "cpu_time": 6.8044112149555713e+03, + "time_unit": "ns" + }, + { + "name": "BM_SQL_Multithreaded/real_time", + "family_index": 27, + "per_family_instance_index": 0, + "run_name": "BM_SQL_Multithreaded/real_time", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 215, + "real_time": 3.2163211860596528e+06, + "cpu_time": 6.8673441860502680e+03, + "time_unit": "ns" + }, + { + "name": "BM_SQL_Multithreaded/real_time", + "family_index": 28, + "per_family_instance_index": 0, + "run_name": "BM_SQL_Multithreaded/real_time", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 114, + "real_time": 6.1605299473612504e+06, + "cpu_time": 5.7971666666632946e+03, + "time_unit": "ns" + }, + { + "name": "BM_SQL_Multithreaded/real_time", + "family_index": 29, + "per_family_instance_index": 0, + "run_name": "BM_SQL_Multithreaded/real_time", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 113, + "real_time": 5.8682074159150943e+06, + "cpu_time": 5.4813097345176830e+03, + "time_unit": "ns" + }, + { + "name": "BM_SQL_Multithreaded/real_time", + "family_index": 30, + "per_family_instance_index": 0, + "run_name": "BM_SQL_Multithreaded/real_time", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 61, + "real_time": 1.1749900573734328e+07, + "cpu_time": 6.1474918032748528e+03, + "time_unit": "ns" + }, + { + "name": "BM_SQL_Multithreaded/real_time", + "family_index": 31, + "per_family_instance_index": 0, + "run_name": "BM_SQL_Multithreaded/real_time", + "run_type": "iteration", + "repetitions": 1, + "repetition_index": 0, + "threads": 1, + "iterations": 61, + "real_time": 1.1562019360650590e+07, + "cpu_time": 7.6402295082020755e+03, + "time_unit": "ns" + } + ] +} diff --git a/cmake/FetchAntlr4.cmake b/cmake/FetchAntlr4.cmake new file mode 100644 index 0000000..0a764d8 --- /dev/null +++ b/cmake/FetchAntlr4.cmake @@ -0,0 +1,17 @@ +include(FetchContent) + +set(ANTLR_BUILD_STATIC ON) +set(ANTLR_BUILD_SHARED OFF) +set(DISABLE_WARNINGS ON) +set(ANTLR_BUILD_CPP_TESTS OFF) +set(ANTLR_EXECUTABLE $ENV{ANTLR_JAR}) + +FetchContent_Declare( + antlr4 + GIT_REPOSITORY https://github.com/antlr/antlr4.git + GIT_TAG cc82115a4e7f53d71d9d905caa2c2dfa4da58899 + SOURCE_SUBDIR runtime/Cpp +) + +FetchContent_MakeAvailable(antlr4) +include(${antlr4_SOURCE_DIR}/runtime/Cpp/cmake/FindANTLR.cmake) diff --git a/cmake/FetchBoost.cmake b/cmake/FetchBoost.cmake new file mode 100644 index 0000000..359c609 --- /dev/null +++ b/cmake/FetchBoost.cmake @@ -0,0 +1,14 @@ +include(FetchContent) + +FetchContent_Declare( + Boost + URL https://github.com/boostorg/boost/releases/download/boost-1.90.0/boost-1.90.0-cmake.tar.gz + URL_HASH SHA256=913ca43d49e93d1b158c9862009add1518a4c665e7853b349a6492d158b036d4 + DOWNLOAD_EXTRACT_TIMESTAMP ON + EXCLUDE_FROM_ALL + OVERRIDE_FIND_PACKAGE +) + +set(BOOST_INCLUDE_LIBRARIES asio thread filesystem) + +FetchContent_MakeAvailable(Boost) diff --git a/cmake/FetchGBenchmark.cmake b/cmake/FetchGBenchmark.cmake new file mode 100644 index 0000000..dbeb87a --- /dev/null +++ b/cmake/FetchGBenchmark.cmake @@ -0,0 +1,15 @@ +include(FetchContent) +include(FetchGTest) + +FetchContent_Declare( + benchmark + GIT_REPOSITORY https://github.com/google/benchmark.git + GIT_TAG 12235e24652fc7f809373e7c11a5f73c5763fc4c +) + +FetchContent_GetProperties(benchmark) +if (NOT benchmark_POPULATED) + FetchContent_Populate(benchmark) + add_subdirectory(${benchmark_SOURCE_DIR} ${benchmark_BINARY_DIR} + EXCLUDE_FROM_ALL) +endif () diff --git a/cmake/FetchGTest.cmake b/cmake/FetchGTest.cmake new file mode 100644 index 0000000..318358c --- /dev/null +++ b/cmake/FetchGTest.cmake @@ -0,0 +1,14 @@ +include(FetchContent) + +FetchContent_Declare( + googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG 03597a01ee50ed33e9dfd640b249b4be3799d395 +) + +FetchContent_GetProperties(googletest) +if (NOT googletest_POPULATED) + FetchContent_Populate(googletest) + add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR} + EXCLUDE_FROM_ALL) +endif () diff --git a/cmake/SetupLLVM.cmake b/cmake/SetupLLVM.cmake new file mode 100644 index 0000000..a61d32d --- /dev/null +++ b/cmake/SetupLLVM.cmake @@ -0,0 +1,7 @@ +find_package(ZLIB QUIET) + +set(LLVM_DIR "/home/st/c/llvm-project/build/lib/cmake/llvm") +find_package(LLVM REQUIRED CONFIG) + +message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") +message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") diff --git a/compile_commands.json b/compile_commands.json new file mode 120000 index 0000000..25eb4b2 --- /dev/null +++ b/compile_commands.json @@ -0,0 +1 @@ +build/compile_commands.json \ No newline at end of file diff --git a/flake.nix b/flake.nix index b8a043f..d3566d8 100644 --- a/flake.nix +++ b/flake.nix @@ -21,21 +21,37 @@ pythonEnv = pkgs.python313.withPackages (ps: [ ps.pip ps.virtualenv + ps.pygments ]); + tex = (pkgs.texlive.combine { + inherit (pkgs.texlive) scheme-full + latexmk; + }); in { devShells.default = pkgs.mkShell.override {stdenv = pkgs.llvmPackages_21.stdenv;} { buildInputs = with pkgs; [ code-cursor-fhs pythonEnv + antlr + cmake + zlib + zlib.dev + gdb + perf + perl + tex + plantuml + inkscape ]; nativeBuildInputs = [ - pkgs.clang-tools_19 + pkgs.clang-tools ]; NIX_LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath [ pkgs.stdenv.cc.cc pkgs.zlib + pkgs.zlib.dev ]; NIX_LD = pkgs.lib.fileContents "${pkgs.stdenv.cc}/nix-support/dynamic-linker"; @@ -61,4 +77,3 @@ }; }); } - diff --git a/flamegraph.svg b/flamegraph.svg new file mode 100644 index 0000000..e69de29 diff --git a/include/stewkk/sql/logic/executor/buffer_size.hpp b/include/stewkk/sql/logic/executor/buffer_size.hpp new file mode 100644 index 0000000..cf4bb29 --- /dev/null +++ b/include/stewkk/sql/logic/executor/buffer_size.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include + +namespace stewkk::sql { + +constexpr static std::size_t kBufSize = 2048; + +} // stewkk::sql + diff --git a/include/stewkk/sql/logic/executor/channel.hpp b/include/stewkk/sql/logic/executor/channel.hpp new file mode 100644 index 0000000..293cc6f --- /dev/null +++ b/include/stewkk/sql/logic/executor/channel.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include + +#include + +namespace stewkk::sql { + +using TuplesChannel = boost::asio::experimental::concurrent_channel; +using AttributesInfoChannel = boost::asio::experimental::concurrent_channel; + +} // namespace stewkk::sql diff --git a/include/stewkk/sql/logic/executor/executor.hpp b/include/stewkk/sql/logic/executor/executor.hpp new file mode 100644 index 0000000..8cb3765 --- /dev/null +++ b/include/stewkk/sql/logic/executor/executor.hpp @@ -0,0 +1,454 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace stewkk::sql { + +using ExecExpression = std::function; + +class InterpretedExpressionExecutor { + public: + explicit InterpretedExpressionExecutor(boost::asio::any_io_executor executor); + boost::asio::awaitable GetExpressionExecutor(const Expression& expr, const AttributesInfo& attrs); +}; + +class JitCompiledExpressionExecutor { + public: + explicit JitCompiledExpressionExecutor(boost::asio::any_io_executor executor); + boost::asio::awaitable GetExpressionExecutor(const Expression& expr, const AttributesInfo& attrs); + private: + JITCompiler compiler_; +}; + +class CachedJitCompiledExpressionExecutor { + public: + explicit CachedJitCompiledExpressionExecutor(boost::asio::any_io_executor executor); + boost::asio::awaitable GetExpressionExecutor(const Expression& expr, const AttributesInfo& attrs); + private: + JITCompiler compiler_; + std::unordered_map cache_; +}; + +template +class Executor { +public: + using SequentialScan = std::function>( + const std::string& table_name, AttributesInfoChannel& attr_chan, TuplesChannel& tuples_chan)>; + Executor(SequentialScan seq_scan, boost::asio::any_io_executor executor); + + boost::asio::awaitable> Execute(const Operator& op); +private: + boost::asio::awaitable Execute(const Operator& op, AttributesInfoChannel& attr_chan, + TuplesChannel& tuples_chan); + boost::asio::awaitable ExecuteProjection(const Projection& proj, AttributesInfoChannel& attr_chan, + TuplesChannel& tuples_chan); + boost::asio::awaitable ExecuteFilter(const Filter& filter, AttributesInfoChannel& attr_chan, + TuplesChannel& tuples_chan); + boost::asio::awaitable ExecuteCrossJoin(const CrossJoin& cross_join, + AttributesInfoChannel& attr_chan, + TuplesChannel& tuples_chan); + boost::asio::awaitable ExecuteJoin(const Join& join, AttributesInfoChannel& attr_chan, + TuplesChannel& tuples_chan); + boost::asio::awaitable SpawnExecutor(const Operator& op, AttributesInfoChannel& attr_chan, TuplesChannel& tuple_chan); + +private: + SequentialScan sequential_scan_; + ExpressionExecutor expression_executor_; +}; + +Type GetExpressionType(const Expression& expr, const AttributesInfo& available_attrs); +Type GetExpressionTypeUnchecked(const Expression& expr, const AttributesInfo& available_attrs); +AttributesInfo GetAttributesAfterProjection(const AttributesInfo& attrs, const Projection& proj); + +template + requires std::invocable + && std::same_as, Ret> +Value ApplyIntegersOperator(Value lhs, Value rhs) { + if (lhs.is_null || rhs.is_null) { + return Value{true}; + } + return Value{false, Op{}(lhs.value.int_value, rhs.value.int_value)}; +} + +template + requires std::invocable + && std::same_as, bool> +Value ApplyBooleanOperator(Value lhs, Value rhs) { + if (lhs.is_null || rhs.is_null) { + return Value{true}; + } + return Value{false, Op{}(lhs.value.bool_value, rhs.value.bool_value)}; +} + +struct IntPow { + int64_t operator()(int64_t base, int64_t exp) const { + return static_cast(std::pow(base, exp)); + } +}; + +Value CalcExpression(const Tuple& source, const AttributesInfo& source_attrs, const Expression& expr); +Tuple ApplyProjection(const Tuple& source, const AttributesInfo& source_attrs, const std::vector& expressions); +bool ApplyFilter(const Tuple& source, const AttributesInfo& source_attrs, const ExecExpression& filter); +boost::asio::awaitable> GetChannels(); +boost::asio::awaitable ReceiveTuples(TuplesChannel& chan); +boost::asio::awaitable ConcatAttrs(AttributesInfoChannel& lhs_attrs_chan, AttributesInfoChannel& rhs_attrs_chan); +boost::asio::awaitable MaterializeChannel(TuplesChannel& tuples_chan); +Tuple ConcatTuples(const Tuple& lhs, const Tuple& rhs); + +template +Executor::Executor(SequentialScan seq_scan, boost::asio::any_io_executor executor) + : sequential_scan_(std::move(seq_scan)), expression_executor_(executor) {} + +template +boost::asio::awaitable> Executor::Execute(const Operator& op) { + auto [attr_chan, tuples_chan] = co_await GetChannels(); + co_await SpawnExecutor(op, attr_chan, tuples_chan); + + auto attrs = co_await attr_chan.async_receive(boost::asio::use_awaitable); +#ifdef DEBUG + std::clog << "Received attrs in root\n"; +#endif + + Tuples result; + for (;;) { + auto buf = co_await ReceiveTuples(tuples_chan); + if (buf.empty()) { + break; + } +#ifdef DEBUG + std::clog << std::format("Received {} tuples in root\n", buf.size()); +#endif + std::move(buf.begin(), buf.end(), std::back_inserter(result)); + } + +#ifdef DEBUG + std::clog << std::format("Total {} tuples in root\n", result.size()); +#endif + co_return Ok(Relation{std::move(attrs), std::move(result)}); +} + +template +boost::asio::awaitable Executor::Execute(const Operator& op, AttributesInfoChannel& attr_chan, TuplesChannel& tuples_chan) { + struct ExecuteVisitor{ + boost::asio::awaitable operator()(const Table& table) { + co_await executor.sequential_scan_(table.name, attr_chan, tuples_chan); + co_return; + } + boost::asio::awaitable operator()(const Projection& projection) { + // NOTE: We are using multiset relational algebra projection (i.e. not + // eleminating duplicate tuples) + co_await executor.ExecuteProjection(projection, attr_chan, tuples_chan); + co_return; + } + boost::asio::awaitable operator()(const Filter& filter) { + co_await executor.ExecuteFilter(filter, attr_chan, tuples_chan); + co_return; + } + boost::asio::awaitable operator()(const Join& join) { + co_await executor.ExecuteJoin(join, attr_chan, tuples_chan); + co_return; + } + boost::asio::awaitable operator()(const CrossJoin& cross_join) { + co_await executor.ExecuteCrossJoin(cross_join, attr_chan, tuples_chan); + co_return; + } + + AttributesInfoChannel& attr_chan; + TuplesChannel& tuples_chan; + Executor& executor; + }; + co_await std::visit(ExecuteVisitor{attr_chan, tuples_chan, *this}, op); + co_return; +} + +template +boost::asio::awaitable Executor::ExecuteProjection(const Projection& proj, + AttributesInfoChannel& out_attr_chan, + TuplesChannel& out_tuples_chan) { +#ifdef DEBUG + std::clog << "Executing projection\n"; +#endif + auto [in_attrs_chan, in_tuples_chan] = co_await GetChannels(); + co_await SpawnExecutor(*proj.source, in_attrs_chan, in_tuples_chan); + + auto attrs = co_await in_attrs_chan.async_receive(boost::asio::use_awaitable); + auto attrs_after = GetAttributesAfterProjection(attrs, proj); + co_await out_attr_chan.async_send(boost::system::error_code{}, attrs_after, + boost::asio::use_awaitable); + out_attr_chan.close(); + + std::vector executors; + executors.reserve(proj.expressions.size()); + for (const auto& expr : proj.expressions) { + executors.push_back(co_await expression_executor_.GetExpressionExecutor(expr, attrs)); + } + + for (;;) { + auto buf = co_await ReceiveTuples(in_tuples_chan); + if (buf.empty()) { + break; + } +#ifdef DEBUG + std::clog << std::format("Received {} tuples in projection\n", buf.size()); +#endif + buf = buf | std::views::transform([&](const auto& tuple) { + return ApplyProjection(tuple, attrs, executors); + }) | std::ranges::to(); + co_await out_tuples_chan.async_send(boost::system::error_code{}, std::move(buf), + boost::asio::use_awaitable); + } + out_tuples_chan.close(); +} + +template +boost::asio::awaitable Executor::ExecuteFilter(const Filter& filter, + AttributesInfoChannel& out_attr_chan, + TuplesChannel& out_tuples_chan) { +#ifdef DEBUG + std::clog << "Executing filter\n"; +#endif + auto [in_attrs_chan, in_tuples_chan] = co_await GetChannels(); + co_await SpawnExecutor(*filter.source, in_attrs_chan, in_tuples_chan); + + auto attrs = co_await in_attrs_chan.async_receive(boost::asio::use_awaitable); +#ifdef DEBUG + std::clog << "Filter received attrs\n"; +#endif + + if (GetExpressionType(filter.expr, attrs) != Type::kBool) { + throw std::logic_error{"filter expr should return bool"}; + } + +#ifdef DEBUG + std::clog << "Filter sending attrs\n"; +#endif + co_await out_attr_chan.async_send(boost::system::error_code{}, attrs, boost::asio::use_awaitable); + out_attr_chan.close(); +#ifdef DEBUG + std::clog << "Filter sent attrs\n"; +#endif + + auto filter_executor = co_await expression_executor_.GetExpressionExecutor(filter.expr, attrs); + + Tuples output_buf; + output_buf.reserve(kBufSize); + for (;;) { + auto input_buf = co_await ReceiveTuples(in_tuples_chan); + if (input_buf.empty()) { + break; + } +#ifdef DEBUG + std::clog << std::format("Received {} tuples in filter\n", input_buf.size()); +#endif + auto filtered_view = input_buf | std::views::filter([&](const auto& tuple) { + return ApplyFilter(tuple, attrs, filter_executor); + }) | std::views::as_rvalue; + for (auto&& tuple : filtered_view) { + output_buf.push_back(std::move(tuple)); + if (output_buf.size() == kBufSize) { +#ifdef DEBUG + std::clog << std::format("Sending {} tuples in filter\n", output_buf.size()); +#endif + co_await out_tuples_chan.async_send(boost::system::error_code{}, std::move(output_buf), + boost::asio::use_awaitable); + output_buf.clear(); + } + } + } +#ifdef DEBUG + std::clog << std::format("{} tuples left in output_buf\n", output_buf.size()); +#endif + if (!output_buf.empty()) { +#ifdef DEBUG + std::clog << std::format("Sending {} tuples in filter\n", output_buf.size()); +#endif + co_await out_tuples_chan.async_send(boost::system::error_code{}, std::move(output_buf), + boost::asio::use_awaitable); + } + out_tuples_chan.close(); +} + +template +boost::asio::awaitable Executor::ExecuteCrossJoin(const CrossJoin& cross_join, + AttributesInfoChannel& attr_chan, + TuplesChannel& tuples_chan) { + std::clog << "Executing cross join\n"; + auto [lhs_attrs_chan, lhs_tuples_chan] = co_await GetChannels(); + co_await SpawnExecutor(*cross_join.lhs, lhs_attrs_chan, lhs_tuples_chan); + auto [rhs_attrs_chan, rhs_tuples_chan] = co_await GetChannels(); + co_await SpawnExecutor(*cross_join.rhs, rhs_attrs_chan, rhs_tuples_chan); + + auto attrs = co_await ConcatAttrs(lhs_attrs_chan, rhs_attrs_chan); + std::clog << "Cross join received attrs\n"; + + std::clog << "Cross join sending attrs\n"; + co_await attr_chan.async_send(boost::system::error_code{}, attrs, boost::asio::use_awaitable); + attr_chan.close(); + std::clog << "Cross join sent attrs\n"; + + auto reader = co_await MaterializeChannel(lhs_tuples_chan); + std::clog << std::format("Materialized tuples in cross join\n"); + + for (;;) { + auto buf_rhs = co_await ReceiveTuples(rhs_tuples_chan); + if (buf_rhs.empty()) { + break; + } + std::clog << std::format("Received {} tuples in cross join as rhs\n", buf_rhs.size()); + + for (;;) { + auto buf_lhs = reader.Read(); + if (buf_lhs.empty()) { + break; + } + std::clog << std::format("Read {} tuples back from materialized form\n", buf_lhs.size()); + for (const auto& tuple_lhs : buf_lhs) { + Tuples buf_joined; + buf_joined.reserve(kBufSize); + // NOTE: not optimal if rhs is a small table (<< kBufSize tuples) + for (const auto& tuple_rhs : buf_rhs) { + auto joined_tuple = ConcatTuples(tuple_lhs, tuple_rhs); + buf_joined.push_back(std::move(joined_tuple)); + } +#ifdef DEBUG + std::clog << std::format("Sending {} tuples from cross join\n", buf_joined.size()); +#endif + co_await tuples_chan.async_send(boost::system::error_code{}, std::move(buf_joined), + boost::asio::use_awaitable); + } + } + } + tuples_chan.close(); +} + +template +boost::asio::awaitable Executor::ExecuteJoin(const Join& join, + AttributesInfoChannel& attr_chan, + TuplesChannel& tuples_chan) { +#ifdef DEBUG + std::clog << "Executing join\n"; +#endif + if (join.type == JoinType::kFull) { + throw std::logic_error{"Full joins are not supported by executor"}; + } + if (join.type == JoinType::kLeft) { + std::swap(*join.lhs, *join.rhs); + } + auto [lhs_attrs_chan, lhs_tuples_chan] = co_await GetChannels(); + co_await SpawnExecutor(*join.lhs, lhs_attrs_chan, lhs_tuples_chan); + auto [rhs_attrs_chan, rhs_tuples_chan] = co_await GetChannels(); + co_await SpawnExecutor(*join.rhs, rhs_attrs_chan, rhs_tuples_chan); + + auto attrs = co_await ConcatAttrs(lhs_attrs_chan, rhs_attrs_chan); +#ifdef DEBUG + std::clog << "Join received attrs\n"; +#endif + +#ifdef DEBUG + std::clog << "Join sending attrs\n"; +#endif + co_await attr_chan.async_send(boost::system::error_code{}, attrs, boost::asio::use_awaitable); + attr_chan.close(); +#ifdef DEBUG + std::clog << "Join sent attrs\n"; +#endif + + auto qual_executor = co_await expression_executor_.GetExpressionExecutor(join.qual, attrs); + + auto reader = co_await MaterializeChannel(lhs_tuples_chan); + for (;;) { + auto buf_rhs = co_await ReceiveTuples(rhs_tuples_chan); + if (buf_rhs.empty()) { + break; + } +#ifdef DEBUG + std::clog << std::format("Received {} tuples in join as rhs\n", buf_rhs.size()); +#endif + + std::vector used(buf_rhs.size(), false); + for (;;) { + auto buf_lhs = reader.Read(); + if (buf_lhs.empty()) { + break; + } +#ifdef DEBUG + std::clog << std::format("Read {} tuples back from materialized form\n", buf_lhs.size()); +#endif + + for (const auto& tuple_lhs : buf_lhs) { + Tuples buf_res; + buf_res.reserve(kBufSize); + for (const auto& [rhs_index, tuple_rhs] : buf_rhs | std::views::enumerate) { + auto joined_tuple = ConcatTuples(tuple_lhs, tuple_rhs); + auto qual_expr_res = qual_executor(joined_tuple, attrs); + if (qual_expr_res.value.bool_value) { + buf_res.push_back(std::move(joined_tuple)); + used[rhs_index] = true; + } + } + if (!buf_res.empty()) { +#ifdef DEBUG + std::clog << std::format("Sending {} tuples from join\n", buf_res.size()); +#endif + co_await tuples_chan.async_send(boost::system::error_code{}, std::move(buf_res), + boost::asio::use_awaitable); + } + } + } + + if (join.type == JoinType::kRight || join.type == JoinType::kLeft) { + Tuples buf_res; + buf_res.reserve(kBufSize); + for (auto [rhs_index, is_used] : used | std::views::enumerate) { + if (is_used) { + continue; + } + + auto rhs_tuple = std::move(buf_rhs[rhs_index]); + + auto lhs_size = attrs.size() - rhs_tuple.size(); + Tuple lhs_tuple(lhs_size, Value{true}); + + auto joined_tuple = ConcatTuples(lhs_tuple, rhs_tuple); + buf_res.push_back(std::move(joined_tuple)); + } + if (!buf_res.empty()) { +#ifdef DEBUG + std::clog << std::format("Sending {} tuples from join\n", buf_res.size()); +#endif + co_await tuples_chan.async_send(boost::system::error_code{}, std::move(buf_res), + boost::asio::use_awaitable); + } + } + } + tuples_chan.close(); +} + +template +boost::asio::awaitable Executor::SpawnExecutor(const Operator& op, + AttributesInfoChannel& attr_chan, + TuplesChannel& tuple_chan) { + auto executor = co_await boost::asio::this_coro::executor; + boost::asio::co_spawn(executor, Execute(op, attr_chan, tuple_chan), boost::asio::detached); +} + + +} // namespace stewkk::sql diff --git a/include/stewkk/sql/logic/executor/llvm.hpp b/include/stewkk/sql/logic/executor/llvm.hpp new file mode 100644 index 0000000..1c5e8e3 --- /dev/null +++ b/include/stewkk/sql/logic/executor/llvm.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include +#include + +#include +#include +#include +#include + +#include +#include + +namespace stewkk::sql { + +class JITCompiler { + public: + using CompiledExpression = void (*)(Value*, const Value*, const AttributeInfo*); + + explicit JITCompiler(boost::asio::any_io_executor executor); + + boost::asio::awaitable> + CompileExpression(const Expression& expr, const AttributesInfo& attrs); + + private: + llvm::Function* GenerateIR(llvm::Module& llvm_module, const Expression& expr, + const AttributesInfo& attrs); + + private: + std::unique_ptr jit_; + std::atomic id_; + boost::asio::strand jit_strand_; +}; + +} // namespace stewkk::sql diff --git a/include/stewkk/sql/logic/executor/materialization.hpp b/include/stewkk/sql/logic/executor/materialization.hpp new file mode 100644 index 0000000..e8a3387 --- /dev/null +++ b/include/stewkk/sql/logic/executor/materialization.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include + +#include + +#include + +namespace stewkk::sql { + +namespace fs = boost::filesystem; + +class DiskFileReader { + public: + DiskFileReader(fs::path path, std::size_t tuple_size); + ~DiskFileReader(); + DiskFileReader(DiskFileReader&& other) = default; + DiskFileReader& operator=(DiskFileReader&& other) = default; + Tuples Read(); + private: + fs::path path_; + std::ifstream f_; + std::size_t tuple_size_; +}; + +class DiskFileWriter { + public: + DiskFileWriter(); + void Write(const Tuples& tuples); + DiskFileReader GetDiskFileReader() &&; + private: + fs::path path_; + std::ofstream f_; + std::size_t tuple_size_; +}; + +} // namespace stewkk::sql diff --git a/include/stewkk/sql/logic/executor/sequential_scan.hpp b/include/stewkk/sql/logic/executor/sequential_scan.hpp new file mode 100644 index 0000000..51451e1 --- /dev/null +++ b/include/stewkk/sql/logic/executor/sequential_scan.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include + +#include +#include + +namespace stewkk::sql { + +struct CsvDirSequentialScanner { + std::string dir; + + boost::asio::awaitable> operator()(const std::string& table_name, + AttributesInfoChannel& attrs_chan, + TuplesChannel& tuples_chan) const; +}; + +} // namespace stewkk::sql diff --git a/include/stewkk/sql/logic/parser/parser.hpp b/include/stewkk/sql/logic/parser/parser.hpp new file mode 100644 index 0000000..cf99d18 --- /dev/null +++ b/include/stewkk/sql/logic/parser/parser.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include + +#include +#include + +namespace stewkk::sql { + +Result GetAST(std::istream& in); + +std::string GetDotRepresentation(const Operator& op); + +} // namespace stewkk::sql diff --git a/include/stewkk/sql/logic/result/error.hpp b/include/stewkk/sql/logic/result/error.hpp new file mode 100644 index 0000000..b3d4bc4 --- /dev/null +++ b/include/stewkk/sql/logic/result/error.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include +#include +#include + +namespace stewkk::sql { + +enum class ErrorType { + kUnknown, + kSyntaxError, + kConversionError, + kQueryNotSupported, +}; + +class Error : public std::exception { +private: + struct ErrorData { + ErrorType type; + std::string message; + }; + +public: + Error(ErrorType type, std::string message); + std::string What() const; + virtual const char* what() const noexcept override; + Error& Wrap(ErrorType type, std::string message); + bool Wraps(ErrorType type) const; + +private: + std::vector wrapped_; + std::optional what_; +}; + +} // namespace stewkk::sql diff --git a/include/stewkk/sql/logic/result/result.hpp b/include/stewkk/sql/logic/result/result.hpp new file mode 100644 index 0000000..f2c070f --- /dev/null +++ b/include/stewkk/sql/logic/result/result.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include +#include + +#include + +namespace stewkk::sql { + +struct EmptyResult {}; + +template using Result = std::expected; + +template auto Ok(T&& v = {}) { return Result(std::forward(v)); } + +template +std::unexpected MakeError(const std::format_string fmt, Args&&... args) { + return std::unexpected(Error{ErrorType, std::format(fmt, std::forward(args)...)}); +} + +template +std::unexpected WrapError(Result&& result, const std::format_string fmt, Args&&... args) { + return std::unexpected(result.error().Wrap(ErrorType, std::format(fmt, std::forward(args)...))); +} + +std::string What(const Error& error); + +} // namespace stewkk::sql diff --git a/include/stewkk/sql/models/executor/tuple.hpp b/include/stewkk/sql/models/executor/tuple.hpp new file mode 100644 index 0000000..b7189a6 --- /dev/null +++ b/include/stewkk/sql/models/executor/tuple.hpp @@ -0,0 +1,52 @@ +#pragma once + +#include +#include + +namespace stewkk::sql { + +enum class Type { + kInt, + kBool, +}; + +std::string ToString(Type type); + +struct AttributeInfo { + std::string table; + std::string name; + Type type; + + auto operator<=>(const AttributeInfo& other) const = default; +}; + +// NOTE: union leaves possibility to add other data types later +union NonNullValue { + int64_t int_value; + bool bool_value; +}; + +std::string ToString(bool v); + +// NOTE: bare struct for compatibility with llvm +struct Value { + bool is_null; + NonNullValue value; + + bool operator==(const Value& other) const; +}; + +std::string ToString(Value v, const AttributeInfo& attr); + +using Tuple = std::vector; +using Tuples = std::vector; +using AttributesInfo = std::vector; + +struct Relation { + AttributesInfo attributes; + Tuples tuples; +}; + +std::string ToString(const Relation& relation); + +} // namespace stewkk::sql diff --git a/include/stewkk/sql/models/parser/relational_algebra_ast.hpp b/include/stewkk/sql/models/parser/relational_algebra_ast.hpp new file mode 100644 index 0000000..0f8ea9d --- /dev/null +++ b/include/stewkk/sql/models/parser/relational_algebra_ast.hpp @@ -0,0 +1,133 @@ +#pragma once + +#include +#include +#include +#include + +namespace stewkk::sql { + +constexpr static std::string kEmptyTableName = "_EMPTY_TABLE_"; + +struct Attribute { + std::string table; + std::string name; + + auto operator<=>(const Attribute& other) const = default; +}; + +std::string ToString(const Attribute& attr); + +using IntConst = std::int64_t; + +struct Table; +struct Projection; +struct Filter; +struct CrossJoin; +struct Join; + +using Operator = std::variant; + +struct Table { + std::string name; + + auto operator<=>(const Table& other) const = default; +}; + +struct BinaryExpression; +struct UnaryExpression; + +enum class Literal { + kNull, + kTrue, + kFalse, + kUnknown, +}; + +std::string ToString(Literal literal); + +using Expression = std::variant; + +std::string ToString(const Expression& expr); + +struct Projection { + std::vector expressions; + std::shared_ptr source; + + bool operator==(const Projection& other) const; +}; + +enum class BinaryOp { + kGt, + kLt, + kLe, + kGe, + kNotEq, + kEq, + kOr, + kAnd, + kPlus, + kMinus, + kMul, + kDiv, + kMod, + kPow, +}; + +std::string ToString(BinaryOp binop); + +struct BinaryExpression { + std::shared_ptr lhs; + BinaryOp binop; + std::shared_ptr rhs; + + bool operator==(const BinaryExpression& other) const; +}; + +enum class UnaryOp { + kNot, + kMinus, +}; + +std::string ToString(UnaryOp op); + +struct UnaryExpression { + UnaryOp op; + std::shared_ptr child; + + bool operator==(const UnaryExpression& other) const; +}; + +struct Filter { + Expression expr; + std::shared_ptr source; + + bool operator==(const Filter& other) const; +}; + +struct CrossJoin { + std::shared_ptr lhs; + std::shared_ptr rhs; + + bool operator==(const CrossJoin& other) const; +}; + +enum class JoinType { + kInner, + kFull, + kLeft, + kRight, +}; + +std::string ToString(JoinType type); + +struct Join { + JoinType type; + Expression qual; + std::shared_ptr lhs; + std::shared_ptr rhs; + + bool operator==(const Join& other) const; +}; + +} // namespace stewkk::sql diff --git a/report/Emblem.png b/report/Emblem.png new file mode 100644 index 0000000..d5d065d Binary files /dev/null and b/report/Emblem.png differ diff --git a/report/Makefile b/report/Makefile new file mode 100644 index 0000000..3670e34 --- /dev/null +++ b/report/Makefile @@ -0,0 +1,20 @@ +.PHONY: build + +all: build + +build: + @latexmk -f -pdf -output-directory=build -shell-escape ./report.tex + +bib: + @cp ./biblio.bib ./build + @cd build && biber report + +clean: + @rm -rf build + +uml: + @plantuml dbms_scheme.puml + +view: + @evince ./build/report.pdf + diff --git a/report/biblio.bib b/report/biblio.bib new file mode 100644 index 0000000..edb22c7 --- /dev/null +++ b/report/biblio.bib @@ -0,0 +1,70 @@ + +@misc{DBReport, +title = {Исследование рынка СУБД}, +url = {https://www.mordorintelligence.com/industry-reports/database-market}, +language = {english}, +note = {(дата обращения: 17.01.2026)} +} + +@misc{PostgresDocs, +title = {Документация PostgreSQL}, +url = {https://www.postgresql.org/docs/current/sql-select.html}, +language = {english}, +note = {(дата обращения: 17.01.2026)} +} + +@misc{PostgresBisonGrammar, +title = {Грамматика PostgreSQL}, +url = {https://github.com/postgres/postgres/blob/master/src/backend/parser/gram.y}, +language = {english}, +note = {(дата обращения: 17.01.2026)} +} + +@misc{Antlr4PostgreSQL, +title = {Грамматика PostgreSQL для ANTLR4}, +url = {https://github.com/antlr/grammars-v4/blob/master/sql/postgresql/PostgreSQLParser.g4}, +language = {english}, +note = {(дата обращения: 17.01.2026)} +} + +@book{silberschatz2020database, + title={Database system concepts}, + author={Silberschatz, Abraham and Korth, Henry F and Sudarshan, Shashank and others}, + year={2020}, + publisher={Mcgraw-hill New York}, + language = {english}, + note = {(дата обращения: 17.01.2026)} +} + +@inproceedings{pantilimonov2019machine, + title={Machine code caching in postgresql query jit-compiler}, + author={Pantilimonov, Michael and Buchatskiy, Ruben and Zhuykov, Roman and Sharygin, Eugene and Melnik, Dmitry}, + booktitle={2019 Ivannikov Memorial Workshop (IVMEM)}, + pages={18--25}, + year={2019}, + organization={IEEE}, + language = {english}, + note = {(дата обращения: 17.01.2026)} +} + +@book{petrov2019database, + title={Database Internals: A deep dive into how distributed data systems work}, + author={Petrov, Alex}, + year={2019}, + publisher={O'Reilly Media}, + language = {english}, + note = {(дата обращения: 17.01.2026)} +} + +@article{graefe2002volcano, + title={Volcano - an extensible and parallel query evaluation system}, + author={Graefe, Goetz}, + journal={IEEE Transactions on Knowledge and Data Engineering}, + volume={6}, + number={1}, + pages={120--135}, + year={2002}, + publisher={IEEE}, + language = {english}, + note = {(дата обращения: 17.01.2026)} +} diff --git a/report/dbms_scheme.png b/report/dbms_scheme.png new file mode 100644 index 0000000..adc167d Binary files /dev/null and b/report/dbms_scheme.png differ diff --git a/report/dbms_scheme.puml b/report/dbms_scheme.puml new file mode 100644 index 0000000..d01bc9e --- /dev/null +++ b/report/dbms_scheme.puml @@ -0,0 +1,33 @@ +@startuml + +package "Модуль хранения данных" { +component "Система авторизации" +component "Система управления файлами" +component "Система страничной\nорганизации памяти" + +database "Файлы с данными" as DataFiles +database "Хранилище метаданных" as Metadata +database "Индексы" as Indexes +} + +package "Модуль обработки запросов" { +component "Парсер запросов\nв синтаксическое дерево" +component "Модуль преобразования\nсинтаксического дерева\nв план исполнения запроса" +component "Оптимизатор планов\nисполнения запросов" +component "Модуль исполнения плана" +} + +package "Модуль управления транзакциями" { +component "Система восстановления\nпосле перезапуска" +component "Система синхронизации" +} + +"Модуль обработки запросов" --> "Модуль хранения данных" +"Модуль управления транзакциями" --> "Модуль хранения данных" +"Модуль управления транзакциями" --> "Модуль обработки запросов" + +"Система управления файлами" --> DataFiles +"Система управления файлами" --> Metadata +"Система управления файлами" --> Indexes + +@enduml diff --git a/report/expression.png b/report/expression.png new file mode 100644 index 0000000..99995e5 Binary files /dev/null and b/report/expression.png differ diff --git a/report/listings/grammar1.g4 b/report/listings/grammar1.g4 new file mode 100644 index 0000000..092b79e --- /dev/null +++ b/report/listings/grammar1.g4 @@ -0,0 +1,48 @@ +root + : stmtmulti EOF + ; + +stmt + : selectstmt + | ... + ; + +stmtmulti + : stmt? (SEMI stmt?)* + ; + +select_with_parens + : OPEN_PAREN select_no_parens CLOSE_PAREN + | OPEN_PAREN select_with_parens CLOSE_PAREN + ; + +select_no_parens + : select_clause sort_clause_? ( + for_locking_clause select_limit_? + | select_limit for_locking_clause_? + )? + | with_clause select_clause sort_clause_? ( + for_locking_clause select_limit_? + | select_limit for_locking_clause_? + )? + ; + +select_clause + : simple_select_intersect ((UNION | EXCEPT) all_or_distinct? simple_select_intersect)* + ; + +simple_select_intersect + : simple_select_pramary (INTERSECT all_or_distinct? simple_select_pramary)* + ; + +simple_select_pramary + : ( + SELECT + ( all_clause_? target_list_? + into_clause? from_clause? where_clause? + group_clause? having_clause? window_clause? + | distinct_clause target_list + into_clause? from_clause? where_clause? + group_clause? having_clause? window_clause? + ) + ) diff --git a/report/listings/grammar2.g4 b/report/listings/grammar2.g4 new file mode 100644 index 0000000..83ac6fc --- /dev/null +++ b/report/listings/grammar2.g4 @@ -0,0 +1,50 @@ + | values_clause + | TABLE relation_expr + | select_with_parens + ; + +from_clause + : FROM from_list + + ; + +from_list + : table_ref (COMMA table_ref)* + ; + +table_ref + : ( + relation_expr alias_clause? tablesample_clause? + | func_table func_alias_clause? + | xmltable alias_clause? + | select_with_parens alias_clause? + | LATERAL_P ( + xmltable alias_clause? + | func_table func_alias_clause? + | select_with_parens alias_clause? + ) + | OPEN_PAREN table_ref CLOSE_PAREN alias_clause? + ) ( + CROSS JOIN table_ref + | NATURAL join_type? JOIN table_ref + | join_type? JOIN table_ref join_qual + )* + ; + +join_type + : INNER_P + | (FULL | LEFT | RIGHT) OUTER_P? + ; + +join_qual + : USING OPEN_PAREN name_list CLOSE_PAREN + | ON a_expr + ; +relation_expr + : qualified_name STAR? + | ONLY (qualified_name | OPEN_PAREN qualified_name CLOSE_PAREN) + ; + +where_clause + : WHERE a_expr + ; diff --git a/report/listings/grammar3.g4 b/report/listings/grammar3.g4 new file mode 100644 index 0000000..61f5c45 --- /dev/null +++ b/report/listings/grammar3.g4 @@ -0,0 +1,46 @@ +a_expr_qual + : a_expr_lessless ({this->OnlyAcceptableOps()}? qual_op | ) + ; + +a_expr_lessless + : a_expr_or ((LESS_LESS | GREATER_GREATER) a_expr_or)* + ; + +a_expr_or + : a_expr_and (OR a_expr_and)* + ; + +a_expr_and + : a_expr_between (AND a_expr_between)* + ; + +a_expr_between + : a_expr_in (NOT? BETWEEN SYMMETRIC? a_expr_in AND a_expr_in)? + ; + +a_expr_in + : a_expr_unary_not (NOT? IN_P in_expr)? + ; + +a_expr_unary_not + : NOT? a_expr_isnull + ; + +a_expr_isnull + : a_expr_is_not (ISNULL | NOTNULL)? + ; + +a_expr_is_not + : a_expr_compare ( + IS NOT? ( + NULL_P + | TRUE_P + | FALSE_P + | UNKNOWN + | DISTINCT FROM a_expr + | OF OPEN_PAREN type_list CLOSE_PAREN + | DOCUMENT_P + | unicode_normal_form? NORMALIZED + ) + )? + ; diff --git a/report/listings/grammar4.g4 b/report/listings/grammar4.g4 new file mode 100644 index 0000000..6e5bf5c --- /dev/null +++ b/report/listings/grammar4.g4 @@ -0,0 +1,46 @@ +a_expr_compare + : a_expr_like ( + (LT | GT | EQUAL | LESS_EQUALS | GREATER_EQUALS | NOT_EQUALS) a_expr_like + | subquery_Op sub_type (select_with_parens | OPEN_PAREN a_expr CLOSE_PAREN) /*21*/ + )? + ; + +a_expr_like + : a_expr_qual_op (NOT? (LIKE | ILIKE | SIMILAR TO) a_expr_qual_op escape_?)? + ; + +a_expr_qual_op + : a_expr_unary_qualop (qual_op a_expr_unary_qualop)* + ; + +a_expr_unary_qualop + : qual_op? a_expr_add + ; + +a_expr_add + : a_expr_mul ((MINUS | PLUS) a_expr_mul)* + ; + +a_expr_mul + : a_expr_caret ((STAR | SLASH | PERCENT) a_expr_caret)* + ; + +a_expr_caret + : a_expr_unary_sign (CARET a_expr_unary_sign)? + ; + +a_expr_unary_sign + : (MINUS | PLUS)? a_expr_at_time_zone /* */ + ; + +a_expr_at_time_zone + : a_expr_collate (AT TIME ZONE a_expr)? + ; + +a_expr_collate + : a_expr_typecast (COLLATE any_name)? + ; + +a_expr_typecast + : c_expr (TYPECAST typename)* + ; diff --git a/report/listings/grammar5.g4 b/report/listings/grammar5.g4 new file mode 100644 index 0000000..460d022 --- /dev/null +++ b/report/listings/grammar5.g4 @@ -0,0 +1,49 @@ +c_expr + : EXISTS select_with_parens # c_expr_exists + | ARRAY (select_with_parens | array_expr) # c_expr_expr + | PARAM opt_indirection # c_expr_expr + | GROUPING OPEN_PAREN expr_list CLOSE_PAREN # c_expr_expr + | /*22*/ UNIQUE select_with_parens # c_expr_expr + | columnref # c_expr_expr + | aexprconst # c_expr_expr + | OPEN_PAREN a_expr_in_parens = a_expr + CLOSE_PAREN opt_indirection # c_expr_expr + | case_expr # c_expr_case + | func_expr # c_expr_expr + | select_with_parens indirection? # c_expr_expr + | explicit_row # c_expr_expr + | implicit_row # c_expr_expr + | row OVERLAPS row /* 14*/ # c_expr_expr + | DEFAULT # c_expr_expr + ; + +columnref + : colid indirection? + ; + +target_list + : target_el (COMMA target_el)* + ; + +target_el + : a_expr (AS colLabel | bareColLabel |) # target_label + | STAR # target_star + ; + +qualified_name + : colid indirection? + ; + +aexprconst + : iconst + | TRUE_P + | FALSE_P + | NULL_P + ; + +iconst + : Integral + | BinaryIntegral + | OctalIntegral + | HexadecimalIntegral + ; diff --git a/report/listings/ir_generator.cpp b/report/listings/ir_generator.cpp new file mode 100644 index 0000000..2beace5 --- /dev/null +++ b/report/listings/ir_generator.cpp @@ -0,0 +1,39 @@ + struct GenerateIRVisitor { + llvm::Value* operator()(const BinaryExpression& expr) { + auto* lhs = std::visit(*this, *expr.lhs); + auto* rhs = std::visit(*this, *expr.rhs); + + auto* is_null_lhs = CheckNull(lhs); + auto* is_null_rhs = CheckNull(rhs); + auto* value_lhs = LoadValue(lhs); + auto* value_rhs = LoadValue(rhs); + + auto* is_null = builder.CreateOr(is_null_lhs, is_null_rhs); + llvm::Value* res_value; + + switch (expr.binop) { + case BinaryOp::kGt: + { + auto* tmp = builder.CreateICmpSGT(value_lhs, value_rhs); + res_value = builder.CreateZExt(tmp, builder.getInt64Ty(), "i1_to_i64_zext"); + break; + } + case BinaryOp::kLt: + { + auto* tmp = builder.CreateICmpSLT(value_lhs, value_rhs); + res_value = builder.CreateZExt(tmp, builder.getInt64Ty(), "i1_to_i64_zext"); + break; + } + case BinaryOp::kLe: + { + auto* tmp = builder.CreateICmpSLE(value_lhs, value_rhs); + res_value = builder.CreateZExt(tmp, builder.getInt64Ty(), "i1_to_i64_zext"); + break; + } + case BinaryOp::kGe: + { + auto* tmp = builder.CreateICmpSGE(value_lhs, value_rhs); + res_value = builder.CreateZExt(tmp, builder.getInt64Ty(), "i1_to_i64_zext"); + break; + } +... diff --git a/report/listings/jit_compiler_constructor.cpp b/report/listings/jit_compiler_constructor.cpp new file mode 100644 index 0000000..157a7d7 --- /dev/null +++ b/report/listings/jit_compiler_constructor.cpp @@ -0,0 +1,41 @@ +JITCompiler::JITCompiler(boost::asio::any_io_executor executor) : jit_strand_(executor) { + llvm::InitializeNativeTarget(); + llvm::InitializeNativeTargetAsmPrinter(); + llvm::InitializeNativeTargetAsmParser(); + auto jit_or_error = llvm::orc::LLJITBuilder().create(); + if (!jit_or_error) { + throw std::runtime_error("failed to create llvm::LLJIT"); + } + jit_ = std::move(*jit_or_error); + jit_->getIRTransformLayer().setTransform( + [](llvm::orc::ThreadSafeModule tsm, llvm::orc::MaterializationResponsibility& r) + -> llvm::Expected { + tsm.withModuleDo([](llvm::Module& m) { + llvm::LoopAnalysisManager lam; + llvm::FunctionAnalysisManager fam; + llvm::CGSCCAnalysisManager cgam; + llvm::ModuleAnalysisManager mam; + llvm::PassBuilder pb; + pb.registerModuleAnalyses(mam); + pb.registerCGSCCAnalyses(cgam); + pb.registerFunctionAnalyses(fam); + pb.registerLoopAnalyses(lam); + pb.crossRegisterProxies(lam, fam, cgam, mam); + llvm::ModulePassManager mpm; + llvm::FunctionPassManager fpm; + fpm.addPass(llvm::EarlyCSEPass(true)); + fpm.addPass(llvm::SROAPass(llvm::SROAOptions::ModifyCFG)); + fpm.addPass(llvm::InstCombinePass()); + fpm.addPass(llvm::SimplifyCFGPass()); + fpm.addPass(llvm::ReassociatePass()); + fpm.addPass(llvm::GVNPass()); + fpm.addPass(llvm::MemCpyOptPass()); + fpm.addPass(llvm::SimplifyCFGPass()); + fpm.addPass(llvm::InstCombinePass()); + fpm.addPass(llvm::DCEPass()); + fpm.addPass(llvm::ADCEPass()); + mpm.addPass(llvm::createModuleToFunctionPassAdaptor( + std::move(fpm))); + mpm.run(m, mam); + }); +... diff --git a/report/perf.png b/report/perf.png new file mode 100644 index 0000000..c77c372 Binary files /dev/null and b/report/perf.png differ diff --git a/report/query.png b/report/query.png new file mode 100644 index 0000000..c47639d Binary files /dev/null and b/report/query.png differ diff --git a/report/report.pdf b/report/report.pdf new file mode 100644 index 0000000..158f2cd Binary files /dev/null and b/report/report.pdf differ diff --git a/report/report.tex b/report/report.tex new file mode 100644 index 0000000..e1c9ec6 --- /dev/null +++ b/report/report.tex @@ -0,0 +1,1941 @@ +% !TeX TXS-program:bibliography = txs:///biber +\documentclass[14pt, russian]{scrartcl} +\let\counterwithout\relax +\let\counterwithin\relax +%\usepackage{lmodern} +\usepackage{float} +\usepackage{xcolor} +\usepackage{extsizes} +\usepackage{subfig} +\usepackage[export]{adjustbox} +\usepackage{tocvsec2} % возможность менять учитываемую глубину разделов в оглавлении +\usepackage[subfigure]{tocloft} +\usepackage[newfloat]{minted} +\captionsetup[listing]{position=top} + +\AtBeginEnvironment{figure}{\vspace{0.5cm}} +\AtBeginEnvironment{table}{\vspace{0.5cm}} +\AtBeginEnvironment{listing}{\vspace{0.5cm}} +\AtBeginEnvironment{algorithm}{\vspace{0.5cm}} +\AtBeginEnvironment{minted}{\vspace{-0.5cm}} + +\usepackage{fancyvrb} +\usepackage{ulem,bm,mathrsfs,ifsym} %зачеркивания, особо жирный стиль и RSFS начертание +\usepackage{sectsty} % переопределение стилей подразделов +%%%%%%%%%%%%%%%%%%%%%%% + +%%% Поля и разметка страницы %%% +\usepackage{pdflscape} % Для включения альбомных страниц +\usepackage{geometry} % Для последующего задания полей +\geometry{a4paper,tmargin=2cm,bmargin=2cm,lmargin=3cm,rmargin=1cm} % тоже самое, но лучше + +%%% Математические пакеты %%% +\usepackage{amsthm,amsfonts,amsmath,amssymb,amscd} % Математические дополнения от AMS +\usepackage{mathtools} % Добавляет окружение multlined +\usepackage[perpage]{footmisc} +%\usepackage{times} + +\def\ojoin{\setbox0=\hbox{$\bowtie$}% + \rule[-.02ex]{.25em}{.4pt}\llap{\rule[\ht0]{.25em}{.4pt}}} +\def\leftouterjoin{\mathbin{\ojoin\mkern-5.8mu\bowtie}} +\def\rightouterjoin{\mathbin{\bowtie\mkern-5.8mu\ojoin}} +\def\fullouterjoin{\mathbin{\ojoin\mkern-5.8mu\bowtie\mkern-5.8mu\ojoin}} + +%%%% Установки для размера шрифта 14 pt %%%% +%% Формирование переменных и констант для сравнения (один раз для всех подключаемых файлов)%% +%% должно располагаться до вызова пакета fontspec или polyglossia, потому что они сбивают его работу +%\newlength{\curtextsize} +%\newlength{\bigtextsize} +%\setlength{\bigtextsize}{13pt} +\KOMAoptions{fontsize=14pt} + +\makeatletter +\def\showfontsize{\f@size{} point} +\makeatother + +%\makeatletter +%\show\f@size % неплохо для отслеживания, но вызывает стопорение процесса, если документ компилируется без команды -interaction=nonstopmode +%\setlength{\curtextsize}{\f@size pt} +%\makeatother + +%шрифт times +\usepackage{tempora} +%\usepackage{pscyr} +%\setmainfont[Ligatures={TeX,Historic}]{Times New Roman} + + %%% Решение проблемы копирования текста в буфер кракозябрами +% \input glyphtounicode.tex +% \input glyphtounicode-cmr.tex %from pdfx package +% \pdfgentounicode=1 + \usepackage{cmap} % Улучшенный поиск русских слов в полученном pdf-файле + \usepackage[T1]{fontenc} % Поддержка русских букв + \usepackage[utf8]{inputenc} % Кодировка utf8 + \usepackage[english, main=russian]{babel} % Языки: русский, английский +% \IfFileExists{pscyr.sty}{\usepackage{pscyr}}{} % Красивые русские шрифты +%\renewcommand{\rmdefault}{ftm} +%%% Оформление абзацев %%% +\usepackage{indentfirst} % Красная строка +%\usepackage{eskdpz} + +%%% Таблицы %%% +\usepackage{longtable} % Длинные таблицы +\usepackage{multirow,makecell,array} % Улучшенное форматирование таблиц +\usepackage{booktabs} % Возможность оформления таблиц в классическом книжном стиле (при правильном использовании не противоречит ГОСТ) + +%%% Общее форматирование +\usepackage{soulutf8} % Поддержка переносоустойчивых подчёркиваний и зачёркиваний +\usepackage{icomma} % Запятая в десятичных дробях + + + +%%% Изображения %%% +\usepackage{graphicx} % Подключаем пакет работы с графикой +\usepackage{wrapfig} + +\usepackage{tikz} +\usetikzlibrary{shapes.misc} +\usetikzlibrary{trees} +\usetikzlibrary{arrows.meta} + +%%% Списки %%% +\usepackage{enumitem} + +%%% Подписи %%% +\usepackage{caption} % Для управления подписями (рисунков и таблиц) % Может управлять номерами рисунков и таблиц с caption %Иногда может управлять заголовками в списках рисунков и таблиц +%% Использование: +%\begin{table}[h!]\ContinuedFloat - чтобы не переключать счетчик +%\captionsetup{labelformat=continued}% должен стоять до самого caption +%\caption{} +% либо ручками \caption*{Продолжение таблицы~\ref{...}.} :) + +%%% Интервалы %%% +\addto\captionsrussian{% + \renewcommand{\listingname}{Листинг}% +} +%%% Счётчики %%% +\usepackage[figure,table,section]{totalcount} % Счётчик рисунков и таблиц +\DeclareTotalCounter{lstlisting} +\usepackage{totcount} % Пакет создания счётчиков на основе последнего номера подсчитываемого элемента (может требовать дважды компилировать документ) +\usepackage{totpages} % Счётчик страниц, совместимый с hyperref (ссылается на номер последней страницы). Желательно ставить последним пакетом в преамбуле + +%%% Продвинутое управление групповыми ссылками (пока только формулами) %%% +%% Кодировки и шрифты %%% + +% \newfontfamily{\cyrillicfont}{Times New Roman} +% \newfontfamily{\cyrillicfonttt}{CMU Typewriter Text} + %\setmainfont{Times New Roman} + %\newfontfamily\cyrillicfont{Times New Roman} + %\setsansfont{Times New Roman} %% задаёт шрифт без засечек +% \setmonofont{Liberation Mono} %% задаёт моноширинный шрифт +% \IfFileExists{pscyr.sty}{\renewcommand{\rmdefault}{ftm}}{} +%%% Интервалы %%% +%linespread-реализация ближе к реализации полуторного интервала в ворде. +%setspace реализация заточена под шрифты 10, 11, 12pt, под остальные кегли хуже, но всё же ближе к типографской классике. +\linespread{1.3} % Полуторный интервал (ГОСТ Р 7.0.11-2011, 5.3.6) +%\renewcommand{\@biblabel}[1]{#1} + +%%% Гиперссылки %%% +\usepackage{hyperref} + +%%% Выравнивание и переносы %%% +\sloppy % Избавляемся от переполнений +\clubpenalty=10000 % Запрещаем разрыв страницы после первой строки абзаца +\widowpenalty=10000 % Запрещаем разрыв страницы после последней строки абзаца + +\makeatletter % малые заглавные, small caps shape +\let\@@scshape=\scshape +\renewcommand{\scshape}{% + \ifnum\strcmp{\f@series}{bx}=\z@ + \usefont{T1}{cmr}{bx}{sc}% + \else + \ifnum\strcmp{\f@shape}{it}=\z@ + \fontshape{scsl}\selectfont + \else + \@@scshape + \fi + \fi} +\makeatother + +%%% Подписи %%% +%\captionsetup{% +%singlelinecheck=off, % Многострочные подписи, например у таблиц +%skip=2pt, % Вертикальная отбивка между подписью и содержимым рисунка или таблицы определяется ключом +%justification=centering, % Центрирование подписей, заданных командой \caption +%} +%%% Подключение пакетов %%% +\usepackage{ifthen} % добавляет ifthenelse +%%% Инициализирование переменных, не трогать! %%% +\newcounter{intvl} +\newcounter{otstup} +\newcounter{contnumeq} +\newcounter{contnumfig} +\newcounter{contnumtab} +\newcounter{pgnum} +\newcounter{bibliosel} +\newcounter{chapstyle} +\newcounter{headingdelim} +\newcounter{headingalign} +\newcounter{headingsize} +\newcounter{tabcap} +\newcounter{tablaba} +\newcounter{tabtita} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%% Область упрощённого управления оформлением %%% + +%% Интервал между заголовками и между заголовком и текстом +% Заголовки отделяют от текста сверху и снизу тремя интервалами (ГОСТ Р 7.0.11-2011, 5.3.5) +\setcounter{intvl}{3} % Коэффициент кратности к размеру шрифта + +%% Отступы у заголовков в тексте +\setcounter{otstup}{0} % 0 --- без отступа; 1 --- абзацный отступ + +%% Нумерация формул, таблиц и рисунков +\setcounter{contnumeq}{1} % Нумерация формул: 0 --- пораздельно (во введении подряд, без номера раздела); 1 --- сквозная нумерация по всей диссертации +\setcounter{contnumfig}{1} % Нумерация рисунков: 0 --- пораздельно (во введении подряд, без номера раздела); 1 --- сквозная нумерация по всей диссертации +\setcounter{contnumtab}{1} % Нумерация таблиц: 0 --- пораздельно (во введении подряд, без номера раздела); 1 --- сквозная нумерация по всей диссертации + +%% Оглавление +\setcounter{pgnum}{0} % 0 --- номера страниц никак не обозначены; 1 --- Стр. над номерами страниц (дважды компилировать после изменения) + +%% Библиография +\setcounter{bibliosel}{1} % 0 --- встроенная реализация с загрузкой файла через движок bibtex8; 1 --- реализация пакетом biblatex через движок biber + +%% Текст и форматирование заголовков +\setcounter{chapstyle}{1} % 0 --- разделы только под номером; 1 --- разделы с названием "Глава" перед номером +\setcounter{headingdelim}{1} % 0 --- номер отделен пропуском в 1em или \quad; 1 --- номера разделов и приложений отделены точкой с пробелом, подразделы пропуском без точки; 2 --- номера разделов, подразделов и приложений отделены точкой с пробелом. + +%% Выравнивание заголовков в тексте +\setcounter{headingalign}{0} % 0 --- по центру; 1 --- по левому краю + +%% Размеры заголовков в тексте +\setcounter{headingsize}{0} % 0 --- по ГОСТ, все всегда 14 пт; 1 --- пропорционально изменяющийся размер в зависимости от базового шрифта + +%% Подпись таблиц +\setcounter{tabcap}{0} % 0 --- по ГОСТ, номер таблицы и название разделены тире, выровнены по левому краю, при необходимости на нескольких строках; 1 --- подпись таблицы не по ГОСТ, на двух и более строках, дальнейшие настройки: +%Выравнивание первой строки, с подписью и номером +\setcounter{tablaba}{2} % 0 --- по левому краю; 1 --- по центру; 2 --- по правому краю +%Выравнивание строк с самим названием таблицы +\setcounter{tabtita}{1} % 0 --- по левому краю; 1 --- по центру; 2 --- по правому краю + +%%% Рисунки %%% +\DeclareCaptionLabelSeparator*{emdash}{~--- } % (ГОСТ 2.105, 4.3.1) +\captionsetup[figure]{labelsep=emdash,font=onehalfspacing,position=bottom} + +%%% Таблицы %%% +\ifthenelse{\equal{\thetabcap}{0}}{% + \newcommand{\tabcapalign}{\raggedright} % по левому краю страницы или аналога parbox +} + +\ifthenelse{\equal{\thetablaba}{0} \AND \equal{\thetabcap}{1}}{% + \newcommand{\tabcapalign}{\raggedright} % по левому краю страницы или аналога parbox +} + +\ifthenelse{\equal{\thetablaba}{1} \AND \equal{\thetabcap}{1}}{% + \newcommand{\tabcapalign}{\centering} % по центру страницы или аналога parbox +} + +\ifthenelse{\equal{\thetablaba}{2} \AND \equal{\thetabcap}{1}}{% + \newcommand{\tabcapalign}{\raggedleft} % по правому краю страницы или аналога parbox +} + +\ifthenelse{\equal{\thetabtita}{0} \AND \equal{\thetabcap}{1}}{% + \newcommand{\tabtitalign}{\raggedright} % по левому краю страницы или аналога parbox +} + +\ifthenelse{\equal{\thetabtita}{1} \AND \equal{\thetabcap}{1}}{% + \newcommand{\tabtitalign}{\centering} % по центру страницы или аналога parbox +} + +\ifthenelse{\equal{\thetabtita}{2} \AND \equal{\thetabcap}{1}}{% + \newcommand{\tabtitalign}{\raggedleft} % по правому краю страницы или аналога parbox +} + +\DeclareCaptionFormat{tablenocaption}{\tabcapalign #1\strut} % Наименование таблицы отсутствует +\ifthenelse{\equal{\thetabcap}{0}}{% + \DeclareCaptionFormat{tablecaption}{\tabcapalign #1#2#3} + \captionsetup[table]{labelsep=emdash} % тире как разделитель идентификатора с номером от наименования +}{% + \DeclareCaptionFormat{tablecaption}{\tabcapalign #1#2\par% % Идентификатор таблицы на отдельной строке + \tabtitalign{#3}} % Наименование таблицы строкой ниже + \captionsetup[table]{labelsep=space} % пробельный разделитель идентификатора с номером от наименования +} +\captionsetup[table]{format=tablecaption,singlelinecheck=off,font=onehalfspacing,position=top,skip=-5pt} % многострочные наименования и прочее +\DeclareCaptionLabelFormat{continued}{Продолжение таблицы~#2} +\setlength{\belowcaptionskip}{.2cm} +\setlength{\intextsep}{0ex} + +%%% Подписи подрисунков %%% +\renewcommand{\thesubfigure}{\asbuk{subfigure}} % Буквенные номера подрисунков +\captionsetup[subfigure]{font={normalsize}, % Шрифт подписи названий подрисунков (не отличается от основного) + labelformat=brace, % Формат обозначения подрисунка + justification=centering, % Выключка подписей (форматирование), один из вариантов +} +%\DeclareCaptionFont{font12pt}{\fontsize{12pt}{13pt}\selectfont} % объявляем шрифт 12pt для использования в подписях, тут же надо интерлиньяж объявлять, если не наследуется +%\captionsetup[subfigure]{font={font12pt}} % Шрифт подписи названий подрисунков (всегда 12pt) + +%%% Настройки гиперссылок %%% + +\definecolor{linkcolor}{rgb}{0.0,0,0} +\definecolor{citecolor}{rgb}{0,0.0,0} +\definecolor{urlcolor}{rgb}{0,0,0} + +\hypersetup{ + linktocpage=true, % ссылки с номера страницы в оглавлении, списке таблиц и списке рисунков +% linktoc=all, % both the section and page part are links +% pdfpagelabels=false, % set PDF page labels (true|false) + plainpages=true, % Forces page anchors to be named by the Arabic form of the page number, rather than the formatted form + colorlinks, % ссылки отображаются раскрашенным текстом, а не раскрашенным прямоугольником, вокруг текста + linkcolor={linkcolor}, % цвет ссылок типа ref, eqref и подобных + citecolor={citecolor}, % цвет ссылок-цитат + urlcolor={urlcolor}, % цвет гиперссылок + pdflang={ru}, +} +\urlstyle{same} +%%% Шаблон %%% +%\DeclareRobustCommand{\todo}{\textcolor{red}} % решаем проблему превращения названия цвета в результате \MakeUppercase, http://tex.stackexchange.com/a/187930/79756 , \DeclareRobustCommand protects \todo from expanding inside \MakeUppercase +\setlength{\parindent}{2.5em} % Абзацный отступ. Должен быть одинаковым по всему тексту и равен пяти знакам (ГОСТ Р 7.0.11-2011, 5.3.7). + +%%% Списки %%% +% Используем дефис для ненумерованных списков (ГОСТ 2.105-95, 4.1.7) +%\renewcommand{\labelitemi}{\normalfont\bfseries~{---}} +\renewcommand{\labelitemi}{\bfseries~{---}} +\setlist{nosep,% % Единый стиль для всех списков (пакет enumitem), без дополнительных интервалов. + labelindent=\parindent,leftmargin=*% % Каждый пункт, подпункт и перечисление записывают с абзацного отступа (ГОСТ 2.105-95, 4.1.8) +} +%%%%%%%%%%%%%%%%%%%%%% +%\usepackage{xltxtra} % load xunicode + +\usepackage{ragged2e} +\usepackage[explicit]{titlesec} +\usepackage{placeins} +\usepackage{xparse} +\usepackage{csquotes} + +\usepackage{listingsutf8} +\usepackage{url} %пакеты расширений +\usepackage{algorithm, algorithmicx} +\usepackage[noend]{algpseudocode} +\usepackage{blkarray} +\usepackage{chngcntr} +\usepackage{tabularx} +\usepackage[backend=biber, + bibstyle=gost-numeric, + citestyle=nature]{biblatex} +\newcommand*\template[1]{\text{<}#1\text{>}} +\addbibresource{biblio.bib} + +\titleformat{name=\section,numberless}[block]{\normalfont\Large\centering}{}{0em}{#1} +\titleformat{\section}[block]{\normalfont\Large\bfseries\raggedright}{}{0em}{\thesection\hspace{0.25em}#1} +\titleformat{\subsection}[block]{\normalfont\Large\bfseries\raggedright}{}{0em}{\thesubsection\hspace{0.25em}#1} +\titleformat{\subsubsection}[block]{\normalfont\large\bfseries\raggedright}{}{0em}{\thesubsubsection\hspace{0.25em}#1} + +\let\Algorithm\algorithm +\renewcommand\algorithm[1][]{\Algorithm[#1]\setstretch{1.5}} +%\renewcommand{\listingscaption}{Листинг} + +\usepackage{pifont} +\usepackage{calc} +\usepackage{suffix} +\usepackage{csquotes} +\DeclareQuoteStyle{russian} + {\guillemotleft}{\guillemotright}[0.025em] + {\quotedblbase}{\textquotedblleft} +\ExecuteQuoteOptions{style=russian} +\newcommand{\enq}[1]{\enquote{#1}} +\newcommand{\eng}[1]{\begin{english}#1\end{english}} +% Подчиненные счетчики в окружениях http://old.kpfu.ru/journals/izv_vuz/arch/sample1251.tex +\newcounter{cTheorem} +\newcounter{cDefinition} +\newcounter{cConsequent} +\newcounter{cExample} +\newcounter{cLemma} +\newcounter{cConjecture} +\newtheorem{Theorem}{Теорема}[cTheorem] +\newtheorem{Definition}{Определение}[cDefinition] +\newtheorem{Consequent}{Следствие}[cConsequent] +\newtheorem{Example}{Пример}[cExample] +\newtheorem{Lemma}{Лемма}[cLemma] +\newtheorem{Conjecture}{Гипотеза}[cConjecture] + +\renewcommand{\theTheorem}{\arabic{Theorem}} +\renewcommand{\theDefinition}{\arabic{Definition}} +\renewcommand{\theConsequent}{\arabic{Consequent}} +\renewcommand{\theExample}{\arabic{Example}} +\renewcommand{\theLemma}{\arabic{Lemma}} +\renewcommand{\theConjecture}{\arabic{Conjecture}} +%\makeatletter +\NewDocumentCommand{\Newline}{}{\text{\\}} +\newcommand{\sequence}[2]{\ensuremath \left(#1,\ \dots,\ #2\right)} + +\definecolor{mygreen}{rgb}{0,0.6,0} +\definecolor{mygray}{rgb}{0.5,0.5,0.5} +\definecolor{mymauve}{rgb}{0.58,0,0.82} +\renewcommand{\listalgorithmname}{Список алгоритмов} +\floatname{algorithm}{Листинг} +\renewcommand{\lstlistingname}{Листинг} +\renewcommand{\thealgorithm}{\arabic{algorithm}} + +\newcommand{\refAlgo}[1]{(листинг~\ref{#1})} +\newcommand{\refImage}[1]{(рисунок~\ref{#1})} + +\renewcommand{\theenumi}{\arabic{enumi}.}% Меняем везде перечисления на цифра.цифра +\renewcommand{\labelenumi}{\arabic{enumi}.}% Меняем везде перечисления на цифра.цифра +\renewcommand{\theenumii}{\arabic{enumii}}% Меняем везде перечисления на цифра.цифра +\renewcommand{\labelenumii}{(\arabic{enumii})}% Меняем везде перечисления на цифра.цифра +\renewcommand{\theenumiii}{\roman{enumiii}}% Меняем везде перечисления на цифра.цифра +\renewcommand{\labelenumiii}{(\roman{enumiii})}% Меняем везде перечисления на цифра.цифра +%\newfontfamily\AnkaCoder[Path=src/fonts/]{AnkaCoder-r.ttf} +\renewcommand{\labelitemi}{---} +\renewcommand{\labelitemii}{---} + +%\usepackage{courier} + +\lstdefinelanguage{Refal}{ + alsodigit = {.,<,>}, + morekeywords = [1]{$ENTRY}, + morekeywords = [2]{Go, Put, Get, Open, Close, Arg, Add, Sub, Mul, Div, Symb, Explode, Implode}, + %keyword4 + morekeywords = [3]{<,>}, + %keyword5 + morekeywords = [4]{e.,t.,s.}, + sensitive = true, + morecomment = [l]{*}, + morecomment = [s]{/*}{*/}, + commentstyle = \color{mygreen}, + morestring = [b]", + morestring = [b]', + stringstyle = \color{purple} +} + +\makeatletter +\def\p@subsection{} +\def\p@subsubsection{\thesection\,\thesubsection\,} +\makeatother +\newcommand{\prog}[1]{{\ttfamily\small#1}} +\lstset{ % + backgroundcolor=\color{white}, % choose the background color; you must add \usepackage{color} or \usepackage{xcolor} + basicstyle=\ttfamily\footnotesize, + %basicstyle=\footnotesize\AnkaCoder, % the size of the fonts that are used for the code + breakatwhitespace=false, % sets if automatic breaks shoulbd only happen at whitespace + breaklines=true, % sets automatic line breaking + captionpos=top, % sets the caption-position to bottom + commentstyle=\color{mygreen}, % comment style + deletekeywords={...}, % if you want to delete keywords from the given language + escapeinside={\%*}{*)}, % if you want to add LaTeX within your code + extendedchars=true, % lets you use non-ASCII characters; for 8-bits encodings only, does not work with UTF-8 + inputencoding=utf8, + frame=single, % adds a frame around the code + keepspaces=true, % keeps spaces in text, useful for keeping indentation of code (possibly needs columns=flexible) + keywordstyle=\bf, % keyword style + language=Refal, % the language of the code + morekeywords={<,>,$ENTRY,Go,Arg, Open, Close, e., s., t., Get, Put}, + % if you want to add more keywords to the set + numbers=left, % where to put the line-numbers; possible values are (none, left, right) + numbersep=5pt, % how far the line-numbers are from the code + xleftmargin=25pt, + xrightmargin=25pt, + numberstyle=\small\color{black}, % the style that is used for the line-numbers + rulecolor=\color{black}, % if not set, the frame-color may be changed on line-breaks within not-black text (e.g. comments (green here)) + showspaces=false, % show spaces everywhere adding particular underscores; it overrides 'showstringspaces' + showstringspaces=false, % underline spaces within strings only + showtabs=false, % show tabs within strings adding particular underscores + stepnumber=1, % the step between two line-numbers. If it's 1, each line will be numbered + stringstyle=\color{mymauve}, % string literal style + tabsize=8, % sets default tabsize to 8 spaces + title=\lstname % show the filename of files included with \lstinputlisting; also try caption instead of title +} +\newcommand{\anonsection}[1]{\cleardoublepage +\phantomsection +\addcontentsline{toc}{section}{\protect\numberline{}#1} +\section*{#1}\vspace*{2.5ex} % По госту положены 3 пустые строки после заголовка ненумеруемого раздела +} +\newcommand{\sectionbreak}{\clearpage} +\renewcommand{\sectionfont}{\normalsize} % Сбиваем стиль оглавления в стандартный +\renewcommand{\cftsecleader}{\cftdotfill{\cftdotsep}} % Точки в оглавлении напротив разделов + +\renewcommand{\cftsecfont}{\normalfont\large} % Переключение на times в содержании +\renewcommand{\cftsubsecfont}{\normalfont\large} % Переключение на times в содержании + +\usepackage{caption} +%\captionsetup[table]{justification=raggedleft} +%\captionsetup[figure]{justification=centering,labelsep=endash} +\usepackage{amsmath} % \bar (матрицы и проч. ...) +\usepackage{amsfonts} % \mathbb (символ для множества действительных чисел и проч. ...) +\usepackage{mathtools} % \abs, \norm + \DeclarePairedDelimiter\abs{\lvert}{\rvert} % операция модуля + \DeclarePairedDelimiter\norm{\lVert}{\rVert} % операция нормы +\DeclareTextCommandDefault{\textvisiblespace}{% + \mbox{\kern.06em\vrule \@height.3ex}% + \vbox{\hrule \@width.3em}% + \hbox{\vrule \@height.3ex}} +\newsavebox{\spacebox} +\begin{lrbox}{\spacebox} +\verb*! ! +\end{lrbox} +\newcommand{\aspace}{\usebox{\spacebox}} +\DeclareTotalCounter{listing} + +\makeatletter +\renewcommand*{\p@subsubsection}{} +\makeatother + +\makeatletter +\AddToHook{begindocument/before}{\@ifpackageloaded{minted}{\removefromtoclist[float]{lol}}{}} +\makeatother + +\begin{document} +\sloppy + +\def\figurename{Рисунок} + +\begin{titlepage} + \thispagestyle{empty} + \newpage + + \vspace*{-30pt} + \hspace{-45pt} + \begin{minipage}{0.17\textwidth} + \hspace*{-20pt}\centering + \includegraphics[width=1.3\textwidth]{emblem.png} + \end{minipage} + \begin{minipage}{0.82\textwidth}\small \textbf{ + \vspace*{-0.7ex} + \hspace*{-10pt}\centerline{Министерство науки и высшего образования Российской Федерации} + \vspace*{-0.7ex} + \centerline{Федеральное государственное автономное образовательное учреждение } + \vspace*{-0.7ex} + \centerline{высшего образования} + \vspace*{-0.7ex} + \centerline{<<Московский государственный технический университет} + \vspace*{-0.7ex} + \centerline{имени Н.Э. Баумана} + \vspace*{-0.7ex} + \centerline{(национальный исследовательский университет)>>} + \vspace*{-0.7ex} + \centerline{(МГТУ им. Н.Э. Баумана)}} + \end{minipage} + + \vspace{-2pt} + \hspace{-34.5pt}\rule{\textwidth}{2.5pt} + + \vspace*{-20.3pt} + \hspace{-34.5pt}\rule{\textwidth}{0.4pt} + + \vspace{0.5ex} + \noindent \small ФАКУЛЬТЕТ\hspace{80pt} <<Информатика и системы управления>> + + \vspace*{-16pt} + \hspace{35pt}\rule{0.855\textwidth}{0.4pt} + + \vspace{0.5ex} + \noindent \small КАФЕДРА\hspace{50pt} <<Теоретическая информатика и компьютерные технологии>> + + \vspace*{-16pt} + \hspace{25pt}\rule{0.875\textwidth}{0.4pt} + + + \vspace{3em} + + \begin{center} + \Large \bf{РАСЧЕТНО-ПОЯСНИТЕЛЬНАЯ ЗАПИСКА\\\textbf{\textit{К КУРСОВОЙ РАБОТЕ\\НА ТЕМУ:}} \\} + \end{center} + + \vspace*{-6ex} + \begin{center} + \Large{\textit{\textbf{<<Оптимизирующий компилятор запросов }}} + + \vspace*{-3ex} + \rule{0.9\textwidth}{1.2pt} + + \vspace*{-0.2ex} + \Large{\textit{\textbf{подмножества SQL на основе LLVM>>}}} + + \vspace*{-3ex} + \vspace*{-0.2ex} + \rule{0.9\textwidth}{1.2pt} + + \vspace*{-0.2ex} + \rule{0.9\textwidth}{1.2pt} + + \vspace*{-0.2ex} + \rule{0.9\textwidth}{1.2pt} + + \vspace*{-0.2ex} + \rule{0.9\textwidth}{1.2pt} + \end{center} + + \vspace{\fill} + + + \newlength{\ML} + \settowidth{\ML}{«\underline{\hspace{0.7cm}}» \underline{\hspace{2cm}}} + + \noindent Студент \underline{\text{ИУ9-71Б}} \hfill \underline{ \hspace{4cm}}\quad + \raisebox{0.45ex}{\underline{\parbox{4cm}{\centering Старовойтов А.И.}}} + + \vspace{-2.1ex} + \noindent\hspace{9ex}\scriptsize{(Группа)}\normalsize\hspace{170pt}\hspace{2ex}\scriptsize{(Подпись, дата)}\normalsize\hspace{30pt}\hspace{6ex}\scriptsize{(И.О. Фамилия)}\normalsize + + \bigskip + + \noindent Руководитель \hfill \underline{\hspace{4cm}}\quad + \raisebox{0.35ex}{\underline{\parbox{4cm}{\centering Непейвода А.Н.}}} + + \vspace{-2ex} + \noindent\hspace{13.5ex}\normalsize\hspace{170pt}\hspace{2ex}\scriptsize{(Подпись, дата)}\normalsize\hspace{30pt}\hspace{6ex}\scriptsize{(И.О. Фамилия)}\normalsize + + \bigskip + + \noindent Консультант\hfill \underline{\hspace{4cm}}\quad + \underline{\hspace{4cm}} + + \vspace{-2ex} + \noindent\hspace{13.5ex}\normalsize\hspace{170pt}\hspace{2ex}\scriptsize{(Подпись, дата)}\normalsize\hspace{30pt}\hspace{6ex}\scriptsize{(И.О. Фамилия)}\normalsize + \vfill + + %\vspace{\fill} + + + + \begin{center} + \textsl{2026 г.} + \end{center} +\end{titlepage} + +%\renewcommand{\ttdefault}{pcr} + +\setlength{\tabcolsep}{3pt} +\newpage +\setcounter{page}{2} +%---------------------------------------------------------------------------- +% ОТСЮДА --- СОБСТВЕННО ТЕКСТ +%---------------------------------------------------------------------------- + +\newpage +\renewcommand\contentsname{\hfill{\normalfont{СОДЕРЖАНИЕ}}\hfill} %Оглавление +\tableofcontents +\newpage +\anonsection{ВВЕДЕНИЕ} %Введение + +С развитием технологий обработки больших данных и появлением все большего числа +распределенных высоконагруженных систем, как никогда актуальным становится +вопрос эффективного хранения данных. Системы управления базами данных решают эти +задачи, упрощая разработку и экономя вычислительные ресурсы, а также место на +дисках. + +Реляционные системы управления базами данных занимают более половины +рынка~\cite{DBReport} и остаются стандартом для хранения данных. Основным языком +запросов к таким системам является SQL. + +Разработчики СУБД постоянно борются за производительность исполнения SQL +запросов, применяя различные техники, например: машинное обучение, аппаратное +ускорение, векторизированное исполнение и т.д. Одним из способов оптимизации, +позволяющим сэкономить ресурсы процессора при выполнении сложных запросов, может +быть JIT-компиляция некоторых частей запроса. Такая техника реализована в самых +популярных СУБД, таких как PostgreSQL~\cite{pantilimonov2019machine} и является +довольно актуальной для автоматически сгенерированных запросов, например в +системах визуализации данных в виде графиков и диаграмм, ввиду сложности +выражений для фильтрации и их неоптимальности. + +Целью данной работы является реализация модельной реляционной СУБД с поддержкой +опциональной JIT-компиляции выражений в SELECT запросах на основе LLVM-JIT, а +также сравнение производительности исполнения с компиляцией и без. + +\section{Обзор предметной области} + +Обычно, СУБД верхнеуровнево разделяют на следующие +модули~\cite{silberschatz2020database}~\refImage{fig:dbms-scheme}: + +\begin{itemize} + \item модуль хранения данных; + \item модуль обработки запросов; + \item модуль управления транзакциями. +\end{itemize} + +\begin{figure}[H] + \centering + \begin{minipage}[t]{\textwidth} + \centering + \includegraphics[width=\textwidth]{dbms_scheme} + \end{minipage} + \caption{Схема верхнеуровнего устройства СУБД.}\label{fig:dbms-scheme} +\end{figure} + +\subsection{Модуль хранения данных} + +Модуль хранения данных реализует удобный интерфейс для физического хранения +данных на диске, предоставляя возможность сохранять, читать и обновлять +информацию в базе данных. + +Подсистемами модуля хранения данных являются: + +\begin{itemize} + \item система авторизации; + \item система управления файлами; + \item система страничной организации памяти. +\end{itemize} + +Данные на диске хранятся в нескольких формах: файлы с даннми, хранилище +метаданных и индексы. + +\subsection{Модуль обработки запросов} + +Модуль обработки запросов отвечает за исполнение запросов пользователя. Его подсистемами являются: + +\begin{itemize} + \item парсер запросов в синтаксическое дерево; + \item модуль преобразования синтаксического дерева в план исполнения запроса; + \item оптимизатор планов исполнения запросов; + \item модуль исполнения плана. +\end{itemize} + +\subsection{Модуль управления транзакциями} + +Задача этого модуля --- обеспечить атомарное выполнение нескольких запросов, +чтобы сохранить определенные инварианты относительно хранимых данных. Его подсистемами могут являться: + +\begin{itemize} + \item система восстановления после перезапуска; + \item система синхронизации. +\end{itemize} + +\subsection{Реляционная модель и реляционная алгебра} + +Реляционная модель объединяет несколько концептов: + +\begin{itemize} + \item \emph{структура}: определения отношений и их содержимого не зависит от + физического представления. Каждое отношение --- множество атрибутов, + каждый атрибут имеет множество значений; + \item \emph{целостность}: соблюдение определенных инвариантов относительно + хранимых данных; + \item \emph{интерфейс}: декларативный интерфейс для доступа и изменения данных + при помощи отношений. Разработчик задает только желаемый результат, а + СУБД определяет наиболее оптимальный способ его достижения. +\end{itemize} + +Все это образует фреймворк для работы с данными, который не отличается от одной +СУБД к другой и избавляет от заботы о низкоуровневых деталях хранения. + +\begin{Definition}[Отношение] + Неупорядоченное множество, элементами которого являются кортежи из значений + атрибутов, задающих сущности. Отношения иногда называют таблицами. +\end{Definition} + +\begin{Definition}[Кортеж] + Множество значений атрибутов в отношении. Значениями могут быть скаляры или + более сложные структуры данных. Каждый атрибут, если не задано специальное + ограничение, может принимать значение \verb|NULL|, означающее, что для данного + кортежа значение данного атрибута не определено. +\end{Definition} + +\begin{Definition}[Реляционная алгебра] + Множество фундаментальных оперторов для получения и изменения кортежей в + отношении. Каждый оператор принимает одно или несколько отношений в качестве + входа и возвращает новое отношение в качестве выхода. +\end{Definition} + +Чтобы представлить SQL запрос в терминах реляционной алгебры можно +скомбинировать соответствующие операторы. Перечислим основные: + +\begin{itemize} + \item $\sigma_{\text{predicate}}(R)$ --- позволяет фильтровать кортежи по + предикату; + \item $\pi_{A_{1}, \ldots, A\_{n}}(R)$ --- позволяет выбрать нужные атрибуты + из кортежа; + \item $\cap, \cup, -$ --- стандартные операции над множествами; + \item $\times$ --- декартово произведение, соответствует \verb|INNER JOIN|; + \item $\leftouterjoin, \rightouterjoin, \fullouterjoin$ --- реализуют + \verb|OUTER JOIN|. +\end{itemize} + +\subsection{Язык SQL} + +С помощью языка запросов SQL, ``Structured Query Language'', происходит все +взаимодействие клиентов с СУБД: определение схем данных, изменение содержимого +таблиц и т.п. Этот язык появился в начале 1970-х и продолжает развиваться по сей +день. Язык разделяют на две части: + +\begin{itemize} + \item ``Data-definition language'' --- язык для определения схем таблиц; + \item ``Data-manipulation language'' --- язык для получения и изменения данных в таблицах. +\end{itemize} + +В этой работе мы фокусируемся на DML, а именно на части для получения данных, +где наиболее актуальна JIT-компиляция. Этот функционал реализован с помощью +ключевого слова ``SELECT''. + +Грамматика ``SELECT''~\refAlgo{lst:select_grammar} позволяет задать: + +\begin{itemize} + \item ``FROM'' --- из каких таблиц брать данные; + \item ``WHERE'' --- как их отфильтровать; + \item ``GROUP BY'' --- какие функции агрегации использовать; + \item ``ORDER BY'' --- порядок сортировки; + \item ``LIMIT'' --- ограничение на количество кортежей; + \item ``select\_list'' --- какие атрибуты возвращать. +\end{itemize} + +\begin{listing} + \caption{Грамматика ``SELECT''~\cite{PostgresDocs}.} + \label{lst:select_grammar} + \begin{minted}[style=bw, breaklines, frame=single, fontsize = \footnotesize, linenos=false, xleftmargin = 1.5em]{text} +SELECT [ DISTINCT | ALL ] select_list + [ FROM table_expression ] + [ WHERE condition ] + [ GROUP BY grouping_element [, ...] ] + [ HAVING condition ] + [ WINDOW window_name AS ( window_definition ) [, ...] ] + [ ORDER BY sort_expression [ ASC | DESC | USING operator ] [, ...] ] + [ LIMIT { count | ALL } ] + [ OFFSET start [ ROW | ROWS ] ] + [ FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } ONLY ] + [ FOR { UPDATE | SHARE } [ OF table_name [, ...] ] [ NOWAIT | SKIP LOCKED ] [, ...] ] ; + \end{minted} +\end{listing} + +Пример ``SELECT'' запроса представлен в листинге~\ref{lst:select_example}. + +\begin{listing} + \caption{Пример SQL запроса.} + \label{lst:select_example} + \begin{minted}[style=bw, breaklines, frame=single, fontsize = \footnotesize, linenos=false, xleftmargin = 1.5em]{SQL} +SELECT name, phone FROM users WHERE age > 22; + \end{minted} +\end{listing} + +\subsection{Парсинг SQL запросов} + +Парсер отвечает за преобразование SQL-запросов в абстрактное синтаксическое +дерево. + +Помимо ANSI стандартов язка практически каждая СУБД реализует свой набор +расширений. Самым популярным из них считается синтаксис ``PostgreSQL''. + +Синтаксис SQL довольно объемный, поэтому обычно используют генераторы +лексических и синтаксических анализаторов, такие как Bison и ANTLR. Например, +Postgres использует Bison~\cite{PostgresBisonGrammar}. + +\subsection{Исполнение SQL запросов} + +После синтаксического разбора, СУБД преобразует дерево обхода во внутреннее +представление. Обычно, для этого используют представления на основе расширенной +реляционной алгебры. Дополнительно, на этом этапе проверяется наличие таблиц и +атрибутов, к которым обращается запрос. + +Для работы с деревом обхода инструменты, такие как ANTLR, предоставляют +несколько механизмов: + +\begin{itemize} + \item обход в глубину с помощью паттерна ``Посетитель''; + \item функции обрабатывающие события начала и конца обхода каждого правила; + \item написание обрабатывающего кода на целевом языке в файле с описанием + грамматики. +\end{itemize} + +Из перечисленных способов паттерн ``Посетитель'' является самым гибким, потому +что позволяет реализовывать обход в нужном порядке и полностью отделяет описание +граматики от реализации обхода дерева разбора. + +Есть несколько вариантов, как исполнить один конкретный запрос: в каком порядке +применять фильтрацию и сортировку, когда делать проекцию? За нахождение +оптимального порядка отвечает оптимизатор. Он получает на вход запрос в форме +реляционной алгебры, а на выходе строит физический план выполнения. В процессе +работы оптимизатор применяет преобразования, которые не меняют семантику +запроса, используя для этого законы реляционной алгебры. + +Физический план принципиально отличается от запроса в формате реляционной +алгебры тем, что содержит все детали выполнения: конкретные алгоритмы исполнения +каждого этапа, используемые индексы и т.п. + +Физический план является деревом, в котором данные перемещаются от листьев к +корню~\refImage{fig:query-plan}. Листья являются таблицами, а остальные вершины +--- операторами. Стрелочки показывают направление движения данных. Операторы +обычно являются одноместными или двуместными и соответствуют операторам +расширенной реляционной алгебры. + +\begin{figure}[H] + \centering + \begin{minipage}[t]{\textwidth} + \centering + \includegraphics[width=0.5\textwidth]{query} + \end{minipage} + \caption{План запроса}\label{fig:query-plan} +\end{figure} + +Существует три основные модели исполнения физических планов: + +\begin{itemize} + \item модель итераторов; + \item материализационная модель; + \item векторизированная модель. +\end{itemize} + +\subsubsection{Модель итераторов} + +Самая распространенная модель исполнения --- модель +итераторов~\cite{graefe2002volcano}. Каждый оператор является итератором --- +реализует функцию \verb|Next()|, которая возвращает следующий кортеж из +отношения. Простота данной идеи выгодно отличает ее от других вариантов и +позволяет легко комбинировать операторы, и, что важнее, свободно рассуждать о +них, потому что каждый оператор независим от другого. + +В этой модели естественным образом получается конвейеризированное исполнение: +когда кортеж проходит все возможные операторы до чтения следующего. Операторы, +которые исполняются вместе, называют конвейером. + +Некоторые операторы блокируют конвейверное исполнение. Например, для сортировки +требуется иметь в доступе все кортежи. + +Также, в модели итераторов легко реализуется ограничение количества кортежей. +Это достигается путем прекращения вызовов \verb|Next()|, когда нужное количество +данных уже получено. + +Минусом данной модели является большое количество накладных расходов на вызов +функций. Применение каждого оператора к каждому кортежу является вызовом функции +\verb|Next()|. + +\subsubsection{Материализационная модель} + +В материализационной модели каждый оператор обрабатывает все данные за один +вызов. Вместо \verb|Next()| реализуют функцию \verb|Output()|, которая в +качестве результата возвращается весь набор кортежей. + +Зачастую, отношения настолько большие, что их нельзя держать целиком в памяти, +поэтому в результате каждой операции создается временная таблица на диске для +хранения промежуточных данных. + +Эта модель подходит для баз данных для обработки транзакций, где запросы +затрагивают небольшое количество кортежей, но плохо работает в колоночных СУБД, +потому что там обрабатывается большое количество данных и постоянно приходится +сохранять промежуточные результаты на диск. + +\subsubsection{Векторизированная модель} + +Векторизованная модель схожа с моделью итераторов в том, что в ней обычно +реализуют функцию \verb|Next()|. Отличием является то, что эта функция +возвращает не один кортеж, а сразу массив из них. + +Эта модель может показывать большую эффективность на современных процессорах, +потому что позволяет обрабатывать массивы данных без зависимости от управляющих +конструкций, таких как вызовы функций в итераторной модели. + +\subsubsection{Порядок обработки} + +Реализуют две модели: + +\begin{itemize} + \item сверху-вниз; + \item снизу-вверх. +\end{itemize} + +В модели сверху-вниз операторы запрашивают данные у своих потомков, что +предполагает вызовы функций. Здесь сложнее реализовать конкурентность в рамках +одного запроса, потому что оператор должен блокироваться на вызове +\verb|Next()|. + +В модели снизу-вверх данные передаются от потомков к родителям. Эта модель +позволяет добиться прироста к производительности засчет более эффективного +использование кэша процессора в конвейерном исполнении запроса. Минусами можно +назвать более сложность ограничения количества обрабатываемых кортежей и +сложность реализации некоторых операторов в целом. + +\subsubsection{Алгоритмы для реализации операторов реляционной алгебры} + +Для доступа к данным на диске реализуют следующие основные алгоритмы: + +\begin{itemize} + \item последовательное сканирование; + \item параллельное сканирование; + \item сканирование с использованием индекса. +\end{itemize} + +Последовательное сканирование итерируется по всем кортежам в одном потоке +исполнения. + +Параллельное сканирование использует несколько потоков, которые читают +непересекающиеся блоки таблиц. + +Сканирование с использованием индекса объединяет чтение таблицы и ее фильтрацию, +и использует для это индекс. Выбор подходящего индекса зависит от содержимого +таблицы и запроса, и может сильно ускорить чтение относительно последовательного +сканирования. + +Операторы проекции и фильтрации реализуются очевидным образом и не ограничивают +конвейеризированное выполнение. + +% TODO: sort, join, ... ? + +Выражения в SQL используются в качестве условий для фильтрации, проекции, +определения операции соединения и т.д. Они представляются в виде дерева, где +узлами являются операции и значения: + +\begin{enumerate} + \item операции сравнения: \verb|=, <, >, !=|; + \item логические операции: \verb|AND, OR и NOT|; + \item арифметические операции: \verb|+, -, *, /, %|; + \item константы; + \item атрибуты отношений. +\end{enumerate} + +Например, для выражения в запросе на листинге~\ref{lst:expression}, дерево +выглядит как на рисунке~\ref{fig:expression}. + +\begin{listing} + \caption{Пример запроса с выражением.} + \label{lst:expression} + \begin{minted}[style=bw, breaklines, frame=single, fontsize = \footnotesize, linenos=false, xleftmargin = 1.5em]{text} +SELECT * FROM users WHERE users.age > 33 + 1; + \end{minted} +\end{listing} + +\begin{figure}[H] + \centering + \begin{minipage}[t]{\textwidth} + \centering + \includegraphics[width=0.5\textwidth]{expression} + \end{minipage} + \caption{Дерево для вычисления выражения из примера на листинге~\ref{lst:expression}.}\label{fig:expression} +\end{figure} + +Чтобы вычислить значение такого выражения, СУБД хранит информацию о текущем +кортеже и схемах используемых таблиц. Затем производится обход дерева с +выполнением операторов снизу-вверх. Результатом вычислений считается результат +вычисления оператора в корневой вершине. + +Вычисление относительно сложных выражений происходит медленно, потому что каждый +оператор требует вызова функции, поэтому появляется множество вохможностей для +оптимазиции. Например: + +\begin{itemize} + \item JIT-компиляция; + \item векторизация; + \item сворачивание выражений с константами; + \item дедупликация. +\end{itemize} + +\subsection{JIT-компиляция} + +JIT-компиляция означает динамическую генерацию машинного кода под текущую +аппаратную платформу во время исполнения запроса. Это позволяет значительно +упростить само выражение, применяя различные оптимизации, от сворачивания +констант, до исключения повторяющихся или невозможных частей. Особенная +эффективность данного подхода наблюдается в аналитических запросах, которые +работают с большими объемами данных и зачастую вычисляют запросы со сложными +условиями фильтрации, агрегации и большим количеством производных данных. Также +в числе возможных оптимизаций вычисление сдвигов для доступа к атрибутам внутри +кортежей. + +Эту технику реализует большинство современных баз данных. Например, Postgres и +Clickhouse. + +Основным преимуществом является возможность использования для оптимизаций +данных, доступных во время выполнения запроса, таких как схемы таблиц и типы +атрибутов. Недостатком можно считать большие затраты по времени на компиляцию, +которые делают JIT-компиляцию нецелесообразной для несложных или затрагивающих +небольшое количество кортежей запросов. + +\section{Разработка модельной СУБД} + +В рамках данной работы была разработана модельная реляционная СУБД, +поддерживающая опциональную JIT-компиляцию выражений. + +% 3. >=8 Конструкторский ("разработка ...."): обоснованный выбор алгоритма, +% подробно его применение в данной задаче, проектирование архитектуры и +% интерфейсов + +\subsection{Парсер} + +В качестве синтаксиса SQL было выбрано подмножество синтаксиса PostgreSQL, как +наиболее популярного на данный момент. + +Из грамматики оставлены только \verb|SELECT| запросы, потому что в них зачастую +встречаются выражения и они представляют наибольший интерес для оптимизаций. +Также, именно запросы на чтение обычно автогенерируются системами визуализации +данных. Сокращенная версию грамматики для \verb|SELECT| запросов находится в +листингах~\ref{lst:grammar1}~-~\ref{lst:grammar5}. + +На вход парсер получает запрос в виде строки. На выходе в случае успешного +разбора получается синтаксическое дерево, а в случае ошибки или +неподдерживаемого запроса об этом сообщается пользователю. + +Так как полная грамматика SQL очень большая, было решено воспользоваться одним +из генераторов синтаксических и лексических анализаторов и взять для него +готовое определение грамматики PostgreSQL. + +Ограничение синтаксиса реализовано на уровне обхода дерева разбора. То есть при +обходе проверяется наличие неподдерживаемых узлов, и генерируется +соответствующая ошибка при их наличии. + +Грамматика \verb|SELECT| запросов ограничена операторами: + +\begin{itemize} + \item \verb|OUTER JOIN|; + \item \verb|INNER JOIN|; + \item \verb|WHERE|; + \item \verb|FROM|; + \item вычисления выражений. +\end{itemize} + +В выражениях разрешено использовать арифеметические и логические операции, а +также операторы сравнения. + +\subsection{Преобразование запроса в реляционную алгебру} + +После этапа лексического и синтаксического анализа, полученное дерево необходимо +преобразовать в представление в формате реляционной алгебры. Это достигается +засчет обхода дерева в глубину с применением паттерна ``Посетитель'' и возврата +соответствущих операторов реляционной алгебры вместо поддеревьев дерева разбора. + +Операторы представляются в виде алгебраического типа с возможностью ссылаться на +самого себя через указатели. Отношения представляются таким же интерфейсом, но +не ссылаются ни на какие другие операторы. Для запросов не использующих таблицы, +а лишь вычисляющих значения некоторых выражений предусматривается специальный +оператор означающий пустое отношение. + +Выражения, используемые внутри операторов также представляются в виде деревьев с +узлами в виде алгебраического типа и связями с помощью указателей. + +Типы выражений и атрибутов для простоты ограничиваются знаковым целочисленным и +логическим. Поддержку \verb|NULL| было решено выделить в отдельное поле +\verb|is_null|. + +В результате получается дерево, состоящее из операторов реляционной алгебры и +отношений в качестве листьев. Для отладки было решено реализовать его +визуализацию с помощью обхода в глубину и генерации кода на языке +dot~\refImage{fig:query-plan}. + +Разрешение имен в целях упрощения ограничено форматом +\verb|table_name.column_name|, где \verb|table_name| --- название отношения, а +\verb|column_name| --- имя атрибута. Атрибутам и отношениям нельзя назначить +имена. Таким образом, нельзя сослаться на производные атрибуты, а также +запрещены запросы с параметрами. + +Дальнейших преобразований запроса в формате реляционной алгебры предусмотрено не +было, так как это работа оптимизатора, что выходит за рамки работы и является +отдельной сложной темой. + +\subsection{Исполнение запросов} + +Далее, запрос необходимо исполнить. Для того, чтобы не увеличивать количество +внутренних представлений, запрос принято решение интерпретировать запрос +напрямую в форме реляционной алгебры. + +Модель исполнения была выбрана векторизированная. Это сделано для того, чтобы не +органичивать возможности параллельного исполнения в рамках одного запроса и +использовать потенциал современных процессоров по-максимуму. + +Порядок обработки был выбран снизу-вверх, а коммуникация между операторами +реализована с помощью потокобезопасных каналов, как в языке программирования Go. +Это упрощает рассуждения и уменьшает возможную площать для возникновения ошибок +в реализации. + +Таким образом, каждый оператор создает по отдельному каналу для кортежей и типов +атрибутов своих потомков. Затем вызывает их в цикле читает из канала +кортежи~\refImage{fig:query_execution}. Такая схема легко реализуется и +предполагает одинаковый интерфейс у всех операторов, что позволяет с легкостью +их комбинировать. + +\begin{figure}[H] + \centering + \begin{tikzpicture}[ + node distance=1.5cm, + every node/.style={draw, rectangle, minimum width=2.5cm, minimum height=1cm, align=center}, + arrow style/.style={line width=1pt, double distance=3pt, arrows = {-Latex[length=0pt 3 0]}}, + label node/.style={draw=none, rectangle=none, minimum width=0, minimum height=0} + ] + \begin{scope}[xshift=-4cm] + \node (users_left) at (0,0) {users}; + \node (groups_left) at (3.5,0) {groups}; + + \node[minimum width=4.5cm, minimum height=1.5cm] (join_left) at (1.75,2.5) {$\leftouterjoin$\\ON users.group\_id = groups.id}; + + \node[minimum width=4cm, minimum height=1.5cm] (filter_left) at (1.75,5.5) {$\sigma$\\users.age $>$ 18}; + + \node[minimum width=4cm, minimum height=1.5cm] (proj_left) at (1.75,8.5) {$\pi$\\users.id, groups.id}; + + \draw[arrow style] (users_left) -- node[label node, left, xshift=-0.5cm] {\scriptsize атрубуты} (join_left); + \draw[arrow style] (groups_left) -- node[label node, right, xshift=0.5cm] {\scriptsize атрубуты} (join_left); + \draw[arrow style] (join_left) -- node[label node, left, xshift=-0.5cm] {\scriptsize атрубуты} (filter_left); + \draw[arrow style] (filter_left) -- node[label node, left, xshift=-0.5cm] {\scriptsize атрубуты} (proj_left); + + \node[label node] at (1.75,10.5) {\textbf{Этап 1}}; + \end{scope} + + \begin{scope}[xshift=4cm] + \node (users_right) at (0,0) {users}; + \node (groups_right) at (3.5,0) {groups}; + + \node[minimum width=4.5cm, minimum height=1.5cm] (join_right) at (1.75,2.5) {$\leftouterjoin$\\ON users.group\_id = groups.id}; + + \node[minimum width=4cm, minimum height=1.5cm] (filter_right) at (1.75,5.5) {$\sigma$\\users.age $>$ 18}; + + \node[minimum width=4cm, minimum height=1.5cm] (proj_right) at (1.75,8.5) {$\pi$\\users.id, groups.id}; + + \draw[arrow style] (users_right) -- node[label node, left, xshift=-0.5cm] {\scriptsize кортежи} (join_right); + \draw[arrow style] (groups_right) -- node[label node, right, xshift=0.5cm] {\scriptsize кортежи} (join_right); + \draw[arrow style] (join_right) -- node[label node, left, xshift=-0.5cm] {\scriptsize кортежи} (filter_right); + \draw[arrow style] (filter_right) -- node[label node, left, xshift=-0.5cm] {\scriptsize кортежи} (proj_right); + + \node[label node] at (1.75,10.5) {\textbf{Этап 2}}; + \end{scope} + \end{tikzpicture} + \caption{Двухэтапное исполнение запроса.} +\label{fig:query_execution} +\end{figure} + +Во время первого этапа вычисляются атрибуты отношений на выходе каждого +оператора~\refImage{fig:op-tree-attrs}: + +\begin{itemize} + \item фильтрация сохраняет атрибуты; + \item соединение конкатенирует атрибуты двух участвующих отношений; + \item проекция вычисляет новые атрибуты в зависимости от типов использованных + выражений. +\end{itemize} + +\begin{figure}[H] + \centering + \begin{tikzpicture}[ + level distance=2.2cm, + sibling distance=3.8cm, + edge from parent/.style={draw,-{Stealth}}, + every node/.style={draw, rounded corners, align=center, inner sep=3pt} + ] + \node{Projection\\attrs: (users.id:int, int, bool)} + child { node{Filter\\attrs = (users.id:int, users.age:int)} + child { node{Table users\\attrs: (users.id:int, users.age:int)} } + }; + \end{tikzpicture} + \caption{Пример вычисления атрибутов при обходе дерева операторов.} + \label{fig:op-tree-attrs} +\end{figure} + +Аналогичный процесс происходит и при вычислении +выражений~\refImage{fig:expression-typed}. + +\begin{figure}[H] + \centering + \begin{tikzpicture}[ + level distance=1.1cm, + sibling distance=3.2cm, + edge from parent/.style={draw,-{Stealth}}, + every node/.style={draw, rounded corners, align=center, inner sep=3pt} + ] + \node{ $>$ : \textbf{bool} } + child { node{ users.age : \textbf{int} } } + child { node{ $+$ : \textbf{int} } + child { node{ 33 : \textbf{int} } } + child { node{ 1 : \textbf{int} } } + }; + \end{tikzpicture} + \caption{Пример вычисления типа результата операции.} + \label{fig:expression-typed} +\end{figure} + +\subsection{Модуль хранения данных} + +В целях простоты, а также ввиду реализации только запросов чтения, было решено +хранить данные в формате CSV (Comma-separated values) таблиц. Данный формат +легок в поддержке, и иделаьно подходит для реализации модельной СУБД в условиях +неизменяемости хранимых таблиц. + +Каждая таблица хранится в отдельном CSV файле, который начинается с заголовка, +определяющего названия и типы атрибутов. В следующих строках содержатся кортежи. +Для простоты решено поддержать только два типа атрибутов: целочисленный и +логический. Пример отношения \verb|users|, состоящего из двух атрибутов: +\verb|id| и \verb|age|, можно увидеть на листинге~\ref{lst:users_relation}. + +\begin{listing}[H] + \caption{Пример CSV файла, где хранится отношение users.} + \label{lst:users_relation} + \begin{minted}[style=bw, breaklines, frame=single, fontsize = \footnotesize, linenos=false, xleftmargin = 1.5em]{text} +id:int,age:int +1,33 +2,64 +3,22 +4,NULL +5,15 + \end{minted} +\end{listing} + +Для чтения данных из CSV файла применяется алгоритм последовательного +сканирования, ввиду удобства реализации и очевидной оценки сложности. + +\subsection{Алгоритмы для операторов реляционной алгебры} + +Первый и простейший оператор, проекция, реализуется с помощью цикла, отражающего +каждый кортеж в новый с нужными атрибутами~\refAlgo{lst:projection}. Это +работает, т.к. $A_{1}, \ldots, A_{n}$ --- выражения, которые могут включать +атрибуты, константы и операции над ними, что позволяет добавлять значения, +производные от существующих. + +\begin{listing}[H] + \caption{Алгоритм выполнения проекции.} + \label{lst:projection} + \begin{algorithmic}[1] + \Procedure{Projection}{$\pi_{A_1, \ldots, A_n}(R)$, $\text{out\_attr\_chan}$, $\text{out\_tuples\_chan}$} + \State $(\text{attrs}, \text{tuples}) \gets \text{Compute}(R)$ + \State $\text{out\_attr\_chan} \gets \text{map}(\text{GetExpressionType}, [A_1, \ldots, A_n])$ + \For{$\text{tuple} \in \text{tuples}$} + \For{$\text{expr} \in [A_1, \ldots, A_n]$} + \State $\text{out\_tuples\_chan} \gets \text{CalcExpression}(\text{expr}, \text{tuple})$ + \EndFor + \EndFor + \EndProcedure + \end{algorithmic} +\end{listing} + +Следующий оператор, фильтрация, реализуется аналогично~\refAlgo{lst:filtration}. Включать ли в результат +текущий кортеж определяет значение выражения над ним. + +\begin{listing}[H] + \caption{Алгоритм выполнения фильтрации.} + \label{lst:filtration} + \begin{algorithmic}[1] + \Procedure{Filter}{$\sigma_{\text{predicate}}(R)$, $\text{out\_attr\_chan}$, $\text{out\_tuples\_chan}$} + \State $(\text{attrs}, \text{tuples}) \gets \text{Compute}(R)$ + \State $\text{out\_attr\_chan} \gets \text{attrs}$ + \For{$\text{tuple} \in \text{tuples}$} + \If{$\text{CalcExpression}(\text{predicate}, \text{tuple}) = \text{true}$} + \State $\text{out\_tuples\_chan} \gets \text{tuple}$ + \EndIf + \EndFor + \EndProcedure + \end{algorithmic} +\end{listing} + +Оператор соединения реализуется с помощью материализации одного из отношений на +диск и последующего многократного чтения и объединения с кортежами из второго +отношения~\refAlgo{lst:cross-join}. + +\begin{listing}[H] + \caption{Алгоритм выполнения декартова произведения.} + \label{lst:cross-join} + \begin{algorithmic}[1] + \Procedure{CrossJoin}{$R_1 \times R_2$, $\text{out\_attr\_chan}$, $\text{out\_tuples\_chan}$} + \State $\text{out\_attr\_chan} \gets \text{Concat}(\text{attrs}_1, \text{attrs}_2)$ + \State $\text{materialized}_1 \gets \text{Materialize}(\text{Compute}(R_1))$ + \State $(\text{attrs}_2, \text{tuples}_2) \gets \text{Compute}(R_2)$ + \For{$\text{tuple}_2 \in \text{tuples}_2$} + \For{$\text{tuple}_1 \in \text{materialized}_1$} + \State $\text{joined} \gets \text{ConcatTuples}(\text{tuple}_1, \text{tuple}_2)$ + \State $\text{out\_tuples\_chan} \gets \text{joined}$ + \EndFor + \EndFor + \EndProcedure + \end{algorithmic} +\end{listing} + +Алгоритмы для \verb|OUTER| соединений аналоичны реализации \verb|INNER JOIN|, но +добавляют фильтрацию после генерации соединенных кортежей. + +Наибольший интерес представляет вычисление выражений, которое, как можно +заметить, используется в реализации операторов реляционной алгебры повсеместно. + +В случае вычисления выражения путем прямой интерпретации, необходимо рекурсией +обойти дерево, которым это выражение представлено, и вычислить каждую операцию. +Каждая вершина такого дерева требует вызов функции, что для больших и сложных +выражений, умножить на количество кортежей в отношении, выливается в большие +накладные расходы на рекурсию~\refAlgo{lst:expression-interpretation}. + +\begin{listing}[H] + \caption{Алгоритм интерпретации выражения.} + \label{lst:expression-interpretation} + \begin{algorithmic}[1] + \Function{CalcExpression}{$\text{expr}$, $\text{tuple}$, $\text{attrs}$} + \If{$\text{expr}$ --- бинарная операция $(lhs, op, rhs)$} + \State $\text{val}_1 \gets \textbf{\text{CalcExpression}}(lhs, \text{tuple}, \text{attrs})$ + \State $\text{val}_2 \gets \textbf{\text{CalcExpression}}(rhs, \text{tuple}, \text{attrs})$ + \State \Return $\text{ApplyOperator}(op, \text{val}_1, \text{val}_2)$ + \ElsIf{$\text{expr}$ --- унарная операция $(op, child)$} + \State $\text{val} \gets \textbf{\text{CalcExpression}}(child, \text{tuple}, \text{attrs})$ + \State \Return $\text{ApplyUnaryOperator}(op, \text{val})$ + \ElsIf{$\text{expr}$ --- атрибут $A$} + \State \Return $\text{Lookup}(A, \text{tuple}, \text{attrs})$ + \ElsIf{$\text{expr}$ --- константа $c$} + \State \Return $c$ + \ElsIf{$\text{expr}$ --- литерал $l$} + \State \Return $l$ + \EndIf + \EndFunction + \end{algorithmic} +\end{listing} + +\subsection{JIT-компиляция} + +Проблема высоких накладных расходов при рекурсивной интерпретации выражений +решается с помощью JIT-компиляции. Во время исполнения запроса, каждое выражение +перед исполнением компилируется в машинный код, что позволяет напрямую выполнить +набор инструкций для вычисления каждого выражения. + +Скомпилированный код кэшируется в словарь, а затем переиспользуется для +вычисления каждого выражения. + +В качестве фреймворка для JIT-компиляции был выбран LLVM, а в частности +современный интерфейс \verb|ORC v2|, ввиду наличия широкого набора +оптимизационных проходов, хорошей документации и понятного API для JIT. + +Скомпилированный код представляет собой функцию, которая принимает на вход +указатель на результат, указатель на кортеж и указатель на информацию о типах и +названиях атрибутов. Результат вычисления выражения записывается по +соответствующему указателю. + +Выражение вычисляется как комбинация операций эквивалентных исходному дереву. +Ветвления не используются в целях оптимизации. + +Выбраны следующие оптимизационные проходы из доступных в LLVM, актуальные для +данной задачи: + +\begin{itemize} + \item \verb|EarlyCSEPass| --- раннее устранение общих подвыражений; + \item \verb|SROAPass| --- скалярная замена агрегатов; + \item \verb|InstCombinePass| --- комбинирование инструкций, включая сворачивание констант; + \item \verb|SimplifyCFGPass| --- упрощение графа потока управления; + \item \verb|ReassociatePass| --- переассоциация выражений; + \item \verb|GVNPass| --- глобальная нумерация значений; + \item \verb|MemCpyOptPass| --- оптимизация копирований памяти; + \item \verb|SimplifyCFGPass| --- повторное упрощение графа потока управления; + \item \verb|InstCombinePass| --- повторное комбинирование инструкций; + \item \verb|ADCEPass| --- агрессивное удаление мёртвого кода. +\end{itemize} + +\verb|EarlyCSEPass| --- легковесный проход, который исключает дублирующие +вычисления, путем обхода дерева доминаторов. + +\verb|SROAPass| --- заменяет выделения памяти под структуры на скаляры, что +упрощает IR. + +\verb|InstCombinePass| --- кобинирует инструкции, делая алгебраические +преобразования. + +\verb|SimplifyCFGPass| --- убирает мертвый код. + +\verb|ReassociatePass| --- меняет местами операнды и делает некоторые +алгебраические преобразования, чтобы позволить другим проходам сделать +дополнительные оптимизации. + +\verb|GVNPass| --- убирает лишние, дублирующиеся, вычисления, где это возможно. + +\verb|MemCpyOptPass| --- оптимизирует некоторые копирования и инициализации. + +\verb|ADCEPass| --- удаляет мертвый код после всех других проходов. + +Вместе все эти проходы делают все возможные оптимизации для ускорения вычисления +выражений. + +\section{Реализация модельной СУБД} + +Для выполнения поставленной задачи необходимо реализовать парсер, преобразование +в реляционную алгебру, выполнение соответствующих операторов и JIT-компиляцию +выражений, а также модульные тесты и бенчмарки производительности. + +В качестве языка программирования использовался C++, ввиду следующих его +особенностей: + +\begin{itemize} + \item Высокая производительность. Современные СУБД обрабатывают огромные + потоки данных от миллионов клиентов, поэтому важны минимальное + потребление ресурсов и задержки. + \item Возможность работать на низком уровне. Ручное управление памятью и + прямая работа с системными вызовами открывает возможности для + оптимизаций и позволяет сделать время обработки запросов предсказуемым. + \item Поддержка ООП и RAII. Позволяет разрабатывать системный код читаемым и + поддерживаемым. + \item Широкий выбор библиотек для производительного сетевого взаимодействия и + бинарной сериализации данных. +\end{itemize} + +Все эти причины позволили C++ стать де-факто стандартным языком для реализации +СУБД. + +Разработка проекта осуществлялась в редакторе кода Emacs. Данный редактор может +быть использван в качестве IDE благодаря обширной библиотеке плагинов. + +Для сборки использовалось окружение NixOS. Этот дистрибутив Linux построен на +пакетном менеджере \verb|nix| и позволяет декларативно и воспроизводимо задавать +зависимости для каждого проекта, используя функциональный доменно-специфичный +язык. + +В качестве системы сборки использован CMake, а компилятором выступает clang с +поддержкой стандарта C++23. + +Для реализации конкурентной обработки запросов, были использованы C++20 корутины +в связке с boost::asio, так как это становится стандартным способом реализации +асинхронной модели в C++, и позволяет писать код, который выглядит линейно, но +исполняется конкурентно. + +\subsection{Особенности реализации парсера} + +Для реализации парсера был выбран ANTLR4, ввиду его удобства и возможности +генерировать лексические и синтаксические анализаторы под практически любой язык +программирования. + +Грамматика PostgreSQL была взята из официального репозитория проекта +ANTLR4~\cite{Antlr4PostgreSQL}. Она была портирована автоматически из грамматики +для Bison~\cite{PostgresBisonGrammar} из официального репозитория Postgres, +поэтому является наиболее полной из существующих. + +ANTLR4 генерирует несколько файлов на C++, в том числе лексический и +синтаксический анализаторы, а также класс \verb|Visitor| для обхода дерева +разбора. + +\verb|Visitor| в своем интерфейсе передает везде +\verb|std::any|~\refAlgo{lst:visit-where}, ввиду реализации кодогенератора +\verb|ANTLR4|. В объекте \verb|ctx| лежат ссылки на дочерние узлы дерева +разбора. Сгенерированный интерфейс позволяет удобно реализовать построение +внутреннего представления~\refAlgo{lst:visit-where-impl}. + +\begin{listing}[H] + \caption{Интерфейс функции для посещения правила Where.} + \label{lst:visit-where} + \begin{minted}[style=bw, breaklines, frame=single, fontsize = \footnotesize, linenos=false, xleftmargin = 1.5em]{C++} +virtual std::any visitWhere_clause(codegen::PostgreSQLParser::Where_clauseContext *ctx) override; + \end{minted} +\end{listing} + +Основная функция определяющая интерфейс парсера представлена в +листинге~\ref{lst:getAst}. Она принимает поток, откуда читает запрос, а +возвращает \verb|Operator|~\refAlgo{lst:operator}, который является деревом из +операторов реляционной алгебры. + +\begin{listing}[H] + \caption{Интерфейс парсера.} + \label{lst:getAst} + \begin{minted}[style=bw, breaklines, frame=single, fontsize = \footnotesize, linenos=false, xleftmargin = 1.5em]{C++} +Result GetAST(std::istream& in); + \end{minted} +\end{listing} + +\begin{listing}[H] + \caption{Типы Operator, Table и Projection.} + \label{lst:operator} + \begin{minted}[style=bw, breaklines, frame=single, fontsize = \footnotesize, linenos=false, xleftmargin = 1.5em]{C++} +using Operator = std::variant; + +struct Table { + std::string name; + auto operator<=>(const Table& other) const = default; +}; + +struct Projection { + std::vector expressions; + std::shared_ptr source; + bool operator==(const Projection& other) const; +}; + \end{minted} +\end{listing} + +\verb|Operator| реализован с помощью \verb|std::variant|. Связи с другими +операторами реализованы через \verb|std::shared_ptr|, что добавляет накладные +расходы на выделение памяти, но упрощает работу с данным алгебраическим типом. + +Выражения хранятся в алгебраическом типе \verb|Expression|, реализованном +аналогично \verb|Operator|. + +Функция \verb|GetAST| внутри строит абстрактное синтаксическое дерево и обходит +его с помощью \verb|Visitor|, который и генерирует представление запроса в виде +дерева из \verb|Operator|. + +Дополнительно реализована визуализация дерева из операторов реляционной алгебры +в формате Graphviz с помощью функции \verb|GetDotRepresentation|. + +\subsection{Особенности реализации хранения данных} + +Данные хранятся в одной директории, где каждому отношению соответствует файл с +CSV таблицей. Название файла совпадает с названием отношения. + +Для чтения таблиц реализован класс \verb|CsvDirSequentialScanner|~\refAlgo{lst:csv-dir-seq-scanner}. + +\begin{listing}[H] + \caption{Объявление класса CsvDirSequentialScanner.} + \label{lst:csv-dir-seq-scanner} + \begin{minted}[style=bw, breaklines, frame=single, fontsize = \footnotesize, linenos=false, xleftmargin = 1.5em]{C++} +struct CsvDirSequentialScanner { + std::string dir; + + boost::asio::awaitable> operator()(const std::string& table_name, + AttributesInfoChannel& attrs_chan, + TuplesChannel& tuples_chan) const; +}; + \end{minted} +\end{listing} + +\subsection{Особенности реализации исполнения запроса} + +За исполнение запросов отвечает класс \verb|Executor|~\refAlgo{lst:executor}. Он +реализует исполнение всего дерева операторов, и каждого оператора отдельно, с +помощью функций \verb|Execute|. + +\begin{listing}[H] + \caption{Объявление класса Executor.} + \label{lst:executor} + \begin{minted}[style=bw, breaklines, frame=single, fontsize = \footnotesize, linenos=false, xleftmargin = 1.5em]{C++} +template +class Executor { +public: + using SequentialScan = std::function>( + const std::string& table_name, AttributesInfoChannel& attr_chan, TuplesChannel& tuples_chan)>; + Executor(SequentialScan seq_scan, boost::asio::any_io_executor executor); + boost::asio::awaitable> Execute(const Operator& op); +private: + boost::asio::awaitable Execute(const Operator& op, AttributesInfoChannel& attr_chan, + TuplesChannel& tuples_chan); + boost::asio::awaitable ExecuteProjection(const Projection& proj, AttributesInfoChannel& attr_chan, + TuplesChannel& tuples_chan); +... + boost::asio::awaitable SpawnExecutor(const Operator& op, AttributesInfoChannel& attr_chan, TuplesChannel& tuple_chan); +private: + SequentialScan sequential_scan_; + ExpressionExecutor expression_executor_; +}; + \end{minted} +\end{listing} + +Этот класс параметризуется интерфейсами \verb|SequentialScan| и +\verb|ExpressionExecutor|. + +Первый служит для того, чтобы выбирать различные реализации чтения таблиц с +диска. + +\verb|ExpressionExecutor| является шаблонным параметром и нужен для выбора +реализации исполнения выражений. Реализовано три таких класса: + +\begin{itemize} + \item \verb|InterpretedExpressionExecutor| --- реализует обыкновенную + интерпретацию выражений с помощью рекурсии; + \item \verb|JitCompiledExpressionExecutor| --- реализует JIT-компиляцию + выражения; + \item + \verb|CachedJitCompiledExpressionExecutor|~\refAlgo{lst:cached-jit-executor} + --- кэширует результаты JIT-компиляции для переиспользования. +\end{itemize} + +\begin{listing}[H] + \caption{Объявление класса CachedJitCompiledExpressionExecutor.} + \label{lst:cached-jit-executor} + \begin{minted}[style=bw, breaklines, frame=single, fontsize = \footnotesize, linenos=false, xleftmargin = 1.5em]{C++} +using ExecExpression = std::function; +class CachedJitCompiledExpressionExecutor { + public: + explicit CachedJitCompiledExpressionExecutor(boost::asio::any_io_executor executor); + boost::asio::awaitable GetExpressionExecutor(const Expression& expr, const AttributesInfo& attrs); + private: + JITCompiler compiler_; + std::unordered_map cache_; +}; + \end{minted} +\end{listing} + +Значения внутри выражений передаются в виде объектов класса +\verb|Value|~\refAlgo{lst:value}. Этот класс состоит из флага \verb|is_null|, +означающего определено ли данное значение и объекта \verb|NonNullValue|, где +\verb|NonNullValue| --- объединение \verb|int64_t| и \verb|bool|. + +\begin{listing}[H] + \caption{Объявление класса Value.} + \label{lst:value} + \begin{minted}[style=bw, breaklines, frame=single, fontsize = \footnotesize, linenos=false, xleftmargin = 1.5em]{C++} +union NonNullValue { + int64_t int_value; + bool bool_value; +}; + +struct Value { + bool is_null; + NonNullValue value; + + bool operator==(const Value& other) const; +}; + \end{minted} +\end{listing} + +Отношения представлены в виде списка атрибутов и списка кортежей. Атрибуты +представлены в виде структуры с полями: имя таблицы, название атрибута и тип +атрибута. Кортеж --- вектор объектов класса \verb|Value|. + +Коммуникация между операторами осуществляется при помощи класса +\verb|boost::asio::concurrent_channel|. Он предоставляет интерфейс, схожий с +каналами в языке Go. Его особенности: + +\begin{itemize} + \item потокобезопасность; + \item буферизированность; + \item асинхронность при использовании \verb|async_read| и \verb|async_write|; + \item совместимость с корутинами. +\end{itemize} + +В модельной СУБД используется два типа каналов: \verb|TuplesChannel| для +передачи кортежей и \verb|AttributesChannel| для передачи атрибутов отношений~\refAlgo{lst:channels}. + +\begin{listing}[H] + \caption{Объявление алиасов для каналов.} + \label{lst:channels} + \begin{minted}[style=bw, breaklines, frame=single, fontsize = \footnotesize, linenos=false, xleftmargin = 1.5em]{C++} +using TuplesChannel = boost::asio::experimental::concurrent_channel< +void(boost::system::error_code, Tuples)>; +using AttributesInfoChannel = boost::asio::experimental::concurrent_channel< +void(boost::system::error_code, AttributesInfo)>; + \end{minted} +\end{listing} + +\subsection{Особенности реализации JIT-компиляции} + +JIT-компиляция происходит в классе +\verb|JITCompiler|~\refAlgo{lst:jit_compiler}. Метод \verb|CompileExpression| +принимает поддерево в реляционной алгебре и список доступных атрибутов, а +возвращает \verb|CompiledExpression| --- указатель на скомпилированную функцию, +которую можно по нему вызвать. + +\begin{listing}[H] + \caption{Объявление класса JITCompiler.} + \label{lst:jit_compiler} + \begin{minted}[style=bw, breaklines, frame=single, fontsize = \footnotesize, linenos=false, xleftmargin = 1.5em]{C++} +class JITCompiler { + public: + using CompiledExpression = void (*)(Value*, const Value*, const AttributeInfo*); + explicit JITCompiler(boost::asio::any_io_executor executor); + boost::asio::awaitable> + CompileExpression(const Expression& expr, const AttributesInfo& attrs); + private: + llvm::Function* GenerateIR(llvm::Module& llvm_module, const Expression& expr, + const AttributesInfo& attrs); + private: + std::unique_ptr jit_; + std::atomic id_; + boost::asio::strand jit_strand_; +}; + \end{minted} +\end{listing} + +В конструкторе~\refAlgo{lst:jit_compiler_constructor} производится настройка +оптимизирующих проходов и остальной инфраструктуры llvm. + +На примере класса \verb|GenerateIRVisitor|~\refAlgo{lst:ir_generator} можно +увидеть, как производится генерация LLVM IR. Здесь нет ветвлений и вызовов +функций, что позволяет генерировать оптимальный код, и делать это быстро. +Результат генерации после оптимизации для выражения на листинге~\ref{lst:expression_for_ir} можно увидеть на +листинге~\ref{lst:ir_example}. + +\begin{listing}[H] + \caption{Пример выражения.} + \label{lst:expression_for_ir} + \begin{minted}[style=bw, breaklines, frame=single, fontsize = \footnotesize, linenos=false, xleftmargin = 1.5em]{text} +users.age > 30 AND users.age < 60 OR users.age = 10; + \end{minted} +\end{listing} + +\begin{listing}[H] + \caption{LLVM IR для примера на листинге~\ref{lst:expression_for_ir}.} + \label{lst:ir_example} + \begin{minted}[style=bw, breaklines, frame=single, fontsize = \footnotesize, linenos=false, xleftmargin = 1.5em]{text} +; ModuleID = 'expr_module_0' +source_filename = "expr_module_0" +target datalayout = "e-m:e-p270:32:32-p271:32\ +:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" + +%Value = type { i8, i64 } + +define void @eval_expr_1(ptr noalias %0, ptr %1, ptr %2) { +entry: + %struct_ptr = getelementptr inbounds nuw i8, ptr %1, i64 16 + %loaded_struct = load %Value, ptr %struct_ptr, align 8 + %value.is_null = extractvalue %Value %loaded_struct, 0 + %is_null = icmp ne i8 %value.is_null, 0 + %value.value = extractvalue %Value %loaded_struct, 1 + %is_null_i8 = zext i1 %is_null to i8 + %result.with_is_null = insertvalue %Value undef, i8 %is_null_i8, 0 + %3 = add i64 %value.value, -31 + %4 = icmp ult i64 %3, 29 + %5 = icmp eq i64 %value.value, 10 + %6 = or i1 %5, %4 + %i1_to_i64_zext38 = zext i1 %6 to i64 + %result41 = insertvalue %Value %result.with_is_null, i64 %i1_to_i64_zext38, 1 + store %Value %result41, ptr %0, align 8 + ret void +} + \end{minted} +\end{listing} + +\section{Тестирование} + +Тестирование разработанной модельной СУБД осуществлялось с помощью модульных +тестов. Также для замеров производительности были реализованы бенчмарки. + +\subsection{Модульные тесты} + +Модульные тесты реализованы с использованием библиотеки googletests и проверяют +корректность реализации основных классов в парсере и исполнителе выражений. + +Пример такого теста приведен в листинге~\ref{lst:googletest}. + +\begin{listing}[H] + \caption{Пример модульного теста.} + \label{lst:googletest} + \begin{minted}[style=bw, breaklines, frame=single, fontsize = \footnotesize, linenos=false, xleftmargin = 1.5em]{cpp} +TEST(ParserTest, SelectSingleColumnFromSingleTable) { + std::stringstream s{"SELECT users.id FROM users;"}; + + Operator got = GetAST(s).value(); + + ASSERT_THAT(got, VariantWith( + Projection{std::vector{ + {Attribute{"users", "id"}}}, + std::make_shared(Table{"users"})})); +} + \end{minted} +\end{listing} + +\subsection{Бенчмарки} + +Тесты производительности реализованы с помощью библиотеки google benchmarks. Они +служат для измерения производительности \verb|SELECT| запросов с JIT-компиляцией +и без в различных профилях нагрузки и с различными настройками. Пример такого +бенчмарка можно увидеть в листинге~\ref{lst:bench}. + +\begin{listing}[H] + \caption{Пример бенчмарка.} + \label{lst:bench} + \begin{minted}[style=bw, breaklines, frame=single, fontsize = \footnotesize, linenos=false, xleftmargin = 1.5em]{cpp} +template +void BM_SQL(benchmark::State& state) { + std::ofstream nullstream("/dev/null"); + std::clog.rdbuf(nullstream.rdbuf()); + boost::asio::io_context ctx; + boost::asio::co_spawn( + ctx, + [&state]() -> boost::asio::awaitable { + std::stringstream s{Query}; + Operator op = GetAST(s).value(); + CsvDirSequentialScanner seq_scan{kProjectDir + "/test/static/executor/test_data"}; + Executor executor( + std::move(seq_scan), + co_await boost::asio::this_coro::executor + ); + benchmark::DoNotOptimize(co_await executor.Execute(op)); + for (auto _ : state) { + benchmark::DoNotOptimize(co_await executor.Execute(op)); + } + }(), + [](std::exception_ptr p) {}); + ctx.run(); +} + \end{minted} +\end{listing} + +При дебаге проблем с производительностью также было удобно пользоваться утилитой +\verb|perf|, с помощью которой были построены и проанализированы ``флеймграфы''. + +Далее, с помощью \verb|Python| и библиотеки \verb|pandas| были проанализированы +результаты выполнения бенчмарков~\refImage{fig:perf}. На рисунке по оси абсцисс +изображен условный размер используемых отображений в количестве кортежей. Как +можно увидеть на рисунке~\ref{fig:speedup}, на среднем количестве кортежей, где +не так сильно влияет время на чтение и запись на диск, получается около $30\%$ +прироста к производительности. + +\newpage +\anonsection{ЗАКЛЮЧЕНИЕ} %Заключение + +В ходе выполнения курсовой работы была разработана модельная реляционная СУБД с +поддержкой опциональной JIT-компиляции выражений, реализация проверена с помощью +модульных тестов, а также проведены измерения производительности. + +Цель курсовой работы была достигнута. Получена стабильная система, +демонстрирующая возможности JIT-компиляции для оптимизации запросов на чтение. + +В заключение, несмотря на достигнутые положительные результаты, существует +потенциал для дальнейшего улучшения реализации модельной СУБД. Это включает в +себя поддержку большего объема синтаксиса языка SQL, а также реализация более +продвинутых вариаций алгоритмов для основных операций реляционной алгебры. + +\newpage +\renewcommand\refname{СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ} +% Список литературы +\clearpage +\phantomsection +\addcontentsline{toc}{section}{\protect\numberline{}\refname} +%\bibliographystyle{ugost2008s} %utf8gost71u.bst} %utf8gost705u} %gost2008s} +{\catcode`"\active\def"{\relax} +% \bibliography{biblio2} +\printbibliography +} +\newpage +\settocdepth{section} +\anonsection{ПРИЛОЖЕНИЕ А} +\vspace{-30pt} + +\begin{listing}[H] + \caption{Реализация конструктора класса JITCompiler.} + \label{lst:jit_compiler_constructor} + \inputminted[style=bw, breaklines, frame=single, fontsize = \footnotesize, linenos=false, xleftmargin = 1.5em]{cpp}{./listings/jit_compiler_constructor.cpp} +\end{listing} + +\begin{listing}[H] + \caption{Класс GenerateIRVisitor} + \label{lst:ir_generator} + \inputminted[style=bw, breaklines, frame=single, fontsize = \footnotesize, linenos=false, xleftmargin = 1.5em]{cpp}{./listings/ir_generator.cpp} +\end{listing} + +\begin{listing}[H] + \caption{Реализация функции для посещения правила Where.} + \label{lst:visit-where-impl} + \begin{minted}[style=bw, breaklines, frame=single, fontsize = \footnotesize, linenos=false, xleftmargin = 1.5em]{C++} +std::any Visitor::visitWhere_clause( + codegen::PostgreSQLParser::Where_clauseContext *ctx + ) { + auto where_expr = std::any_cast(visit(ctx->a_expr())); + return Operator{Filter{where_expr, nullptr}}; +} + \end{minted} +\end{listing} + +\begin{figure}[H] + \centering + \begin{minipage}[t]{\textwidth} + \centering + \includegraphics[width=\textwidth]{perf} + \end{minipage} + \caption{Результаты бенчмарков.}\label{fig:perf} +\end{figure} + +\begin{figure}[H] + \centering + \begin{minipage}[t]{\textwidth} + \centering + \includegraphics[width=\textwidth]{speedup} + \end{minipage} + \caption{Относительный прирост производительности.}\label{fig:speedup} +\end{figure} + +\begin{listing}[H] + \caption{Грамматика для SELECT (часть 1).} + \label{lst:grammar1} + \inputminted[style=bw, breaklines, frame=single, fontsize = \footnotesize, linenos=false, xleftmargin = 1.5em]{cpp}{./listings/grammar1.g4} +\end{listing} + +\begin{listing}[H] + \caption{Грамматика для SELECT (часть 2).} + \label{lst:grammar2} + \inputminted[style=bw, breaklines, frame=single, fontsize = \footnotesize, linenos=false, xleftmargin = 1.5em]{cpp}{./listings/grammar2.g4} +\end{listing} + +\begin{listing}[H] + \caption{Грамматика для SELECT (часть 3).} + \label{lst:grammar3} + \inputminted[style=bw, breaklines, frame=single, fontsize = \footnotesize, linenos=false, xleftmargin = 1.5em]{cpp}{./listings/grammar3.g4} +\end{listing} + +\begin{listing}[H] + \caption{Грамматика для SELECT (часть 4).} + \label{lst:grammar4} + \inputminted[style=bw, breaklines, frame=single, fontsize = \footnotesize, linenos=false, xleftmargin = 1.5em]{cpp}{./listings/grammar4.g4} +\end{listing} + +\begin{listing}[H] + \caption{Грамматика для SELECT (часть 5).} + \label{lst:grammar5} + \inputminted[style=bw, breaklines, frame=single, fontsize = \footnotesize, linenos=false, xleftmargin = 1.5em]{cpp}{./listings/grammar5.g4} +\end{listing} + +\end{document} diff --git a/report/speedup.png b/report/speedup.png new file mode 100644 index 0000000..feb077d Binary files /dev/null and b/report/speedup.png differ diff --git a/src/stewkk/sql/CMakeLists.txt b/src/stewkk/sql/CMakeLists.txt new file mode 100644 index 0000000..be6ee2a --- /dev/null +++ b/src/stewkk/sql/CMakeLists.txt @@ -0,0 +1,68 @@ +include(FetchAntlr4) +include(SetupLLVM) +include(FetchBoost) + +add_definitions(-DANTLR4CPP_STATIC) + +add_library(libsql + logic/parser/codegen/PostgreSQLLexer.cpp + logic/parser/codegen/PostgreSQLParser.cpp + logic/parser/codegen/PostgreSQLParserBaseListener.cpp + logic/parser/codegen/PostgreSQLParserBaseVisitor.cpp + logic/parser/codegen/PostgreSQLParserListener.cpp + logic/parser/codegen/PostgreSQLParserVisitor.cpp + logic/parser/PostgreSQLLexerBase.cpp + logic/parser/PostgreSQLParserBase.cpp + logic/parser/parser.cpp + logic/parser/visitor.cpp + models/parser/relational_algebra_ast.cpp + logic/result/error.cpp + logic/result/result.cpp + logic/executor/executor.cpp + logic/executor/sequential_scan.cpp + models/executor/tuple.cpp + logic/executor/materialization.cpp + logic/executor/llvm.cpp +) +add_library(stewkk::libsql ALIAS libsql) +target_compile_features(libsql PUBLIC cxx_std_23) +set_target_properties(libsql PROPERTIES + CXX_STANDART 23 + CXX_STANDART_REQUIRED YES + CXX_EXTENSIONS YES +) +set_target_properties(libsql PROPERTIES OUTPUT_NAME stewkk_sql) +target_include_directories( + libsql PUBLIC $ + $ + ${ANTLR4_INCLUDE_DIRS} + ${LLVM_INCLUDE_DIRS} + $ + $ + $ +) +target_compile_options(libsql PRIVATE ${BASE_COMPILE_FLAGS}) +target_link_options(libsql PRIVATE ${BASE_LINK_FLAGS}) +llvm_map_components_to_libnames(llvm_libs Support Core IRReader OrcJIT X86CodeGen X86AsmParser X86Desc X86Info) +target_link_directories(libsql PUBLIC ${LLVM_LIBRARY_DIRS}) +target_link_libraries(libsql PRIVATE + antlr4_static + ${llvm_libs} + Boost::asio + Boost::thread + Boost::filesystem +) + +add_executable(sql + main.cpp +) +target_compile_features(sql PRIVATE cxx_std_23) +set_target_properties(sql PROPERTIES + CXX_STANDART 23 + CXX_STANDART_REQUIRED YES + CXX_EXTENSIONS YES +) +target_compile_options(sql PRIVATE ${BASE_COMPILE_FLAGS}) +target_link_libraries(sql PRIVATE + libsql +) diff --git a/src/stewkk/sql/logic/executor/executor.cpp b/src/stewkk/sql/logic/executor/executor.cpp new file mode 100644 index 0000000..322a550 --- /dev/null +++ b/src/stewkk/sql/logic/executor/executor.cpp @@ -0,0 +1,348 @@ +#include + +namespace stewkk::sql { + +Type GetExpressionType(const Expression& expr, const AttributesInfo& available_attrs) { + struct ExpressionTypeVisitor { + Type operator()(const BinaryExpression& binop) const { + auto lhs_type = std::visit(*this, *binop.lhs); + auto rhs_type = std::visit(*this, *binop.rhs); + if (lhs_type != rhs_type) { + throw std::logic_error{"types mismatch"}; + } + if (std::ranges::contains(std::vector{BinaryOp::kPlus, BinaryOp::kMinus, BinaryOp::kMul, + BinaryOp::kDiv, BinaryOp::kMod, BinaryOp::kPow}, + binop.binop)) { + if (lhs_type != Type::kInt) { + throw std::logic_error{"types mismatch"}; + } + return Type::kInt; + } + return Type::kBool; + } + Type operator()(const UnaryExpression& unop) const { + auto child_type = std::visit(*this, *unop.child); + if (unop.op == UnaryOp::kMinus) { + if (child_type != Type::kInt) { + throw std::logic_error{"types mismatch"}; + } + return Type::kInt; + } + if (child_type != Type::kBool) { + throw std::logic_error{"types mismatch"}; + } + return Type::kBool; + } + Type operator()(const IntConst& iconst) const { + return Type::kInt; + } + Type operator()(const Literal& literal) const { + // NOTE: we are using switch because compiler will remind about adding + // type of new literal here + switch (literal) { + case Literal::kNull: + return Type::kBool; + case Literal::kTrue: + return Type::kBool; + case Literal::kFalse: + return Type::kBool; + case Literal::kUnknown: + return Type::kBool; + } + } + Type operator()(const Attribute& attr) const { + auto it = std::find_if(available_attrs.begin(), available_attrs.end(), + [&attr](const AttributeInfo& attr_info) { + return attr_info.name == attr.name && attr_info.table == attr.table; + }); + if (it != available_attrs.end()) { + return it->type; + } + throw std::logic_error{"no such attribute"}; + } + + const AttributesInfo& available_attrs; + }; + return std::visit(ExpressionTypeVisitor{available_attrs}, expr); +} + +Type GetExpressionTypeUnchecked(const Expression& expr, const AttributesInfo& available_attrs) { + struct ExpressionTypeVisitor { + Type operator()(const BinaryExpression& binop) const { + if (std::ranges::contains(std::vector{BinaryOp::kPlus, BinaryOp::kMinus, BinaryOp::kDiv, + BinaryOp::kMod, BinaryOp::kPow}, + binop.binop)) { + return Type::kInt; + } + return Type::kBool; + } + Type operator()(const UnaryExpression& unop) const { + if (unop.op == UnaryOp::kMinus) { + return Type::kInt; + } + return Type::kBool; + } + Type operator()(const IntConst& iconst) const { + return Type::kInt; + } + Type operator()(const Literal& literal) const { + switch (literal) { + case Literal::kNull: + return Type::kBool; + case Literal::kTrue: + return Type::kBool; + case Literal::kFalse: + return Type::kBool; + case Literal::kUnknown: + return Type::kBool; + } + } + Type operator()(const Attribute& attr) const { + auto it = std::find_if(available_attrs.begin(), available_attrs.end(), + [&attr](const AttributeInfo& attr_info) { + return attr_info.name == attr.name && attr_info.table == attr.table; + }); + if (it != available_attrs.end()) { + return it->type; + } + throw std::logic_error{"no such attribute"}; + } + + const AttributesInfo& available_attrs; + }; + return std::visit(ExpressionTypeVisitor{available_attrs}, expr); +} + +AttributesInfo GetAttributesAfterProjection(const AttributesInfo& attrs, const Projection& proj) { + AttributesInfo result_attributes; + result_attributes.reserve(proj.expressions.size()); + for (const auto& target : proj.expressions) { + AttributeInfo projection_result; + projection_result.type = GetExpressionType(target, attrs); + if (const Attribute* attr = std::get_if(&target)) { + projection_result.name = std::move(attr->name); + projection_result.table = std::move(attr->table); + } + result_attributes.push_back(std::move(projection_result)); + } + return result_attributes; +} + +Value CalcExpression(const Tuple& source, const AttributesInfo& source_attrs, const Expression& expr) { + struct ExpressionVisitor { + Value operator()(const BinaryExpression& expr) { + auto lhs = std::visit(*this, *expr.lhs); + auto rhs = std::visit(*this, *expr.rhs); + switch (expr.binop) { + case BinaryOp::kGt: + if (GetExpressionTypeUnchecked(*expr.lhs, source_attrs) == Type::kBool) { + return ApplyBooleanOperator>(std::move(lhs), std::move(rhs)); + } + return ApplyIntegersOperator, bool>(std::move(lhs), std::move(rhs)); + case BinaryOp::kLt: + if (GetExpressionTypeUnchecked(*expr.lhs, source_attrs) == Type::kBool) { + return ApplyBooleanOperator>(std::move(lhs), std::move(rhs)); + } + return ApplyIntegersOperator, bool>(std::move(lhs), std::move(rhs)); + case BinaryOp::kLe: + if (GetExpressionTypeUnchecked(*expr.lhs, source_attrs) == Type::kBool) { + return ApplyBooleanOperator>(std::move(lhs), std::move(rhs)); + } + return ApplyIntegersOperator, bool>(std::move(lhs), std::move(rhs)); + case BinaryOp::kGe: + if (GetExpressionTypeUnchecked(*expr.lhs, source_attrs) == Type::kBool) { + return ApplyBooleanOperator>(std::move(lhs), std::move(rhs)); + } + return ApplyIntegersOperator, bool>(std::move(lhs), std::move(rhs)); + case BinaryOp::kNotEq: + if (GetExpressionTypeUnchecked(*expr.lhs, source_attrs) == Type::kBool) { + return ApplyBooleanOperator>(std::move(lhs), std::move(rhs)); + } + return ApplyIntegersOperator, bool>(std::move(lhs), std::move(rhs)); + case BinaryOp::kEq: + if (GetExpressionTypeUnchecked(*expr.lhs, source_attrs) == Type::kBool) { + return ApplyBooleanOperator>(std::move(lhs), std::move(rhs)); + } + return ApplyIntegersOperator, bool>(std::move(lhs), std::move(rhs)); + case BinaryOp::kOr: + return ApplyBooleanOperator>(std::move(lhs), std::move(rhs)); + case BinaryOp::kAnd: + return ApplyBooleanOperator>(std::move(lhs), std::move(rhs)); + case BinaryOp::kPlus: + return ApplyIntegersOperator, int64_t>(std::move(lhs), std::move(rhs)); + case BinaryOp::kMinus: + return ApplyIntegersOperator, int64_t>(std::move(lhs), std::move(rhs)); + case BinaryOp::kMul: + return ApplyIntegersOperator, int64_t>(std::move(lhs), std::move(rhs)); + case BinaryOp::kDiv: + return ApplyIntegersOperator, int64_t>(std::move(lhs), std::move(rhs)); + case BinaryOp::kMod: + return ApplyIntegersOperator, int64_t>(std::move(lhs), std::move(rhs)); + case BinaryOp::kPow: + return ApplyIntegersOperator(std::move(lhs), std::move(rhs)); + } + } + Value operator()(const UnaryExpression& expr) { + auto child = std::visit(*this, *expr.child); + + switch (expr.op) { + case UnaryOp::kNot: + if (child.is_null) { + return Value{true}; + } + if (child.value.bool_value) { + return Value{false, false}; + } + return Value{false, true}; + case UnaryOp::kMinus: + if (child.is_null) { + return Value{true}; + } + return Value{false, -child.value.int_value}; + } + } + Value operator()(const Attribute& expr) { + auto it = std::find_if(source_attrs.begin(), source_attrs.end(), + [&expr](const AttributeInfo& attr_info) { + return attr_info.name == expr.name && attr_info.table == expr.table; + }); + // NOTE: already checked in GetExpressionType + auto index = it - source_attrs.begin(); + return source[index]; + } + Value operator()(const IntConst& expr) { + return Value{false, expr}; + } + Value operator()(const Literal& expr) { + switch (expr) { + case Literal::kNull: + return Value{true}; + case Literal::kTrue: { + return Value{false, true}; + } + case Literal::kFalse: { + return Value{false, false}; + } + case Literal::kUnknown: { + return Value{true}; + } + } + } + + const AttributesInfo& source_attrs; + const Tuple& source; + }; + + return std::visit(ExpressionVisitor{source_attrs, source}, expr); +} + +Tuple ApplyProjection(const Tuple& source, const AttributesInfo& source_attrs, const std::vector& expressions) { + return expressions | std::views::transform([&](const auto& expression) { + return expression(source, source_attrs); + }) | std::ranges::to(); +} + +bool ApplyFilter(const Tuple& source, const AttributesInfo& source_attrs, const ExecExpression& filter) { + auto v = filter(source, source_attrs); + if (v.is_null) { + return false; + } + return v.value.bool_value; +} + +boost::asio::awaitable> GetChannels() { + auto executor = co_await boost::asio::this_coro::executor; + co_return std::make_pair(AttributesInfoChannel{executor, 1}, TuplesChannel{executor, 1}); +} + +boost::asio::awaitable ReceiveTuples(TuplesChannel& chan) { + Tuples buf; + try { + buf = co_await chan.async_receive(boost::asio::use_awaitable); + } catch (const boost::system::system_error& ex) {} + co_return buf; +} + +boost::asio::awaitable ConcatAttrs(AttributesInfoChannel& lhs_attrs_chan, AttributesInfoChannel& rhs_attrs_chan) { + auto attrs = co_await lhs_attrs_chan.async_receive(boost::asio::use_awaitable); + auto rhs_attrs = co_await rhs_attrs_chan.async_receive(boost::asio::use_awaitable); + std::ranges::copy(std::move(rhs_attrs), std::back_inserter(attrs)); + co_return attrs; +} + +boost::asio::awaitable MaterializeChannel(TuplesChannel& tuples_chan) { + DiskFileWriter writer; + for (;;) { + auto buf = co_await ReceiveTuples(tuples_chan); + if (buf.empty()) { + break; + } + writer.Write(buf); + } + + co_return std::move(writer).GetDiskFileReader(); +} + +Tuple ConcatTuples(const Tuple& lhs, const Tuple& rhs) { + Tuple joined_tuple; + joined_tuple.reserve(lhs.size() + rhs.size()); + std::ranges::copy(lhs, std::back_inserter(joined_tuple)); + std::ranges::copy(rhs, std::back_inserter(joined_tuple)); + return joined_tuple; +} + +boost::asio::awaitable InterpretedExpressionExecutor::GetExpressionExecutor(const Expression& expr, const AttributesInfo& attrs) { + struct Executor { + Value operator()(const Tuple& source, const AttributesInfo& source_attrs) { + return CalcExpression(source, source_attrs, expr); + } + + const Expression& expr; + }; + co_return Executor{expr}; +} + +boost::asio::awaitable JitCompiledExpressionExecutor::GetExpressionExecutor(const Expression& expr, const AttributesInfo& attrs) { + struct Executor { + Value operator()(const Tuple& source, const AttributesInfo& source_attrs) { + Value result; + compiled_expr(&result, source.data(), source_attrs.data()); + return result; + } + + JITCompiler::CompiledExpression compiled_expr; + llvm::orc::ResourceTrackerSP guard; + }; + auto [compiled_expr, guard] = co_await compiler_.CompileExpression(expr, attrs); + co_return Executor{std::move(compiled_expr), std::move(guard)}; +} + +JitCompiledExpressionExecutor::JitCompiledExpressionExecutor(boost::asio::any_io_executor executor) : compiler_(executor) {} + +InterpretedExpressionExecutor::InterpretedExpressionExecutor(boost::asio::any_io_executor executor) {} + +boost::asio::awaitable CachedJitCompiledExpressionExecutor::GetExpressionExecutor(const Expression& expr, const AttributesInfo& attrs) { + auto expr_str = ToString(expr); + if (auto it = cache_.find(expr_str); it != cache_.end()) { + co_return it->second; + } + + struct Executor { + Value operator()(const Tuple& source, const AttributesInfo& source_attrs) { + Value result; + compiled_expr(&result, source.data(), source_attrs.data()); + return result; + } + + JITCompiler::CompiledExpression compiled_expr; + llvm::orc::ResourceTrackerSP guard; + }; + auto [compiled_expr, guard] = co_await compiler_.CompileExpression(expr, attrs); + auto executor = Executor{std::move(compiled_expr), std::move(guard)}; + cache_[expr_str] = executor; + co_return executor; +} + +CachedJitCompiledExpressionExecutor::CachedJitCompiledExpressionExecutor(boost::asio::any_io_executor executor) : compiler_(executor) {} + +} // namespace stewkk::sql diff --git a/src/stewkk/sql/logic/executor/executor_test.cpp b/src/stewkk/sql/logic/executor/executor_test.cpp new file mode 100644 index 0000000..73e182e --- /dev/null +++ b/src/stewkk/sql/logic/executor/executor_test.cpp @@ -0,0 +1,315 @@ +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +using ::testing::Eq; + +namespace stewkk::sql { + +const static std::string kProjectDir = std::getenv("PWD"); + +namespace { + +std::string ReadFromFile(std::filesystem::path path) { + std::ifstream f{path}; + std::ostringstream stream; + stream << f.rdbuf(); + return stream.str(); +} + +} // namespace + +template +class ExecutorTest : public testing::Test {}; + +TYPED_TEST_SUITE_P(ExecutorTest); + +TEST(ExecutorTest, SimpleSelect) { + boost::asio::io_context ctx; + boost::asio::co_spawn( + ctx, + []() -> boost::asio::awaitable> { + std::stringstream s{"SELECT * FROM users;"}; + Operator op = GetAST(s).value(); + CsvDirSequentialScanner seq_scan{kProjectDir + "/test/static/executor/test_data"}; + Executor executor(std::move(seq_scan), co_await boost::asio::this_coro::executor); + + auto got = co_await executor.Execute(op); + + co_return got; + }(), + [](std::exception_ptr p, Result got) { + if (p) std::rethrow_exception(p); + + ASSERT_THAT(got.value().attributes, + Eq(AttributesInfo{{"users", "id", Type::kInt}, {"users", "age", Type::kInt}})); + ASSERT_THAT(got.value().tuples[0], Eq(Tuple{Value{false, 1}, Value{false, 33}})); + ASSERT_THAT(got.value().tuples.size(), Eq(17)); + }); + + ctx.run(); +} + +TEST(ExecutorTest, SimpleSelectWithParallelism) { + boost::asio::thread_pool pool{4}; + boost::asio::co_spawn( + pool, + []() -> boost::asio::awaitable> { + std::stringstream s{"SELECT * FROM users;"}; + Operator op = GetAST(s).value(); + CsvDirSequentialScanner seq_scan{kProjectDir + "/test/static/executor/test_data"}; + Executor executor(std::move(seq_scan), co_await boost::asio::this_coro::executor); + + auto got = co_await executor.Execute(op); + + co_return got; + }(), + [](std::exception_ptr p, Result got) { + if (p) std::rethrow_exception(p); + + ASSERT_THAT(got.value().attributes, + Eq(AttributesInfo{{"users", "id", Type::kInt}, {"users", "age", Type::kInt}})); + ASSERT_THAT(got.value().tuples[0], Eq(Tuple{Value{false, 1}, Value{false, 33}})); + ASSERT_THAT(got.value().tuples.size(), Eq(17)); + }); + + pool.join(); +} + +TYPED_TEST_P(ExecutorTest, Projection) { + boost::asio::thread_pool pool{4}; + boost::asio::co_spawn( + pool, + []() -> boost::asio::awaitable> { + std::stringstream s{"SELECT users.id FROM users;"}; + Operator op = GetAST(s).value(); + CsvDirSequentialScanner seq_scan{kProjectDir + "/test/static/executor/test_data"}; + Executor executor(std::move(seq_scan), co_await boost::asio::this_coro::executor); + + auto got = co_await executor.Execute(op); + + co_return got; + }(), + [](std::exception_ptr p, Result got) { + if (p) std::rethrow_exception(p); + + ASSERT_THAT(got.value().attributes, + Eq(AttributesInfo{{"users", "id", Type::kInt}})); + ASSERT_THAT(got.value().tuples[1], Eq(Tuple{Value{false, 2}})); + ASSERT_THAT(got.value().tuples.size(), Eq(17)); + }); + + pool.join(); +} + +TYPED_TEST_P(ExecutorTest, Filter) { + boost::asio::thread_pool pool{4}; + boost::asio::co_spawn( + pool, + []() -> boost::asio::awaitable> { + std::stringstream s{"SELECT users.id FROM users WHERE users.age < 10;"}; + Operator op = GetAST(s).value(); + CsvDirSequentialScanner seq_scan{kProjectDir + "/test/static/executor/test_data"}; + Executor executor(std::move(seq_scan), co_await boost::asio::this_coro::executor); + + auto got = co_await executor.Execute(op); + + co_return got; + }(), + [](std::exception_ptr p, Result got) { + if (p) std::rethrow_exception(p); + + ASSERT_THAT(got.value().attributes, + Eq(AttributesInfo{{"users", "id", Type::kInt}})); + ASSERT_THAT(got.value().tuples[0], Eq(Tuple{Value{false, 5}})); + ASSERT_THAT(got.value().tuples.size(), Eq(2)); + }); + + pool.join(); +} + +TYPED_TEST_P(ExecutorTest, FilterMany) { + boost::asio::thread_pool pool{4}; + boost::asio::co_spawn( + pool, + []() -> boost::asio::awaitable> { + std::stringstream s{"SELECT users.id FROM users WHERE users.age > 10;"}; + Operator op = GetAST(s).value(); + CsvDirSequentialScanner seq_scan{kProjectDir + "/test/static/executor/test_data"}; + Executor executor(std::move(seq_scan), co_await boost::asio::this_coro::executor); + + auto got = co_await executor.Execute(op); + + co_return got; + }(), + [](std::exception_ptr p, Result got) { + if (p) std::rethrow_exception(p); + + ASSERT_THAT(got.value().attributes, + Eq(AttributesInfo{{"users", "id", Type::kInt}})); + ASSERT_THAT(got.value().tuples[0], Eq(Tuple{Value{false, 1}})); + ASSERT_THAT(got.value().tuples.size(), Eq(15)); + }); + + pool.join(); +} + +TYPED_TEST_P(ExecutorTest, CrossJoin) { + boost::asio::thread_pool pool{4}; + boost::asio::co_spawn( + pool, + []() -> boost::asio::awaitable> { + std::stringstream s{"SELECT * FROM users, books WHERE users.age < 10;"}; + Operator op = GetAST(s).value(); + CsvDirSequentialScanner seq_scan{kProjectDir + "/test/static/executor/test_data"}; + Executor executor(std::move(seq_scan), co_await boost::asio::this_coro::executor); + + auto got = co_await executor.Execute(op); + + co_return got; + }(), + [](std::exception_ptr p, Result got) { + if (p) std::rethrow_exception(p); + + ASSERT_THAT(got.value().attributes, Eq(AttributesInfo{ + {"users", "id", Type::kInt}, + {"users", "age", Type::kInt}, + {"books", "id", Type::kInt}, + {"books", "price", Type::kInt}, + })); + ASSERT_THAT(got.value().tuples[0], Eq(Tuple{Value{false, 5}, Value{false, 1}, Value{false, 1}, Value{false, 55}})); + ASSERT_THAT(got.value().tuples.size(), Eq(6)); + }); + + pool.join(); +} + +TYPED_TEST_P(ExecutorTest, InnerJoin) { + boost::asio::thread_pool pool{4}; + boost::asio::co_spawn( + pool, + []() -> boost::asio::awaitable> { + std::stringstream s{"SELECT * FROM employees JOIN departments ON employees.department_id = departments.id;"}; + Operator op = GetAST(s).value(); + CsvDirSequentialScanner seq_scan{kProjectDir + "/test/static/executor/test_data"}; + Executor executor(std::move(seq_scan), co_await boost::asio::this_coro::executor); + + auto got = co_await executor.Execute(op); + + co_return got; + }(), + [](std::exception_ptr p, Result got) { + if (p) std::rethrow_exception(p); + + ASSERT_THAT(got.value().attributes, Eq(AttributesInfo{ + {"employees", "id", Type::kInt}, + {"employees", "department_id", Type::kInt}, + {"departments", "id", Type::kInt}, + })); + ASSERT_THAT(got.value().tuples.size(), Eq(3)); + ASSERT_THAT(ToString(got.value()), Eq(ReadFromFile(kProjectDir+"/test/static/executor/expected_inner_join.txt"))); + }); + + pool.join(); +} + +TYPED_TEST_P(ExecutorTest, LeftJoin) { + boost::asio::thread_pool pool{4}; + boost::asio::co_spawn( + pool, + []() -> boost::asio::awaitable> { + std::stringstream s{"SELECT * FROM employees LEFT OUTER JOIN departments ON employees.department_id = departments.id;"}; + Operator op = GetAST(s).value(); + CsvDirSequentialScanner seq_scan{kProjectDir + "/test/static/executor/test_data"}; + Executor executor(std::move(seq_scan), co_await boost::asio::this_coro::executor); + + auto got = co_await executor.Execute(op); + + co_return got; + }(), + [](std::exception_ptr p, Result got) { + if (p) std::rethrow_exception(p); + + ASSERT_THAT(got.value().attributes, Eq(AttributesInfo{ + {"departments", "id", Type::kInt}, + {"employees", "id", Type::kInt}, + {"employees", "department_id", Type::kInt}, + })); + ASSERT_THAT(got.value().tuples.size(), Eq(11)); + ASSERT_THAT(ToString(got.value()), Eq(ReadFromFile(kProjectDir+"/test/static/executor/expected_left_join.txt"))); + }); + + pool.join(); +} + +TYPED_TEST_P(ExecutorTest, RightJoin) { + boost::asio::thread_pool pool{4}; + boost::asio::co_spawn( + pool, + []() -> boost::asio::awaitable> { + std::stringstream s{"SELECT * FROM employees RIGHT JOIN departments ON employees.department_id = departments.id;"}; + Operator op = GetAST(s).value(); + CsvDirSequentialScanner seq_scan{kProjectDir + "/test/static/executor/test_data"}; + Executor executor(std::move(seq_scan), co_await boost::asio::this_coro::executor); + + auto got = co_await executor.Execute(op); + + co_return got; + }(), + [](std::exception_ptr p, Result got) { + if (p) std::rethrow_exception(p); + + ASSERT_THAT(got.value().attributes, Eq(AttributesInfo{ + {"employees", "id", Type::kInt}, + {"employees", "department_id", Type::kInt}, + {"departments", "id", Type::kInt}, + })); + ASSERT_THAT(got.value().tuples.size(), Eq(5)); + ASSERT_THAT(ToString(got.value()), Eq(ReadFromFile(kProjectDir+"/test/static/executor/expected_right_join.txt"))); + }); + + pool.join(); +} + +TYPED_TEST_P(ExecutorTest, ComplexJoin) { + boost::asio::thread_pool pool{4}; + boost::asio::co_spawn( + pool, + []() -> boost::asio::awaitable> { + std::stringstream s{"SELECT departments.id*2, employees.id+1 FROM employees RIGHT JOIN departments ON employees.department_id = departments.id AND departments.id > 3 AND departments.id*2*2/2 < 30;"}; + Operator op = GetAST(s).value(); + CsvDirSequentialScanner seq_scan{kProjectDir + "/test/static/executor/test_data"}; + Executor executor(std::move(seq_scan), co_await boost::asio::this_coro::executor); + + auto got = co_await executor.Execute(op); + + co_return got; + }(), + [](std::exception_ptr p, Result got) { + if (p) std::rethrow_exception(p); + + ASSERT_THAT(got.value().attributes, Eq(AttributesInfo{ + {"", "", Type::kInt}, + {"", "", Type::kInt}, + })); + ASSERT_THAT(got.value().tuples.size(), Eq(5)); + ASSERT_THAT(ToString(got.value()), Eq(ReadFromFile(kProjectDir+"/test/static/executor/expected_complex_join.txt"))); + }); + + pool.join(); +} + +REGISTER_TYPED_TEST_SUITE_P(ExecutorTest, Projection, Filter, FilterMany, CrossJoin, InnerJoin, LeftJoin, RightJoin, ComplexJoin); +using ExecutorTypes = ::testing::Types; +INSTANTIATE_TYPED_TEST_SUITE_P(TypedExecutorTest, ExecutorTest, ExecutorTypes); + +} // namespace stewkk::sql diff --git a/src/stewkk/sql/logic/executor/llvm.cpp b/src/stewkk/sql/logic/executor/llvm.cpp new file mode 100644 index 0000000..c807ff0 --- /dev/null +++ b/src/stewkk/sql/logic/executor/llvm.cpp @@ -0,0 +1,359 @@ +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace stewkk::sql { + +JITCompiler::JITCompiler(boost::asio::any_io_executor executor) : jit_strand_(executor) { + llvm::InitializeNativeTarget(); + llvm::InitializeNativeTargetAsmPrinter(); + llvm::InitializeNativeTargetAsmParser(); + + auto jit_or_error = llvm::orc::LLJITBuilder().create(); + if (!jit_or_error) { + throw std::runtime_error("failed to create llvm::LLJIT"); + } + jit_ = std::move(*jit_or_error); + + jit_->getIRTransformLayer().setTransform( + [](llvm::orc::ThreadSafeModule tsm, llvm::orc::MaterializationResponsibility& r) + -> llvm::Expected { + tsm.withModuleDo([](llvm::Module& m) { +#ifdef DEBUG + std::clog << "IR before optimization:\n"; + m.print(llvm::errs(), nullptr); +#endif + llvm::LoopAnalysisManager lam; + llvm::FunctionAnalysisManager fam; + llvm::CGSCCAnalysisManager cgam; + llvm::ModuleAnalysisManager mam; + + llvm::PassBuilder pb; + + pb.registerModuleAnalyses(mam); + pb.registerCGSCCAnalyses(cgam); + pb.registerFunctionAnalyses(fam); + pb.registerLoopAnalyses(lam); + pb.crossRegisterProxies(lam, fam, cgam, mam); + + llvm::ModulePassManager mpm; + llvm::FunctionPassManager fpm; + + fpm.addPass(llvm::EarlyCSEPass(true)); + fpm.addPass(llvm::SROAPass(llvm::SROAOptions::ModifyCFG)); + + fpm.addPass(llvm::InstCombinePass()); + fpm.addPass(llvm::SimplifyCFGPass()); + + fpm.addPass(llvm::ReassociatePass()); + fpm.addPass(llvm::GVNPass()); + fpm.addPass(llvm::MemCpyOptPass()); + + fpm.addPass(llvm::SimplifyCFGPass()); + fpm.addPass(llvm::InstCombinePass()); + fpm.addPass(llvm::DCEPass()); + fpm.addPass(llvm::ADCEPass()); + + // TODO: SIMD + //fpm.addPass(llvm::SLPVectorizerPass()); + //fpm.addPass(llvm::LoopVectorizePass()); + + mpm.addPass(llvm::createModuleToFunctionPassAdaptor(std::move(fpm))); + + mpm.run(m, mam); + +#ifdef DEBUG + std::clog << "IR after optimization:\n"; + m.print(llvm::errs(), nullptr); +#endif + }); + return std::move(tsm); + }); +} + +boost::asio::awaitable> +JITCompiler::CompileExpression(const Expression& expr, const AttributesInfo& attrs) { + boost::asio::any_io_executor current_executor = co_await boost::asio::this_coro::executor; + co_await boost::asio::dispatch(boost::asio::bind_executor(jit_strand_, boost::asio::deferred)); + + auto resource_tracker = jit_->getMainJITDylib().createResourceTracker(); + + auto ctx = std::make_unique(); + + auto module_name = std::format("expr_module_{}", id_.fetch_add(1)); + auto llvm_module = std::make_unique(std::move(module_name), *ctx); + llvm_module->setDataLayout(jit_->getDataLayout()); + llvm::orc::ThreadSafeModule tsm(std::move(llvm_module), std::move(ctx)); + + std::string func_name; + tsm.withModuleDo([&](llvm::Module& m) { + auto* func = GenerateIR(m, expr, attrs); + func_name = func->getName().str(); + }); + + auto err = jit_->addIRModule(resource_tracker, std::move(tsm)); + if (err) { + throw std::runtime_error("failed to add IR module"); + } + + auto symbol = jit_->lookup(func_name); + if (!symbol) { + throw std::runtime_error("lookup failed"); + } + + auto* compiled_expression = symbol->toPtr(); + co_await boost::asio::dispatch(boost::asio::bind_executor(current_executor, boost::asio::deferred)); + co_return std::make_pair(compiled_expression, std::move(resource_tracker)); +} + +llvm::Function* JITCompiler::GenerateIR( + llvm::Module& llvm_module, + const Expression& expr, + const AttributesInfo& attrs) { + + llvm::IRBuilder<> builder(llvm_module.getContext()); + + auto* value_type = llvm::StructType::create( + llvm_module.getContext(), + {builder.getInt8Ty(), builder.getInt64Ty()}, + "Value"); + + auto* tuple_type = llvm::PointerType::getUnqual(value_type); + auto* attrs_type = llvm::PointerType::getUnqual( + llvm::StructType::get(llvm_module.getContext())); + + auto* result_ptr_type = llvm::PointerType::getUnqual(value_type); + auto* func_type = llvm::FunctionType::get( + llvm::Type::getVoidTy(llvm_module.getContext()), + {result_ptr_type, tuple_type, attrs_type}, false); + auto func_name = std::format("eval_expr_{}", id_.fetch_add(1)); + auto* func = llvm::Function::Create( + func_type, llvm::Function::ExternalLinkage, func_name, &llvm_module); + + func->addParamAttr(0, llvm::Attribute::NoAlias); + + auto* entry = llvm::BasicBlock::Create(llvm_module.getContext(), "entry", func); + builder.SetInsertPoint(entry); + + struct GenerateIRVisitor { + llvm::Value* operator()(const BinaryExpression& expr) { + auto* lhs = std::visit(*this, *expr.lhs); + auto* rhs = std::visit(*this, *expr.rhs); + + auto* is_null_lhs = CheckNull(lhs); + auto* is_null_rhs = CheckNull(rhs); + auto* value_lhs = LoadValue(lhs); + auto* value_rhs = LoadValue(rhs); + + auto* is_null = builder.CreateOr(is_null_lhs, is_null_rhs); + llvm::Value* res_value; + + switch (expr.binop) { + case BinaryOp::kGt: + { + auto* tmp = builder.CreateICmpSGT(value_lhs, value_rhs); + res_value = builder.CreateZExt(tmp, builder.getInt64Ty(), "i1_to_i64_zext"); + break; + } + case BinaryOp::kLt: + { + auto* tmp = builder.CreateICmpSLT(value_lhs, value_rhs); + res_value = builder.CreateZExt(tmp, builder.getInt64Ty(), "i1_to_i64_zext"); + break; + } + case BinaryOp::kLe: + { + auto* tmp = builder.CreateICmpSLE(value_lhs, value_rhs); + res_value = builder.CreateZExt(tmp, builder.getInt64Ty(), "i1_to_i64_zext"); + break; + } + case BinaryOp::kGe: + { + auto* tmp = builder.CreateICmpSGE(value_lhs, value_rhs); + res_value = builder.CreateZExt(tmp, builder.getInt64Ty(), "i1_to_i64_zext"); + break; + } + case BinaryOp::kNotEq: + { + auto* tmp = builder.CreateICmpNE(value_lhs, value_rhs); + res_value = builder.CreateZExt(tmp, builder.getInt64Ty(), "i1_to_i64_zext"); + break; + } + case BinaryOp::kEq: + { + auto* tmp = builder.CreateICmpEQ(value_lhs, value_rhs); + res_value = builder.CreateZExt(tmp, builder.getInt64Ty(), "i1_to_i64_zext"); + break; + } + case BinaryOp::kOr: + { + auto* trunc_lhs = builder.CreateTrunc(value_lhs, builder.getInt1Ty(), "i64_to_i1_trunc"); + auto* trunc_rhs = builder.CreateTrunc(value_rhs, builder.getInt1Ty(), "i64_to_i1_trunc"); + res_value = builder.CreateLogicalOr(trunc_lhs, trunc_rhs); + res_value = builder.CreateZExt(res_value, builder.getInt64Ty(), "i1_to_i64_zext"); + break; + } + case BinaryOp::kAnd: + { + auto* trunc_lhs = builder.CreateTrunc(value_lhs, builder.getInt1Ty(), "i64_to_i1_trunc"); + auto* trunc_rhs = builder.CreateTrunc(value_rhs, builder.getInt1Ty(), "i64_to_i1_trunc"); + res_value = builder.CreateLogicalAnd(trunc_lhs, trunc_rhs); + res_value = builder.CreateZExt(res_value, builder.getInt64Ty(), "i1_to_i64_zext"); + break; + } + case BinaryOp::kPlus: + res_value = builder.CreateAdd(value_lhs, value_rhs); + break; + case BinaryOp::kMinus: + res_value = builder.CreateSub(value_lhs, value_rhs); + break; + case BinaryOp::kMul: + res_value = builder.CreateMul(value_lhs, value_rhs); + break; + case BinaryOp::kDiv: + // TODO: handle div by zero + res_value = builder.CreateSDiv(value_lhs, value_rhs); + break; + case BinaryOp::kMod: + // TODO: handle div by zero + res_value = builder.CreateSRem(value_lhs, value_rhs); + break; + case BinaryOp::kPow: + throw std::logic_error{"pow is not supported in llvm codegen"}; + } + + auto* is_null_i8 = builder.CreateZExt(is_null, builder.getInt8Ty(), "is_null_i8"); + + llvm::Value* value = llvm::UndefValue::get(value_type); + value = builder.CreateInsertValue(value, is_null_i8, {0}, "result.with_is_null"); + value = builder.CreateInsertValue(value, res_value, {1}, "result"); + + return value; + } + llvm::Value* operator()(const UnaryExpression& expr) { + auto* child = std::visit(*this, *expr.child); + switch (expr.op) { + case UnaryOp::kNot: { + auto is_null = CheckNull(child); + auto value = LoadValue(child); + + auto* is_zero = builder.CreateICmpEQ( + value, builder.getIntN(value->getType()->getIntegerBitWidth(), 0), "is_zero"); + auto* logical_not + = builder.CreateZExt(is_zero, value->getType(), "logical_not_result"); + + auto* select = builder.CreateSelect( + is_null, + llvm::ConstantStruct::get(static_cast(value_type), + {builder.getInt8(1), builder.getInt64(0)}), + logical_not); + return select; + } + case UnaryOp::kMinus: { + auto is_null = CheckNull(child); + auto value = LoadValue(child); + + auto* negated = builder.CreateNeg(value); + + auto* select = builder.CreateSelect( + is_null, + llvm::ConstantStruct::get(static_cast(value_type), + {builder.getInt8(1), builder.getInt64(0)}), + negated); + return select; + } + } + } + llvm::Value* operator()(const IntConst& expr) { + return llvm::ConstantStruct::get(static_cast(value_type), + {builder.getInt8(0), builder.getInt64(expr)}); + } + llvm::Value* operator()(const Literal& expr) { + switch (expr) { + case Literal::kNull: + return + llvm::ConstantStruct::get(static_cast(value_type), + {builder.getInt8(1), builder.getInt64(0)}); + case Literal::kTrue: + return + llvm::ConstantStruct::get(static_cast(value_type), + {builder.getInt8(0), builder.getInt64(1)}); + case Literal::kFalse: + return + llvm::ConstantStruct::get(static_cast(value_type), + {builder.getInt8(0), builder.getInt64(0)}); + case Literal::kUnknown: + return + llvm::ConstantStruct::get(static_cast(value_type), + {builder.getInt8(1), builder.getInt64(0)}); + } + } + llvm::Value* operator()(const Attribute& expr) { + auto it = std::find_if( + attrs.begin(), attrs.end(), [&expr](const AttributeInfo& attr_info) { + return attr_info.name == expr.name && attr_info.table == expr.table; + }); + // NOTE: already checked in GetExpressionType + auto index = it - attrs.begin(); + auto* index_const = llvm::ConstantInt::get(builder.getInt32Ty(), index); + + auto* struct_ptr = builder.CreateInBoundsGEP( + value_type, + tuples_arg, + index_const, + "struct_ptr"); + + auto* loaded_struct = builder.CreateLoad( + value_type, + struct_ptr, + "loaded_struct"); + + return loaded_struct; + } + + llvm::Value* LoadIsNull(llvm::Value* v) { + return builder.CreateExtractValue(v, {0}, "value.is_null"); + } + + llvm::Value* LoadValue(llvm::Value* v) { + return builder.CreateExtractValue(v, {1}, "value.value"); + } + + llvm::Value* CheckNull(llvm::Value* v) { + auto* is_null_value = LoadIsNull(v); + return builder.CreateICmpNE( + is_null_value, builder.getInt8(0), "is_null"); + } + + llvm::Module& llvm_module; + llvm::IRBuilder<>& builder; + llvm::StructType* value_type; + const AttributesInfo& attrs; + llvm::Value* tuples_arg; + }; + + auto* result_value = std::visit( + GenerateIRVisitor{llvm_module, builder, value_type, attrs, func->getArg(1)}, expr); + auto* result_ptr = func->getArg(0); + builder.CreateStore(result_value, result_ptr); + builder.CreateRetVoid(); + + return func; +} + +} // namespace stewkk::sql diff --git a/src/stewkk/sql/logic/executor/materialization.cpp b/src/stewkk/sql/logic/executor/materialization.cpp new file mode 100644 index 0000000..3dcbfe0 --- /dev/null +++ b/src/stewkk/sql/logic/executor/materialization.cpp @@ -0,0 +1,52 @@ +#include + +#include + +// TODO: implement async file io with asio (and benchmark it) + +namespace stewkk::sql { + +DiskFileWriter::DiskFileWriter() + : path_(fs::temp_directory_path() / fs::unique_path("%%%%.tmp")), f_(path_, std::ios::binary) {} + +void DiskFileWriter::Write(const Tuples& tuples) { + tuple_size_ = tuples.front().size(); + for (const auto& tuple : tuples) { + std::size_t tuple_size = tuple.size(); + // NOTE: better to store tuples in continious buffer and than flush to + // disk + f_.write(reinterpret_cast(tuple.data()), + tuple.size() * sizeof(Tuple::value_type)); + } +} + +DiskFileReader DiskFileWriter::GetDiskFileReader() && { + f_.flush(); + f_.close(); + return DiskFileReader(std::move(path_), tuple_size_); +} + +DiskFileReader::DiskFileReader(fs::path path, std::size_t tuple_size) + : path_(std::move(path)), f_(path_, std::ios::binary), tuple_size_(tuple_size) {} + +DiskFileReader::~DiskFileReader() { + f_.close(); + fs::remove(path_); +} + +Tuples DiskFileReader::Read() { + Tuples buf; + buf.reserve(kBufSize); + while (buf.size() < kBufSize) { + Tuple tuple; + tuple.resize(tuple_size_); + f_.read(reinterpret_cast(tuple.data()), tuple_size_*sizeof(Tuple::value_type)); + if (f_.gcount() == 0) { + break; + } + buf.push_back(std::move(tuple)); + } + return buf; +} + +} // namespace stewkk::sql diff --git a/src/stewkk/sql/logic/executor/sequential_scan.cpp b/src/stewkk/sql/logic/executor/sequential_scan.cpp new file mode 100644 index 0000000..26dc178 --- /dev/null +++ b/src/stewkk/sql/logic/executor/sequential_scan.cpp @@ -0,0 +1,107 @@ +#include + +#include +#include +#include + +#include + +#include +#include + +namespace stewkk::sql { + +namespace { + +Type GetTypeFromString(const std::string& s) { + if (s == "int") { + return Type::kInt; + } + std::unreachable(); +} + +Value BuildValueFromString(Type type, const std::string& table, const std::string attr_name, const std::string& value) { + if (value == "NULL") { + return Value{true}; + } + switch (type) { + case Type::kInt: + return Value{false, std::stoi(value)}; + default: + std::unreachable(); + } +} + +Tuple ParseTuple(const std::string& line, + const AttributesInfo& attributes, + const std::string& table_name) { + return line | std::views::split(',') | std::views::enumerate + | std::views::transform([&attributes, &table_name](const auto& attr) { + const auto& [index, value_range] = attr; + auto value = value_range | std::ranges::to(); + const auto& [_, attr_name, type] = attributes[index]; + return BuildValueFromString(type, table_name, attr_name, value); + }) + | std::ranges::to(); +} + +} // namespace + +boost::asio::awaitable> CsvDirSequentialScanner::operator()( + const std::string& table_name, AttributesInfoChannel& attrs_chan, + TuplesChannel& tuples_chan) const { +#ifdef DEBUG + std::clog << "Executing sequential scan\n"; +#endif + auto path = std::format("{}/{}.csv", dir, table_name); + std::ifstream input{std::move(path)}; + std::string line; + std::getline(input, line); + auto attributes = line | std::views::split(',') | std::views::transform([&table_name](const auto& attr) { + auto mid = std::find(attr.begin(), attr.end(), ':'); + auto attr_name = std::string{attr.begin(), mid}; + auto attr_type = GetTypeFromString(std::string{mid + 1, attr.end()}); + return AttributeInfo{table_name, std::move(attr_name), attr_type}; + }) + | std::ranges::to(); + + co_await attrs_chan.async_send(boost::system::error_code{}, attributes, + boost::asio::use_awaitable); + attrs_chan.close(); + + Tuples buf; + buf.reserve(kBufSize); + while (std::getline(input, line)) { + auto tuple = ParseTuple(line, attributes, table_name); + buf.emplace_back(std::move(tuple)); +#ifdef DEBUG + std::clog << std::format("buf size is {}\n", buf.size()); +#endif + + if (buf.size() == kBufSize) { +#ifdef DEBUG + std::clog << std::format("Sending {} tuples from table\n", buf.size()); +#endif + co_await tuples_chan.async_send(boost::system::error_code{}, std::move(buf), + boost::asio::use_awaitable); + buf.clear(); + } + } + + if (!buf.empty()) { +#ifdef DEBUG + std::clog << std::format("Sending {} tuples from table\n", buf.size()); +#endif + co_await tuples_chan.async_send(boost::system::error_code{}, std::move(buf), + boost::asio::use_awaitable); + } + + tuples_chan.close(); +#ifdef DEBUG + std::clog << "Done sending tuples from table\n"; +#endif + + co_return Ok(); +} + +} // namespace stewkk::sql diff --git a/src/stewkk/sql/logic/parser/PostgreSQLLexer.g4 b/src/stewkk/sql/logic/parser/PostgreSQLLexer.g4 new file mode 100644 index 0000000..1c71cd6 --- /dev/null +++ b/src/stewkk/sql/logic/parser/PostgreSQLLexer.g4 @@ -0,0 +1,1474 @@ +/* +based on +https://github.com/tunnelvisionlabs/antlr4-grammar-postgresql/blob/master/src/com/tunnelvisionlabs/postgresql/PostgreSqlLexer.g4 +*/ + +/* + * [The "MIT license"] + * Copyright (C) 2014 Sam Harwell, Tunnel Vision Laboratories, LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * 1. The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * 2. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * 3. Except as contained in this notice, the name of Tunnel Vision + * Laboratories, LLC. shall not be used in advertising or otherwise to + * promote the sale, use or other dealings in this Software without prior + * written authorization from Tunnel Vision Laboratories, LLC. + */ + +// $antlr-format alignTrailingComments true, columnLimit 150, maxEmptyLinesToKeep 1, reflowComments false, useTab false +// $antlr-format allowShortRulesOnASingleLine true, allowShortBlocksOnASingleLine true, minEmptyLines 0, alignSemicolons ownLine +// $antlr-format alignColons trailing, singleLineOverrulesHangingColon true, alignLexerCommands true, alignLabels true, alignTrailers true + +lexer grammar PostgreSQLLexer; +/* Reference: + * http://www.postgresql.org/docs/9.3/static/sql-syntax-lexical.html + */ + +options { + superClass = PostgreSQLLexerBase; + caseInsensitive = true; +} + +@header {#include "PostgreSQLLexerBase.h"} + +Dollar: '$'; + +OPEN_PAREN: '('; + +CLOSE_PAREN: ')'; + +OPEN_BRACKET: '['; + +CLOSE_BRACKET: ']'; + +COMMA: ','; + +SEMI: ';'; + +COLON: ':'; + +STAR: '*'; + +EQUAL: '='; + +DOT: '.'; +//NamedArgument : ':='; + +PLUS: '+'; + +MINUS: '-'; + +SLASH: '/'; + +CARET: '^'; + +LT: '<'; + +GT: '>'; + +LESS_LESS: '<<'; + +GREATER_GREATER: '>>'; + +COLON_EQUALS: ':='; + +LESS_EQUALS: '<='; + +EQUALS_GREATER: '=>'; + +GREATER_EQUALS: '>='; + +DOT_DOT: '..'; + +NOT_EQUALS: '<>'; + +TYPECAST: '::'; + +PERCENT: '%'; + +PARAM: '$' ([0-9])+; +// + +// OPERATORS (4.1.3) + +// + +// this rule does not allow + or - at the end of a multi-character operator + +Operator: + ( + ( + OperatorCharacter + | ('+' | '-' {this->CheckLaMinus()}? )+ (OperatorCharacter | '/' {this->CheckLaStar()}? ) + | '/' {this->CheckLaStar()}? + )+ + | // special handling for the single-character operators + and - + [+-] + ) + //TODO somehow rewrite this part without using Actions + {this->HandleLessLessGreaterGreater();} +; +/* This rule handles operators which end with + or -, and sets the token type to Operator. It is comprised of four + * parts, in order: + * + * 1. A prefix, which does not contain a character from the required set which allows + or - to appear at the end of + * the operator. + * 2. A character from the required set which allows + or - to appear at the end of the operator. + * 3. An optional sub-token which takes the form of an operator which does not include a + or - at the end of the + * sub-token. + * 4. A suffix sequence of + and - characters. + */ + +OperatorEndingWithPlusMinus: + (OperatorCharacterNotAllowPlusMinusAtEnd | '-' {this->CheckLaMinus()}? | '/' {this->CheckLaStar()}? )* OperatorCharacterAllowPlusMinusAtEnd Operator? ( + '+' + | '-' {this->CheckLaMinus()}? + )+ -> type (Operator) +; +// Each of the following fragment rules omits the +, -, and / characters, which must always be handled in a special way + +// by the operator rules above. + +fragment OperatorCharacter: [*<>=~!@%^&|`?#]; +// these are the operator characters that don't count towards one ending with + or - + +fragment OperatorCharacterNotAllowPlusMinusAtEnd: [*<>=+]; +// an operator may end with + or - if it contains one of these characters + +fragment OperatorCharacterAllowPlusMinusAtEnd: [~!@%^&|`?#]; +// + +// KEYWORDS (Appendix C) + + + +JSON: 'JSON'; +JSON_ARRAY: 'JSON_ARRAY'; +JSON_ARRAYAGG: 'JSON_ARRAYAGG'; +JSON_EXISTS: 'JSON_EXISTS'; +JSON_OBJECT: 'JSON_OBJECT'; +JSON_OBJECTAGG: 'JSON_OBJECTAGG'; +JSON_QUERY: 'JSON_QUERY'; +JSON_SCALAR: 'JSON_SCALAR'; +JSON_SERIALIZE: 'JSON_SERIALIZE'; +JSON_TABLE: 'JSON_TABLE'; +JSON_VALUE: 'JSON_VALUE'; +MERGE_ACTION: 'MERGE_ACTION'; + +SYSTEM_USER: 'SYSTEM_USER'; + +ABSENT: 'ABSENT'; +ASENSITIVE: 'ASENSITIVE'; +ATOMIC: 'ATOMIC'; +BREADTH: 'BREATH'; +COMPRESSION: 'COMPRESSION'; +CONDITIONAL: 'CONDITIONAL'; +DEPTH: 'DEPTH'; +EMPTY_P: 'EMPTY'; +FINALIZE: 'FINALIZE'; +INDENT: 'INDENT'; +KEEP: 'KEEP'; +KEYS: 'KEYS'; +NESTED: 'NESTED'; +OMIT: 'OMIT'; +PARAMETER: 'PARAMETER'; +PATH: 'PATH'; +PLAN: 'PLAN'; +QUOTES: 'QUOTES'; +SCALAR: 'SCALAR'; +SOURCE: 'SOURCE'; +STRING_P: 'STRING'; +TARGET: 'TARGET'; +UNCONDITIONAL: 'UNCONDITIONAL'; + +PERIOD: 'PERIOD'; + +FORMAT_LA: 'FORMAT_LA'; + +// + +// + +// reserved keywords + +// + +ALL: 'ALL'; + +ANALYSE: 'ANALYSE'; + +ANALYZE: 'ANALYZE'; + +AND: 'AND'; + +ANY: 'ANY'; + +ARRAY: 'ARRAY'; + +AS: 'AS'; + +ASC: 'ASC'; + +ASYMMETRIC: 'ASYMMETRIC'; + +BOTH: 'BOTH'; + +CASE: 'CASE'; + +CAST: 'CAST'; + +CHECK: 'CHECK'; + +COLLATE: 'COLLATE'; + +COLUMN: 'COLUMN'; + +CONSTRAINT: 'CONSTRAINT'; + +CREATE: 'CREATE'; + +CURRENT_CATALOG: 'CURRENT_CATALOG'; + +CURRENT_DATE: 'CURRENT_DATE'; + +CURRENT_ROLE: 'CURRENT_ROLE'; + +CURRENT_TIME: 'CURRENT_TIME'; + +CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP'; + +CURRENT_USER: 'CURRENT_USER'; + +DEFAULT: 'DEFAULT'; + +DEFERRABLE: 'DEFERRABLE'; + +DESC: 'DESC'; + +DISTINCT: 'DISTINCT'; + +DO: 'DO'; + +ELSE: 'ELSE'; + +EXCEPT: 'EXCEPT'; + +FALSE_P: 'FALSE'; + +FETCH: 'FETCH'; + +FOR: 'FOR'; + +FOREIGN: 'FOREIGN'; + +FROM: 'FROM'; + +GRANT: 'GRANT'; + +GROUP_P: 'GROUP'; + +HAVING: 'HAVING'; + +IN_P: 'IN'; + +INITIALLY: 'INITIALLY'; + +INTERSECT: 'INTERSECT'; + +INTO: 'INTO'; + +LATERAL_P: 'LATERAL'; + +LEADING: 'LEADING'; + +LIMIT: 'LIMIT'; + +LOCALTIME: 'LOCALTIME'; + +LOCALTIMESTAMP: 'LOCALTIMESTAMP'; + +NOT: 'NOT'; + +NULL_P: 'NULL'; + +OFFSET: 'OFFSET'; + +ON: 'ON'; + +ONLY: 'ONLY'; + +OR: 'OR'; + +ORDER: 'ORDER'; + +PLACING: 'PLACING'; + +PRIMARY: 'PRIMARY'; + +REFERENCES: 'REFERENCES'; + +RETURNING: 'RETURNING'; + +SELECT: 'SELECT'; + +SESSION_USER: 'SESSION_USER'; + +SOME: 'SOME'; + +SYMMETRIC: 'SYMMETRIC'; + +TABLE: 'TABLE'; + +THEN: 'THEN'; + +TO: 'TO'; + +TRAILING: 'TRAILING'; + +TRUE_P: 'TRUE'; + +UNION: 'UNION'; + +UNIQUE: 'UNIQUE'; + +USER: 'USER'; + +USING: 'USING'; + +VARIADIC: 'VARIADIC'; + +WHEN: 'WHEN'; + +WHERE: 'WHERE'; + +WINDOW: 'WINDOW'; + +WITH: 'WITH'; + +// + +// reserved keywords (can be function or type) + +// + +AUTHORIZATION: 'AUTHORIZATION'; + +BINARY: 'BINARY'; + +COLLATION: 'COLLATION'; + +CONCURRENTLY: 'CONCURRENTLY'; + +CROSS: 'CROSS'; + +CURRENT_SCHEMA: 'CURRENT_SCHEMA'; + +FREEZE: 'FREEZE'; + +FULL: 'FULL'; + +ILIKE: 'ILIKE'; + +INNER_P: 'INNER'; + +IS: 'IS'; + +ISNULL: 'ISNULL'; + +JOIN: 'JOIN'; + +LEFT: 'LEFT'; + +LIKE: 'LIKE'; + +NATURAL: 'NATURAL'; + +NOTNULL: 'NOTNULL'; + +OUTER_P: 'OUTER'; + +OVER: 'OVER'; + +OVERLAPS: 'OVERLAPS'; + +RIGHT: 'RIGHT'; + +SIMILAR: 'SIMILAR'; + +VERBOSE: 'VERBOSE'; +// + +// non-reserved keywords + +// + +ABORT_P: 'ABORT'; + +ABSOLUTE_P: 'ABSOLUTE'; + +ACCESS: 'ACCESS'; + +ACTION: 'ACTION'; + +ADD_P: 'ADD'; + +ADMIN: 'ADMIN'; + +AFTER: 'AFTER'; + +AGGREGATE: 'AGGREGATE'; + +ALSO: 'ALSO'; + +ALTER: 'ALTER'; + +ALWAYS: 'ALWAYS'; + +ASSERTION: 'ASSERTION'; + +ASSIGNMENT: 'ASSIGNMENT'; + +AT: 'AT'; + +ATTRIBUTE: 'ATTRIBUTE'; + +BACKWARD: 'BACKWARD'; + +BEFORE: 'BEFORE'; + +BEGIN_P: 'BEGIN'; + +BY: 'BY'; + +CACHE: 'CACHE'; + +CALLED: 'CALLED'; + +CASCADE: 'CASCADE'; + +CASCADED: 'CASCADED'; + +CATALOG: 'CATALOG'; + +CHAIN: 'CHAIN'; + +CHARACTERISTICS: 'CHARACTERISTICS'; + +CHECKPOINT: 'CHECKPOINT'; + +CLASS: 'CLASS'; + +CLOSE: 'CLOSE'; + +CLUSTER: 'CLUSTER'; + +COMMENT: 'COMMENT'; + +COMMENTS: 'COMMENTS'; + +COMMIT: 'COMMIT'; + +COMMITTED: 'COMMITTED'; + +CONFIGURATION: 'CONFIGURATION'; + +CONNECTION: 'CONNECTION'; + +CONSTRAINTS: 'CONSTRAINTS'; + +CONTENT_P: 'CONTENT'; + +CONTINUE_P: 'CONTINUE'; + +CONVERSION_P: 'CONVERSION'; + +COPY: 'COPY'; + +COST: 'COST'; + +CSV: 'CSV'; + +CURSOR: 'CURSOR'; + +CYCLE: 'CYCLE'; + +DATA_P: 'DATA'; + +DATABASE: 'DATABASE'; + +DAY_P: 'DAY'; + +DEALLOCATE: 'DEALLOCATE'; + +DECLARE: 'DECLARE'; + +DEFAULTS: 'DEFAULTS'; + +DEFERRED: 'DEFERRED'; + +DEFINER: 'DEFINER'; + +DELETE_P: 'DELETE'; + +DELIMITER: 'DELIMITER'; + +DELIMITERS: 'DELIMITERS'; + +DICTIONARY: 'DICTIONARY'; + +DISABLE_P: 'DISABLE'; + +DISCARD: 'DISCARD'; + +DOCUMENT_P: 'DOCUMENT'; + +DOMAIN_P: 'DOMAIN'; + +DOUBLE_P: 'DOUBLE'; + +DROP: 'DROP'; + +EACH: 'EACH'; + +ENABLE_P: 'ENABLE'; + +ENCODING: 'ENCODING'; + +ENCRYPTED: 'ENCRYPTED'; + +ENUM_P: 'ENUM'; + +ESCAPE: 'ESCAPE'; + +EVENT: 'EVENT'; + +EXCLUDE: 'EXCLUDE'; + +EXCLUDING: 'EXCLUDING'; + +EXCLUSIVE: 'EXCLUSIVE'; + +EXECUTE: 'EXECUTE'; + +EXPLAIN: 'EXPLAIN'; + +EXTENSION: 'EXTENSION'; + +EXTERNAL: 'EXTERNAL'; + +FAMILY: 'FAMILY'; + +FIRST_P: 'FIRST'; + +FOLLOWING: 'FOLLOWING'; + +FORCE: 'FORCE'; + +FORWARD: 'FORWARD'; + +FUNCTION: 'FUNCTION'; + +FUNCTIONS: 'FUNCTIONS'; + +GLOBAL: 'GLOBAL'; + +GRANTED: 'GRANTED'; + +HANDLER: 'HANDLER'; + +HEADER_P: 'HEADER'; + +HOLD: 'HOLD'; + +HOUR_P: 'HOUR'; + +IDENTITY_P: 'IDENTITY'; + +IF_P: 'IF'; + +IMMEDIATE: 'IMMEDIATE'; + +IMMUTABLE: 'IMMUTABLE'; + +IMPLICIT_P: 'IMPLICIT'; + +INCLUDING: 'INCLUDING'; + +INCREMENT: 'INCREMENT'; + +INDEX: 'INDEX'; + +INDEXES: 'INDEXES'; + +INHERIT: 'INHERIT'; + +INHERITS: 'INHERITS'; + +INLINE_P: 'INLINE'; + +INSENSITIVE: 'INSENSITIVE'; + +INSERT: 'INSERT'; + +INSTEAD: 'INSTEAD'; + +INVOKER: 'INVOKER'; + +ISOLATION: 'ISOLATION'; + +KEY: 'KEY'; + +LABEL: 'LABEL'; + +LANGUAGE: 'LANGUAGE'; + +LARGE_P: 'LARGE'; + +LAST_P: 'LAST'; +//LC_COLLATE : 'LC'_'COLLATE; + +//LC_CTYPE : 'LC'_'CTYPE; + +LEAKPROOF: 'LEAKPROOF'; + +LEVEL: 'LEVEL'; + +LISTEN: 'LISTEN'; + +LOAD: 'LOAD'; + +LOCAL: 'LOCAL'; + +LOCATION: 'LOCATION'; + +LOCK_P: 'LOCK'; + +MAPPING: 'MAPPING'; + +MATCH: 'MATCH'; + +MATCHED: 'MATCHED'; + +MATERIALIZED: 'MATERIALIZED'; + +MAXVALUE: 'MAXVALUE'; + +MERGE: 'MERGE'; + +MINUTE_P: 'MINUTE'; + +MINVALUE: 'MINVALUE'; + +MODE: 'MODE'; + +MONTH_P: 'MONTH'; + +MOVE: 'MOVE'; + +NAME_P: 'NAME'; + +NAMES: 'NAMES'; + +NEXT: 'NEXT'; + +NO: 'NO'; + +NOTHING: 'NOTHING'; + +NOTIFY: 'NOTIFY'; + +NOWAIT: 'NOWAIT'; + +NULLS_P: 'NULLS'; + +OBJECT_P: 'OBJECT'; + +OF: 'OF'; + +OFF: 'OFF'; + +OIDS: 'OIDS'; + +OPERATOR: 'OPERATOR'; + +OPTION: 'OPTION'; + +OPTIONS: 'OPTIONS'; + +OWNED: 'OWNED'; + +OWNER: 'OWNER'; + +PARSER: 'PARSER'; + +PARTIAL: 'PARTIAL'; + +PARTITION: 'PARTITION'; + +PASSING: 'PASSING'; + +PASSWORD: 'PASSWORD'; + +PLANS: 'PLANS'; + +PRECEDING: 'PRECEDING'; + +PREPARE: 'PREPARE'; + +PREPARED: 'PREPARED'; + +PRESERVE: 'PRESERVE'; + +PRIOR: 'PRIOR'; + +PRIVILEGES: 'PRIVILEGES'; + +PROCEDURAL: 'PROCEDURAL'; + +PROCEDURE: 'PROCEDURE'; + +PROGRAM: 'PROGRAM'; + +QUOTE: 'QUOTE'; + +RANGE: 'RANGE'; + +READ: 'READ'; + +REASSIGN: 'REASSIGN'; + +RECHECK: 'RECHECK'; + +RECURSIVE: 'RECURSIVE'; + +REF: 'REF'; + +REFRESH: 'REFRESH'; + +REINDEX: 'REINDEX'; + +RELATIVE_P: 'RELATIVE'; + +RELEASE: 'RELEASE'; + +RENAME: 'RENAME'; + +REPEATABLE: 'REPEATABLE'; + +REPLACE: 'REPLACE'; + +REPLICA: 'REPLICA'; + +RESET: 'RESET'; + +RESTART: 'RESTART'; + +RESTRICT: 'RESTRICT'; + +RETURNS: 'RETURNS'; + +REVOKE: 'REVOKE'; + +ROLE: 'ROLE'; + +ROLLBACK: 'ROLLBACK'; + +ROWS: 'ROWS'; + +RULE: 'RULE'; + +SAVEPOINT: 'SAVEPOINT'; + +SCHEMA: 'SCHEMA'; + +SCROLL: 'SCROLL'; + +SEARCH: 'SEARCH'; + +SECOND_P: 'SECOND'; + +SECURITY: 'SECURITY'; + +SEQUENCE: 'SEQUENCE'; + +SEQUENCES: 'SEQUENCES'; + +SERIALIZABLE: 'SERIALIZABLE'; + +SERVER: 'SERVER'; + +SESSION: 'SESSION'; + +SET: 'SET'; + +SHARE: 'SHARE'; + +SHOW: 'SHOW'; + +SIMPLE: 'SIMPLE'; + +SNAPSHOT: 'SNAPSHOT'; + +STABLE: 'STABLE'; + +STANDALONE_P: 'STANDALONE'; + +START: 'START'; + +STATEMENT: 'STATEMENT'; + +STATISTICS: 'STATISTICS'; + +STDIN: 'STDIN'; + +STDOUT: 'STDOUT'; + +STORAGE: 'STORAGE'; + +STRICT_P: 'STRICT'; + +STRIP_P: 'STRIP'; + +SYSID: 'SYSID'; + +SYSTEM_P: 'SYSTEM'; + +TABLES: 'TABLES'; + +TABLESPACE: 'TABLESPACE'; + +TEMP: 'TEMP'; + +TEMPLATE: 'TEMPLATE'; + +TEMPORARY: 'TEMPORARY'; + +TEXT_P: 'TEXT'; + +TRANSACTION: 'TRANSACTION'; + +TRIGGER: 'TRIGGER'; + +TRUNCATE: 'TRUNCATE'; + +TRUSTED: 'TRUSTED'; + +TYPE_P: 'TYPE'; + +TYPES_P: 'TYPES'; + +UNBOUNDED: 'UNBOUNDED'; + +UNCOMMITTED: 'UNCOMMITTED'; + +UNENCRYPTED: 'UNENCRYPTED'; + +UNKNOWN: 'UNKNOWN'; + +UNLISTEN: 'UNLISTEN'; + +UNLOGGED: 'UNLOGGED'; + +UNTIL: 'UNTIL'; + +UPDATE: 'UPDATE'; + +VACUUM: 'VACUUM'; + +VALID: 'VALID'; + +VALIDATE: 'VALIDATE'; + +VALIDATOR: 'VALIDATOR'; +//VALUE : 'VALUE; + +VARYING: 'VARYING'; + +VERSION_P: 'VERSION'; + +VIEW: 'VIEW'; + +VOLATILE: 'VOLATILE'; + +WHITESPACE_P: 'WHITESPACE'; + +WITHOUT: 'WITHOUT'; + +WORK: 'WORK'; + +WRAPPER: 'WRAPPER'; + +WRITE: 'WRITE'; + +XML_P: 'XML'; + +YEAR_P: 'YEAR'; + +YES_P: 'YES'; + +ZONE: 'ZONE'; +// + +// non-reserved keywords (can not be function or type) + +// + +BETWEEN: 'BETWEEN'; + +BIGINT: 'BIGINT'; + +BIT: 'BIT'; + +BOOLEAN_P: 'BOOLEAN'; + +CHAR_P: 'CHAR'; + +CHARACTER: 'CHARACTER'; + +COALESCE: 'COALESCE'; + +DEC: 'DEC'; + +DECIMAL_P: 'DECIMAL'; + +EXISTS: 'EXISTS'; + +EXTRACT: 'EXTRACT'; + +FLOAT_P: 'FLOAT'; + +GREATEST: 'GREATEST'; + +INOUT: 'INOUT'; + +INT_P: 'INT'; + +INTEGER: 'INTEGER'; + +INTERVAL: 'INTERVAL'; + +LEAST: 'LEAST'; + +NATIONAL: 'NATIONAL'; + +NCHAR: 'NCHAR'; + +NONE: 'NONE'; + +NULLIF: 'NULLIF'; + +NUMERIC: 'NUMERIC'; + +OVERLAY: 'OVERLAY'; + +POSITION: 'POSITION'; + +PRECISION: 'PRECISION'; + +REAL: 'REAL'; + +ROW: 'ROW'; + +SETOF: 'SETOF'; + +SMALLINT: 'SMALLINT'; + +SUBSTRING: 'SUBSTRING'; + +TIME: 'TIME'; + +TIMESTAMP: 'TIMESTAMP'; + +TREAT: 'TREAT'; + +TRIM: 'TRIM'; + +VALUES: 'VALUES'; + +VARCHAR: 'VARCHAR'; + +XMLATTRIBUTES: 'XMLATTRIBUTES'; + +XMLCOMMENT: 'XMLCOMMENT'; + +XMLAGG: 'XMLAGG'; + +XML_IS_WELL_FORMED: 'XML_IS_WELL_FORMED'; + +XML_IS_WELL_FORMED_DOCUMENT: 'XML_IS_WELL_FORMED_DOCUMENT'; + +XML_IS_WELL_FORMED_CONTENT: 'XML_IS_WELL_FORMED_CONTENT'; + +XPATH: 'XPATH'; + +XPATH_EXISTS: 'XPATH_EXISTS'; + +XMLCONCAT: 'XMLCONCAT'; + +XMLELEMENT: 'XMLELEMENT'; + +XMLEXISTS: 'XMLEXISTS'; + +XMLFOREST: 'XMLFOREST'; + +XMLPARSE: 'XMLPARSE'; + +XMLPI: 'XMLPI'; + +XMLROOT: 'XMLROOT'; + +XMLSERIALIZE: 'XMLSERIALIZE'; +//MISSED + +CALL: 'CALL'; + +CURRENT_P: 'CURRENT'; + +ATTACH: 'ATTACH'; + +DETACH: 'DETACH'; + +EXPRESSION: 'EXPRESSION'; + +GENERATED: 'GENERATED'; + +LOGGED: 'LOGGED'; + +STORED: 'STORED'; + +INCLUDE: 'INCLUDE'; + +ROUTINE: 'ROUTINE'; + +TRANSFORM: 'TRANSFORM'; + +IMPORT_P: 'IMPORT'; + +POLICY: 'POLICY'; + +METHOD: 'METHOD'; + +REFERENCING: 'REFERENCING'; + +NEW: 'NEW'; + +OLD: 'OLD'; + +VALUE_P: 'VALUE'; + +SUBSCRIPTION: 'SUBSCRIPTION'; + +PUBLICATION: 'PUBLICATION'; + +OUT_P: 'OUT'; + +END_P: 'END'; + +ROUTINES: 'ROUTINES'; + +SCHEMAS: 'SCHEMAS'; + +PROCEDURES: 'PROCEDURES'; + +INPUT_P: 'INPUT'; + +SUPPORT: 'SUPPORT'; + +PARALLEL: 'PARALLEL'; + +SQL_P: 'SQL'; + +DEPENDS: 'DEPENDS'; + +OVERRIDING: 'OVERRIDING'; + +CONFLICT: 'CONFLICT'; + +SKIP_P: 'SKIP'; + +LOCKED: 'LOCKED'; + +TIES: 'TIES'; + +ROLLUP: 'ROLLUP'; + +CUBE: 'CUBE'; + +GROUPING: 'GROUPING'; + +SETS: 'SETS'; + +TABLESAMPLE: 'TABLESAMPLE'; + +ORDINALITY: 'ORDINALITY'; + +XMLTABLE: 'XMLTABLE'; + +COLUMNS: 'COLUMNS'; + +XMLNAMESPACES: 'XMLNAMESPACES'; + +ROWTYPE: 'ROWTYPE'; + +NORMALIZED: 'NORMALIZED'; + +WITHIN: 'WITHIN'; + +FILTER: 'FILTER'; + +GROUPS: 'GROUPS'; + +OTHERS: 'OTHERS'; + +NFC: 'NFC'; + +NFD: 'NFD'; + +NFKC: 'NFKC'; + +NFKD: 'NFKD'; + +UESCAPE: 'UESCAPE'; + +VIEWS: 'VIEWS'; + +NORMALIZE: 'NORMALIZE'; + +DUMP: 'DUMP'; + +ERROR: 'ERROR'; + +USE_VARIABLE: 'USE_VARIABLE'; + +USE_COLUMN: 'USE_COLUMN'; + +CONSTANT: 'CONSTANT'; + +PERFORM: 'PERFORM'; + +GET: 'GET'; + +DIAGNOSTICS: 'DIAGNOSTICS'; + +STACKED: 'STACKED'; + +ELSIF: 'ELSIF'; + +WHILE: 'WHILE'; + +FOREACH: 'FOREACH'; + +SLICE: 'SLICE'; + +EXIT: 'EXIT'; + +RETURN: 'RETURN'; + +RAISE: 'RAISE'; + +SQLSTATE: 'SQLSTATE'; + +DEBUG: 'DEBUG'; + +INFO: 'INFO'; + +NOTICE: 'NOTICE'; + +WARNING: 'WARNING'; + +EXCEPTION: 'EXCEPTION'; + +ASSERT: 'ASSERT'; + +LOOP: 'LOOP'; + +OPEN: 'OPEN'; + +FORMAT: 'FORMAT'; + + + + + +Identifier: IdentifierStartChar IdentifierChar*; + +fragment IdentifierStartChar options { + caseInsensitive = false; +}: // these are the valid identifier start characters below 0x7F + [a-zA-Z_] + | // these are the valid characters from 0x80 to 0xFF + [\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF] + | // these are the letters above 0xFF which only need a single UTF-16 code unit + [\u0100-\uD7FF\uE000-\uFFFF] {this->CharIsLetter()}? + | // letters which require multiple UTF-16 code units + [\uD800-\uDBFF] [\uDC00-\uDFFF] {this->CheckIfUtf32Letter()}? +; + +fragment IdentifierChar: StrictIdentifierChar | '$'; + +fragment StrictIdentifierChar: IdentifierStartChar | [0-9]; +/* Quoted Identifiers + * + * These are divided into four separate tokens, allowing distinction of valid quoted identifiers from invalid quoted + * identifiers without sacrificing the ability of the lexer to reliably recover from lexical errors in the input. + */ + +QuotedIdentifier: UnterminatedQuotedIdentifier '"'; +// This is a quoted identifier which only contains valid characters but is not terminated + +UnterminatedQuotedIdentifier: '"' ('""' | ~ [\u0000"])*; +// This is a quoted identifier which is terminated but contains a \u0000 character + +InvalidQuotedIdentifier: InvalidUnterminatedQuotedIdentifier '"'; +// This is a quoted identifier which is unterminated and contains a \u0000 character + +InvalidUnterminatedQuotedIdentifier: '"' ('""' | ~ '"')*; +/* Unicode Quoted Identifiers + * + * These are divided into four separate tokens, allowing distinction of valid Unicode quoted identifiers from invalid + * Unicode quoted identifiers without sacrificing the ability of the lexer to reliably recover from lexical errors in + * the input. Note that escape sequences are never checked as part of this determination due to the ability of users + * to change the escape character with a UESCAPE clause following the Unicode quoted identifier. + * + * TODO: these rules assume "" is still a valid escape sequence within a Unicode quoted identifier. + */ + +UnicodeQuotedIdentifier: 'U' '&' QuotedIdentifier; +// This is a Unicode quoted identifier which only contains valid characters but is not terminated + +UnterminatedUnicodeQuotedIdentifier: 'U' '&' UnterminatedQuotedIdentifier; +// This is a Unicode quoted identifier which is terminated but contains a \u0000 character + +InvalidUnicodeQuotedIdentifier: 'U' '&' InvalidQuotedIdentifier; +// This is a Unicode quoted identifier which is unterminated and contains a \u0000 character + +InvalidUnterminatedUnicodeQuotedIdentifier: 'U' '&' InvalidUnterminatedQuotedIdentifier; +// + +// CONSTANTS (4.1.2) + +// + +// String Constants (4.1.2.1) + +StringConstant: UnterminatedStringConstant '\''; + +UnterminatedStringConstant: '\'' ('\'\'' | ~ '\'')*; +// String Constants with C-style Escapes (4.1.2.2) + +BeginEscapeStringConstant: 'E' '\'' -> more, pushMode (EscapeStringConstantMode); +// String Constants with Unicode Escapes (4.1.2.3) + +// + +// Note that escape sequences are never checked as part of this token due to the ability of users to change the escape + +// character with a UESCAPE clause following the Unicode string constant. + +// + +// TODO: these rules assume '' is still a valid escape sequence within a Unicode string constant. + +UnicodeEscapeStringConstant: UnterminatedUnicodeEscapeStringConstant '\''; + +UnterminatedUnicodeEscapeStringConstant: 'U' '&' UnterminatedStringConstant; +// Dollar-quoted String Constants (4.1.2.4) + +BeginDollarStringConstant: '$' Tag? '$' {this->PushTag();} -> pushMode (DollarQuotedStringMode); +/* "The tag, if any, of a dollar-quoted string follows the same rules as an + * unquoted identifier, except that it cannot contain a dollar sign." + */ + +fragment Tag: IdentifierStartChar StrictIdentifierChar*; +// Bit-strings Constants (4.1.2.5) + +BinaryStringConstant: UnterminatedBinaryStringConstant '\''; + +UnterminatedBinaryStringConstant: 'B' '\'' [01]*; + +InvalidBinaryStringConstant: InvalidUnterminatedBinaryStringConstant '\''; + +InvalidUnterminatedBinaryStringConstant: 'B' UnterminatedStringConstant; + +HexadecimalStringConstant: UnterminatedHexadecimalStringConstant '\''; + +UnterminatedHexadecimalStringConstant: 'X' '\'' [0-9A-F]*; + +InvalidHexadecimalStringConstant: InvalidUnterminatedHexadecimalStringConstant '\''; + +InvalidUnterminatedHexadecimalStringConstant: 'X' UnterminatedStringConstant; +// Numeric Constants (4.1.2.6) + +Integral: Digits; + +BinaryIntegral: '0b' Digits; + +OctalIntegral: '0o' Digits; + +HexadecimalIntegral: '0x' Digits; + +NumericFail: Digits '..' {this->HandleNumericFail();}; + +Numeric: + Digits '.' Digits? /*? replaced with + to solve problem with DOT_DOT .. but this surely must be rewriten */ ( + 'E' [+-]? Digits + )? + | '.' Digits ('E' [+-]? Digits)? + | Digits 'E' [+-]? Digits +; + +fragment Digits: [0-9]+; + +PLSQLVARIABLENAME: ':' [A-Z_] [A-Z_0-9$]*; + +PLSQLIDENTIFIER: ':"' ('\\' . | '""' | ~ ('"' | '\\'))* '"'; +// + +// WHITESPACE (4.1) + +// + +Whitespace: [ \t]+ -> channel (HIDDEN); + +Newline: ('\r' '\n'? | '\n') -> channel (HIDDEN); +// + +// COMMENTS (4.1.5) + +// + +LineComment: '--' ~ [\r\n]* -> channel (HIDDEN); + +BlockComment: + ('/*' ('/'* BlockComment | ~ [/*] | '/'+ ~ [/*] | '*'+ ~ [/*])* '*'* '*/') -> channel (HIDDEN) +; + +UnterminatedBlockComment: + '/*' ( + '/'* BlockComment + | // these characters are not part of special sequences in a block comment + ~ [/*] + | // handle / or * characters which are not part of /* or */ and do not appear at the end of the file + ('/'+ ~ [/*] | '*'+ ~ [/*]) + )* + // Handle the case of / or * characters at the end of the file, or a nested unterminated block comment + ('/'+ | '*'+ | '/'* UnterminatedBlockComment)? + // Optional assertion to make sure this rule is working as intended + {this->UnterminatedBlockCommentDebugAssert();} +; +// + +// META-COMMANDS + +// + +// http://www.postgresql.org/docs/9.3/static/app-psql.html + +MetaCommand: '\\' -> pushMode(META), more ; + +// + +// ERROR + +// + +// Any character which does not match one of the above rules will appear in the token stream as an ErrorCharacter token. + +// This ensures the lexer itself will never encounter a syntax error, so all error handling may be performed by the + +// parser. + +ErrorCharacter: .; + +mode EscapeStringConstantMode; +EscapeStringConstant: EscapeStringText '\'' -> mode (AfterEscapeStringConstantMode); + +UnterminatedEscapeStringConstant: + EscapeStringText + // Handle a final unmatched \ character appearing at the end of the file + '\\'? EOF +; + +fragment EscapeStringText options { caseInsensitive = false; }: + ( + '\'\'' + | '\\' ( + // two-digit hex escapes are still valid when treated as single-digit escapes + 'x' [0-9a-fA-F] + | 'u' [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] + | 'U' [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F] + | // Any character other than the Unicode escapes can follow a backslash. Some have special meaning, + // but that doesn't affect the syntax. + ~ [xuU] + ) + | ~ ['\\] + )* +; + +InvalidEscapeStringConstant: InvalidEscapeStringText '\'' -> mode (AfterEscapeStringConstantMode); + +InvalidUnterminatedEscapeStringConstant: + InvalidEscapeStringText + // Handle a final unmatched \ character appearing at the end of the file + '\\'? EOF +; + +fragment InvalidEscapeStringText: ('\'\'' | '\\' . | ~ ['\\])*; + +mode AfterEscapeStringConstantMode; +AfterEscapeStringConstantMode_Whitespace: Whitespace -> type (Whitespace), channel (HIDDEN); + +AfterEscapeStringConstantMode_Newline: + Newline -> type (Newline), channel (HIDDEN), mode (AfterEscapeStringConstantWithNewlineMode) +; + +AfterEscapeStringConstantMode_NotContinued: + -> skip, popMode +; + +mode AfterEscapeStringConstantWithNewlineMode; +AfterEscapeStringConstantWithNewlineMode_Whitespace: + Whitespace -> type (Whitespace), channel (HIDDEN) +; + +AfterEscapeStringConstantWithNewlineMode_Newline: Newline -> type (Newline), channel (HIDDEN); + +AfterEscapeStringConstantWithNewlineMode_Continued: + '\'' -> more, mode (EscapeStringConstantMode) +; + +AfterEscapeStringConstantWithNewlineMode_NotContinued: + -> skip, popMode +; + +mode DollarQuotedStringMode; +DollarText: + ~ '$'+ + //| '$'([0-9])+ + | // this alternative improves the efficiency of handling $ characters within a dollar-quoted string which are + + // not part of the ending tag. + '$' ~ '$'* +; + +// NB: Next rule on two lines in order to make transformGrammar.py easy. +EndDollarStringConstant: ('$' Tag? '$') {this->IsTag()}? + {this->PopTag();} -> popMode; + +mode META; +MetaSemi : {this->IsSemiColon()}? ';' -> type(SEMI), popMode ; +MetaOther : ~[;\r\n\\"] .*? ('\\\\' | [\r\n]+) -> type(SEMI), popMode ; diff --git a/src/stewkk/sql/logic/parser/PostgreSQLLexerBase.cpp b/src/stewkk/sql/logic/parser/PostgreSQLLexerBase.cpp new file mode 100644 index 0000000..13f1dfd --- /dev/null +++ b/src/stewkk/sql/logic/parser/PostgreSQLLexerBase.cpp @@ -0,0 +1,81 @@ +#include "antlr4-runtime.h" +#include "PostgreSQLLexerBase.h" +#include "PostgreSQLLexer.h" +#include +#include +#include + +PostgreSQLLexerBase::PostgreSQLLexerBase(antlr4::CharStream * input) : antlr4::Lexer(input) +{ + _input = input; +} + +void PostgreSQLLexerBase::PushTag() +{ + tags.push(this->getText()); +} + +bool PostgreSQLLexerBase::IsTag() +{ + return this->getText() == tags.top(); +} + +void PostgreSQLLexerBase::PopTag() +{ + tags.pop(); +} + +void PostgreSQLLexerBase::UnterminatedBlockCommentDebugAssert() +{ +} + +bool PostgreSQLLexerBase::CheckLaMinus() +{ + return this->getInputStream()->LA(1) != '-'; +} + +bool PostgreSQLLexerBase::CheckLaStar() +{ + return this->getInputStream()->LA(1) != '*'; +} + +bool PostgreSQLLexerBase::CharIsLetter() +{ + return std::iswalpha(static_cast(this->getInputStream()->LA(-1))); +} + +void PostgreSQLLexerBase::HandleNumericFail() +{ + this->getInputStream()->seek(this->getInputStream()->index() - 2); + this->setType(stewkk::sql::codegen::PostgreSQLLexer::Integral); +} + +void PostgreSQLLexerBase::HandleLessLessGreaterGreater() +{ + if (this->getText() == "<<") this->setType(stewkk::sql::codegen::PostgreSQLLexer::LESS_LESS); + if (this->getText() == ">>") this->setType(stewkk::sql::codegen::PostgreSQLLexer::GREATER_GREATER); +} + + +char32_t surrogate_to_utf32(char16_t high, char16_t low) +{ + return (high << 10) + low - 0x35fdc00; +} + +int toCodePoint(int high, int low) +{ + return surrogate_to_utf32(high, low); +} + + +bool PostgreSQLLexerBase::CheckIfUtf32Letter() +{ + char high = static_cast(this->getInputStream()->LA(-2)); + char low = static_cast(this->getInputStream()->LA(-1)); + return std::iswalpha(toCodePoint(high, low)); +} + +bool PostgreSQLLexerBase::IsSemiColon() +{ + return ';' == (char)this->getInputStream()->LA(1); +} diff --git a/src/stewkk/sql/logic/parser/PostgreSQLLexerBase.h b/src/stewkk/sql/logic/parser/PostgreSQLLexerBase.h new file mode 100644 index 0000000..d55d507 --- /dev/null +++ b/src/stewkk/sql/logic/parser/PostgreSQLLexerBase.h @@ -0,0 +1,24 @@ +#pragma once +#include "antlr4-runtime.h" +#include +#include + +class PostgreSQLLexerBase : public antlr4::Lexer +{ + public: + PostgreSQLLexerBase(antlr4::CharStream * input); + void PushTag(); + bool IsTag(); + void PopTag(); + void UnterminatedBlockCommentDebugAssert(); + bool CheckLaMinus(); + bool CheckLaStar(); + bool CharIsLetter(); + void HandleNumericFail(); + void HandleLessLessGreaterGreater(); + bool CheckIfUtf32Letter(); + bool IsSemiColon(); + private: + std::stack tags; + +}; diff --git a/src/stewkk/sql/logic/parser/PostgreSQLParser.g4 b/src/stewkk/sql/logic/parser/PostgreSQLParser.g4 new file mode 100644 index 0000000..a5e7a48 --- /dev/null +++ b/src/stewkk/sql/logic/parser/PostgreSQLParser.g4 @@ -0,0 +1,5461 @@ +/* +PostgreSQL grammar. +The MIT License (MIT). +Copyright (c) 2021-2023, Oleksii Kovalov (Oleksii.Kovalov@outlook.com). +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +// $antlr-format alignTrailingComments true, columnLimit 150, minEmptyLines 1, maxEmptyLinesToKeep 1, reflowComments false, useTab false +// $antlr-format allowShortRulesOnASingleLine false, allowShortBlocksOnASingleLine true, alignSemicolons hanging, alignColons hanging + +parser grammar PostgreSQLParser; + +options { + tokenVocab = PostgreSQLLexer; + superClass = PostgreSQLParserBase; +} + +@header {#include "PostgreSQLParserBase.h"} + +root + : stmtblock EOF + ; + +stmtblock + : stmtmulti + ; + +stmtmulti + : stmt? (SEMI stmt?)* + ; + +stmt + : altereventtrigstmt + | altercollationstmt + | alterdatabasestmt + | alterdatabasesetstmt + | alterdefaultprivilegesstmt + | alterdomainstmt + | alterenumstmt + | alterextensionstmt + | alterextensioncontentsstmt + | alterfdwstmt + | alterforeignserverstmt + | alterfunctionstmt + | altergroupstmt + | alterobjectdependsstmt + | alterobjectschemastmt + | alterownerstmt + | alteroperatorstmt + | altertypestmt + | alterpolicystmt + | alterseqstmt + | altersystemstmt + | altertablestmt + | altertblspcstmt + | altercompositetypestmt + | alterpublicationstmt + | alterrolesetstmt + | alterrolestmt + | altersubscriptionstmt + | alterstatsstmt + | altertsconfigurationstmt + | altertsdictionarystmt + | alterusermappingstmt + | analyzestmt + | callstmt + | checkpointstmt + | closeportalstmt + | clusterstmt + | commentstmt + | constraintssetstmt + | copystmt + | createamstmt + | createasstmt + | createassertionstmt + | createcaststmt + | createconversionstmt + | createdomainstmt + | createextensionstmt + | createfdwstmt + | createforeignserverstmt + | createforeigntablestmt + | createfunctionstmt + | creategroupstmt + | creatematviewstmt + | createopclassstmt + | createopfamilystmt + | createpublicationstmt + | alteropfamilystmt + | createpolicystmt + | createplangstmt + | createschemastmt + | createseqstmt + | createstmt + | createsubscriptionstmt + | createstatsstmt + | createtablespacestmt + | createtransformstmt + | createtrigstmt + | createeventtrigstmt + | createrolestmt + | createuserstmt + | createusermappingstmt + | createdbstmt + | deallocatestmt + | declarecursorstmt + | definestmt + | deletestmt + | discardstmt + | dostmt + | dropcaststmt + | dropopclassstmt + | dropopfamilystmt + | dropownedstmt + | dropstmt + | dropsubscriptionstmt + | droptablespacestmt + | droptransformstmt + | droprolestmt + | dropusermappingstmt + | dropdbstmt + | executestmt + | explainstmt + | fetchstmt + | grantstmt + | grantrolestmt + | importforeignschemastmt + | indexstmt + | insertstmt + | mergestmt + | listenstmt + | refreshmatviewstmt + | loadstmt + | lockstmt + | notifystmt + | preparestmt + | reassignownedstmt + | reindexstmt + | removeaggrstmt + | removefuncstmt + | removeoperstmt + | renamestmt + | revokestmt + | revokerolestmt + | rulestmt + | seclabelstmt + | selectstmt + | transactionstmt + | truncatestmt + | unlistenstmt + | updatestmt + | vacuumstmt + | variableresetstmt + | variablesetstmt + | variableshowstmt + | viewstmt + ; + +callstmt + : CALL func_application + ; + +createrolestmt + : CREATE ROLE roleid with_? optrolelist + ; + +with_ + : WITH + //| WITH_LA + + ; + +optrolelist + : createoptroleelem* + ; + +alteroptrolelist + : alteroptroleelem* + ; + +alteroptroleelem + : PASSWORD (sconst | NULL_P) + | (ENCRYPTED | UNENCRYPTED) PASSWORD sconst + | INHERIT + | CONNECTION LIMIT signediconst + | VALID UNTIL sconst + | USER role_list + | identifier + ; + +createoptroleelem + : alteroptroleelem + | SYSID iconst + | ADMIN role_list + | ROLE role_list + | IN_P (ROLE | GROUP_P) role_list + ; + +createuserstmt + : CREATE USER roleid with_? optrolelist + ; + +alterrolestmt + : ALTER (ROLE | USER) rolespec with_? alteroptrolelist + ; + +in_database_ + : + IN_P DATABASE name + ; + +alterrolesetstmt + : ALTER (ROLE | USER) ALL? rolespec in_database_? setresetclause + ; + +droprolestmt + : DROP (ROLE | USER | GROUP_P) (IF_P EXISTS)? role_list + ; + +creategroupstmt + : CREATE GROUP_P roleid with_? optrolelist + ; + +altergroupstmt + : ALTER GROUP_P rolespec add_drop USER role_list + ; + +add_drop + : ADD_P + | DROP + ; + +createschemastmt + : CREATE SCHEMA (IF_P NOT EXISTS)? (optschemaname? AUTHORIZATION rolespec | colid) optschemaeltlist + ; + +optschemaname + : colid + + ; + +optschemaeltlist + : schema_stmt* + ; + +schema_stmt + : createstmt + | indexstmt + | createseqstmt + | createtrigstmt + | grantstmt + | viewstmt + ; + +variablesetstmt + : SET (LOCAL | SESSION)? set_rest + ; + +set_rest + : TRANSACTION transaction_mode_list + | SESSION CHARACTERISTICS AS TRANSACTION transaction_mode_list + | set_rest_more + ; + +generic_set + : var_name (TO | EQUAL) (var_list | DEFAULT) + ; + +set_rest_more + : generic_set + | var_name FROM CURRENT_P + | TIME ZONE zone_value + | CATALOG sconst + | SCHEMA sconst + | NAMES encoding_? + | ROLE nonreservedword_or_sconst + | SESSION AUTHORIZATION nonreservedword_or_sconst + | XML_P OPTION document_or_content + | TRANSACTION SNAPSHOT sconst + ; + +var_name + : colid (DOT colid)* + ; + +var_list + : var_value (COMMA var_value)* + ; + +var_value + : boolean_or_string_ + | numericonly + ; + +iso_level + : READ (UNCOMMITTED | COMMITTED) + | REPEATABLE READ + | SERIALIZABLE + ; + +boolean_or_string_ + : TRUE_P + | FALSE_P + | ON + | nonreservedword_or_sconst + ; + +zone_value + : sconst + | identifier + | constinterval sconst interval_? + | constinterval OPEN_PAREN iconst CLOSE_PAREN sconst + | numericonly + | DEFAULT + | LOCAL + ; + +encoding_ + : sconst + | DEFAULT + + ; + +nonreservedword_or_sconst + : nonreservedword + | sconst + ; + +variableresetstmt + : RESET reset_rest + ; + +reset_rest + : generic_reset + | TIME ZONE + | TRANSACTION ISOLATION LEVEL + | SESSION AUTHORIZATION + ; + +generic_reset + : var_name + | ALL + ; + +setresetclause + : SET set_rest + | variableresetstmt + ; + +functionsetresetclause + : SET set_rest_more + | variableresetstmt + ; + +variableshowstmt + : SHOW (var_name | TIME ZONE | TRANSACTION ISOLATION LEVEL | SESSION AUTHORIZATION | ALL) + ; + +constraintssetstmt + : SET CONSTRAINTS constraints_set_list constraints_set_mode + ; + +constraints_set_list + : ALL + | qualified_name_list + ; + +constraints_set_mode + : DEFERRED + | IMMEDIATE + ; + +checkpointstmt + : CHECKPOINT + ; + +discardstmt + : DISCARD (ALL | TEMP | TEMPORARY | PLANS | SEQUENCES) + ; + +altertablestmt + : ALTER TABLE (IF_P EXISTS)? relation_expr (alter_table_cmds | partition_cmd) + | ALTER TABLE ALL IN_P TABLESPACE name (OWNED BY role_list)? SET TABLESPACE name nowait_? + | ALTER INDEX (IF_P EXISTS)? qualified_name (alter_table_cmds | index_partition_cmd) + | ALTER INDEX ALL IN_P TABLESPACE name (OWNED BY role_list)? SET TABLESPACE name nowait_? + | ALTER SEQUENCE (IF_P EXISTS)? qualified_name alter_table_cmds + | ALTER VIEW (IF_P EXISTS)? qualified_name alter_table_cmds + | ALTER MATERIALIZED VIEW (IF_P EXISTS)? qualified_name alter_table_cmds + | ALTER MATERIALIZED VIEW ALL IN_P TABLESPACE name (OWNED BY role_list)? SET TABLESPACE name nowait_? + | ALTER FOREIGN TABLE (IF_P EXISTS)? relation_expr alter_table_cmds + ; + +alter_table_cmds + : alter_table_cmd (COMMA alter_table_cmd)* + ; + +partition_cmd + : ATTACH PARTITION qualified_name partitionboundspec + | DETACH PARTITION qualified_name + ; + +index_partition_cmd + : ATTACH PARTITION qualified_name + ; + +alter_table_cmd + : ADD_P columnDef + | ADD_P IF_P NOT EXISTS columnDef + | ADD_P COLUMN columnDef + | ADD_P COLUMN IF_P NOT EXISTS columnDef + | ALTER column_? colid alter_column_default + | ALTER column_? colid DROP NOT NULL_P + | ALTER column_? colid SET NOT NULL_P + | ALTER column_? colid DROP EXPRESSION + | ALTER column_? colid DROP EXPRESSION IF_P EXISTS + | ALTER column_? colid SET STATISTICS signediconst + | ALTER column_? iconst SET STATISTICS signediconst + | ALTER column_? colid SET reloptions + | ALTER column_? colid RESET reloptions + | ALTER column_? colid SET STORAGE colid + | ALTER column_? colid ADD_P GENERATED generated_when AS IDENTITY_P optparenthesizedseqoptlist? + | ALTER column_? colid alter_identity_column_option_list + | ALTER column_? colid DROP IDENTITY_P + | ALTER column_? colid DROP IDENTITY_P IF_P EXISTS + | DROP column_? IF_P EXISTS colid drop_behavior_? + | DROP column_? colid drop_behavior_? + | ALTER column_? colid set_data_? TYPE_P typename collate_clause_? alter_using? + | ALTER column_? colid alter_generic_options + | ADD_P tableconstraint + | ALTER CONSTRAINT name constraintattributespec + | VALIDATE CONSTRAINT name + | DROP CONSTRAINT IF_P EXISTS name drop_behavior_? + | DROP CONSTRAINT name drop_behavior_? + | SET WITHOUT OIDS + | CLUSTER ON name + | SET WITHOUT CLUSTER + | SET LOGGED + | SET UNLOGGED + | ENABLE_P TRIGGER name + | ENABLE_P ALWAYS TRIGGER name + | ENABLE_P REPLICA TRIGGER name + | ENABLE_P TRIGGER ALL + | ENABLE_P TRIGGER USER + | DISABLE_P TRIGGER name + | DISABLE_P TRIGGER ALL + | DISABLE_P TRIGGER USER + | ENABLE_P RULE name + | ENABLE_P ALWAYS RULE name + | ENABLE_P REPLICA RULE name + | DISABLE_P RULE name + | INHERIT qualified_name + | NO INHERIT qualified_name + | OF any_name + | NOT OF + | OWNER TO rolespec + | SET TABLESPACE name + | SET reloptions + | RESET reloptions + | REPLICA IDENTITY_P replica_identity + | ENABLE_P ROW LEVEL SECURITY + | DISABLE_P ROW LEVEL SECURITY + | FORCE ROW LEVEL SECURITY + | NO FORCE ROW LEVEL SECURITY + | alter_generic_options + ; + +alter_column_default + : SET DEFAULT a_expr + | DROP DEFAULT + ; + +drop_behavior_ + : CASCADE + | RESTRICT + + ; + +collate_clause_ + : COLLATE any_name + + ; + +alter_using + : USING a_expr + + ; + +replica_identity + : NOTHING + | FULL + | DEFAULT + | USING INDEX name + ; + +reloptions + : OPEN_PAREN reloption_list CLOSE_PAREN + ; + +reloptions_ + : WITH reloptions + + ; + +reloption_list + : reloption_elem (COMMA reloption_elem)* + ; + +reloption_elem + : colLabel (EQUAL def_arg | DOT colLabel (EQUAL def_arg)?)? + ; + +alter_identity_column_option_list + : alter_identity_column_option+ + ; + +alter_identity_column_option + : RESTART (with_? numericonly)? + | SET (seqoptelem | GENERATED generated_when) + ; + +partitionboundspec + : FOR VALUES WITH OPEN_PAREN hash_partbound CLOSE_PAREN + | FOR VALUES IN_P OPEN_PAREN expr_list CLOSE_PAREN + | FOR VALUES FROM OPEN_PAREN expr_list CLOSE_PAREN TO OPEN_PAREN expr_list CLOSE_PAREN + | DEFAULT + ; + +hash_partbound_elem + : nonreservedword iconst + ; + +hash_partbound + : hash_partbound_elem (COMMA hash_partbound_elem)* + ; + +altercompositetypestmt + : ALTER TYPE_P any_name alter_type_cmds + ; + +alter_type_cmds + : alter_type_cmd (COMMA alter_type_cmd)* + ; + +alter_type_cmd + : ADD_P ATTRIBUTE tablefuncelement drop_behavior_? + | DROP ATTRIBUTE (IF_P EXISTS)? colid drop_behavior_? + | ALTER ATTRIBUTE colid set_data_? TYPE_P typename collate_clause_? drop_behavior_? + ; + +closeportalstmt + : CLOSE (cursor_name | ALL) + ; + +copystmt + : COPY binary_? qualified_name column_list_? copy_from program_? copy_file_name copy_delimiter? with_? copy_options where_clause? + | COPY OPEN_PAREN preparablestmt CLOSE_PAREN TO program_? copy_file_name with_? copy_options + ; + +copy_from + : FROM + | TO + ; + +program_ + : PROGRAM + + ; + +copy_file_name + : sconst + | STDIN + | STDOUT + ; + +copy_options + : copy_opt_list + | OPEN_PAREN copy_generic_opt_list CLOSE_PAREN + ; + +copy_opt_list + : copy_opt_item* + ; + +copy_opt_item + : BINARY + | FREEZE + | DELIMITER as_? sconst + | NULL_P as_? sconst + | CSV + | HEADER_P + | QUOTE as_? sconst + | ESCAPE as_? sconst + | FORCE QUOTE columnlist + | FORCE QUOTE STAR + | FORCE NOT NULL_P columnlist + | FORCE NULL_P columnlist + | ENCODING sconst + ; + +binary_ + : BINARY + + ; + +copy_delimiter + : using_? DELIMITERS sconst + + ; + +using_ + : USING + + ; + +copy_generic_opt_list + : copy_generic_opt_elem (COMMA copy_generic_opt_elem)* + ; + +copy_generic_opt_elem + : colLabel copy_generic_opt_arg? + ; + +copy_generic_opt_arg + : boolean_or_string_ + | numericonly + | STAR + | OPEN_PAREN copy_generic_opt_arg_list CLOSE_PAREN + + ; + +copy_generic_opt_arg_list + : copy_generic_opt_arg_list_item (COMMA copy_generic_opt_arg_list_item)* + ; + +copy_generic_opt_arg_list_item + : boolean_or_string_ + ; + +createstmt + : CREATE opttemp? TABLE (IF_P NOT EXISTS)? qualified_name ( + OPEN_PAREN opttableelementlist? CLOSE_PAREN optinherit? optpartitionspec? table_access_method_clause? optwith? oncommitoption? opttablespace? + | OF any_name opttypedtableelementlist? optpartitionspec? table_access_method_clause? optwith? oncommitoption? opttablespace? + | PARTITION OF qualified_name opttypedtableelementlist? partitionboundspec optpartitionspec? table_access_method_clause? optwith? oncommitoption? + opttablespace? + ) + ; + +opttemp + : TEMPORARY + | TEMP + | LOCAL (TEMPORARY | TEMP) + | GLOBAL (TEMPORARY | TEMP) + | UNLOGGED + + ; + +opttableelementlist + : tableelementlist + + ; + +opttypedtableelementlist + : OPEN_PAREN typedtableelementlist CLOSE_PAREN + + ; + +tableelementlist + : tableelement (COMMA tableelement)* + ; + +typedtableelementlist + : typedtableelement (COMMA typedtableelement)* + ; + +tableelement + : tableconstraint + | tablelikeclause + | columnDef + ; + +typedtableelement + : columnOptions + | tableconstraint + ; + +columnDef + : colid typename create_generic_options? colquallist + ; + +columnOptions + : colid (WITH OPTIONS)? colquallist + ; + +colquallist + : colconstraint* + ; + +colconstraint + : CONSTRAINT name colconstraintelem + | colconstraintelem + | constraintattr + | COLLATE any_name + ; + +colconstraintelem + : NOT NULL_P + | NULL_P + | UNIQUE definition_? optconstablespace? + | PRIMARY KEY definition_? optconstablespace? + | CHECK OPEN_PAREN a_expr CLOSE_PAREN no_inherit_? + | DEFAULT b_expr + | GENERATED generated_when AS ( + IDENTITY_P optparenthesizedseqoptlist? + | OPEN_PAREN a_expr CLOSE_PAREN STORED + ) + | REFERENCES qualified_name column_list_? key_match? key_actions? + ; + +generated_when + : ALWAYS + | BY DEFAULT + ; + +constraintattr + : DEFERRABLE + | NOT DEFERRABLE + | INITIALLY (DEFERRED | IMMEDIATE) + ; + +tablelikeclause + : LIKE qualified_name tablelikeoptionlist + ; + +tablelikeoptionlist + : ((INCLUDING | EXCLUDING) tablelikeoption)* + ; + +tablelikeoption + : COMMENTS + | CONSTRAINTS + | DEFAULTS + | IDENTITY_P + | GENERATED + | INDEXES + | STATISTICS + | STORAGE + | ALL + ; + +tableconstraint + : CONSTRAINT name constraintelem + | constraintelem + ; + +constraintelem + : CHECK OPEN_PAREN a_expr CLOSE_PAREN constraintattributespec + | UNIQUE ( + OPEN_PAREN columnlist CLOSE_PAREN c_include_? definition_? optconstablespace? constraintattributespec + | existingindex constraintattributespec + ) + | PRIMARY KEY ( + OPEN_PAREN columnlist CLOSE_PAREN c_include_? definition_? optconstablespace? constraintattributespec + | existingindex constraintattributespec + ) + | EXCLUDE access_method_clause? OPEN_PAREN exclusionconstraintlist CLOSE_PAREN c_include_? definition_? optconstablespace? exclusionwhereclause? + constraintattributespec + | FOREIGN KEY OPEN_PAREN columnlist CLOSE_PAREN REFERENCES qualified_name column_list_? key_match? key_actions? constraintattributespec + ; + +no_inherit_ + : NO INHERIT + + ; + +column_list_ + : OPEN_PAREN columnlist CLOSE_PAREN + + ; + +columnlist + : columnElem (COMMA columnElem)* + ; + +columnElem + : colid + ; + +c_include_ + : INCLUDE OPEN_PAREN columnlist CLOSE_PAREN + + ; + +key_match + : MATCH (FULL | PARTIAL | SIMPLE) + + ; + +exclusionconstraintlist + : exclusionconstraintelem (COMMA exclusionconstraintelem)* + ; + +exclusionconstraintelem + : index_elem WITH (any_operator | OPERATOR OPEN_PAREN any_operator CLOSE_PAREN) + ; + +exclusionwhereclause + : WHERE OPEN_PAREN a_expr CLOSE_PAREN + + ; + +key_actions + : key_update + | key_delete + | key_update key_delete + | key_delete key_update + + ; + +key_update + : ON UPDATE key_action + ; + +key_delete + : ON DELETE_P key_action + ; + +key_action + : NO ACTION + | RESTRICT + | CASCADE + | SET (NULL_P | DEFAULT) + ; + +optinherit + : INHERITS OPEN_PAREN qualified_name_list CLOSE_PAREN + + ; + +optpartitionspec + : partitionspec + + ; + +partitionspec + : PARTITION BY colid OPEN_PAREN part_params CLOSE_PAREN + ; + +part_params + : part_elem (COMMA part_elem)* + ; + +part_elem + : colid collate_? class_? + | func_expr_windowless collate_? class_? + | OPEN_PAREN a_expr CLOSE_PAREN collate_? class_? + ; + +table_access_method_clause + : USING name + + ; + +optwith + : WITH reloptions + | WITHOUT OIDS + + ; + +oncommitoption + : ON COMMIT (DROP | DELETE_P ROWS | PRESERVE ROWS) + + ; + +opttablespace + : TABLESPACE name + + ; + +optconstablespace + : USING INDEX TABLESPACE name + + ; + +existingindex + : USING INDEX name + ; + +createstatsstmt + : CREATE STATISTICS (IF_P NOT EXISTS)? any_name name_list_? ON expr_list FROM from_list + ; + +alterstatsstmt + : ALTER STATISTICS (IF_P EXISTS)? any_name SET STATISTICS signediconst + ; + +createasstmt + : CREATE opttemp? TABLE (IF_P NOT EXISTS)? create_as_target AS selectstmt with_data_? + ; + +create_as_target + : qualified_name column_list_? table_access_method_clause? optwith? oncommitoption? opttablespace? + ; + +with_data_ + : WITH (DATA_P | NO DATA_P) + + ; + +creatematviewstmt + : CREATE optnolog? MATERIALIZED VIEW (IF_P NOT EXISTS)? create_mv_target AS selectstmt with_data_? + ; + +create_mv_target + : qualified_name column_list_? table_access_method_clause? reloptions_? opttablespace? + ; + +optnolog + : UNLOGGED + + ; + +refreshmatviewstmt + : REFRESH MATERIALIZED VIEW concurrently_? qualified_name with_data_? + ; + +createseqstmt + : CREATE opttemp? SEQUENCE (IF_P NOT EXISTS)? qualified_name optseqoptlist? + ; + +alterseqstmt + : ALTER SEQUENCE (IF_P EXISTS)? qualified_name seqoptlist + ; + +optseqoptlist + : seqoptlist + + ; + +optparenthesizedseqoptlist + : OPEN_PAREN seqoptlist CLOSE_PAREN + + ; + +seqoptlist + : seqoptelem+ + ; + +seqoptelem + : AS simpletypename + | CACHE numericonly + | CYCLE + | INCREMENT by_? numericonly + | MAXVALUE numericonly + | MINVALUE numericonly + | NO (MAXVALUE | MINVALUE | CYCLE) + | OWNED BY any_name + | SEQUENCE NAME_P any_name + | START with_? numericonly + | RESTART with_? numericonly? + ; + +by_ + : BY + + ; + +numericonly + : fconst + | PLUS fconst + | MINUS fconst + | signediconst + ; + +numericonly_list + : numericonly (COMMA numericonly)* + ; + +createplangstmt + : CREATE or_replace_? trusted_? procedural_? LANGUAGE name ( + HANDLER handler_name inline_handler_? validator_? + )? + ; + +trusted_ + : TRUSTED + + ; + +handler_name + : name attrs? + ; + +inline_handler_ + : INLINE_P handler_name + + ; + +validator_clause + : VALIDATOR handler_name + | NO VALIDATOR + ; + +validator_ + : validator_clause + + ; + +procedural_ + : PROCEDURAL + + ; + +createtablespacestmt + : CREATE TABLESPACE name opttablespaceowner? LOCATION sconst reloptions_? + ; + +opttablespaceowner + : OWNER rolespec + + ; + +droptablespacestmt + : DROP TABLESPACE (IF_P EXISTS)? name + ; + +createextensionstmt + : CREATE EXTENSION (IF_P NOT EXISTS)? name with_? create_extension_opt_list + ; + +create_extension_opt_list + : create_extension_opt_item* + ; + +create_extension_opt_item + : SCHEMA name + | VERSION_P nonreservedword_or_sconst + | FROM nonreservedword_or_sconst + | CASCADE + ; + +alterextensionstmt + : ALTER EXTENSION name UPDATE alter_extension_opt_list + ; + +alter_extension_opt_list + : alter_extension_opt_item* + ; + +alter_extension_opt_item + : TO nonreservedword_or_sconst + ; + +alterextensioncontentsstmt + : ALTER EXTENSION name add_drop object_type_name name + | ALTER EXTENSION name add_drop object_type_any_name any_name + | ALTER EXTENSION name add_drop AGGREGATE aggregate_with_argtypes + | ALTER EXTENSION name add_drop CAST OPEN_PAREN typename AS typename CLOSE_PAREN + | ALTER EXTENSION name add_drop DOMAIN_P typename + | ALTER EXTENSION name add_drop FUNCTION function_with_argtypes + | ALTER EXTENSION name add_drop OPERATOR operator_with_argtypes + | ALTER EXTENSION name add_drop OPERATOR CLASS any_name USING name + | ALTER EXTENSION name add_drop OPERATOR FAMILY any_name USING name + | ALTER EXTENSION name add_drop PROCEDURE function_with_argtypes + | ALTER EXTENSION name add_drop ROUTINE function_with_argtypes + | ALTER EXTENSION name add_drop TRANSFORM FOR typename LANGUAGE name + | ALTER EXTENSION name add_drop TYPE_P typename + ; + +createfdwstmt + : CREATE FOREIGN DATA_P WRAPPER name fdw_options_? create_generic_options? + ; + +fdw_option + : HANDLER handler_name + | NO HANDLER + | VALIDATOR handler_name + | NO VALIDATOR + ; + +fdw_options + : fdw_option+ + ; + +fdw_options_ + : fdw_options + + ; + +alterfdwstmt + : ALTER FOREIGN DATA_P WRAPPER name fdw_options_? alter_generic_options + | ALTER FOREIGN DATA_P WRAPPER name fdw_options + ; + +create_generic_options + : OPTIONS OPEN_PAREN generic_option_list CLOSE_PAREN + + ; + +generic_option_list + : generic_option_elem (COMMA generic_option_elem)* + ; + +alter_generic_options + : OPTIONS OPEN_PAREN alter_generic_option_list CLOSE_PAREN + ; + +alter_generic_option_list + : alter_generic_option_elem (COMMA alter_generic_option_elem)* + ; + +alter_generic_option_elem + : generic_option_elem + | SET generic_option_elem + | ADD_P generic_option_elem + | DROP generic_option_name + ; + +generic_option_elem + : generic_option_name generic_option_arg + ; + +generic_option_name + : colLabel + ; + +generic_option_arg + : sconst + ; + +createforeignserverstmt + : CREATE SERVER name type_? foreign_server_version_? FOREIGN DATA_P WRAPPER name create_generic_options? + | CREATE SERVER IF_P NOT EXISTS name type_? foreign_server_version_? FOREIGN DATA_P WRAPPER name create_generic_options? + ; + +type_ + : TYPE_P sconst + + ; + +foreign_server_version + : VERSION_P (sconst | NULL_P) + ; + +foreign_server_version_ + : foreign_server_version + + ; + +alterforeignserverstmt + : ALTER SERVER name (alter_generic_options | foreign_server_version alter_generic_options?) + ; + +createforeigntablestmt + : CREATE FOREIGN TABLE qualified_name OPEN_PAREN opttableelementlist? CLOSE_PAREN optinherit? SERVER name create_generic_options? + | CREATE FOREIGN TABLE IF_P NOT EXISTS qualified_name OPEN_PAREN opttableelementlist? CLOSE_PAREN optinherit? SERVER name create_generic_options? + | CREATE FOREIGN TABLE qualified_name PARTITION OF qualified_name opttypedtableelementlist? partitionboundspec SERVER name create_generic_options? + | CREATE FOREIGN TABLE IF_P NOT EXISTS qualified_name PARTITION OF qualified_name opttypedtableelementlist? partitionboundspec SERVER name + create_generic_options? + ; + +importforeignschemastmt + : IMPORT_P FOREIGN SCHEMA name import_qualification? FROM SERVER name INTO name create_generic_options? + ; + +import_qualification_type + : LIMIT TO + | EXCEPT + ; + +import_qualification + : import_qualification_type OPEN_PAREN relation_expr_list CLOSE_PAREN + + ; + +createusermappingstmt + : CREATE USER MAPPING FOR auth_ident SERVER name create_generic_options? + | CREATE USER MAPPING IF_P NOT EXISTS FOR auth_ident SERVER name create_generic_options? + ; + +auth_ident + : rolespec + | USER + ; + +dropusermappingstmt + : DROP USER MAPPING FOR auth_ident SERVER name + | DROP USER MAPPING IF_P EXISTS FOR auth_ident SERVER name + ; + +alterusermappingstmt + : ALTER USER MAPPING FOR auth_ident SERVER name alter_generic_options + ; + +createpolicystmt + : CREATE POLICY name ON qualified_name rowsecuritydefaultpermissive? rowsecuritydefaultforcmd? rowsecuritydefaulttorole? rowsecurityoptionalexpr? + rowsecurityoptionalwithcheck? + ; + +alterpolicystmt + : ALTER POLICY name ON qualified_name rowsecurityoptionaltorole? rowsecurityoptionalexpr? rowsecurityoptionalwithcheck? + ; + +rowsecurityoptionalexpr + : USING OPEN_PAREN a_expr CLOSE_PAREN + + ; + +rowsecurityoptionalwithcheck + : WITH CHECK OPEN_PAREN a_expr CLOSE_PAREN + + ; + +rowsecuritydefaulttorole + : TO role_list + + ; + +rowsecurityoptionaltorole + : TO role_list + + ; + +rowsecuritydefaultpermissive + : AS identifier + + ; + +rowsecuritydefaultforcmd + : FOR row_security_cmd + + ; + +row_security_cmd + : ALL + | SELECT + | INSERT + | UPDATE + | DELETE_P + ; + +createamstmt + : CREATE ACCESS METHOD name TYPE_P am_type HANDLER handler_name + ; + +am_type + : INDEX + | TABLE + ; + +createtrigstmt + : CREATE TRIGGER name triggeractiontime triggerevents ON qualified_name triggerreferencing? triggerforspec? triggerwhen? EXECUTE + function_or_procedure func_name OPEN_PAREN triggerfuncargs CLOSE_PAREN + | CREATE CONSTRAINT TRIGGER name AFTER triggerevents ON qualified_name optconstrfromtable? constraintattributespec FOR EACH ROW triggerwhen? EXECUTE + function_or_procedure func_name OPEN_PAREN triggerfuncargs CLOSE_PAREN + ; + +triggeractiontime + : BEFORE + | AFTER + | INSTEAD OF + ; + +triggerevents + : triggeroneevent (OR triggeroneevent)* + ; + +triggeroneevent + : INSERT + | DELETE_P + | UPDATE + | UPDATE OF columnlist + | TRUNCATE + ; + +triggerreferencing + : REFERENCING triggertransitions + + ; + +triggertransitions + : triggertransition+ + ; + +triggertransition + : transitionoldornew transitionrowortable as_? transitionrelname + ; + +transitionoldornew + : NEW + | OLD + ; + +transitionrowortable + : TABLE + | ROW + ; + +transitionrelname + : colid + ; + +triggerforspec + : FOR triggerforopteach? triggerfortype + + ; + +triggerforopteach + : EACH + + ; + +triggerfortype + : ROW + | STATEMENT + ; + +triggerwhen + : WHEN OPEN_PAREN a_expr CLOSE_PAREN + + ; + +function_or_procedure + : FUNCTION + | PROCEDURE + ; + +triggerfuncargs + : (triggerfuncarg |) (COMMA triggerfuncarg)* + ; + +triggerfuncarg + : iconst + | fconst + | sconst + | colLabel + ; + +optconstrfromtable + : FROM qualified_name + + ; + +constraintattributespec + : constraintattributeElem* + ; + +constraintattributeElem + : NOT DEFERRABLE + | DEFERRABLE + | INITIALLY IMMEDIATE + | INITIALLY DEFERRED + | NOT VALID + | NO INHERIT + ; + +createeventtrigstmt + : CREATE EVENT TRIGGER name ON colLabel EXECUTE function_or_procedure func_name OPEN_PAREN CLOSE_PAREN + | CREATE EVENT TRIGGER name ON colLabel WHEN event_trigger_when_list EXECUTE function_or_procedure func_name OPEN_PAREN CLOSE_PAREN + ; + +event_trigger_when_list + : event_trigger_when_item (AND event_trigger_when_item)* + ; + +event_trigger_when_item + : colid IN_P OPEN_PAREN event_trigger_value_list CLOSE_PAREN + ; + +event_trigger_value_list + : sconst (COMMA sconst)* + ; + +altereventtrigstmt + : ALTER EVENT TRIGGER name enable_trigger + ; + +enable_trigger + : ENABLE_P + | ENABLE_P REPLICA + | ENABLE_P ALWAYS + | DISABLE_P + ; + +createassertionstmt + : CREATE ASSERTION any_name CHECK OPEN_PAREN a_expr CLOSE_PAREN constraintattributespec + ; + +definestmt + : CREATE or_replace_? AGGREGATE func_name aggr_args definition + | CREATE or_replace_? AGGREGATE func_name old_aggr_definition + | CREATE OPERATOR any_operator definition + | CREATE TYPE_P any_name definition + | CREATE TYPE_P any_name + | CREATE TYPE_P any_name AS OPEN_PAREN opttablefuncelementlist? CLOSE_PAREN + | CREATE TYPE_P any_name AS ENUM_P OPEN_PAREN enum_val_list_? CLOSE_PAREN + | CREATE TYPE_P any_name AS RANGE definition + | CREATE TEXT_P SEARCH PARSER any_name definition + | CREATE TEXT_P SEARCH DICTIONARY any_name definition + | CREATE TEXT_P SEARCH TEMPLATE any_name definition + | CREATE TEXT_P SEARCH CONFIGURATION any_name definition + | CREATE COLLATION any_name definition + | CREATE COLLATION IF_P NOT EXISTS any_name definition + | CREATE COLLATION any_name FROM any_name + | CREATE COLLATION IF_P NOT EXISTS any_name FROM any_name + ; + +definition + : OPEN_PAREN def_list CLOSE_PAREN + ; + +def_list + : def_elem (COMMA def_elem)* + ; + +def_elem + : colLabel (EQUAL def_arg)? + ; + +def_arg + : func_type + | reserved_keyword + | qual_all_op + | numericonly + | sconst + | NONE + ; + +old_aggr_definition + : OPEN_PAREN old_aggr_list CLOSE_PAREN + ; + +old_aggr_list + : old_aggr_elem (COMMA old_aggr_elem)* + ; + +old_aggr_elem + : identifier EQUAL def_arg + ; + +enum_val_list_ + : enum_val_list + + ; + +enum_val_list + : sconst (COMMA sconst)* + ; + +alterenumstmt + : ALTER TYPE_P any_name ADD_P VALUE_P if_not_exists_? sconst + | ALTER TYPE_P any_name ADD_P VALUE_P if_not_exists_? sconst BEFORE sconst + | ALTER TYPE_P any_name ADD_P VALUE_P if_not_exists_? sconst AFTER sconst + | ALTER TYPE_P any_name RENAME VALUE_P sconst TO sconst + ; + +if_not_exists_ + : IF_P NOT EXISTS + + ; + +createopclassstmt + : CREATE OPERATOR CLASS any_name default_? FOR TYPE_P typename USING name opfamily_? AS opclass_item_list + ; + +opclass_item_list + : opclass_item (COMMA opclass_item)* + ; + +opclass_item + : OPERATOR iconst any_operator opclass_purpose? recheck_? + | OPERATOR iconst operator_with_argtypes opclass_purpose? recheck_? + | FUNCTION iconst function_with_argtypes + | FUNCTION iconst OPEN_PAREN type_list CLOSE_PAREN function_with_argtypes + | STORAGE typename + ; + +default_ + : DEFAULT + + ; + +opfamily_ + : FAMILY any_name + + ; + +opclass_purpose + : FOR SEARCH + | FOR ORDER BY any_name + + ; + +recheck_ + : RECHECK + + ; + +createopfamilystmt + : CREATE OPERATOR FAMILY any_name USING name + ; + +alteropfamilystmt + : ALTER OPERATOR FAMILY any_name USING name ADD_P opclass_item_list + | ALTER OPERATOR FAMILY any_name USING name DROP opclass_drop_list + ; + +opclass_drop_list + : opclass_drop (COMMA opclass_drop)* + ; + +opclass_drop + : OPERATOR iconst OPEN_PAREN type_list CLOSE_PAREN + | FUNCTION iconst OPEN_PAREN type_list CLOSE_PAREN + ; + +dropopclassstmt + : DROP OPERATOR CLASS any_name USING name drop_behavior_? + | DROP OPERATOR CLASS IF_P EXISTS any_name USING name drop_behavior_? + ; + +dropopfamilystmt + : DROP OPERATOR FAMILY any_name USING name drop_behavior_? + | DROP OPERATOR FAMILY IF_P EXISTS any_name USING name drop_behavior_? + ; + +dropownedstmt + : DROP OWNED BY role_list drop_behavior_? + ; + +reassignownedstmt + : REASSIGN OWNED BY role_list TO rolespec + ; + +dropstmt + : DROP object_type_any_name IF_P EXISTS any_name_list_ drop_behavior_? + | DROP object_type_any_name any_name_list_ drop_behavior_? + | DROP drop_type_name IF_P EXISTS name_list drop_behavior_? + | DROP drop_type_name name_list drop_behavior_? + | DROP object_type_name_on_any_name name ON any_name drop_behavior_? + | DROP object_type_name_on_any_name IF_P EXISTS name ON any_name drop_behavior_? + | DROP TYPE_P type_name_list drop_behavior_? + | DROP TYPE_P IF_P EXISTS type_name_list drop_behavior_? + | DROP DOMAIN_P type_name_list drop_behavior_? + | DROP DOMAIN_P IF_P EXISTS type_name_list drop_behavior_? + | DROP INDEX CONCURRENTLY any_name_list_ drop_behavior_? + | DROP INDEX CONCURRENTLY IF_P EXISTS any_name_list_ drop_behavior_? + ; + +object_type_any_name + : TABLE + | SEQUENCE + | VIEW + | MATERIALIZED VIEW + | INDEX + | FOREIGN TABLE + | COLLATION + | CONVERSION_P + | STATISTICS + | TEXT_P SEARCH PARSER + | TEXT_P SEARCH DICTIONARY + | TEXT_P SEARCH TEMPLATE + | TEXT_P SEARCH CONFIGURATION + ; + +object_type_name + : drop_type_name + | DATABASE + | ROLE + | SUBSCRIPTION + | TABLESPACE + ; + +drop_type_name + : ACCESS METHOD + | EVENT TRIGGER + | EXTENSION + | FOREIGN DATA_P WRAPPER + | procedural_? LANGUAGE + | PUBLICATION + | SCHEMA + | SERVER + ; + +object_type_name_on_any_name + : POLICY + | RULE + | TRIGGER + ; + +any_name_list_ + : any_name (COMMA any_name)* + ; + +any_name + : colid attrs? + ; + +attrs + : (DOT attr_name)+ + ; + +type_name_list + : typename (COMMA typename)* + ; + +truncatestmt + : TRUNCATE table_? relation_expr_list restart_seqs_? drop_behavior_? + ; + +restart_seqs_ + : CONTINUE_P IDENTITY_P + | RESTART IDENTITY_P + + ; + +commentstmt + : COMMENT ON object_type_any_name any_name IS comment_text + | COMMENT ON COLUMN any_name IS comment_text + | COMMENT ON object_type_name name IS comment_text + | COMMENT ON TYPE_P typename IS comment_text + | COMMENT ON DOMAIN_P typename IS comment_text + | COMMENT ON AGGREGATE aggregate_with_argtypes IS comment_text + | COMMENT ON FUNCTION function_with_argtypes IS comment_text + | COMMENT ON OPERATOR operator_with_argtypes IS comment_text + | COMMENT ON CONSTRAINT name ON any_name IS comment_text + | COMMENT ON CONSTRAINT name ON DOMAIN_P any_name IS comment_text + | COMMENT ON object_type_name_on_any_name name ON any_name IS comment_text + | COMMENT ON PROCEDURE function_with_argtypes IS comment_text + | COMMENT ON ROUTINE function_with_argtypes IS comment_text + | COMMENT ON TRANSFORM FOR typename LANGUAGE name IS comment_text + | COMMENT ON OPERATOR CLASS any_name USING name IS comment_text + | COMMENT ON OPERATOR FAMILY any_name USING name IS comment_text + | COMMENT ON LARGE_P OBJECT_P numericonly IS comment_text + | COMMENT ON CAST OPEN_PAREN typename AS typename CLOSE_PAREN IS comment_text + ; + +comment_text + : sconst + | NULL_P + ; + +seclabelstmt + : SECURITY LABEL provider_? ON object_type_any_name any_name IS security_label + | SECURITY LABEL provider_? ON COLUMN any_name IS security_label + | SECURITY LABEL provider_? ON object_type_name name IS security_label + | SECURITY LABEL provider_? ON TYPE_P typename IS security_label + | SECURITY LABEL provider_? ON DOMAIN_P typename IS security_label + | SECURITY LABEL provider_? ON AGGREGATE aggregate_with_argtypes IS security_label + | SECURITY LABEL provider_? ON FUNCTION function_with_argtypes IS security_label + | SECURITY LABEL provider_? ON LARGE_P OBJECT_P numericonly IS security_label + | SECURITY LABEL provider_? ON PROCEDURE function_with_argtypes IS security_label + | SECURITY LABEL provider_? ON ROUTINE function_with_argtypes IS security_label + ; + +provider_ + : FOR nonreservedword_or_sconst + + ; + +security_label + : sconst + | NULL_P + ; + +fetchstmt + : FETCH fetch_args + | MOVE fetch_args + ; + +fetch_args + : cursor_name + | from_in cursor_name + | NEXT from_in_? cursor_name + | PRIOR from_in_? cursor_name + | FIRST_P from_in_? cursor_name + | LAST_P from_in_? cursor_name + | ABSOLUTE_P signediconst from_in_? cursor_name + | RELATIVE_P signediconst from_in_? cursor_name + | signediconst from_in_? cursor_name + | ALL from_in_? cursor_name + | FORWARD from_in_? cursor_name + | FORWARD signediconst from_in_? cursor_name + | FORWARD ALL from_in_? cursor_name + | BACKWARD from_in_? cursor_name + | BACKWARD signediconst from_in_? cursor_name + | BACKWARD ALL from_in_? cursor_name + ; + +from_in + : FROM + | IN_P + ; + +from_in_ + : from_in + + ; + +grantstmt + : GRANT privileges ON privilege_target TO grantee_list grant_grant_option_? + ; + +revokestmt + : REVOKE privileges ON privilege_target FROM grantee_list drop_behavior_? + | REVOKE GRANT OPTION FOR privileges ON privilege_target FROM grantee_list drop_behavior_? + ; + +privileges + : privilege_list + | ALL + | ALL PRIVILEGES + | ALL OPEN_PAREN columnlist CLOSE_PAREN + | ALL PRIVILEGES OPEN_PAREN columnlist CLOSE_PAREN + ; + +privilege_list + : privilege (COMMA privilege)* + ; + +privilege + : SELECT column_list_? + | REFERENCES column_list_? + | CREATE column_list_? + | colid column_list_? + ; + +privilege_target + : qualified_name_list + | TABLE qualified_name_list + | SEQUENCE qualified_name_list + | FOREIGN DATA_P WRAPPER name_list + | FOREIGN SERVER name_list + | FUNCTION function_with_argtypes_list + | PROCEDURE function_with_argtypes_list + | ROUTINE function_with_argtypes_list + | DATABASE name_list + | DOMAIN_P any_name_list_ + | LANGUAGE name_list + | LARGE_P OBJECT_P numericonly_list + | SCHEMA name_list + | TABLESPACE name_list + | TYPE_P any_name_list_ + | ALL TABLES IN_P SCHEMA name_list + | ALL SEQUENCES IN_P SCHEMA name_list + | ALL FUNCTIONS IN_P SCHEMA name_list + | ALL PROCEDURES IN_P SCHEMA name_list + | ALL ROUTINES IN_P SCHEMA name_list + ; + +grantee_list + : grantee (COMMA grantee)* + ; + +grantee + : rolespec + | GROUP_P rolespec + ; + +grant_grant_option_ + : WITH GRANT OPTION + + ; + +grantrolestmt + : GRANT privilege_list TO role_list grant_admin_option_? granted_by_? + ; + +revokerolestmt + : REVOKE privilege_list FROM role_list granted_by_? drop_behavior_? + | REVOKE ADMIN OPTION FOR privilege_list FROM role_list granted_by_? drop_behavior_? + ; + +grant_admin_option_ + : WITH ADMIN OPTION + + ; + +granted_by_ + : GRANTED BY rolespec + + ; + +alterdefaultprivilegesstmt + : ALTER DEFAULT PRIVILEGES defacloptionlist defaclaction + ; + +defacloptionlist + : defacloption* + ; + +defacloption + : IN_P SCHEMA name_list + | FOR ROLE role_list + | FOR USER role_list + ; + +defaclaction + : GRANT privileges ON defacl_privilege_target TO grantee_list grant_grant_option_? + | REVOKE privileges ON defacl_privilege_target FROM grantee_list drop_behavior_? + | REVOKE GRANT OPTION FOR privileges ON defacl_privilege_target FROM grantee_list drop_behavior_? + ; + +defacl_privilege_target + : TABLES + | FUNCTIONS + | ROUTINES + | SEQUENCES + | TYPES_P + | SCHEMAS + ; + +//create index + +indexstmt + : CREATE unique_? INDEX concurrently_? index_name_? ON relation_expr access_method_clause? OPEN_PAREN index_params CLOSE_PAREN include_? + reloptions_? opttablespace? where_clause? + | CREATE unique_? INDEX concurrently_? IF_P NOT EXISTS name ON relation_expr access_method_clause? OPEN_PAREN index_params CLOSE_PAREN + include_? reloptions_? opttablespace? where_clause? + ; + +unique_ + : UNIQUE + + ; + +single_name_ + : colid + ; + +concurrently_ + : CONCURRENTLY + + ; + +index_name_ + : name + + ; + +access_method_clause + : USING name + + ; + +index_params + : index_elem (COMMA index_elem)* + ; + +index_elem_options + : collate_? class_? asc_desc_? nulls_order_? + | collate_? any_name reloptions asc_desc_? nulls_order_? + ; + +index_elem + : colid index_elem_options + | func_expr_windowless index_elem_options + | OPEN_PAREN a_expr CLOSE_PAREN index_elem_options + ; + +include_ + : INCLUDE OPEN_PAREN index_including_params CLOSE_PAREN + + ; + +index_including_params + : index_elem (COMMA index_elem)* + ; + +collate_ + : COLLATE any_name + + ; + +class_ + : any_name + + ; + +asc_desc_ + : ASC + | DESC + + ; + +//TOD NULLS_LA was used + +nulls_order_ + : NULLS_P FIRST_P + | NULLS_P LAST_P + + ; + +createfunctionstmt + : CREATE or_replace_? (FUNCTION | PROCEDURE) func_name func_args_with_defaults ( + RETURNS (func_return | TABLE OPEN_PAREN table_func_column_list CLOSE_PAREN) + )? createfunc_opt_list + ; + +or_replace_ + : OR REPLACE + + ; + +func_args + : OPEN_PAREN func_args_list? CLOSE_PAREN + ; + +func_args_list + : func_arg (COMMA func_arg)* + ; + +function_with_argtypes_list + : function_with_argtypes (COMMA function_with_argtypes)* + ; + +function_with_argtypes + : func_name func_args + | type_func_name_keyword + | colid indirection? + ; + +func_args_with_defaults + : OPEN_PAREN func_args_with_defaults_list? CLOSE_PAREN + ; + +func_args_with_defaults_list + : func_arg_with_default (COMMA func_arg_with_default)* + ; + +func_arg + : arg_class param_name? func_type + | param_name arg_class? func_type + | func_type + ; + +arg_class + : IN_P OUT_P? + | OUT_P + | INOUT + | VARIADIC + ; + +param_name + : type_function_name + ; + +func_return + : func_type + ; + +func_type + : typename + | SETOF? type_function_name attrs PERCENT TYPE_P + ; + +func_arg_with_default + : func_arg ((DEFAULT | EQUAL) a_expr)? + ; + +aggr_arg + : func_arg + ; + +aggr_args + : OPEN_PAREN ( + STAR + | aggr_args_list + | ORDER BY aggr_args_list + | aggr_args_list ORDER BY aggr_args_list + ) CLOSE_PAREN + ; + +aggr_args_list + : aggr_arg (COMMA aggr_arg)* + ; + +aggregate_with_argtypes + : func_name aggr_args + ; + +aggregate_with_argtypes_list + : aggregate_with_argtypes (COMMA aggregate_with_argtypes)* + ; + +createfunc_opt_list + : createfunc_opt_item+ {this->ParseRoutineBody();} + // | createfunc_opt_list createfunc_opt_item + ; + +common_func_opt_item + : CALLED ON NULL_P INPUT_P + | RETURNS NULL_P ON NULL_P INPUT_P + | STRICT_P + | IMMUTABLE + | STABLE + | VOLATILE + | EXTERNAL SECURITY DEFINER + | EXTERNAL SECURITY INVOKER + | SECURITY DEFINER + | SECURITY INVOKER + | LEAKPROOF + | NOT LEAKPROOF + | COST numericonly + | ROWS numericonly + | SUPPORT any_name + | functionsetresetclause + | PARALLEL colid + ; + +createfunc_opt_item + : AS func_as + | LANGUAGE nonreservedword_or_sconst + | TRANSFORM transform_type_list + | WINDOW + | common_func_opt_item + ; + +//https://www.postgresql.org/docs/9.1/sql-createfunction.html + +// | AS 'definition' + +// | AS 'obj_file', 'link_symbol' + +func_as + : + /* |AS 'definition'*/ def = sconst + /*| AS 'obj_file', 'link_symbol'*/ + | sconst COMMA sconst + ; + +transform_type_list + : FOR TYPE_P typename (COMMA FOR TYPE_P typename)* + ; + +definition_ + : WITH definition + + ; + +table_func_column + : param_name func_type + ; + +table_func_column_list + : table_func_column (COMMA table_func_column)* + ; + +alterfunctionstmt + : ALTER (FUNCTION | PROCEDURE | ROUTINE) function_with_argtypes alterfunc_opt_list restrict_? + ; + +alterfunc_opt_list + : common_func_opt_item+ + ; + +restrict_ + : RESTRICT + + ; + +removefuncstmt + : DROP FUNCTION function_with_argtypes_list drop_behavior_? + | DROP FUNCTION IF_P EXISTS function_with_argtypes_list drop_behavior_? + | DROP PROCEDURE function_with_argtypes_list drop_behavior_? + | DROP PROCEDURE IF_P EXISTS function_with_argtypes_list drop_behavior_? + | DROP ROUTINE function_with_argtypes_list drop_behavior_? + | DROP ROUTINE IF_P EXISTS function_with_argtypes_list drop_behavior_? + ; + +removeaggrstmt + : DROP AGGREGATE aggregate_with_argtypes_list drop_behavior_? + | DROP AGGREGATE IF_P EXISTS aggregate_with_argtypes_list drop_behavior_? + ; + +removeoperstmt + : DROP OPERATOR operator_with_argtypes_list drop_behavior_? + | DROP OPERATOR IF_P EXISTS operator_with_argtypes_list drop_behavior_? + ; + +oper_argtypes + : OPEN_PAREN typename CLOSE_PAREN + | OPEN_PAREN typename COMMA typename CLOSE_PAREN + | OPEN_PAREN NONE COMMA typename CLOSE_PAREN + | OPEN_PAREN typename COMMA NONE CLOSE_PAREN + ; + +any_operator + : (colid DOT)* all_op + ; + +operator_with_argtypes_list + : operator_with_argtypes (COMMA operator_with_argtypes)* + ; + +operator_with_argtypes + : any_operator oper_argtypes + ; + +dostmt + : DO dostmt_opt_list + ; + +dostmt_opt_list + : dostmt_opt_item+ + ; + +dostmt_opt_item + : sconst + | LANGUAGE nonreservedword_or_sconst + ; + +createcaststmt + : CREATE CAST OPEN_PAREN typename AS typename CLOSE_PAREN WITH FUNCTION function_with_argtypes cast_context? + | CREATE CAST OPEN_PAREN typename AS typename CLOSE_PAREN WITHOUT FUNCTION cast_context? + | CREATE CAST OPEN_PAREN typename AS typename CLOSE_PAREN WITH INOUT cast_context? + ; + +cast_context + : AS IMPLICIT_P + | AS ASSIGNMENT + + ; + +dropcaststmt + : DROP CAST if_exists_? OPEN_PAREN typename AS typename CLOSE_PAREN drop_behavior_? + ; + +if_exists_ + : IF_P EXISTS + + ; + +createtransformstmt + : CREATE or_replace_? TRANSFORM FOR typename LANGUAGE name OPEN_PAREN transform_element_list CLOSE_PAREN + ; + +transform_element_list + : FROM SQL_P WITH FUNCTION function_with_argtypes COMMA TO SQL_P WITH FUNCTION function_with_argtypes + | TO SQL_P WITH FUNCTION function_with_argtypes COMMA FROM SQL_P WITH FUNCTION function_with_argtypes + | FROM SQL_P WITH FUNCTION function_with_argtypes + | TO SQL_P WITH FUNCTION function_with_argtypes + ; + +droptransformstmt + : DROP TRANSFORM if_exists_? FOR typename LANGUAGE name drop_behavior_? + ; + +reindexstmt + : REINDEX reindex_option_list? reindex_target_relation concurrently_? qualified_name + | REINDEX reindex_option_list? SCHEMA concurrently_? name + | REINDEX reindex_option_list? reindex_target_all concurrently_? single_name_? + ; + +reindex_target_relation + : INDEX + | TABLE + ; + +reindex_target_all + : SYSTEM_P + | DATABASE + ; + +reindex_option_list + : OPEN_PAREN utility_option_list CLOSE_PAREN + ; + +altertblspcstmt + : ALTER TABLESPACE name SET reloptions + | ALTER TABLESPACE name RESET reloptions + ; + +renamestmt + : ALTER AGGREGATE aggregate_with_argtypes RENAME TO name + | ALTER COLLATION any_name RENAME TO name + | ALTER CONVERSION_P any_name RENAME TO name + | ALTER DATABASE name RENAME TO name + | ALTER DOMAIN_P any_name RENAME TO name + | ALTER DOMAIN_P any_name RENAME CONSTRAINT name TO name + | ALTER FOREIGN DATA_P WRAPPER name RENAME TO name + | ALTER FUNCTION function_with_argtypes RENAME TO name + | ALTER GROUP_P roleid RENAME TO roleid + | ALTER procedural_? LANGUAGE name RENAME TO name + | ALTER OPERATOR CLASS any_name USING name RENAME TO name + | ALTER OPERATOR FAMILY any_name USING name RENAME TO name + | ALTER POLICY name ON qualified_name RENAME TO name + | ALTER POLICY IF_P EXISTS name ON qualified_name RENAME TO name + | ALTER PROCEDURE function_with_argtypes RENAME TO name + | ALTER PUBLICATION name RENAME TO name + | ALTER ROUTINE function_with_argtypes RENAME TO name + | ALTER SCHEMA name RENAME TO name + | ALTER SERVER name RENAME TO name + | ALTER SUBSCRIPTION name RENAME TO name + | ALTER TABLE relation_expr RENAME TO name + | ALTER TABLE IF_P EXISTS relation_expr RENAME TO name + | ALTER SEQUENCE qualified_name RENAME TO name + | ALTER SEQUENCE IF_P EXISTS qualified_name RENAME TO name + | ALTER VIEW qualified_name RENAME TO name + | ALTER VIEW IF_P EXISTS qualified_name RENAME TO name + | ALTER MATERIALIZED VIEW qualified_name RENAME TO name + | ALTER MATERIALIZED VIEW IF_P EXISTS qualified_name RENAME TO name + | ALTER INDEX qualified_name RENAME TO name + | ALTER INDEX IF_P EXISTS qualified_name RENAME TO name + | ALTER FOREIGN TABLE relation_expr RENAME TO name + | ALTER FOREIGN TABLE IF_P EXISTS relation_expr RENAME TO name + | ALTER TABLE relation_expr RENAME column_? name TO name + | ALTER TABLE IF_P EXISTS relation_expr RENAME column_? name TO name + | ALTER VIEW qualified_name RENAME column_? name TO name + | ALTER VIEW IF_P EXISTS qualified_name RENAME column_? name TO name + | ALTER MATERIALIZED VIEW qualified_name RENAME column_? name TO name + | ALTER MATERIALIZED VIEW IF_P EXISTS qualified_name RENAME column_? name TO name + | ALTER TABLE relation_expr RENAME CONSTRAINT name TO name + | ALTER TABLE IF_P EXISTS relation_expr RENAME CONSTRAINT name TO name + | ALTER FOREIGN TABLE relation_expr RENAME column_? name TO name + | ALTER FOREIGN TABLE IF_P EXISTS relation_expr RENAME column_? name TO name + | ALTER RULE name ON qualified_name RENAME TO name + | ALTER TRIGGER name ON qualified_name RENAME TO name + | ALTER EVENT TRIGGER name RENAME TO name + | ALTER ROLE roleid RENAME TO roleid + | ALTER USER roleid RENAME TO roleid + | ALTER TABLESPACE name RENAME TO name + | ALTER STATISTICS any_name RENAME TO name + | ALTER TEXT_P SEARCH PARSER any_name RENAME TO name + | ALTER TEXT_P SEARCH DICTIONARY any_name RENAME TO name + | ALTER TEXT_P SEARCH TEMPLATE any_name RENAME TO name + | ALTER TEXT_P SEARCH CONFIGURATION any_name RENAME TO name + | ALTER TYPE_P any_name RENAME TO name + | ALTER TYPE_P any_name RENAME ATTRIBUTE name TO name drop_behavior_? + ; + +column_ + : COLUMN + + ; + +set_data_ + : SET DATA_P + + ; + +alterobjectdependsstmt + : ALTER FUNCTION function_with_argtypes no_? DEPENDS ON EXTENSION name + | ALTER PROCEDURE function_with_argtypes no_? DEPENDS ON EXTENSION name + | ALTER ROUTINE function_with_argtypes no_? DEPENDS ON EXTENSION name + | ALTER TRIGGER name ON qualified_name no_? DEPENDS ON EXTENSION name + | ALTER MATERIALIZED VIEW qualified_name no_? DEPENDS ON EXTENSION name + | ALTER INDEX qualified_name no_? DEPENDS ON EXTENSION name + ; + +no_ + : NO + + ; + +alterobjectschemastmt + : ALTER AGGREGATE aggregate_with_argtypes SET SCHEMA name + | ALTER COLLATION any_name SET SCHEMA name + | ALTER CONVERSION_P any_name SET SCHEMA name + | ALTER DOMAIN_P any_name SET SCHEMA name + | ALTER EXTENSION name SET SCHEMA name + | ALTER FUNCTION function_with_argtypes SET SCHEMA name + | ALTER OPERATOR operator_with_argtypes SET SCHEMA name + | ALTER OPERATOR CLASS any_name USING name SET SCHEMA name + | ALTER OPERATOR FAMILY any_name USING name SET SCHEMA name + | ALTER PROCEDURE function_with_argtypes SET SCHEMA name + | ALTER ROUTINE function_with_argtypes SET SCHEMA name + | ALTER TABLE relation_expr SET SCHEMA name + | ALTER TABLE IF_P EXISTS relation_expr SET SCHEMA name + | ALTER STATISTICS any_name SET SCHEMA name + | ALTER TEXT_P SEARCH PARSER any_name SET SCHEMA name + | ALTER TEXT_P SEARCH DICTIONARY any_name SET SCHEMA name + | ALTER TEXT_P SEARCH TEMPLATE any_name SET SCHEMA name + | ALTER TEXT_P SEARCH CONFIGURATION any_name SET SCHEMA name + | ALTER SEQUENCE qualified_name SET SCHEMA name + | ALTER SEQUENCE IF_P EXISTS qualified_name SET SCHEMA name + | ALTER VIEW qualified_name SET SCHEMA name + | ALTER VIEW IF_P EXISTS qualified_name SET SCHEMA name + | ALTER MATERIALIZED VIEW qualified_name SET SCHEMA name + | ALTER MATERIALIZED VIEW IF_P EXISTS qualified_name SET SCHEMA name + | ALTER FOREIGN TABLE relation_expr SET SCHEMA name + | ALTER FOREIGN TABLE IF_P EXISTS relation_expr SET SCHEMA name + | ALTER TYPE_P any_name SET SCHEMA name + ; + +alteroperatorstmt + : ALTER OPERATOR operator_with_argtypes SET OPEN_PAREN operator_def_list CLOSE_PAREN + ; + +operator_def_list + : operator_def_elem (COMMA operator_def_elem)* + ; + +operator_def_elem + : colLabel EQUAL NONE + | colLabel EQUAL operator_def_arg + ; + +operator_def_arg + : func_type + | reserved_keyword + | qual_all_op + | numericonly + | sconst + ; + +altertypestmt + : ALTER TYPE_P any_name SET OPEN_PAREN operator_def_list CLOSE_PAREN + ; + +alterownerstmt + : ALTER AGGREGATE aggregate_with_argtypes OWNER TO rolespec + | ALTER COLLATION any_name OWNER TO rolespec + | ALTER CONVERSION_P any_name OWNER TO rolespec + | ALTER DATABASE name OWNER TO rolespec + | ALTER DOMAIN_P any_name OWNER TO rolespec + | ALTER FUNCTION function_with_argtypes OWNER TO rolespec + | ALTER procedural_? LANGUAGE name OWNER TO rolespec + | ALTER LARGE_P OBJECT_P numericonly OWNER TO rolespec + | ALTER OPERATOR operator_with_argtypes OWNER TO rolespec + | ALTER OPERATOR CLASS any_name USING name OWNER TO rolespec + | ALTER OPERATOR FAMILY any_name USING name OWNER TO rolespec + | ALTER PROCEDURE function_with_argtypes OWNER TO rolespec + | ALTER ROUTINE function_with_argtypes OWNER TO rolespec + | ALTER SCHEMA name OWNER TO rolespec + | ALTER TYPE_P any_name OWNER TO rolespec + | ALTER TABLESPACE name OWNER TO rolespec + | ALTER STATISTICS any_name OWNER TO rolespec + | ALTER TEXT_P SEARCH DICTIONARY any_name OWNER TO rolespec + | ALTER TEXT_P SEARCH CONFIGURATION any_name OWNER TO rolespec + | ALTER FOREIGN DATA_P WRAPPER name OWNER TO rolespec + | ALTER SERVER name OWNER TO rolespec + | ALTER EVENT TRIGGER name OWNER TO rolespec + | ALTER PUBLICATION name OWNER TO rolespec + | ALTER SUBSCRIPTION name OWNER TO rolespec + ; + +createpublicationstmt + : CREATE PUBLICATION name publication_for_tables_? definition_? + ; + +publication_for_tables_ + : publication_for_tables + + ; + +publication_for_tables + : FOR TABLE relation_expr_list + | FOR ALL TABLES + ; + +alterpublicationstmt + : ALTER PUBLICATION name SET definition + | ALTER PUBLICATION name ADD_P TABLE relation_expr_list + | ALTER PUBLICATION name SET TABLE relation_expr_list + | ALTER PUBLICATION name DROP TABLE relation_expr_list + ; + +createsubscriptionstmt + : CREATE SUBSCRIPTION name CONNECTION sconst PUBLICATION publication_name_list definition_? + ; + +publication_name_list + : publication_name_item (COMMA publication_name_item)* + ; + +publication_name_item + : colLabel + ; + +altersubscriptionstmt + : ALTER SUBSCRIPTION name SET definition + | ALTER SUBSCRIPTION name CONNECTION sconst + | ALTER SUBSCRIPTION name REFRESH PUBLICATION definition_? + | ALTER SUBSCRIPTION name SET PUBLICATION publication_name_list definition_? + | ALTER SUBSCRIPTION name ENABLE_P + | ALTER SUBSCRIPTION name DISABLE_P + ; + +dropsubscriptionstmt + : DROP SUBSCRIPTION name drop_behavior_? + | DROP SUBSCRIPTION IF_P EXISTS name drop_behavior_? + ; + +rulestmt + : CREATE or_replace_? RULE name AS ON event TO qualified_name where_clause? DO instead_? ruleactionlist + ; + +ruleactionlist + : NOTHING + | ruleactionstmt + | OPEN_PAREN ruleactionmulti CLOSE_PAREN + ; + +ruleactionmulti + : ruleactionstmtOrEmpty? (SEMI ruleactionstmtOrEmpty?)* + ; + +ruleactionstmt + : selectstmt + | insertstmt + | updatestmt + | deletestmt + | notifystmt + ; + +ruleactionstmtOrEmpty + : ruleactionstmt + + ; + +event + : SELECT + | UPDATE + | DELETE_P + | INSERT + ; + +instead_ + : INSTEAD + | ALSO + + ; + +notifystmt + : NOTIFY colid notify_payload? + ; + +notify_payload + : COMMA sconst + + ; + +listenstmt + : LISTEN colid + ; + +unlistenstmt + : UNLISTEN colid + | UNLISTEN STAR + ; + +transactionstmt + : ABORT_P transaction_? transaction_chain_? + | BEGIN_P transaction_? transaction_mode_list_or_empty? + | START TRANSACTION transaction_mode_list_or_empty? + | COMMIT transaction_? transaction_chain_? + | END_P transaction_? transaction_chain_? + | ROLLBACK transaction_? transaction_chain_? + | SAVEPOINT colid + | RELEASE SAVEPOINT colid + | RELEASE colid + | ROLLBACK transaction_? TO SAVEPOINT colid + | ROLLBACK transaction_? TO colid + | PREPARE TRANSACTION sconst + | COMMIT PREPARED sconst + | ROLLBACK PREPARED sconst + ; + +transaction_ + : WORK + | TRANSACTION + + ; + +transaction_mode_item + : ISOLATION LEVEL iso_level + | READ ONLY + | READ WRITE + | DEFERRABLE + | NOT DEFERRABLE + ; + +transaction_mode_list + : transaction_mode_item (COMMA? transaction_mode_item)* + ; + +transaction_mode_list_or_empty + : transaction_mode_list + + ; + +transaction_chain_ + : AND NO? CHAIN + + ; + +viewstmt + : CREATE (OR REPLACE)? opttemp? ( + VIEW qualified_name column_list_? reloptions_? + | RECURSIVE VIEW qualified_name OPEN_PAREN columnlist CLOSE_PAREN reloptions_? + ) AS selectstmt check_option_? + ; + +check_option_ + : WITH (CASCADED | LOCAL)? CHECK OPTION + + ; + +loadstmt + : LOAD file_name + ; + +createdbstmt + : CREATE DATABASE name with_? createdb_opt_list? + ; + +createdb_opt_list + : createdb_opt_items + + ; + +createdb_opt_items + : createdb_opt_item+ + ; + +createdb_opt_item + : createdb_opt_name equal_? (signediconst | boolean_or_string_ | DEFAULT) + ; + +createdb_opt_name + : identifier + | CONNECTION LIMIT + | ENCODING + | LOCATION + | OWNER + | TABLESPACE + | TEMPLATE + ; + +equal_ + : EQUAL + + ; + +alterdatabasestmt + : ALTER DATABASE name (WITH createdb_opt_list? | createdb_opt_list? | SET TABLESPACE name) + ; + +alterdatabasesetstmt + : ALTER DATABASE name setresetclause + ; + +dropdbstmt + : DROP DATABASE (IF_P EXISTS)? name (with_? OPEN_PAREN drop_option_list CLOSE_PAREN)? + ; + +drop_option_list + : drop_option (COMMA drop_option)* + ; + +drop_option + : FORCE + ; + +altercollationstmt + : ALTER COLLATION any_name REFRESH VERSION_P + ; + +altersystemstmt + : ALTER SYSTEM_P (SET | RESET) generic_set + ; + +createdomainstmt + : CREATE DOMAIN_P any_name as_? typename colquallist + ; + +alterdomainstmt + : ALTER DOMAIN_P any_name ( + alter_column_default + | DROP NOT NULL_P + | SET NOT NULL_P + | ADD_P tableconstraint + | DROP CONSTRAINT (IF_P EXISTS)? name drop_behavior_? + | VALIDATE CONSTRAINT name + ) + ; + +as_ + : AS + + ; + +altertsdictionarystmt + : ALTER TEXT_P SEARCH DICTIONARY any_name definition + ; + +altertsconfigurationstmt + : ALTER TEXT_P SEARCH CONFIGURATION any_name ADD_P MAPPING FOR name_list any_with any_name_list_ + | ALTER TEXT_P SEARCH CONFIGURATION any_name ALTER MAPPING FOR name_list any_with any_name_list_ + | ALTER TEXT_P SEARCH CONFIGURATION any_name ALTER MAPPING REPLACE any_name any_with any_name + | ALTER TEXT_P SEARCH CONFIGURATION any_name ALTER MAPPING FOR name_list REPLACE any_name any_with any_name + | ALTER TEXT_P SEARCH CONFIGURATION any_name DROP MAPPING FOR name_list + | ALTER TEXT_P SEARCH CONFIGURATION any_name DROP MAPPING IF_P EXISTS FOR name_list + ; + +any_with + : WITH + //TODO + + // | WITH_LA + ; + +createconversionstmt + : CREATE default_? CONVERSION_P any_name FOR sconst TO sconst FROM any_name + ; + +clusterstmt + : CLUSTER verbose_? qualified_name cluster_index_specification? + | CLUSTER verbose_? + | CLUSTER verbose_? name ON qualified_name + ; + +cluster_index_specification + : USING name + + ; + +vacuumstmt + : VACUUM full_? freeze_? verbose_? analyze_? vacuum_relation_list_? + | VACUUM OPEN_PAREN vac_analyze_option_list CLOSE_PAREN vacuum_relation_list_? + ; + +analyzestmt + : analyze_keyword verbose_? vacuum_relation_list_? + | analyze_keyword OPEN_PAREN vac_analyze_option_list CLOSE_PAREN vacuum_relation_list_? + ; + +utility_option_list + : utility_option_elem ( ',' utility_option_elem)* + ; + +vac_analyze_option_list + : vac_analyze_option_elem (COMMA vac_analyze_option_elem)* + ; + +analyze_keyword + : ANALYZE + | ANALYSE + ; + +utility_option_elem + : utility_option_name utility_option_arg? + ; + +utility_option_name + : nonreservedword + | analyze_keyword + | FORMAT_LA + ; + +utility_option_arg + : boolean_or_string_ + | numericonly + ; + +vac_analyze_option_elem + : vac_analyze_option_name vac_analyze_option_arg? + ; + +vac_analyze_option_name + : nonreservedword + | analyze_keyword + ; + +vac_analyze_option_arg + : boolean_or_string_ + | numericonly + + ; + +analyze_ + : analyze_keyword + + ; + +verbose_ + : VERBOSE + + ; + +full_ + : FULL + + ; + +freeze_ + : FREEZE + + ; + +name_list_ + : OPEN_PAREN name_list CLOSE_PAREN + + ; + +vacuum_relation + : qualified_name name_list_? + ; + +vacuum_relation_list + : vacuum_relation (COMMA vacuum_relation)* + ; + +vacuum_relation_list_ + : vacuum_relation_list + + ; + +explainstmt + : EXPLAIN explainablestmt + | EXPLAIN analyze_keyword verbose_? explainablestmt + | EXPLAIN VERBOSE explainablestmt + | EXPLAIN OPEN_PAREN explain_option_list CLOSE_PAREN explainablestmt + ; + +explainablestmt + : selectstmt + | insertstmt + | updatestmt + | deletestmt + | declarecursorstmt + | createasstmt + | creatematviewstmt + | refreshmatviewstmt + | executestmt + ; + +explain_option_list + : explain_option_elem (COMMA explain_option_elem)* + ; + +explain_option_elem + : explain_option_name explain_option_arg? + ; + +explain_option_name + : nonreservedword + | analyze_keyword + ; + +explain_option_arg + : boolean_or_string_ + | numericonly + + ; + +preparestmt + : PREPARE name prep_type_clause? AS preparablestmt + ; + +prep_type_clause + : OPEN_PAREN type_list CLOSE_PAREN + + ; + +preparablestmt + : selectstmt + | insertstmt + | updatestmt + | deletestmt + ; + +executestmt + : EXECUTE name execute_param_clause? + | CREATE opttemp? TABLE create_as_target AS EXECUTE name execute_param_clause? with_data_? + | CREATE opttemp? TABLE IF_P NOT EXISTS create_as_target AS EXECUTE name execute_param_clause? with_data_? + ; + +execute_param_clause + : OPEN_PAREN expr_list CLOSE_PAREN + + ; + +deallocatestmt + : DEALLOCATE name + | DEALLOCATE PREPARE name + | DEALLOCATE ALL + | DEALLOCATE PREPARE ALL + ; + +insertstmt + : with_clause_? INSERT INTO insert_target insert_rest on_conflict_? returning_clause? + ; + +insert_target + : qualified_name (AS colid)? + ; + +insert_rest + : selectstmt + | OVERRIDING override_kind VALUE_P selectstmt + | OPEN_PAREN insert_column_list CLOSE_PAREN (OVERRIDING override_kind VALUE_P)? selectstmt + | DEFAULT VALUES + ; + +override_kind + : USER + | SYSTEM_P + ; + +insert_column_list + : insert_column_item (COMMA insert_column_item)* + ; + +insert_column_item + : colid opt_indirection + ; + +on_conflict_ + : ON CONFLICT conf_expr_? DO (UPDATE SET set_clause_list where_clause? | NOTHING) + + ; + +conf_expr_ + : OPEN_PAREN index_params CLOSE_PAREN where_clause? + | ON CONSTRAINT name + + ; + +returning_clause + : RETURNING target_list + + ; + +// https://www.postgresql.org/docs/current/sql-merge.html +mergestmt + : MERGE INTO? qualified_name alias_clause? USING (select_with_parens | qualified_name) alias_clause? ON a_expr ( + merge_insert_clause merge_update_clause? + | merge_update_clause merge_insert_clause? + ) merge_delete_clause? + ; + +merge_insert_clause + : WHEN NOT MATCHED (AND a_expr)? THEN? INSERT (OPEN_PAREN insert_column_list CLOSE_PAREN)? values_clause + ; + +merge_update_clause + : WHEN MATCHED (AND a_expr)? THEN? UPDATE SET set_clause_list + ; + +merge_delete_clause + : WHEN MATCHED THEN? DELETE_P + ; + +deletestmt + : with_clause_? DELETE_P FROM relation_expr_opt_alias using_clause? where_or_current_clause? returning_clause? + ; + +using_clause + : USING from_list + + ; + +lockstmt + : LOCK_P table_? relation_expr_list lock_? nowait_? + ; + +lock_ + : IN_P lock_type MODE + + ; + +lock_type + : ACCESS (SHARE | EXCLUSIVE) + | ROW (SHARE | EXCLUSIVE) + | SHARE (UPDATE EXCLUSIVE | ROW EXCLUSIVE)? + | EXCLUSIVE + ; + +nowait_ + : NOWAIT + + ; + +nowait_or_skip_ + : NOWAIT + | SKIP_P LOCKED + + ; + +updatestmt + : with_clause_? UPDATE relation_expr_opt_alias SET set_clause_list from_clause? where_or_current_clause? returning_clause? + ; + +set_clause_list + : set_clause (COMMA set_clause)* + ; + +set_clause + : set_target EQUAL a_expr + | OPEN_PAREN set_target_list CLOSE_PAREN EQUAL a_expr + ; + +set_target + : colid opt_indirection + ; + +set_target_list + : set_target (COMMA set_target)* + ; + +declarecursorstmt + : DECLARE cursor_name cursor_options CURSOR hold_? FOR selectstmt + ; + +cursor_name + : name + ; + +cursor_options + : (NO SCROLL | SCROLL | BINARY | INSENSITIVE)* + ; + +hold_ + : + WITH HOLD + | WITHOUT HOLD + ; + +/* +TODO: why select_with_parens alternative is needed at all? +i guess it because original byson grammar can choose selectstmt(2)->select_with_parens on only OPEN_PARENT/SELECT kewords at the begining of statement; +(select * from tab); +parse can go through selectstmt( )->select_no_parens(1)->select_clause(2)->select_with_parens(1)->select_no_parens(1)->select_clause(1)->simple_select +instead of selectstmt(1)->select_no_parens(1)->select_clause(2)->select_with_parens(1)->select_no_parens(1)->select_clause(1)->simple_select +all standard tests passed on both variants +*/ + +selectstmt + : select_no_parens + | select_with_parens + ; + +select_with_parens + : OPEN_PAREN select_no_parens CLOSE_PAREN + | OPEN_PAREN select_with_parens CLOSE_PAREN + ; + +select_no_parens + : select_clause sort_clause_? ( + for_locking_clause select_limit_? + | select_limit for_locking_clause_? + )? + | with_clause select_clause sort_clause_? ( + for_locking_clause select_limit_? + | select_limit for_locking_clause_? + )? + ; + +select_clause + : simple_select_intersect ((UNION | EXCEPT) all_or_distinct? simple_select_intersect)* + ; + +simple_select_intersect + : simple_select_pramary (INTERSECT all_or_distinct? simple_select_pramary)* + ; + +simple_select_pramary + : ( + SELECT + ( all_clause_? target_list_? + into_clause? from_clause? where_clause? + group_clause? having_clause? window_clause? + | distinct_clause target_list + into_clause? from_clause? where_clause? + group_clause? having_clause? window_clause? + ) + ) + | values_clause + | TABLE relation_expr + | select_with_parens + ; + +with_clause + : WITH RECURSIVE? cte_list + ; + +cte_list + : common_table_expr (COMMA common_table_expr)* + ; + +common_table_expr + : name name_list_? AS materialized_? OPEN_PAREN preparablestmt CLOSE_PAREN + ; + +materialized_ + : MATERIALIZED + | NOT MATERIALIZED + + ; + +with_clause_ + : with_clause + + ; + +into_clause + : INTO opttempTableName + ; + +strict_ + : + STRICT_P + ; + +opttempTableName + : (LOCAL | GLOBAL)? (TEMPORARY | TEMP) table_? qualified_name + | UNLOGGED table_? qualified_name + | TABLE qualified_name + | qualified_name + ; + +table_ + : TABLE + + ; + +all_or_distinct + : ALL + | DISTINCT + + ; + +distinct_clause + : DISTINCT (ON OPEN_PAREN expr_list CLOSE_PAREN)? + ; + +all_clause_ + : ALL + + ; + +sort_clause_ + : sort_clause + + ; + +sort_clause + : ORDER BY sortby_list + ; + +sortby_list + : sortby (COMMA sortby)* + ; + +sortby + : a_expr (USING qual_all_op | asc_desc_?) nulls_order_? + ; + +select_limit + : limit_clause offset_clause? + | offset_clause limit_clause? + ; + +select_limit_ + : select_limit + + ; + +limit_clause + : LIMIT select_limit_value (COMMA select_offset_value)? + | FETCH first_or_next ( + select_fetch_first_value row_or_rows (ONLY | WITH TIES) + | row_or_rows (ONLY | WITH TIES) + ) + ; + +offset_clause + : OFFSET (select_offset_value | select_fetch_first_value row_or_rows) + ; + +select_limit_value + : a_expr + | ALL + ; + +select_offset_value + : a_expr + ; + +select_fetch_first_value + : c_expr + | PLUS i_or_f_const + | MINUS i_or_f_const + ; + +i_or_f_const + : iconst + | fconst + ; + +row_or_rows + : ROW + | ROWS + ; + +first_or_next + : FIRST_P + | NEXT + ; + +group_clause + : GROUP_P BY group_by_list + + ; + +group_by_list + : group_by_item (COMMA group_by_item)* + ; + +group_by_item + : empty_grouping_set + | cube_clause + | rollup_clause + | grouping_sets_clause + | a_expr + ; + +empty_grouping_set + : OPEN_PAREN CLOSE_PAREN + ; + +rollup_clause + : ROLLUP OPEN_PAREN expr_list CLOSE_PAREN + ; + +cube_clause + : CUBE OPEN_PAREN expr_list CLOSE_PAREN + ; + +grouping_sets_clause + : GROUPING SETS OPEN_PAREN group_by_list CLOSE_PAREN + ; + +having_clause + : HAVING a_expr + + ; + +for_locking_clause + : for_locking_items + | FOR READ ONLY + ; + +for_locking_clause_ + : for_locking_clause + + ; + +for_locking_items + : for_locking_item+ + ; + +for_locking_item + : for_locking_strength locked_rels_list? nowait_or_skip_? + ; + +for_locking_strength + : FOR ((NO KEY)? UPDATE | KEY? SHARE) + ; + +locked_rels_list + : OF qualified_name_list + + ; + +values_clause + : VALUES OPEN_PAREN expr_list CLOSE_PAREN (COMMA OPEN_PAREN expr_list CLOSE_PAREN)* + ; + +from_clause + : FROM from_list + + ; + +from_list + : table_ref (COMMA table_ref)* + ; + +table_ref + : ( + relation_expr alias_clause? tablesample_clause? + | func_table func_alias_clause? + | xmltable alias_clause? + | select_with_parens alias_clause? + | LATERAL_P ( + xmltable alias_clause? + | func_table func_alias_clause? + | select_with_parens alias_clause? + ) + | OPEN_PAREN table_ref CLOSE_PAREN alias_clause? + ) ( + CROSS JOIN table_ref + | NATURAL join_type? JOIN table_ref + | join_type? JOIN table_ref join_qual + )* + ; + +alias_clause + : AS? colid (OPEN_PAREN name_list CLOSE_PAREN)? + ; + +func_alias_clause + : alias_clause + | (AS colid? | colid) OPEN_PAREN tablefuncelementlist CLOSE_PAREN + + ; + +join_type + : INNER_P + | (FULL | LEFT | RIGHT) OUTER_P? + ; + +join_qual + : USING OPEN_PAREN name_list CLOSE_PAREN + | ON a_expr + ; + +relation_expr + : qualified_name STAR? + | ONLY (qualified_name | OPEN_PAREN qualified_name CLOSE_PAREN) + ; + +relation_expr_list + : relation_expr (COMMA relation_expr)* + ; + +relation_expr_opt_alias + : relation_expr (AS? colid)? + ; + +tablesample_clause + : TABLESAMPLE func_name OPEN_PAREN expr_list CLOSE_PAREN repeatable_clause_? + ; + +repeatable_clause_ + : REPEATABLE OPEN_PAREN a_expr CLOSE_PAREN + + ; + +func_table + : func_expr_windowless ordinality_? + | ROWS FROM OPEN_PAREN rowsfrom_list CLOSE_PAREN ordinality_? + ; + +rowsfrom_item + : func_expr_windowless col_def_list_? + ; + +rowsfrom_list + : rowsfrom_item (COMMA rowsfrom_item)* + ; + +col_def_list_ + : AS OPEN_PAREN tablefuncelementlist CLOSE_PAREN + + ; + +//TODO WITH_LA was used + +ordinality_ + : WITH ORDINALITY + + ; + +where_clause + : WHERE a_expr + + ; + +where_or_current_clause + : WHERE (CURRENT_P OF cursor_name | a_expr) + + ; + +opttablefuncelementlist + : tablefuncelementlist + + ; + +tablefuncelementlist + : tablefuncelement (COMMA tablefuncelement)* + ; + +tablefuncelement + : colid typename collate_clause_? + ; + +xmltable + : XMLTABLE OPEN_PAREN ( + c_expr xmlexists_argument COLUMNS xmltable_column_list + | XMLNAMESPACES OPEN_PAREN xml_namespace_list CLOSE_PAREN COMMA c_expr xmlexists_argument COLUMNS xmltable_column_list + ) CLOSE_PAREN + ; + +xmltable_column_list + : xmltable_column_el (COMMA xmltable_column_el)* + ; + +xmltable_column_el + : colid (typename xmltable_column_option_list? | FOR ORDINALITY) + ; + +xmltable_column_option_list + : xmltable_column_option_el+ + ; + +xmltable_column_option_el + : DEFAULT a_expr + | identifier a_expr + | NOT NULL_P + | NULL_P + ; + +xml_namespace_list + : xml_namespace_el (COMMA xml_namespace_el)* + ; + +xml_namespace_el + : b_expr AS colLabel + | DEFAULT b_expr + ; + +typename + : SETOF? simpletypename + ( opt_array_bounds + | ARRAY (OPEN_BRACKET iconst CLOSE_BRACKET)? + ) + ; + +opt_array_bounds + : (OPEN_BRACKET iconst? CLOSE_BRACKET)* + ; + +simpletypename + : generictype + | numeric + | bit + | character + | constdatetime + | constinterval (interval_? | OPEN_PAREN iconst CLOSE_PAREN) + | jsonType + ; + +consttypename + : numeric + | constbit + | constcharacter + | constdatetime + | jsonType + ; + +generictype + : type_function_name attrs? type_modifiers_? + ; + +type_modifiers_ + : OPEN_PAREN expr_list CLOSE_PAREN + + ; + +numeric + : INT_P + | INTEGER + | SMALLINT + | BIGINT + | REAL + | FLOAT_P float_? + | DOUBLE_P PRECISION + | DECIMAL_P type_modifiers_? + | DEC type_modifiers_? + | NUMERIC type_modifiers_? + | BOOLEAN_P + ; + +float_ + : OPEN_PAREN iconst CLOSE_PAREN + + ; + +//todo: merge alts + +bit + : bitwithlength + | bitwithoutlength + ; + +constbit + : bitwithlength + | bitwithoutlength + ; + +bitwithlength + : BIT varying_? OPEN_PAREN expr_list CLOSE_PAREN + ; + +bitwithoutlength + : BIT varying_? + ; + +character + : character_c (OPEN_PAREN iconst CLOSE_PAREN)? + ; + +constcharacter + : character_c (OPEN_PAREN iconst CLOSE_PAREN)? + ; + +character_c + : (CHARACTER | CHAR_P | NCHAR) varying_? + | VARCHAR + | NATIONAL (CHARACTER | CHAR_P) varying_? + ; + +varying_ + : VARYING + + ; + +constdatetime + : (TIMESTAMP | TIME) (OPEN_PAREN iconst CLOSE_PAREN)? timezone_? + ; + +constinterval + : INTERVAL + ; + +//TODO with_la was used + +timezone_ + : WITH TIME ZONE + | WITHOUT TIME ZONE + + ; + +interval_ + : YEAR_P + | MONTH_P + | DAY_P + | HOUR_P + | MINUTE_P + | interval_second + | YEAR_P TO MONTH_P + | DAY_P TO (HOUR_P | MINUTE_P | interval_second) + | HOUR_P TO (MINUTE_P | interval_second) + | MINUTE_P TO interval_second + + ; + +interval_second + : SECOND_P (OPEN_PAREN iconst CLOSE_PAREN)? + ; + +jsonType + : JSON + ; + +escape_ + : ESCAPE a_expr + + ; + +//precendence accroding to Table 4.2. Operator Precedence (highest to lowest) + +//https://www.postgresql.org/docs/12/sql-syntax-lexical.html#SQL-PRECEDENCE + +/* +original version of a_expr, for info + a_expr: c_expr + //:: left PostgreSQL-style typecast + | a_expr TYPECAST typename -- 1 + | a_expr COLLATE any_name -- 2 + | a_expr AT TIME ZONE a_expr-- 3 + //right unary plus, unary minus + | (PLUS| MINUS) a_expr -- 4 + //left exponentiation + | a_expr CARET a_expr -- 5 + //left multiplication, division, modulo + | a_expr (STAR | SLASH | PERCENT) a_expr -- 6 + //left addition, subtraction + | a_expr (PLUS | MINUS) a_expr -- 7 + //left all other native and user-defined operators + | a_expr qual_op a_expr -- 8 + | qual_op a_expr -- 9 + //range containment, set membership, string matching BETWEEN IN LIKE ILIKE SIMILAR + | a_expr NOT? (LIKE|ILIKE|SIMILAR TO|(BETWEEN SYMMETRIC?)) a_expr opt_escape -- 10 + //< > = <= >= <> comparison operators + | a_expr (LT | GT | EQUAL | LESS_EQUALS | GREATER_EQUALS | NOT_EQUALS) a_expr -- 11 + //IS ISNULL NOTNULL IS TRUE, IS FALSE, IS NULL, IS DISTINCT FROM, etc + | a_expr IS NOT? + ( + NULL_P + |TRUE_P + |FALSE_P + |UNKNOWN + |DISTINCT FROM a_expr + |OF OPEN_PAREN type_list CLOSE_PAREN + |DOCUMENT_P + |unicode_normal_form? NORMALIZED + ) -- 12 + | a_expr (ISNULL|NOTNULL) -- 13 + | row OVERLAPS row -- 14 + //NOT right logical negation + | NOT a_expr -- 15 + //AND left logical conjunction + | a_expr AND a_expr -- 16 + //OR left logical disjunction + | a_expr OR a_expr -- 17 + | a_expr (LESS_LESS|GREATER_GREATER) a_expr -- 18 + | a_expr qual_op -- 19 + | a_expr NOT? IN_P in_expr -- 20 + | a_expr subquery_Op sub_type (select_with_parens|OPEN_PAREN a_expr CLOSE_PAREN) -- 21 + | UNIQUE select_with_parens -- 22 + | DEFAULT -- 23 +; +*/ + +a_expr + : a_expr_qual + ; + +/*23*/ + +/*moved to c_expr*/ + +/*22*/ + +/*moved to c_expr*/ + +/*19*/ + +a_expr_qual + : a_expr_lessless ({this->OnlyAcceptableOps()}? qual_op | ) + ; + +/*18*/ + +a_expr_lessless + : a_expr_or ((LESS_LESS | GREATER_GREATER) a_expr_or)* + ; + +/*17*/ + +a_expr_or + : a_expr_and (OR a_expr_and)* + ; + +/*16*/ + +a_expr_and + : a_expr_between (AND a_expr_between)* + ; + +/*21*/ + +a_expr_between + : a_expr_in (NOT? BETWEEN SYMMETRIC? a_expr_in AND a_expr_in)? + ; + +/*20*/ + +a_expr_in + : a_expr_unary_not (NOT? IN_P in_expr)? + ; + +/*15*/ + +a_expr_unary_not + : NOT? a_expr_isnull + ; + +/*14*/ + +/*moved to c_expr*/ + +/*13*/ + +a_expr_isnull + : a_expr_is_not (ISNULL | NOTNULL)? + ; + +/*12*/ + +a_expr_is_not + : a_expr_compare ( + IS NOT? ( + NULL_P + | TRUE_P + | FALSE_P + | UNKNOWN + | DISTINCT FROM a_expr + | OF OPEN_PAREN type_list CLOSE_PAREN + | DOCUMENT_P + | unicode_normal_form? NORMALIZED + ) + )? + ; + +/*11*/ + +a_expr_compare + : a_expr_like ( + (LT | GT | EQUAL | LESS_EQUALS | GREATER_EQUALS | NOT_EQUALS) a_expr_like + | subquery_Op sub_type (select_with_parens | OPEN_PAREN a_expr CLOSE_PAREN) /*21*/ + )? + ; + +/*10*/ + +a_expr_like + : a_expr_qual_op (NOT? (LIKE | ILIKE | SIMILAR TO) a_expr_qual_op escape_?)? + ; + +/* 8*/ + +a_expr_qual_op + : a_expr_unary_qualop (qual_op a_expr_unary_qualop)* + ; + +/* 9*/ + +a_expr_unary_qualop + : qual_op? a_expr_add + ; + +/* 7*/ + +a_expr_add + : a_expr_mul ((MINUS | PLUS) a_expr_mul)* + ; + +/* 6*/ + +a_expr_mul + : a_expr_caret ((STAR | SLASH | PERCENT) a_expr_caret)* + ; + +/* 5*/ + +a_expr_caret + : a_expr_unary_sign (CARET a_expr_unary_sign)? + ; + +/* 4*/ + +a_expr_unary_sign + : (MINUS | PLUS)? a_expr_at_time_zone /* */ + ; + +/* 3*/ + +a_expr_at_time_zone + : a_expr_collate (AT TIME ZONE a_expr)? + ; + +/* 2*/ + +a_expr_collate + : a_expr_typecast (COLLATE any_name)? + ; + +/* 1*/ + +a_expr_typecast + : c_expr (TYPECAST typename)* + ; + +b_expr + : c_expr + | b_expr TYPECAST typename + //right unary plus, unary minus + | (PLUS | MINUS) b_expr + //^ left exponentiation + | b_expr CARET b_expr + //* / % left multiplication, division, modulo + | b_expr (STAR | SLASH | PERCENT) b_expr + //+ - left addition, subtraction + | b_expr (PLUS | MINUS) b_expr + //(any other operator) left all other native and user-defined operators + | b_expr qual_op b_expr + //< > = <= >= <> comparison operators + | b_expr (LT | GT | EQUAL | LESS_EQUALS | GREATER_EQUALS | NOT_EQUALS) b_expr + | qual_op b_expr + | b_expr qual_op + //S ISNULL NOTNULL IS TRUE, IS FALSE, IS NULL, IS DISTINCT FROM, etc + | b_expr IS NOT? (DISTINCT FROM b_expr | OF OPEN_PAREN type_list CLOSE_PAREN | DOCUMENT_P) + ; + +c_expr + : EXISTS select_with_parens # c_expr_exists + | ARRAY (select_with_parens | array_expr) # c_expr_expr + | PARAM opt_indirection # c_expr_expr + | GROUPING OPEN_PAREN expr_list CLOSE_PAREN # c_expr_expr + | /*22*/ UNIQUE select_with_parens # c_expr_expr + | columnref # c_expr_expr + | aexprconst # c_expr_expr + | OPEN_PAREN a_expr_in_parens = a_expr CLOSE_PAREN opt_indirection # c_expr_expr + | case_expr # c_expr_case + | func_expr # c_expr_expr + | select_with_parens indirection? # c_expr_expr + | explicit_row # c_expr_expr + | implicit_row # c_expr_expr + | row OVERLAPS row /* 14*/ # c_expr_expr + | DEFAULT # c_expr_expr + ; + +plsqlvariablename + : PLSQLVARIABLENAME + ; + +func_application + : func_name OPEN_PAREN ( + func_arg_list (COMMA VARIADIC func_arg_expr)? sort_clause_? + | VARIADIC func_arg_expr sort_clause_? + | (ALL | DISTINCT) func_arg_list sort_clause_? + | STAR + | + ) CLOSE_PAREN + ; + +func_expr + : func_application within_group_clause? filter_clause? over_clause? + | func_expr_common_subexpr + ; + +func_expr_windowless + : func_application + | func_expr_common_subexpr + ; + +func_expr_common_subexpr + : COLLATION FOR OPEN_PAREN a_expr CLOSE_PAREN + | CURRENT_DATE + | CURRENT_TIME (OPEN_PAREN iconst CLOSE_PAREN)? + | CURRENT_TIMESTAMP (OPEN_PAREN iconst CLOSE_PAREN)? + | LOCALTIME (OPEN_PAREN iconst CLOSE_PAREN)? + | LOCALTIMESTAMP (OPEN_PAREN iconst CLOSE_PAREN)? + | CURRENT_ROLE + | CURRENT_USER + | SESSION_USER + | SYSTEM_USER + | USER + | CURRENT_CATALOG + | CURRENT_SCHEMA + | CAST OPEN_PAREN a_expr AS typename CLOSE_PAREN + | EXTRACT OPEN_PAREN extract_list? CLOSE_PAREN + | NORMALIZE OPEN_PAREN a_expr (COMMA unicode_normal_form)? CLOSE_PAREN + | OVERLAY OPEN_PAREN (overlay_list | func_arg_list? ) CLOSE_PAREN + | POSITION OPEN_PAREN position_list? CLOSE_PAREN + | SUBSTRING OPEN_PAREN (substr_list | func_arg_list?) CLOSE_PAREN + | TREAT OPEN_PAREN a_expr AS typename CLOSE_PAREN + | TRIM OPEN_PAREN (BOTH | LEADING | TRAILING)? trim_list CLOSE_PAREN + | NULLIF OPEN_PAREN a_expr COMMA a_expr CLOSE_PAREN + | COALESCE OPEN_PAREN expr_list CLOSE_PAREN + | GREATEST OPEN_PAREN expr_list CLOSE_PAREN + | LEAST OPEN_PAREN expr_list CLOSE_PAREN + | XMLCONCAT OPEN_PAREN expr_list CLOSE_PAREN + | XMLELEMENT OPEN_PAREN NAME_P colLabel (COMMA (xml_attributes | expr_list))? CLOSE_PAREN + | XMLEXISTS OPEN_PAREN c_expr xmlexists_argument CLOSE_PAREN + | XMLFOREST OPEN_PAREN xml_attribute_list CLOSE_PAREN + | XMLPARSE OPEN_PAREN document_or_content a_expr xml_whitespace_option? CLOSE_PAREN + | XMLPI OPEN_PAREN NAME_P colLabel (COMMA a_expr)? CLOSE_PAREN + | XMLROOT OPEN_PAREN XML_P a_expr COMMA xml_root_version xml_root_standalone_? CLOSE_PAREN + | XMLSERIALIZE OPEN_PAREN document_or_content a_expr AS simpletypename CLOSE_PAREN + | JSON_OBJECT OPEN_PAREN (func_arg_list + | json_name_and_value_list + json_object_constructor_null_clause? + json_key_uniqueness_constraint? + json_returning_clause? + | json_returning_clause? ) + CLOSE_PAREN + | JSON_ARRAY OPEN_PAREN (json_value_expr_list + json_array_constructor_null_clause? + json_returning_clause? + | select_no_parens + json_format_clause? + json_returning_clause? + | json_returning_clause? + ) + CLOSE_PAREN + | JSON '(' json_value_expr json_key_uniqueness_constraint? ')' + | JSON_SCALAR '(' a_expr ')' + | JSON_SERIALIZE '(' json_value_expr json_returning_clause? ')' + | MERGE_ACTION '(' ')' + | JSON_QUERY '(' + json_value_expr ',' a_expr json_passing_clause? + json_returning_clause? + json_wrapper_behavior + json_quotes_clause? + json_behavior_clause? + ')' + | JSON_EXISTS '(' + json_value_expr ',' a_expr json_passing_clause? + json_on_error_clause? + ')' + | JSON_VALUE '(' + json_value_expr ',' a_expr json_passing_clause? + json_returning_clause? + json_behavior_clause? + ')' + ; + +/* SQL/XML support */ + +xml_root_version + : VERSION_P a_expr + | VERSION_P NO VALUE_P + ; + +xml_root_standalone_ + : COMMA STANDALONE_P YES_P + | COMMA STANDALONE_P NO + | COMMA STANDALONE_P NO VALUE_P + ; + +xml_attributes + : XMLATTRIBUTES OPEN_PAREN xml_attribute_list CLOSE_PAREN + ; + +xml_attribute_list + : xml_attribute_el (COMMA xml_attribute_el)* + ; + +xml_attribute_el + : a_expr (AS colLabel)? + ; + +document_or_content + : DOCUMENT_P + | CONTENT_P + ; + +xml_whitespace_option + : PRESERVE WHITESPACE_P + | STRIP_P WHITESPACE_P + + ; + +xmlexists_argument + : PASSING c_expr + | PASSING c_expr xml_passing_mech + | PASSING xml_passing_mech c_expr + | PASSING xml_passing_mech c_expr xml_passing_mech + ; + +xml_passing_mech + : BY (REF | VALUE_P) + ; + +within_group_clause + : WITHIN GROUP_P OPEN_PAREN sort_clause CLOSE_PAREN + + ; + +filter_clause + : FILTER OPEN_PAREN WHERE a_expr CLOSE_PAREN + + ; + +window_clause + : WINDOW window_definition_list + + ; + +window_definition_list + : window_definition (COMMA window_definition)* + ; + +window_definition + : colid AS window_specification + ; + +over_clause + : OVER (window_specification | colid) + + ; + +window_specification + : OPEN_PAREN existing_window_name_? partition_clause_? sort_clause_? frame_clause_? CLOSE_PAREN + ; + +existing_window_name_ + : colid + + ; + +partition_clause_ + : PARTITION BY expr_list + + ; + +frame_clause_ + : RANGE frame_extent window_exclusion_clause_? + | ROWS frame_extent window_exclusion_clause_? + | GROUPS frame_extent window_exclusion_clause_? + + ; + +frame_extent + : frame_bound + | BETWEEN frame_bound AND frame_bound + ; + +frame_bound + : UNBOUNDED (PRECEDING | FOLLOWING) + | CURRENT_P ROW + | a_expr (PRECEDING | FOLLOWING) + ; + +window_exclusion_clause_ + : EXCLUDE (CURRENT_P ROW | GROUP_P | TIES | NO OTHERS) + + ; + +row + : ROW OPEN_PAREN expr_list? CLOSE_PAREN + | OPEN_PAREN expr_list COMMA a_expr CLOSE_PAREN + ; + +explicit_row + : ROW OPEN_PAREN expr_list? CLOSE_PAREN + ; + +/* +TODO: +for some reason v1 +implicit_row: OPEN_PAREN expr_list COMMA a_expr CLOSE_PAREN; +works better than v2 +implicit_row: OPEN_PAREN expr_list CLOSE_PAREN; +while looks like they are almost the same, except v2 requieres at least 2 items in list +while v1 allows single item in list +*/ + +implicit_row + : OPEN_PAREN expr_list COMMA a_expr CLOSE_PAREN + ; + +sub_type + : ANY + | SOME + | ALL + ; + +all_op + : Operator + | mathop + ; + +mathop + : PLUS + | MINUS + | STAR + | SLASH + | PERCENT + | CARET + | LT + | GT + | EQUAL + | LESS_EQUALS + | GREATER_EQUALS + | NOT_EQUALS + ; + +qual_op + : Operator + | OPERATOR OPEN_PAREN any_operator CLOSE_PAREN + ; + +qual_all_op + : all_op + | OPERATOR OPEN_PAREN any_operator CLOSE_PAREN + ; + +subquery_Op + : all_op + | OPERATOR OPEN_PAREN any_operator CLOSE_PAREN + | LIKE + | NOT LIKE + | ILIKE + | NOT ILIKE + ; + +expr_list + : a_expr (COMMA a_expr)* + ; + +func_arg_list + : func_arg_expr (COMMA func_arg_expr)* + ; + +func_arg_expr + : a_expr + | param_name (COLON_EQUALS | EQUALS_GREATER) a_expr + ; + +type_list + : typename (COMMA typename)* + ; + +array_expr + : OPEN_BRACKET (expr_list | array_expr_list)? CLOSE_BRACKET + ; + +array_expr_list + : array_expr (COMMA array_expr)* + ; + +extract_list + : extract_arg FROM a_expr + + ; + +extract_arg + : identifier + | YEAR_P + | MONTH_P + | DAY_P + | HOUR_P + | MINUTE_P + | SECOND_P + | sconst + ; + +unicode_normal_form + : NFC + | NFD + | NFKC + | NFKD + ; + +overlay_list + : a_expr PLACING a_expr FROM a_expr (FOR a_expr)? + ; + +position_list + : b_expr IN_P b_expr + + ; + +substr_list + : a_expr FROM a_expr FOR a_expr + | a_expr FOR a_expr FROM a_expr + | a_expr FROM a_expr + | a_expr FOR a_expr + | a_expr SIMILAR a_expr ESCAPE a_expr + ; + +trim_list + : a_expr FROM expr_list + | FROM expr_list + | expr_list + ; + +in_expr + : select_with_parens # in_expr_select + | OPEN_PAREN expr_list CLOSE_PAREN # in_expr_list + ; + +case_expr + : CASE case_arg? when_clause_list case_default? END_P + ; + +when_clause_list + : when_clause+ + ; + +when_clause + : WHEN a_expr THEN a_expr + ; + +case_default + : ELSE a_expr + + ; + +case_arg + : a_expr + + ; + +columnref + : colid indirection? + ; + +indirection_el + : DOT (attr_name | STAR) + | OPEN_BRACKET (a_expr | slice_bound_? COLON slice_bound_?) CLOSE_BRACKET + ; + +slice_bound_ + : a_expr + + ; + +indirection + : indirection_el+ + ; + +opt_indirection + : indirection_el* + ; + +/* SQL/JSON support */ +json_passing_clause: + PASSING json_arguments + ; + +json_arguments: + json_argument + | json_arguments ',' json_argument + ; + +json_argument: + json_value_expr AS colLabel + ; + +/* ARRAY is a noise word */ +json_wrapper_behavior: + WITHOUT WRAPPER + | WITHOUT ARRAY WRAPPER + | WITH WRAPPER + | WITH ARRAY WRAPPER + | WITH CONDITIONAL ARRAY WRAPPER + | WITH UNCONDITIONAL ARRAY WRAPPER + | WITH CONDITIONAL WRAPPER + | WITH UNCONDITIONAL WRAPPER + | + ; + +json_behavior: + DEFAULT a_expr + | json_behavior_type + ; + +json_behavior_type: + ERROR + | NULL_P + | TRUE_P + | FALSE_P + | UNKNOWN + | EMPTY_P ARRAY + | EMPTY_P OBJECT_P + /* non-standard, for Oracle compatibility only */ + | EMPTY_P + ; + +json_behavior_clause: + json_behavior ON EMPTY_P + | json_behavior ON ERROR + | json_behavior ON EMPTY_P json_behavior ON ERROR + ; + +json_on_error_clause: + json_behavior ON ERROR + ; + +json_value_expr: + a_expr json_format_clause? + ; + +json_format_clause: + FORMAT_LA JSON ENCODING name + | FORMAT_LA JSON + ; + + +json_quotes_clause: + KEEP QUOTES ON SCALAR STRING_P + | KEEP QUOTES + | OMIT QUOTES ON SCALAR STRING_P + | OMIT QUOTES + ; + +json_returning_clause: + RETURNING typename json_format_clause? + ; + +/* + * We must assign the only-JSON production a precedence less than IDENT in + * order to favor shifting over reduction when JSON is followed by VALUE_P, + * OBJECT_P, or SCALAR. (ARRAY doesn't need that treatment, because it's a + * fully reserved word.) Because json_predicate_type_constraint is always + * followed by json_key_uniqueness_constraint_opt, we also need the only-JSON + * production to have precedence less than WITH and WITHOUT. UNBOUNDED isn't + * really related to this syntax, but it's a convenient choice because it + * already has a precedence less than IDENT for other reasons. + */ +json_predicate_type_constraint: + JSON + | JSON VALUE_P + | JSON ARRAY + | JSON OBJECT_P + | JSON SCALAR + ; + +/* + * KEYS is a noise word here. To avoid shift/reduce conflicts, assign the + * KEYS-less productions a precedence less than IDENT (i.e., less than KEYS). + * This prevents reducing them when the next token is KEYS. + */ +json_key_uniqueness_constraint: + WITH UNIQUE KEYS + | WITH UNIQUE + | WITHOUT UNIQUE KEYS + | WITHOUT UNIQUE + ; + +json_name_and_value_list: + json_name_and_value + | json_name_and_value_list ',' json_name_and_value + ; + +json_name_and_value: + c_expr VALUE_P json_value_expr + | + a_expr ':' json_value_expr + ; + +/* empty means false for objects, true for arrays */ +json_object_constructor_null_clause: + NULL_P ON NULL_P + | ABSENT ON NULL_P + ; + +json_array_constructor_null_clause: + NULL_P ON NULL_P + | ABSENT ON NULL_P + ; + +json_value_expr_list: + json_value_expr + | json_value_expr_list ',' json_value_expr + ; + +json_aggregate_func: + JSON_OBJECTAGG '(' + json_name_and_value + json_object_constructor_null_clause? + json_key_uniqueness_constraint? + json_returning_clause + ')' + | JSON_ARRAYAGG '(' + json_value_expr + json_array_aggregate_order_by_clause? + json_array_constructor_null_clause? + json_returning_clause + ')' + ; + +json_array_aggregate_order_by_clause: + ORDER BY sortby_list + ; + +/***************************************************************************** + * + * target list for SELECT + * + *****************************************************************************/ + +target_list_ + : target_list + + ; + +target_list + : target_el (COMMA target_el)* + ; + +target_el + : a_expr (AS colLabel | bareColLabel |) # target_label + | STAR # target_star + ; + +qualified_name_list + : qualified_name (COMMA qualified_name)* + ; + +qualified_name + : colid indirection? + ; + +name_list + : name (COMMA name)* + ; + +name + : colid + ; + +attr_name + : colLabel + ; + +file_name + : sconst + ; + +func_name + : type_function_name + | colid indirection + ; + +aexprconst + : iconst + | fconst + | sconst + | bconst + | xconst + | func_name (sconst | OPEN_PAREN func_arg_list sort_clause_? CLOSE_PAREN sconst) + | consttypename sconst + | constinterval (sconst interval_? | OPEN_PAREN iconst CLOSE_PAREN sconst) + | TRUE_P + | FALSE_P + | NULL_P + ; + +xconst + : HexadecimalStringConstant + ; + +bconst + : BinaryStringConstant + ; + +fconst + : Numeric + ; + +iconst + : Integral + | BinaryIntegral + | OctalIntegral + | HexadecimalIntegral + ; + +sconst + : anysconst uescape_? + ; + +anysconst + : StringConstant + | UnicodeEscapeStringConstant + | BeginDollarStringConstant DollarText* EndDollarStringConstant + | EscapeStringConstant + ; + +uescape_ + : UESCAPE anysconst + + ; + +signediconst + : iconst + | PLUS iconst + | MINUS iconst + ; + +roleid + : rolespec + ; + +rolespec + : nonreservedword + | CURRENT_USER + | SESSION_USER + ; + +role_list + : rolespec (COMMA rolespec)* + ; + +/* + * Name classification hierarchy. + * + * IDENT is the lexeme returned by the lexer for identifiers that match + * no known keyword. In most cases, we can accept certain keywords as + * names, not only IDENTs. We prefer to accept as many such keywords + * as possible to minimize the impact of "reserved words" on programmers. + * So, we divide names into several possible classes. The classification + * is chosen in part to make keywords acceptable as names wherever possible. + */ + +/* Column identifier --- names that can be column, table, etc names. + */ +colid + : identifier + | unreserved_keyword + | col_name_keyword + ; + +/* Type/function identifier --- names that can be type or function names. + */ +type_function_name + : identifier + | unreserved_keyword + | type_func_name_keyword + ; + +/* Any not-fully-reserved word --- these names can be, eg, role names. + */ +nonreservedword + : identifier + | unreserved_keyword + | col_name_keyword + | type_func_name_keyword + ; + +/* Column label --- allowed labels in "AS" clauses. + * This presently includes *all* Postgres keywords. + */ +colLabel + : identifier + | unreserved_keyword + | col_name_keyword + | type_func_name_keyword + | reserved_keyword + | EXIT //NB: not in gram.y official source. + ; + +/* Bare column label --- names that can be column labels without writing "AS". + * This classification is orthogonal to the other keyword categories. + */ +bareColLabel + : identifier + | bare_label_keyword + ; + +/* + * Keyword category lists. Generally, every keyword present in + * the Postgres grammar should appear in exactly one of these lists. + * + * Put a new keyword into the first list that it can go into without causing + * shift or reduce conflicts. The earlier lists define "less reserved" + * categories of keywords. + * + * Make sure that each keyword's category in kwlist.h matches where + * it is listed here. (Someday we may be able to generate these lists and + * kwlist.h's table from one source of truth.) + */ + +/* "Unreserved" keywords --- available for use as any kind of name. + */ +unreserved_keyword + : ABORT_P + | ABSENT + | ABSOLUTE_P + | ACCESS + | ACTION + | ADD_P + | ADMIN + | AFTER + | AGGREGATE + | ALSO + | ALTER + | ALWAYS + | ASENSITIVE + | ASSERTION + | ASSIGNMENT + | AT + | ATOMIC + | ATTACH + | ATTRIBUTE + | BACKWARD + | BEFORE + | BEGIN_P + | BREADTH + | BY + | CACHE + | CALL + | CALLED + | CASCADE + | CASCADED + | CATALOG + | CHAIN + | CHARACTERISTICS + | CHECKPOINT + | CLASS + | CLOSE + | CLUSTER + | COLUMNS + | COMMENT + | COMMENTS + | COMMIT + | COMMITTED + | COMPRESSION + | CONDITIONAL + | CONFIGURATION + | CONFLICT + | CONNECTION + | CONSTRAINTS + | CONTENT_P + | CONTINUE_P + | CONVERSION_P + | COPY + | COST + | CSV + | CUBE + | CURRENT_P + | CURSOR + | CYCLE + | DATA_P + | DATABASE + | DAY_P + | DEALLOCATE + | DECLARE + | DEFAULTS + | DEFERRED + | DEFINER + | DELETE_P + | DELIMITER + | DELIMITERS + | DEPENDS + | DEPTH + | DETACH + | DICTIONARY + | DISABLE_P + | DISCARD + | DOCUMENT_P + | DOMAIN_P + | DOUBLE_P + | DROP + | EACH + | EMPTY_P + | ENABLE_P + | ENCODING + | ENCRYPTED + | ENUM_P + | ERROR + | ESCAPE + | EVENT + | EXCLUDE + | EXCLUDING + | EXCLUSIVE + | EXECUTE + | EXPLAIN + | EXPRESSION + | EXTENSION + | EXTERNAL + | FAMILY + | FILTER + | FINALIZE + | FIRST_P + | FOLLOWING + | FORCE + | FORMAT + | FORWARD + | FUNCTION + | FUNCTIONS + | GENERATED + | GLOBAL + | GRANTED + | GROUPS + | HANDLER + | HEADER_P + | HOLD + | HOUR_P + | IDENTITY_P + | IF_P + | IMMEDIATE + | IMMUTABLE + | IMPLICIT_P + | IMPORT_P + | INCLUDE + | INCLUDING + | INCREMENT + | INDENT + | INDEX + | INDEXES + | INHERIT + | INHERITS + | INLINE_P + | INPUT_P + | INSENSITIVE + | INSERT + | INSTEAD + | INVOKER + | ISOLATION + | KEEP + | KEY + | KEYS + | LABEL + | LANGUAGE + | LARGE_P + | LAST_P + | LEAKPROOF + | LEVEL + | LISTEN + | LOAD + | LOCAL + | LOCATION + | LOCK_P + | LOCKED + | LOGGED + | MAPPING + | MATCH + | MATCHED + | MATERIALIZED + | MAXVALUE + | MERGE + | METHOD + | MINUTE_P + | MINVALUE + | MODE + | MONTH_P + | MOVE + | NAME_P + | NAMES + | NESTED + | NEW + | NEXT + | NFC + | NFD + | NFKC + | NFKD + | NO + | NORMALIZED + | NOTHING + | NOTIFY + | NOWAIT + | NULLS_P + | OBJECT_P + | OF + | OFF + | OIDS + | OLD + | OMIT + | OPERATOR + | OPTION + | OPTIONS + | ORDINALITY + | OTHERS + | OVER + | OVERRIDING + | OWNED + | OWNER + | PARALLEL + | PARAMETER + | PARSER + | PARTIAL + | PARTITION + | PASSING + | PASSWORD + | PATH + | PERIOD + | PLAN + | PLANS + | POLICY + | PRECEDING + | PREPARE + | PREPARED + | PRESERVE + | PRIOR + | PRIVILEGES + | PROCEDURAL + | PROCEDURE + | PROCEDURES + | PROGRAM + | PUBLICATION + | QUOTE + | QUOTES + | RANGE + | READ + | REASSIGN +// | RECHECK + | RECURSIVE + | REF + | REFERENCING + | REFRESH + | REINDEX + | RELATIVE_P + | RELEASE + | RENAME + | REPEATABLE + | REPLACE + | REPLICA + | RESET + | RESTART + | RESTRICT + | RETURN + | RETURNS + | REVOKE + | ROLE + | ROLLBACK + | ROLLUP + | ROUTINE + | ROUTINES + | ROWS + | RULE + | SAVEPOINT + | SCALAR + | SCHEMA + | SCHEMAS + | SCROLL + | SEARCH + | SECOND_P + | SECURITY + | SEQUENCE + | SEQUENCES + | SERIALIZABLE + | SERVER + | SESSION + | SET + | SETS + | SHARE + | SHOW + | SIMPLE + | SKIP_P + | SNAPSHOT + | SOURCE + | SQL_P + | STABLE + | STANDALONE_P + | START + | STATEMENT + | STATISTICS + | STDIN + | STDOUT + | STORAGE + | STORED + | STRICT_P + | STRING_P + | STRIP_P + | SUBSCRIPTION + | SUPPORT + | SYSID + | SYSTEM_P + | TABLES + | TABLESPACE + | TARGET + | TEMP + | TEMPLATE + | TEMPORARY + | TEXT_P + | TIES + | TRANSACTION + | TRANSFORM + | TRIGGER + | TRUNCATE + | TRUSTED + | TYPE_P + | TYPES_P + | UESCAPE + | UNBOUNDED + | UNCOMMITTED + | UNCONDITIONAL + | UNENCRYPTED + | UNKNOWN + | UNLISTEN + | UNLOGGED + | UNTIL + | UPDATE + | VACUUM + | VALID + | VALIDATE + | VALIDATOR + | VALUE_P + | VARYING + | VERSION_P + | VIEW + | VIEWS + | VOLATILE + | WHITESPACE_P + | WITHIN + | WITHOUT + | WORK + | WRAPPER + | WRITE + | XML_P + | YEAR_P + | YES_P + | ZONE + ; + +/* Column identifier --- keywords that can be column, table, etc names. + * + * Many of these keywords will in fact be recognized as type or function + * names too; but they have special productions for the purpose, and so + * can't be treated as "generic" type or function names. + * + * The type names appearing here are not usable as function names + * because they can be followed by '(' in typename productions, which + * looks too much like a function call for an LR(1) parser. + */ +col_name_keyword + : BETWEEN + | BIGINT + | BIT + | BOOLEAN_P + | CHAR_P + | character + | COALESCE + | DEC + | DECIMAL_P + | EXISTS + | EXTRACT + | FLOAT_P + | GREATEST + | GROUPING + | INOUT + | INT_P + | INTEGER + | INTERVAL + | JSON + | JSON_ARRAY + | JSON_ARRAYAGG + | JSON_EXISTS + | JSON_OBJECT + | JSON_OBJECTAGG + | JSON_QUERY + | JSON_SCALAR + | JSON_SERIALIZE + | JSON_TABLE + | JSON_VALUE + | LEAST + | MERGE_ACTION + | NATIONAL + | NCHAR + | NONE + | NORMALIZE + | NULLIF + | NUMERIC + | OUT_P + | OVERLAY + | POSITION + | PRECISION + | REAL + | ROW + | SETOF + | SMALLINT + | SUBSTRING + | TIME + | TIMESTAMP + | TREAT + | TRIM + | VALUES + | VARCHAR + | XMLATTRIBUTES + | XMLCONCAT + | XMLELEMENT + | XMLEXISTS + | XMLFOREST + | XMLNAMESPACES + | XMLPARSE + | XMLPI + | XMLROOT + | XMLSERIALIZE + | XMLTABLE + ; + +/* Type/function identifier --- keywords that can be type or function names. + * + * Most of these are keywords that are used as operators in expressions; + * in general such keywords can't be column names because they would be + * ambiguous with variables, but they are unambiguous as function identifiers. + * + * Do not include POSITION, SUBSTRING, etc here since they have explicit + * productions in a_expr to support the goofy SQL9x argument syntax. + * - thomas 2000-11-28 + */ +type_func_name_keyword + : AUTHORIZATION + | BINARY + | COLLATION + | CONCURRENTLY + | CROSS + | CURRENT_SCHEMA + | FREEZE + | FULL + | ILIKE + | INNER_P + | IS + | ISNULL + | JOIN + | LEFT + | LIKE + | NATURAL + | NOTNULL + | OUTER_P + | OVERLAPS + | RIGHT + | SIMILAR + | TABLESAMPLE + | VERBOSE + ; + +/* Reserved keyword --- these keywords are usable only as a ColLabel. + * + * Keywords appear here if they could not be distinguished from variable, + * type, or function names in some contexts. Don't put things here unless + * forced to. + */ +reserved_keyword + : ALL + | ANALYSE + | ANALYZE + | AND + | ANY + | ARRAY + | AS + | ASC + | ASYMMETRIC + | BOTH + | CASE + | CAST + | CHECK + | COLLATE + | COLUMN + | CONSTRAINT + | CREATE + | CURRENT_CATALOG + | CURRENT_DATE + | CURRENT_ROLE + | CURRENT_TIME + | CURRENT_TIMESTAMP + | CURRENT_USER + | DEFAULT + | DEFERRABLE + | DESC + | DISTINCT + | DO + | ELSE + | END_P + | EXCEPT + | FALSE_P + | FETCH + | FOR + | FOREIGN + | FROM + | GRANT + | GROUP_P + | HAVING + | IN_P + | INITIALLY + | INTERSECT + | INTO + | LATERAL_P + | LEADING + | LIMIT + | LOCALTIME + | LOCALTIMESTAMP + | NOT + | NULL_P + | OFFSET + | ON + | ONLY + | OR + | ORDER + | PLACING + | PRIMARY + | REFERENCES + | RETURNING + | SELECT + | SESSION_USER + | SOME + | SYMMETRIC + | SYSTEM_USER + | TABLE + | THEN + | TO + | TRAILING + | TRUE_P + | UNION + | UNIQUE + | USER + | USING + | VARIADIC + | WHEN + | WHERE + | WINDOW + | WITH + ; + +/* + * While all keywords can be used as column labels when preceded by AS, + * not all of them can be used as a "bare" column label without AS. + * Those that can be used as a bare label must be listed here, + * in addition to appearing in one of the category lists above. + * + * Always add a new keyword to this list if possible. Mark it BARE_LABEL + * in kwlist.h if it is included here, or AS_LABEL if it is not. + */ +bare_label_keyword + : ABORT_P + | ABSENT + | ABSOLUTE_P + | ACCESS + | ACTION + | ADD_P + | ADMIN + | AFTER + | AGGREGATE + | ALL + | ALSO + | ALTER + | ALWAYS + | ANALYSE + | ANALYZE + | AND + | ANY + | ASC + | ASENSITIVE + | ASSERTION + | ASSIGNMENT + | ASYMMETRIC + | AT + | ATOMIC + | ATTACH + | ATTRIBUTE + | AUTHORIZATION + | BACKWARD + | BEFORE + | BEGIN_P + | BETWEEN + | BIGINT + | BINARY + | BIT + | BOOLEAN_P + | BOTH + | BREADTH + | BY + | CACHE + | CALL + | CALLED + | CASCADE + | CASCADED + | CASE + | CAST + | CATALOG + | CHAIN + | CHARACTERISTICS + | CHECK + | CHECKPOINT + | CLASS + | CLOSE + | CLUSTER + | COALESCE + | COLLATE + | COLLATION + | COLUMN + | COLUMNS + | COMMENT + | COMMENTS + | COMMIT + | COMMITTED + | COMPRESSION + | CONCURRENTLY + | CONDITIONAL + | CONFIGURATION + | CONFLICT + | CONNECTION + | CONSTRAINT + | CONSTRAINTS + | CONTENT_P + | CONTINUE_P + | CONVERSION_P + | COPY + | COST + | CROSS + | CSV + | CUBE + | CURRENT_CATALOG + | CURRENT_DATE + | CURRENT_P + | CURRENT_ROLE + | CURRENT_SCHEMA + | CURRENT_TIME + | CURRENT_TIMESTAMP + | CURRENT_USER + | CURSOR + | CYCLE + | DATA_P + | DATABASE + | DEALLOCATE + | DEC + | DECIMAL_P + | DECLARE + | DEFAULT + | DEFAULTS + | DEFERRABLE + | DEFERRED + | DEFINER + | DELETE_P + | DELIMITER + | DELIMITERS + | DEPENDS + | DEPTH + | DESC + | DETACH + | DICTIONARY + | DISABLE_P + | DISCARD + | DISTINCT + | DO + | DOCUMENT_P + | DOMAIN_P + | DOUBLE_P + | DROP + | EACH + | ELSE + | EMPTY_P + | ENABLE_P + | ENCODING + | ENCRYPTED + | END_P + | ENUM_P + | ERROR + | ESCAPE + | EVENT + | EXCLUDE + | EXCLUDING + | EXCLUSIVE + | EXECUTE + | EXISTS + | EXPLAIN + | EXPRESSION + | EXTENSION + | EXTERNAL + | EXTRACT + | FALSE_P + | FAMILY + | FINALIZE + | FIRST_P + | FLOAT_P + | FOLLOWING + | FORCE + | FOREIGN + | FORMAT + | FORWARD + | FREEZE + | FULL + | FUNCTION + | FUNCTIONS + | GENERATED + | GLOBAL + | GRANTED + | GREATEST + | GROUPING + | GROUPS + | HANDLER + | HEADER_P + | HOLD + | IDENTITY_P + | IF_P + | ILIKE + | IMMEDIATE + | IMMUTABLE + | IMPLICIT_P + | IMPORT_P + | IN_P + | INCLUDE + | INCLUDING + | INCREMENT + | INDENT + | INDEX + | INDEXES + | INHERIT + | INHERITS + | INITIALLY + | INLINE_P + | INNER_P + | INOUT + | INPUT_P + | INSENSITIVE + | INSERT + | INSTEAD + | INT_P + | INTEGER + | INTERVAL + | INVOKER + | IS + | ISOLATION + | JOIN + | JSON + | JSON_ARRAY + | JSON_ARRAYAGG + | JSON_EXISTS + | JSON_OBJECT + | JSON_OBJECTAGG + | JSON_QUERY + | JSON_SCALAR + | JSON_SERIALIZE + | JSON_TABLE + | JSON_VALUE + | KEEP + | KEY + | KEYS + | LABEL + | LANGUAGE + | LARGE_P + | LAST_P + | LATERAL_P + | LEADING + | LEAKPROOF + | LEAST + | LEFT + | LEVEL + | LIKE + | LISTEN + | LOAD + | LOCAL + | LOCALTIME + | LOCALTIMESTAMP + | LOCATION + | LOCK_P + | LOCKED + | LOGGED + | MAPPING + | MATCH + | MATCHED + | MATERIALIZED + | MAXVALUE + | MERGE + | MERGE_ACTION + | METHOD + | MINVALUE + | MODE + | MOVE + | NAME_P + | NAMES + | NATIONAL + | NATURAL + | NCHAR + | NESTED + | NEW + | NEXT + | NFC + | NFD + | NFKC + | NFKD + | NO + | NONE + | NORMALIZE + | NORMALIZED + | NOT + | NOTHING + | NOTIFY + | NOWAIT + | NULL_P + | NULLIF + | NULLS_P + | NUMERIC + | OBJECT_P + | OF + | OFF + | OIDS + | OLD + | OMIT + | ONLY + | OPERATOR + | OPTION + | OPTIONS + | OR + | ORDINALITY + | OTHERS + | OUT_P + | OUTER_P + | OVERLAY + | OVERRIDING + | OWNED + | OWNER + | PARALLEL + | PARAMETER + | PARSER + | PARTIAL + | PARTITION + | PASSING + | PASSWORD + | PATH + | PERIOD + | PLACING + | PLAN + | PLANS + | POLICY + | POSITION + | PRECEDING + | PREPARE + | PREPARED + | PRESERVE + | PRIMARY + | PRIOR + | PRIVILEGES + | PROCEDURAL + | PROCEDURE + | PROCEDURES + | PROGRAM + | PUBLICATION + | QUOTE + | QUOTES + | RANGE + | READ + | REAL + | REASSIGN + | RECURSIVE + | REF + | REFERENCES + | REFERENCING + | REFRESH + | REINDEX + | RELATIVE_P + | RELEASE + | RENAME + | REPEATABLE + | REPLACE + | REPLICA + | RESET + | RESTART + | RESTRICT + | RETURN + | RETURNS + | REVOKE + | RIGHT + | ROLE + | ROLLBACK + | ROLLUP + | ROUTINE + | ROUTINES + | ROW + | ROWS + | RULE + | SAVEPOINT + | SCALAR + | SCHEMA + | SCHEMAS + | SCROLL + | SEARCH + | SECURITY + | SELECT + | SEQUENCE + | SEQUENCES + | SERIALIZABLE + | SERVER + | SESSION + | SESSION_USER + | SET + | SETOF + | SETS + | SHARE + | SHOW + | SIMILAR + | SIMPLE + | SKIP_P + | SMALLINT + | SNAPSHOT + | SOME + | SOURCE + | SQL_P + | STABLE + | STANDALONE_P + | START + | STATEMENT + | STATISTICS + | STDIN + | STDOUT + | STORAGE + | STORED + | STRICT_P + | STRING_P + | STRIP_P + | SUBSCRIPTION + | SUBSTRING + | SUPPORT + | SYMMETRIC + | SYSID + | SYSTEM_P + | SYSTEM_USER + | TABLE + | TABLES + | TABLESAMPLE + | TABLESPACE + | TARGET + | TEMP + | TEMPLATE + | TEMPORARY + | TEXT_P + | THEN + | TIES + | TIME + | TIMESTAMP + | TRAILING + | TRANSACTION + | TRANSFORM + | TREAT + | TRIGGER + | TRIM + | TRUE_P + | TRUNCATE + | TRUSTED + | TYPE_P + | TYPES_P + | UESCAPE + | UNBOUNDED + | UNCOMMITTED + | UNCONDITIONAL + | UNENCRYPTED + | UNIQUE + | UNKNOWN + | UNLISTEN + | UNLOGGED + | UNTIL + | UPDATE + | USER + | USING + | VACUUM + | VALID + | VALIDATE + | VALIDATOR + | VALUE_P + | VALUES + | VARCHAR + | VARIADIC + | VERBOSE + | VERSION_P + | VIEW + | VIEWS + | VOLATILE + | WHEN + | WHITESPACE_P + | WORK + | WRAPPER + | WRITE + | XML_P + | XMLATTRIBUTES + | XMLCONCAT + | XMLELEMENT + | XMLEXISTS + | XMLFOREST + | XMLNAMESPACES + | XMLPARSE + | XMLPI + | XMLROOT + | XMLSERIALIZE + | XMLTABLE + | YES_P + | ZONE + ; + + +any_identifier + : colid + ; + +identifier + : Identifier uescape_? + | QuotedIdentifier + | UnicodeQuotedIdentifier + | PLSQLVARIABLENAME + ; diff --git a/src/stewkk/sql/logic/parser/PostgreSQLParserBase.cpp b/src/stewkk/sql/logic/parser/PostgreSQLParserBase.cpp new file mode 100644 index 0000000..599def2 --- /dev/null +++ b/src/stewkk/sql/logic/parser/PostgreSQLParserBase.cpp @@ -0,0 +1,17 @@ +#include "PostgreSQLParser.h" + +using namespace antlr4; + +void PostgreSQLParserBase::ParseRoutineBody() +{ +} + +bool PostgreSQLParserBase::OnlyAcceptableOps() +{ + auto c = ((CommonTokenStream*)this->getInputStream())->LT(1); + auto text = c->getText(); + return text == "!" || text == "!!" + || text == "!=-" // Code for specific example. + ; +} + diff --git a/src/stewkk/sql/logic/parser/PostgreSQLParserBase.h b/src/stewkk/sql/logic/parser/PostgreSQLParserBase.h new file mode 100644 index 0000000..921293c --- /dev/null +++ b/src/stewkk/sql/logic/parser/PostgreSQLParserBase.h @@ -0,0 +1,10 @@ +#pragma once + +#include "antlr4-runtime.h" + +class PostgreSQLParserBase : public antlr4::Parser { +public: + PostgreSQLParserBase(antlr4::TokenStream *input) : Parser(input) { } + void ParseRoutineBody(); + bool OnlyAcceptableOps(); +}; diff --git a/src/stewkk/sql/logic/parser/parser.cpp b/src/stewkk/sql/logic/parser/parser.cpp new file mode 100644 index 0000000..0615f49 --- /dev/null +++ b/src/stewkk/sql/logic/parser/parser.cpp @@ -0,0 +1,120 @@ +#include + +#include + +#include + +#include +#include + +#include + +namespace stewkk::sql { + +Result GetAST(std::istream& in) { + antlr4::ANTLRInputStream antlr_input(in); + codegen::PostgreSQLLexer lexer(&antlr_input); + + antlr4::CommonTokenStream tokens(&lexer); + tokens.fill(); + +#ifdef DEBUG + for (auto token : tokens.getTokens()) { + std::clog << token->toString() << std::endl; + } +#endif + + codegen::PostgreSQLParser parser(&tokens); + antlr4::tree::ParseTree* tree = parser.root(); + + if (parser.getNumberOfSyntaxErrors() != 0) { + return MakeError("syntax error"); + } + +#ifdef DEBUG + std::clog << tree->toStringTree(&parser, true) << std::endl << std::endl; +#endif + + Visitor visitor(&parser); + + std::any res; + try { + res = visitor.visit(tree); + } catch (const Error& ex) { + return std::unexpected(ex); + } + + if (Operator* op = std::any_cast(&res)) { + return std::move(*op); + } + + return Table{kEmptyTableName}; +} + +std::string GetDotRepresentation(const Expression& expr) { + struct DotFormatter { + std::string operator()(const BinaryExpression& expr) { + return std::format("{} {} {}", std::visit(DotFormatter{}, *expr.lhs), ToString(expr.binop), + std::visit(DotFormatter{}, *expr.rhs)); + } + std::string operator()(const UnaryExpression& expr) { + return std::format("({} {})",ToString(expr.op), std::visit(DotFormatter{}, *expr.child)); + } + std::string operator()(const Attribute& expr) { + return ToString(expr); + } + std::string operator()(const IntConst& expr) { + return std::to_string(expr); + } + std::string operator()(const Literal& expr) { + return ToString(expr); + } + }; + return std::visit(DotFormatter{}, expr); +} + +std::string GetDotRepresentation(const Operator& op) { + // FIXME: refactor to use osstream + struct DotFormatter { + std::pair operator()(const Projection& op) { + auto exprs = op.expressions + | std::views::transform([](const Expression& expr) { return ToString(expr); }) + | std::views::join_with(',') | std::ranges::to(); + auto node = std::format("π {}", exprs); + auto [source_node, rest] = std::visit(DotFormatter{}, *op.source); + return {node, std::format("\"{}\"\n\"{}\" -> \"{}\"\n{}", node, source_node, node, rest)}; + } + std::pair operator()(const Filter& op) { + auto node = std::format("σ {}", GetDotRepresentation(op.expr)); + auto [source_node, rest] = std::visit(DotFormatter{}, *op.source); + return {node, std::format("\"{}\"\n\"{}\" -> \"{}\"\n{}", node, source_node, node, rest)}; + } + std::pair operator()(const Table& op) { + auto node = std::format("{}", op.name); + return {node, std::format("\"{}\"", node)}; + } + std::pair operator()(const CrossJoin& op) { + auto [lhs_node, lhs_rest] = std::visit(DotFormatter{}, *op.lhs); + auto [rhs_node, rhs_rest] = std::visit(DotFormatter{}, *op.rhs); + auto node = std::format("crossjoin_{}_{}", lhs_node, rhs_node); + auto rest = std::format("\"{}\"[label=\"×\"]\n\"{}\" -> \"{}\"\n\"{}\" -> \"{}\"\n{}\n{}", node, lhs_node, node, rhs_node, + node, lhs_rest, rhs_rest); + return {node, rest}; + } + std::pair operator()(const Join& op) { + auto [lhs_node, lhs_rest] = std::visit(DotFormatter{}, *op.lhs); + auto [rhs_node, rhs_rest] = std::visit(DotFormatter{}, *op.rhs); + auto join_type = ToString(op.type); + auto qual_expr = GetDotRepresentation(op.qual); + auto node = std::format("join_{}_{}", lhs_node, rhs_node); + auto rest = std::format( + "\"{}\"[label=\"{}\\nON {}\"]\n\"{}\" -> \"{}\"\n\"{}\" -> \"{}\"\n{}\n{}", node, + join_type, qual_expr, lhs_node, node, rhs_node, node, lhs_rest, rhs_rest); + return {node, rest}; + } + }; + auto [_, code] = std::visit(DotFormatter{}, op); + return std::format("digraph G {{ rankdir=BT; {} }}\n", code); +} + +} // namespace stewkk::sql diff --git a/src/stewkk/sql/logic/parser/parser_test.cpp b/src/stewkk/sql/logic/parser/parser_test.cpp new file mode 100644 index 0000000..bdb12f9 --- /dev/null +++ b/src/stewkk/sql/logic/parser/parser_test.cpp @@ -0,0 +1,200 @@ +#include + +#include +#include +#include + +#include + +using ::testing::Eq; +using ::testing::IsTrue; +using ::testing::VariantWith; + +namespace stewkk::sql { + +const static std::string kProjectDir = std::getenv("PWD"); + +namespace { + +std::string ReadFromFile(std::filesystem::path path) { + std::ifstream f{path}; + std::ostringstream stream; + stream << f.rdbuf(); + return stream.str(); +} + +} // namespace + + +TEST(ParserTest, SelectAllFromSingleTable) { + std::stringstream s{"SELECT * FROM users;"}; + + Operator got = GetAST(s).value(); + + ASSERT_THAT(got, VariantWith(Table{"users"})); +} + +TEST(ParserTest, SelectSingleColumnFromSingleTable) { + std::stringstream s{"SELECT users.id FROM users;"}; + + Operator got = GetAST(s).value(); + + ASSERT_THAT(got, VariantWith(Projection{std::vector{{Attribute{"users", "id"}}}, + std::make_shared(Table{"users"})})); +} + +TEST(ParserTest, SelectMultipleColumnsFromSingleTable) { + std::stringstream s{"SELECT users.id, users.email, users.phone FROM users;"}; + + Operator got = GetAST(s).value(); + + ASSERT_THAT(got, + VariantWith(Projection{ + std::vector{Attribute{"users", "id"}, Attribute{"users", "email"}, Attribute{"users", "phone"}}, + std::make_shared(Table{"users"})})); +} + +TEST(ParserTest, SelectWithWhereClause) { + std::stringstream s{"SELECT users.id FROM users WHERE users.age > 18;"}; + + Operator got = GetAST(s).value(); + + ASSERT_THAT(got, VariantWith(Projection{ + std::vector{Attribute{"users", "id"}}, + std::make_shared( + Filter{Expression{BinaryExpression{ + std::make_shared(Attribute{"users", "age"}), + BinaryOp::kGt, std::make_shared(IntConst{18})}}, + std::make_shared(Table{"users"})})})); +} + +TEST(ParserTest, GetDotRepresentation) { + std::stringstream s{"SELECT users.id FROM users WHERE users.age > 18;"}; + Operator op = GetAST(s).value(); + auto expected = ReadFromFile(kProjectDir + "/test/static/parser/expected.dot"); + + auto got = GetDotRepresentation(op); + + ASSERT_THAT(got, Eq(expected)); +} + +TEST(ParserTest, SelectWithBooleanExpression) { + std::stringstream s{"SELECT TRUE AND NULL OR FALSE AND NOT NULL;"}; + + Operator got = GetAST(s).value(); + + ASSERT_THAT(got, VariantWith(Projection{ + {BinaryExpression{ + std::make_shared(BinaryExpression{ + std::make_shared(Literal::kTrue), + BinaryOp::kAnd, + std::make_shared(Literal::kNull), + }), + BinaryOp::kOr, + std::make_shared(BinaryExpression{ + std::make_shared(Literal::kFalse), + BinaryOp::kAnd, + std::make_shared(UnaryExpression{ + UnaryOp::kNot, std::make_shared(Literal::kNull)}), + }), + }}, + std::make_shared(Table{"_EMPTY_TABLE_"})})); +} + +TEST(ParserTest, SelectWithArithmeticalOperations) { + std::stringstream s{"SELECT 1+2-3;"}; + + Operator got = GetAST(s).value(); + + ASSERT_THAT( + got, VariantWith(Projection{{BinaryExpression{ + std::make_shared(BinaryExpression{ + std::make_shared(IntConst{1}), + BinaryOp::kPlus, + std::make_shared(IntConst{2}), + }), + BinaryOp::kMinus, + std::make_shared(IntConst{3}), + }}, + std::make_shared(Table{"_EMPTY_TABLE_"})})); +} + +TEST(ParserTest, GetDotRepresentationOfArithmeticalExpression) { + std::stringstream s{"SELECT 1+2-3+4+5-6;"}; + + Operator op = GetAST(s).value(); + auto expected = ReadFromFile(kProjectDir + "/test/static/parser/expected_arithmetical.dot"); + + auto got = GetDotRepresentation(op); + + ASSERT_THAT(got, Eq(expected)); +} + +TEST(ParserTest, SyntaxError) { + std::stringstream s{"xxx;"}; + + auto got = GetAST(s).error(); + + ASSERT_THAT(got.What(), Eq("syntax error")); + ASSERT_THAT(got.Wraps(ErrorType::kSyntaxError), IsTrue()); +} + +TEST(ParserTest, NotSupportedError) { + std::stringstream s{"INSERT INTO users (id) VALUES (1);"}; + + auto got = GetAST(s).error(); + + ASSERT_THAT(got.What(), Eq("insertstmt is currently unsupported")); + ASSERT_THAT(got.Wraps(ErrorType::kQueryNotSupported), IsTrue()); +} + +TEST(ParserTest, EmptyQuery) { + std::stringstream s{""}; + + Operator got = GetAST(s).value(); + + ASSERT_THAT(got, VariantWith
(Table{"_EMPTY_TABLE_"})); +} + +TEST(ParserTest, SelectWithParens) { + std::stringstream s{"((SELECT * FROM users));"}; + + Operator got = GetAST(s).value(); + + ASSERT_THAT(got, VariantWith
(Table{"users"})); +} + +TEST(ParserTest, EmptySelect) { + std::stringstream s{"SELECT;"}; + + Operator got = GetAST(s).value(); + + ASSERT_THAT(got, VariantWith
(Table{"_EMPTY_TABLE_"})); +} + +TEST(ParserTest, SelectWithJoinDot) { + std::stringstream s{"SELECT * FROM users, books;"}; + auto expected = ReadFromFile(kProjectDir + "/test/static/parser/expected_join.dot"); + Operator op = GetAST(s).value(); + + auto got = GetDotRepresentation(op); + + ASSERT_THAT(got, Eq(expected)); +} + +TEST(ParserTest, SelectWithOuterJoinDot) { + std::stringstream s{"SELECT * FROM users LEFT OUTER JOIN books ON users.book = books.id;"}; + auto expected = ReadFromFile(kProjectDir + "/test/static/parser/expected_outer_join.dot"); + Operator op = GetAST(s).value(); + + auto got = GetDotRepresentation(op); + + ASSERT_THAT(got, Eq(expected)); +} + +/* +** ORDER BY +** aggregations: SELECT kind, sum(len) AS total FROM films GROUP BY kind; + */ + +} // namespace stewkk::sql diff --git a/src/stewkk/sql/logic/parser/visitor.cpp b/src/stewkk/sql/logic/parser/visitor.cpp new file mode 100644 index 0000000..49b348f --- /dev/null +++ b/src/stewkk/sql/logic/parser/visitor.cpp @@ -0,0 +1,680 @@ +#include + +#include + +#include +#include + +namespace stewkk::sql { + +namespace { + +Operator GetOperatorWithChild(Operator&& op, Operator&& child) { + struct ChildSetter { + Operator operator() (Table&& parent) { + std::unreachable(); + } + Operator operator() (Projection&& parent) { + parent.source = std::make_shared(std::move(child)); + return parent; + } + Operator operator() (Filter&& filter) { + filter.source = std::make_shared(std::move(child)); + return filter; + } + Operator operator() (CrossJoin&& cross_join) { + std::unreachable(); + } + Operator operator() (Join&& cross_join) { + std::unreachable(); + } + + Operator&& child; + }; + return std::visit(ChildSetter{std::move(child)}, std::move(op)); +} + +} // namespace + +std::any Visitor::visitStmt(codegen::PostgreSQLParser::StmtContext *ctx) { + if (!ctx->children.empty() && !ctx->selectstmt()) { + auto& rule_names = parser_->getRuleNames(); + std::vector unsupported_rules; + for (auto child : ctx->children) { + if (!child) { + continue; + } + if (antlr4::RuleContext* rule_context = dynamic_cast(child)) { + size_t rule_index = rule_context->getRuleIndex(); + unsupported_rules.emplace_back(rule_names[rule_index]); + } + } + std::string rules_list + = unsupported_rules | std::views::join_with(',') | std::ranges::to(); + if (rules_list.empty()) { + throw Error{ErrorType::kQueryNotSupported, "query is not supported"}; + } + // NOTE: concatenation of errors could be useful here + throw Error{ErrorType::kQueryNotSupported, + std::format("{} {} currently unsupported", std::move(rules_list), + unsupported_rules.size() == 1 ? "is" : "are")}; + } + return visitChildren(ctx); +} + +std::any Visitor::visit(antlr4::tree::ParseTree *tree) { + std::string rule_name; + int indentation = 0; + auto& rule_names = parser_->getRuleNames(); + if (antlr4::RuleContext *rule_context = dynamic_cast(tree)) { + size_t rule_index = rule_context->getRuleIndex(); + rule_name = rule_names[rule_index]; + indentation = rule_context->depth()-1; + } + std::string indentation_str(indentation*4, ' '); +#ifdef DEBUG + std::clog << std::format("{}visiting rule: {}\n", indentation_str, rule_name); +#endif + auto tmp = codegen::PostgreSQLParserBaseVisitor::visit(tree); +#ifdef DEBUG + std::clog << std::format("{}exiting rule: {}\n", indentation_str, rule_name); +#endif + return tmp; +} + +std::any Visitor::visitColumnref(codegen::PostgreSQLParser::ColumnrefContext *ctx) { + // NOTE: column reference has form: database_name.schema_name.table_name.column_name + auto table = ctx->colid()->getText(); + if (ctx->indirection()) { + auto column = ctx->indirection()->indirection_el(0)->attr_name()->getText(); + return Expression{Attribute{std::move(table), std::move(column)}}; + } + return Expression{Attribute{"", std::move(table)}}; +} + +std::any Visitor::visitA_expr_compare(codegen::PostgreSQLParser::A_expr_compareContext *ctx) { + if (ctx->subquery_Op()) { + throw Error{ErrorType::kQueryNotSupported, "subquery_Op is not supported"}; + } + auto exprs = ctx->a_expr_like(); + if (exprs.size() == 1) { + return visit(exprs.front()); + } + auto lhs_expr = std::any_cast(visit(exprs.front())); + auto rhs_expr = std::any_cast(visit(exprs.back())); + BinaryOp op; + if (ctx->LT()) { + op = BinaryOp::kLt; + } else if (ctx->GT()) { + op = BinaryOp::kGt; + } else if (ctx->EQUAL()) { + op = BinaryOp::kEq; + } else if (ctx->LESS_EQUALS()) { + op = BinaryOp::kLe; + } else if (ctx->GREATER_EQUALS()) { + op = BinaryOp::kGe; + } else if (ctx->NOT_EQUALS()) { + op = BinaryOp::kNotEq; + } + return Expression{ + BinaryExpression { + std::make_shared(lhs_expr), + op, + std::make_shared(rhs_expr), + }, + }; +} + +Visitor::Visitor(codegen::PostgreSQLParser* parser) : parser_(parser) {} + +std::any Visitor::visitRoot(codegen::PostgreSQLParser::RootContext *ctx) { + return visit(ctx->stmtblock()); +} + +std::any Visitor::visitStmtmulti(codegen::PostgreSQLParser::StmtmultiContext* ctx) { + auto stmt = ctx->stmt(); + if (stmt.empty()) { + return {}; + } + return visit(ctx->stmt()[0]); +} + +std::any Visitor::visitSimple_select_intersect(codegen::PostgreSQLParser::Simple_select_intersectContext *ctx) { + // TODO: INTERSECT (with ALL or DISTINCT) + return visit(ctx->simple_select_pramary().front()); +} + +std::any Visitor::visitTarget_label(codegen::PostgreSQLParser::Target_labelContext *ctx) { + // TODO: AS (rename operation) + return visit(ctx->a_expr()); +} + +std::any Visitor::visitTarget_star(codegen::PostgreSQLParser::Target_starContext* ctx) { + return {}; +} + +std::any Visitor::visitTarget_list(codegen::PostgreSQLParser::Target_listContext* ctx) { + const auto& targets = ctx->target_el(); + auto target_expressions + = targets | std::views::transform([this](const auto& target) { return visit(target); }) + | std::views::filter( + [](const std::any& expr) { return expr.has_value(); }) + | std::views::transform( + [](std::any expr) { return std::any_cast(expr); }) + | std::ranges::to(); + + if (!target_expressions.empty()) { + return Operator{Projection{std::move(target_expressions), nullptr}}; + } + + return {}; +} + +std::any Visitor::visitFrom_clause(codegen::PostgreSQLParser::From_clauseContext *ctx) { + return visit(ctx->from_list()); +} + +std::any Visitor::visitFrom_list(codegen::PostgreSQLParser::From_listContext *ctx) { + auto table_ref = ctx->table_ref(); + auto result = std::any_cast(visit(table_ref.front())); + for (auto it = table_ref.begin()+1; it != table_ref.end(); it++) { + auto rhs = std::any_cast(visit(*it)); + result = CrossJoin{ + std::make_shared(std::move(result)), + std::make_shared(std::move(rhs)), + }; + } + return result; +} + +std::any Visitor::visitTable_ref(codegen::PostgreSQLParser::Table_refContext *ctx) { + if (ctx->xmltable()) { + throw Error{ErrorType::kQueryNotSupported, "xmltable is not supported"}; + } + if (ctx->func_table()) { + // NOTE: may want to support + throw Error{ErrorType::kQueryNotSupported, "func_table is not supported"}; + } + if (ctx->LATERAL_P()) { + throw Error{ErrorType::kQueryNotSupported, "LATERAL clause is not supported"}; + } + + auto children = ctx->children; + auto children_it = children.begin(); + + Operator res; + if (ctx->relation_expr()) { + auto table = std::any_cast(visit(ctx->relation_expr())); + children_it++; + res = Table{std::move(table)}; + } + if (ctx->select_with_parens()) { + res = std::any_cast(visit(ctx->select_with_parens())); + children_it++; + children_it++; + } + auto table_refs = ctx->table_ref(); + auto table_ref_it = table_refs.begin(); + if (ctx->OPEN_PAREN()) { + res = std::any_cast(visit(*table_ref_it)); + children_it++; + table_ref_it++; + } + + if (ctx->alias_clause()) { + throw Error{ErrorType::kQueryNotSupported, "alias_clause is not supported"}; + } + if (ctx->tablesample_clause()) { + throw Error{ErrorType::kQueryNotSupported, "tablesample_clause is not supported"}; + } + + for (; children_it != children.end(); children_it++) { + auto text = (*children_it)->getText(); + if (text == "CROSS") { + // CROSS JOIN table_ref + children_it += 2; + auto rhs = std::any_cast(visit(*children_it)); + res = CrossJoin{ + std::make_shared(std::move(res)), + std::make_shared(std::move(rhs)), + }; + } else if (text == "NATURAL") { + throw Error{ErrorType::kQueryNotSupported, "NATURAL clause is not supported"}; + } else { + Operator rhs; + auto join_type = JoinType::kInner; + Expression qual_expression; + if (text == "JOIN") { + // JOIN table_ref join_qual + children_it++; + rhs = std::any_cast(visit(*children_it)); + children_it++; + qual_expression = std::any_cast(visit(*children_it)); + } else { + // join_type JOIN table_ref join_qual + join_type = std::any_cast(visit(*children_it)); + children_it += 2; + rhs = std::any_cast(visit(*children_it)); + children_it++; + qual_expression = std::any_cast(visit(*children_it)); + } + res = Join{ + join_type, + std::move(qual_expression), + std::make_shared(std::move(res)), + std::make_shared(std::move(rhs)), + }; + } + } + return res; +} + +std::any Visitor::visitJoin_type(codegen::PostgreSQLParser::Join_typeContext *ctx) { + if (ctx->INNER_P()) { + return JoinType::kInner; + } + if (ctx->FULL()) { + return JoinType::kFull; + } + if (ctx->LEFT()) { + return JoinType::kLeft; + } + return JoinType::kRight; +} + +std::any Visitor::visitJoin_qual(codegen::PostgreSQLParser::Join_qualContext *ctx) { + if (ctx->USING()) { + throw Error{ErrorType::kQueryNotSupported, "USING clause is not supported"}; + } + return visit(ctx->a_expr()); +} + +std::any Visitor::visitRelation_expr(codegen::PostgreSQLParser::Relation_exprContext *ctx) { + if (ctx->ONLY()) { + throw Error{ErrorType::kQueryNotSupported, "ONLY clause is not supported"}; + } + if (ctx->STAR()) { + throw Error{ErrorType::kQueryNotSupported, "tablename * clause is not supported"}; + } + return visit(ctx->qualified_name()); +} + +std::any Visitor::visitQualified_name(codegen::PostgreSQLParser::Qualified_nameContext *ctx) { + if (ctx->indirection()) { + throw Error{ErrorType::kQueryNotSupported, "bare column names are not supported"}; + } + return ctx->colid()->getText(); +} + +std::any Visitor::visitSimple_select_pramary( + codegen::PostgreSQLParser::Simple_select_pramaryContext *ctx) { + if (ctx->select_with_parens()) { + return visit(ctx->select_with_parens()); + } + if (!ctx->SELECT()) { + throw Error{ErrorType::kQueryNotSupported, "VALUES and TABLE clauses are not supported"}; + } + if (ctx->distinct_clause()) { + // TODO: support distinct clause + throw Error{ErrorType::kQueryNotSupported, "DISTINCT clause is not supported"}; + } + + // NOTE: all_clause_ is ignored + // TODO: support group_clause, having_clause + + Operator result = Table{kEmptyTableName}; + + if (ctx->from_clause()) { + result = std::any_cast(visit(ctx->from_clause())); + } + + if (ctx->where_clause()) { + auto filter = std::any_cast(visit(ctx->where_clause())); + result = GetOperatorWithChild(std::move(filter), std::move(result)); + } + + if (ctx->target_list_()) { + auto target_list_opt = visit(ctx->target_list_()); + if (target_list_opt.has_value()) { + auto projection = std::any_cast(target_list_opt); + result = GetOperatorWithChild(std::move(projection), std::move(result)); + } + } + + return result; +} + +std::any Visitor::visitWhere_clause(codegen::PostgreSQLParser::Where_clauseContext *ctx) { + auto where_expr = std::any_cast(visit(ctx->a_expr())); + return Operator{Filter{where_expr, nullptr}}; +} + +std::any Visitor::visitSelect_clause(codegen::PostgreSQLParser::Select_clauseContext *ctx) { + // TODO: UNION and EXCEPT (with ALL or DISTINCT) + return visit(ctx->simple_select_intersect().front()); +} + +std::any Visitor::visitSelect_with_parens(codegen::PostgreSQLParser::Select_with_parensContext *ctx) { + if (ctx->select_with_parens()) { + return visit(ctx->select_with_parens()); + } + return visit(ctx->select_no_parens()); +} + +std::any Visitor::visitSelect_no_parens(codegen::PostgreSQLParser::Select_no_parensContext *ctx) { + if (ctx->with_clause()) { + // TODO + } + + auto select_clause = std::any_cast(visit(ctx->select_clause())); + + // TODO: remaining clauses + + return select_clause; +} + +std::any Visitor::visitA_expr_qual(codegen::PostgreSQLParser::A_expr_qualContext *ctx) { + if (ctx->qual_op()) { + throw Error{ErrorType::kQueryNotSupported, "qualified operators are not supported"}; + } + return visit(ctx->a_expr_lessless()); +} + +std::any Visitor::visitA_expr_lessless(codegen::PostgreSQLParser::A_expr_lesslessContext *ctx) { + if (ctx->a_expr_or().size() > 1) { + throw Error{ErrorType::kQueryNotSupported, "<< and >> operators are not supported"}; + } + return visit(ctx->a_expr_or(0)); +} + +std::any Visitor::visitA_expr_or(codegen::PostgreSQLParser::A_expr_orContext *ctx) { + const auto& exprs = ctx->a_expr_and(); + auto result = std::any_cast(visit(exprs.front())); + for (size_t i = 1; i < exprs.size(); i++) { + auto tmp = std::any_cast(visit(exprs[i])); + result = BinaryExpression{std::make_shared(std::move(result)), BinaryOp::kOr, + std::make_shared(std::move(tmp))}; + } + return result; +} + +std::any Visitor::visitA_expr_and(codegen::PostgreSQLParser::A_expr_andContext *ctx) { + const auto& exprs = ctx->a_expr_between(); + auto result = std::any_cast(visit(exprs.front())); + for (size_t i = 1; i < exprs.size(); i++) { + auto tmp = std::any_cast(visit(exprs[i])); + result = BinaryExpression{std::make_shared(std::move(result)), BinaryOp::kAnd, + std::make_shared(std::move(tmp))}; + } + return result; +} + +std::any Visitor::visitA_expr_between(codegen::PostgreSQLParser::A_expr_betweenContext *ctx) { + if (ctx->BETWEEN()) { + // NOTE: may want to support + throw Error{ErrorType::kQueryNotSupported, "BETWEEN clause is not supported"}; + } + return visit(ctx->a_expr_in(0)); +} + +std::any Visitor::visitA_expr_in(codegen::PostgreSQLParser::A_expr_inContext *ctx) { + if (ctx->IN_P()) { + // NOTE: may want to support + throw Error{ErrorType::kQueryNotSupported, "IN clause is not supported"}; + } + return visit(ctx->a_expr_unary_not()); +} + +std::any Visitor::visitA_expr_unary_not(codegen::PostgreSQLParser::A_expr_unary_notContext *ctx) { + auto result = std::any_cast(visit(ctx->a_expr_isnull())); + if (ctx->NOT()) { + result = UnaryExpression{UnaryOp::kNot, std::make_shared(std::move(result))}; + } + return result; +} + +std::any Visitor::visitA_expr_isnull(codegen::PostgreSQLParser::A_expr_isnullContext *ctx) { + auto result = std::any_cast(visit(ctx->a_expr_is_not())); + if (ctx->ISNULL()) { + result = BinaryExpression{std::make_shared(std::move(result)), BinaryOp::kEq, std::make_shared(Literal::kNull)}; + } + if (ctx->NOTNULL()) { + result = BinaryExpression{std::make_shared(std::move(result)), BinaryOp::kEq, std::make_shared(Literal::kNull)}; + result = UnaryExpression{UnaryOp::kNot, std::make_shared(std::move(result))}; + } + return result; +} + +std::any Visitor::visitA_expr_is_not(codegen::PostgreSQLParser::A_expr_is_notContext *ctx) { + auto result = std::any_cast(visit(ctx->a_expr_compare())); + if (!ctx->IS()) { + return result; + } + + if (ctx->NULL_P()) { + result = BinaryExpression{std::make_shared(std::move(result)), BinaryOp::kEq, std::make_shared(Literal::kNull)}; + } else if (ctx->TRUE_P()) { + result = BinaryExpression{std::make_shared(std::move(result)), BinaryOp::kEq, std::make_shared(Literal::kTrue)}; + } else if (ctx->FALSE_P()) { + result = BinaryExpression{std::make_shared(std::move(result)), BinaryOp::kEq, std::make_shared(Literal::kFalse)}; + } else if (ctx->UNKNOWN()) { + result = BinaryExpression{std::make_shared(std::move(result)), BinaryOp::kEq, std::make_shared(Literal::kUnknown)}; + } else if (ctx->DISTINCT()) { + throw Error{ErrorType::kQueryNotSupported, "IS DISTINCT FROM clause is not supported"}; + } else if (ctx->OF()) { + throw Error{ErrorType::kQueryNotSupported, "IS OF (type_list) clause is not supported"}; + } else if (ctx->DOCUMENT_P()) { + throw Error{ErrorType::kQueryNotSupported, "IS DOCUMENT clause is not supported"}; + } else if (ctx->NORMALIZED()) { + throw Error{ErrorType::kQueryNotSupported, "IS NORMALIZED clause is not supported"}; + } + + if (ctx->NOT()) { + result = UnaryExpression{UnaryOp::kNot, std::make_shared(std::move(result))}; + } + return result; +} + +std::any Visitor::visitA_expr_like(codegen::PostgreSQLParser::A_expr_likeContext *ctx) { + const auto& exprs = ctx->a_expr_qual_op(); + if (exprs.size() > 1) { + // NOTE: may want to implement + throw Error{ErrorType::kQueryNotSupported, "LIKE clause is not supported"}; + } + return visit(exprs.front()); +} + +std::any Visitor::visitA_expr_qual_op(codegen::PostgreSQLParser::A_expr_qual_opContext *ctx) { + const auto& exprs = ctx->a_expr_unary_qualop(); + if (exprs.size() > 1) { + // NOTE: may want to implement + throw Error{ErrorType::kQueryNotSupported, "qual_op is not supported"}; + } + return visit(exprs.front()); +} + +std::any Visitor::visitA_expr_unary_qualop(codegen::PostgreSQLParser::A_expr_unary_qualopContext *ctx) { + if (ctx->qual_op()) { + // NOTE: may want to implement + throw Error{ErrorType::kQueryNotSupported, "unary_qual_op is not supported"}; + } + return visit(ctx->a_expr_add()); +} + +std::any Visitor::visitA_expr_add(codegen::PostgreSQLParser::A_expr_addContext *ctx) { + const auto& exprs = ctx->a_expr_mul(); + auto result = std::any_cast(visit(exprs.front())); + auto expr_it = exprs.cbegin()+1; + + const auto& children = ctx->children; + auto op_it = children.cbegin()+1; + + while (expr_it != exprs.cend()) { + auto op = (*op_it)->getText(); + auto rhs = std::any_cast(visit(*expr_it)); + if (op == "+") { + result = BinaryExpression{ + std::make_shared(std::move(result)), + BinaryOp::kPlus, + std::make_shared(std::move(rhs)), + }; + } else if (op == "-") { + result = BinaryExpression{ + std::make_shared(std::move(result)), + BinaryOp::kMinus, + std::make_shared(std::move(rhs)), + }; + } + op_it += 2; + expr_it++; + } + return result; +} + +std::any Visitor::visitA_expr_mul(codegen::PostgreSQLParser::A_expr_mulContext *ctx) { + const auto& exprs = ctx->a_expr_caret(); + auto result = std::any_cast(visit(exprs.front())); + auto expr_it = exprs.cbegin()+1; + + const auto& children = ctx->children; + auto op_it = children.cbegin()+1; + + while (expr_it != exprs.cend()) { + auto op = (*op_it)->getText(); + auto rhs = std::any_cast(visit(*expr_it)); + if (op == "*") { + result = BinaryExpression{ + std::make_shared(std::move(result)), + BinaryOp::kMul, + std::make_shared(std::move(rhs)), + }; + } else if (op == "/") { + result = BinaryExpression{ + std::make_shared(std::move(result)), + BinaryOp::kDiv, + std::make_shared(std::move(rhs)), + }; + } else if (op == "%") { + result = BinaryExpression{ + std::make_shared(std::move(result)), + BinaryOp::kMod, + std::make_shared(std::move(rhs)), + }; + } + op_it += 2; + expr_it++; + } + return result; +} + +std::any Visitor::visitA_expr_caret(codegen::PostgreSQLParser::A_expr_caretContext *ctx) { + auto result = std::any_cast(visit(ctx->a_expr_unary_sign(0))); + if (ctx->CARET()) { + auto rhs = std::any_cast(visit(ctx->a_expr_unary_sign(1))); + result = BinaryExpression{ + std::make_shared(std::move(result)), + BinaryOp::kPow, + std::make_shared(std::move(rhs)), + }; + } + return result; +} + +std::any Visitor::visitA_expr_unary_sign(codegen::PostgreSQLParser::A_expr_unary_signContext *ctx) { + auto result = std::any_cast(visit(ctx->a_expr_at_time_zone())); + if (ctx->MINUS()) { + result = UnaryExpression{UnaryOp::kMinus, std::make_shared(std::move(result))}; + } + return result; +} + +std::any Visitor::visitA_expr_at_time_zone(codegen::PostgreSQLParser::A_expr_at_time_zoneContext *ctx) { + if (ctx->AT()) { + throw Error{ErrorType::kQueryNotSupported, "AT TIME ZONE literal is not supported"}; + } + return visit(ctx->a_expr_collate()); +} + +std::any Visitor::visitA_expr_collate(codegen::PostgreSQLParser::A_expr_collateContext *ctx) { + if (ctx->COLLATE()) { + throw Error{ErrorType::kQueryNotSupported, "COLLATE clause is not supported"}; + } + return visit(ctx->a_expr_typecast()); +} + +std::any Visitor::visitA_expr_typecast(codegen::PostgreSQLParser::A_expr_typecastContext *ctx) { + if (!ctx->TYPECAST().empty()) { + // NOTE: may want to support + throw Error{ErrorType::kQueryNotSupported, "TYPECAST clause is not supported"}; + } + return visit(ctx->c_expr()); +} + +std::any Visitor::visitC_expr_exists(codegen::PostgreSQLParser::C_expr_existsContext *ctx) { + // NOTE: may want to support + throw Error{ErrorType::kQueryNotSupported, "EXISTS clause is not supported"}; +} + +std::any Visitor::visitC_expr_expr(codegen::PostgreSQLParser::C_expr_exprContext *ctx) { + if (ctx->columnref()) { + return visit(ctx->columnref()); + } + if (ctx->aexprconst()) { + return visit(ctx->aexprconst()); + } + // NOTE: may want to support + throw Error{ErrorType::kQueryNotSupported, "c_expr is not fully supported"}; +} + +std::any Visitor::visitC_expr_case(codegen::PostgreSQLParser::C_expr_caseContext *ctx) { + // NOTE: may want to support + throw Error{ErrorType::kQueryNotSupported, "CASE clause is not supported"}; +} + +std::any Visitor::visitAexprconst(codegen::PostgreSQLParser::AexprconstContext *ctx) { + if (ctx->constinterval()) { + throw Error{ErrorType::kQueryNotSupported, "intervals are not supported"}; + } + if (ctx->sconst()) { + throw Error{ErrorType::kQueryNotSupported, "strings are not supported"}; + } + if (ctx->xconst()) { + throw Error{ErrorType::kQueryNotSupported, "hex literals are not supported"}; + } + if (ctx->bconst()) { + throw Error{ErrorType::kQueryNotSupported, "binary literals are not supported"}; + } + if (ctx->fconst()) { + throw Error{ErrorType::kQueryNotSupported, "float literals are not supported"}; + } + if (ctx->TRUE_P()) { + return Expression{Literal::kTrue}; + } + if (ctx->FALSE_P()) { + return Expression{Literal::kFalse}; + } + if (ctx->NULL_P()) { + return Expression{Literal::kNull}; + } + if (ctx->iconst()) { + return visit(ctx->iconst()); + } + throw Error{ErrorType::kUnknown, "some literal is not supported"}; +} + +std::any Visitor::visitIconst(codegen::PostgreSQLParser::IconstContext *ctx) { + if (!ctx->Integral()) { + throw Error{ErrorType::kQueryNotSupported, "binary, octal and hexadecimal constants are not supported"}; + } + + std::stringstream ss(ctx->Integral()->getText()); + int64_t value; + + if (ss >> value) { + return Expression{IntConst{value}}; + } else { + throw Error{ErrorType::kConversionError, std::format("integer literal \"{}\" cannot be converted to 64-bit signed integer", ctx->Integral()->getText())}; + } +} + +} // namespace stewkk::sql diff --git a/src/stewkk/sql/logic/parser/visitor.hpp b/src/stewkk/sql/logic/parser/visitor.hpp new file mode 100644 index 0000000..85b5a9b --- /dev/null +++ b/src/stewkk/sql/logic/parser/visitor.hpp @@ -0,0 +1,71 @@ +#pragma once + +#include + +namespace stewkk::sql { + +class Visitor : public codegen::PostgreSQLParserBaseVisitor { + public: + explicit Visitor(codegen::PostgreSQLParser* parser); + virtual std::any visit(antlr4::tree::ParseTree *tree) override; + virtual std::any visitRoot(codegen::PostgreSQLParser::RootContext* ctx) override; + virtual std::any visitStmt(codegen::PostgreSQLParser::StmtContext *ctx) override; + virtual std::any visitStmtmulti(codegen::PostgreSQLParser::StmtmultiContext* ctx) override; + virtual std::any visitSelect_no_parens(codegen::PostgreSQLParser::Select_no_parensContext *ctx) override; + virtual std::any visitA_expr_compare(codegen::PostgreSQLParser::A_expr_compareContext *ctx) override; + virtual std::any visitColumnref(codegen::PostgreSQLParser::ColumnrefContext *ctx) override; + virtual std::any visitSelect_clause(codegen::PostgreSQLParser::Select_clauseContext *ctx) override; + virtual std::any visitSimple_select_intersect(codegen::PostgreSQLParser::Simple_select_intersectContext *ctx) override; + virtual std::any visitSimple_select_pramary(codegen::PostgreSQLParser::Simple_select_pramaryContext *ctx) override; + virtual std::any visitTarget_list(codegen::PostgreSQLParser::Target_listContext *ctx) override; + virtual std::any visitTarget_label(codegen::PostgreSQLParser::Target_labelContext *ctx) override; + virtual std::any visitTarget_star(codegen::PostgreSQLParser::Target_starContext *ctx) override; + virtual std::any visitFrom_clause(codegen::PostgreSQLParser::From_clauseContext *ctx) override; + virtual std::any visitWhere_clause(codegen::PostgreSQLParser::Where_clauseContext *ctx) override; + virtual std::any visitSelect_with_parens(codegen::PostgreSQLParser::Select_with_parensContext *ctx) override; + virtual std::any visitA_expr_qual(codegen::PostgreSQLParser::A_expr_qualContext *ctx) override; + virtual std::any visitA_expr_lessless(codegen::PostgreSQLParser::A_expr_lesslessContext *ctx) override; + virtual std::any visitA_expr_or(codegen::PostgreSQLParser::A_expr_orContext *ctx) override; + virtual std::any visitA_expr_and(codegen::PostgreSQLParser::A_expr_andContext *ctx) override; + virtual std::any visitA_expr_between(codegen::PostgreSQLParser::A_expr_betweenContext *ctx) override; + virtual std::any visitA_expr_in(codegen::PostgreSQLParser::A_expr_inContext *ctx) override; + virtual std::any visitA_expr_unary_not(codegen::PostgreSQLParser::A_expr_unary_notContext *ctx) override; + virtual std::any visitA_expr_isnull( + codegen::PostgreSQLParser::A_expr_isnullContext *ctx) override; + virtual std::any visitA_expr_is_not( + codegen::PostgreSQLParser::A_expr_is_notContext *ctx) override; + virtual std::any visitA_expr_like(codegen::PostgreSQLParser::A_expr_likeContext *ctx) override; + virtual std::any visitA_expr_qual_op( + codegen::PostgreSQLParser::A_expr_qual_opContext *ctx) override; + virtual std::any visitA_expr_unary_qualop( + codegen::PostgreSQLParser::A_expr_unary_qualopContext *ctx) override; + virtual std::any visitA_expr_add(codegen::PostgreSQLParser::A_expr_addContext *ctx) override; + virtual std::any visitA_expr_mul(codegen::PostgreSQLParser::A_expr_mulContext *ctx) override; + virtual std::any visitA_expr_caret( + codegen::PostgreSQLParser::A_expr_caretContext *ctx) override; + virtual std::any visitA_expr_unary_sign( + codegen::PostgreSQLParser::A_expr_unary_signContext *ctx) override; + virtual std::any visitA_expr_at_time_zone( + codegen::PostgreSQLParser::A_expr_at_time_zoneContext *ctx) override; + virtual std::any visitA_expr_collate( + codegen::PostgreSQLParser::A_expr_collateContext *ctx) override; + virtual std::any visitA_expr_typecast( + codegen::PostgreSQLParser::A_expr_typecastContext *ctx) override; + virtual std::any visitC_expr_exists(codegen::PostgreSQLParser::C_expr_existsContext *ctx) override; + virtual std::any visitC_expr_expr(codegen::PostgreSQLParser::C_expr_exprContext *ctx) override; + virtual std::any visitC_expr_case(codegen::PostgreSQLParser::C_expr_caseContext *ctx) override; + virtual std::any visitAexprconst(codegen::PostgreSQLParser::AexprconstContext *ctx) override; + virtual std::any visitIconst(codegen::PostgreSQLParser::IconstContext *ctx) override; + virtual std::any visitFrom_list(codegen::PostgreSQLParser::From_listContext *ctx) override; + virtual std::any visitTable_ref(codegen::PostgreSQLParser::Table_refContext *ctx) override; + virtual std::any visitRelation_expr(codegen::PostgreSQLParser::Relation_exprContext *ctx) override; + virtual std::any visitQualified_name(codegen::PostgreSQLParser::Qualified_nameContext *ctx) override; + virtual std::any visitJoin_type(codegen::PostgreSQLParser::Join_typeContext *ctx) override; + virtual std::any visitJoin_qual(codegen::PostgreSQLParser::Join_qualContext *ctx) override; + + private: + codegen::PostgreSQLParser* parser_; +}; + + +} // namespace stewkk::sql diff --git a/src/stewkk/sql/logic/result/error.cpp b/src/stewkk/sql/logic/result/error.cpp new file mode 100644 index 0000000..d4002d7 --- /dev/null +++ b/src/stewkk/sql/logic/result/error.cpp @@ -0,0 +1,36 @@ +#include + +#include +#include + +namespace stewkk::sql { + +namespace { +const static std::string kWhat = "no data"; +} + +Error::Error(ErrorType type, std::string message) + : wrapped_({ErrorData{std::move(type), std::move(message)}}) {} + +std::string Error::What() const { + std::ostringstream res; + res << wrapped_.back().message; + auto view_without_first = wrapped_ | std::views::reverse | std::views::drop(1); + for (const auto& el : view_without_first) { + res << ": " << el.message; + } + return res.str(); +} + +Error& Error::Wrap(ErrorType type, std::string message) { + wrapped_.emplace_back(std::move(type), std::move(message)); + return *this; +} + +bool Error::Wraps(ErrorType type) const { + return std::ranges::find(wrapped_, type, &ErrorData::type) != wrapped_.end(); +} + +const char* Error::what() const noexcept { return kWhat.c_str(); } + +} // namespace stewkk::sql diff --git a/src/stewkk/sql/logic/result/result.cpp b/src/stewkk/sql/logic/result/result.cpp new file mode 100644 index 0000000..af48f32 --- /dev/null +++ b/src/stewkk/sql/logic/result/result.cpp @@ -0,0 +1,7 @@ +#include + +namespace stewkk::sql { + +std::string What(const Error& error) { return error.What(); } + +} // namespace stewkk::sql diff --git a/src/stewkk/sql/main.cpp b/src/stewkk/sql/main.cpp new file mode 100644 index 0000000..4d3a5ae --- /dev/null +++ b/src/stewkk/sql/main.cpp @@ -0,0 +1,7 @@ +#include + +int main() { + std::cout << "Hello\n"; + + return 0; +} diff --git a/src/stewkk/sql/models/executor/tuple.cpp b/src/stewkk/sql/models/executor/tuple.cpp new file mode 100644 index 0000000..463cbb3 --- /dev/null +++ b/src/stewkk/sql/models/executor/tuple.cpp @@ -0,0 +1,51 @@ +#include + +#include +#include + +namespace stewkk::sql { + +std::string ToString(Type type) { + switch (type) { + case Type::kInt: + return "int"; + case Type::kBool: + return "bool"; + } + std::unreachable(); +} + +std::string ToString(bool v) { + if (v) { + return "TRUE "; + } + return "FALSE "; +} + +std::string ToString(Value v, const AttributeInfo& attr) { + if (v.is_null) { + return "NULL "; + } + if (attr.type == Type::kInt) { + return std::format("{:<8}", v.value.int_value); + } + return ToString(v.value.bool_value)+' '; +} + +std::string ToString(const Relation& relation) { + std::ostringstream s; + for (const auto& tuple : relation.tuples) { + for (const auto& [val, attr] : std::views::zip(tuple, relation.attributes)) { + s << ToString(val, attr); + } + s << '\n'; + } + + return s.str(); +} + +bool Value::operator==(const Value& other) const { + return (is_null && other.is_null) || (!is_null && !other.is_null && value.int_value == other.value.int_value); +} + +} // namespace stewkk::sql diff --git a/src/stewkk/sql/models/parser/relational_algebra_ast.cpp b/src/stewkk/sql/models/parser/relational_algebra_ast.cpp new file mode 100644 index 0000000..1518f35 --- /dev/null +++ b/src/stewkk/sql/models/parser/relational_algebra_ast.cpp @@ -0,0 +1,122 @@ +#include + +namespace stewkk::sql { + +bool Projection::operator==(const Projection& other) const { + return expressions == other.expressions && *source == *other.source; +} + +bool Filter::operator==(const Filter& other) const { + return expr == other.expr && *source == *other.source; +} + +bool BinaryExpression::operator==(const BinaryExpression& other) const { + return *lhs == *other.lhs && binop == other.binop && *rhs == *other.rhs; +} + +bool UnaryExpression::operator==(const UnaryExpression& other) const { + return op == other.op && *child == *other.child; +} + +bool CrossJoin::operator==(const CrossJoin& other) const { + return *lhs == *other.lhs && *rhs == *other.rhs; +} + +bool Join::operator==(const Join& other) const { + return type == other.type && qual == other.qual && *lhs == *other.lhs && *rhs == *other.rhs; +} + +std::string ToString(BinaryOp binop) { + switch (binop) { + case BinaryOp::kGt: + return ">"; + case BinaryOp::kOr: + return "or"; + case BinaryOp::kAnd: + return "and"; + case BinaryOp::kEq: + return "="; + case BinaryOp::kPlus: + return "+"; + case BinaryOp::kMinus: + return "-"; + case BinaryOp::kMul: + return "*"; + case BinaryOp::kDiv: + return "/"; + case BinaryOp::kMod: + return "%"; + case BinaryOp::kPow: + return "^"; + case BinaryOp::kLt: + return "<"; + case BinaryOp::kLe: + return "<="; + case BinaryOp::kGe: + return ">="; + case BinaryOp::kNotEq: + return "!="; + } +} + +std::string ToString(const Attribute& attr) { + return std::format("{}.{}", attr.table, attr.name); +} + +std::string ToString(UnaryOp op) { + switch (op) { + case UnaryOp::kNot: + return "not"; + case UnaryOp::kMinus: + return "-"; + } +} + +std::string ToString(Literal literal) { + switch (literal) { + case Literal::kNull: + return "NULL"; + case Literal::kTrue: + return "TRUE"; + case Literal::kFalse: + return "FALSE"; + case Literal::kUnknown: + return "UNKNOWN"; + } +} + +std::string ToString(const Expression& expr) { + struct Formatter { + std::string operator()(const BinaryExpression& expr) { + return std::format("{} {} {}", ToString(*expr.lhs), ToString(expr.binop), ToString(*expr.rhs)); + } + std::string operator()(const Attribute& expr) { + return ToString(expr); + } + std::string operator()(const IntConst& expr) { + return std::to_string(expr); + } + std::string operator()(const UnaryExpression& expr) { + return std::format("{} {}", ToString(expr.op), ToString(*expr.child)); + } + std::string operator()(const Literal& expr) { + return ToString(expr); + } + }; + return std::visit(Formatter{}, expr); +} + +std::string ToString(JoinType type) { + switch (type) { + case JoinType::kInner: + return "⋈"; + case JoinType::kFull: + return "⟗"; + case JoinType::kLeft: + return "⟕"; + case JoinType::kRight: + return "⟖"; + } +} + +} // namespace stewkk::sql diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..65187f8 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,31 @@ +include(FetchGTest) +include(GoogleTest) + +add_executable(unittests) +target_sources(unittests PRIVATE + ${PROJECT_SOURCE_DIR}/src/stewkk/sql/logic/parser/parser_test.cpp + ${PROJECT_SOURCE_DIR}/src/stewkk/sql/logic/executor/executor_test.cpp +) +target_compile_features(unittests PRIVATE cxx_std_23) +set_target_properties(unittests PROPERTIES + CXX_STANDART 23 + CXX_STANDART_REQUIRED YES + CXX_EXTENSIONS YES +) +target_include_directories( + unittests PUBLIC $ + $ + ${ANTLR4_INCLUDE_DIRS} + ${LLVM_INCLUDE_DIRS} +) +target_compile_options(unittests PRIVATE ${BASE_COMPILE_FLAGS}) +target_link_options(unittests PRIVATE ${BASE_COMPILE_FLAGS}) +llvm_map_components_to_libnames(llvm_libs Support Core IRReader OrcJIT X86CodeGen X86AsmParser X86Desc X86Info) +target_link_directories(libsql PUBLIC ${LLVM_LIBRARY_DIRS}) +target_link_libraries(unittests PRIVATE gmock_main libsql antlr4_static + Boost::asio + Boost::thread + Boost::filesystem + ${llvm_libs} +) +gtest_discover_tests(unittests) diff --git a/test/static/executor/README.md b/test/static/executor/README.md new file mode 100644 index 0000000..6c71820 --- /dev/null +++ b/test/static/executor/README.md @@ -0,0 +1,29 @@ +# Test script + +``` sql +CREATE TABLE departments (id INT); +CREATE TABLE employees (id INT, department_id INT); + +INSERT INTO departments (id) VALUES +(1), +(2), +(3), +(4), +(5); + +INSERT INTO employees (id, department_id) VALUES +(1,3), +(2,6), +(3,12), +(4,11), +(5,1), +(6,5), +(33,31), +(66,32), +(67,33), +(68,34), +(69,35); + +SELECT departments.id*2, employees.id+1 FROM employees RIGHT JOIN departments ON employees.department_id = departments.id AND departments.id > 3 AND departments.id*2*2/2 < 30; +``` + diff --git a/test/static/executor/expected_complex_join.txt b/test/static/executor/expected_complex_join.txt new file mode 100644 index 0000000..58b4105 --- /dev/null +++ b/test/static/executor/expected_complex_join.txt @@ -0,0 +1,5 @@ +10 7 +2 NULL +4 NULL +6 NULL +8 NULL diff --git a/test/static/executor/expected_inner_join.txt b/test/static/executor/expected_inner_join.txt new file mode 100644 index 0000000..21fe6a9 --- /dev/null +++ b/test/static/executor/expected_inner_join.txt @@ -0,0 +1,3 @@ +1 3 3 +5 1 1 +6 5 5 diff --git a/test/static/executor/expected_left_join.txt b/test/static/executor/expected_left_join.txt new file mode 100644 index 0000000..a4a1e6d --- /dev/null +++ b/test/static/executor/expected_left_join.txt @@ -0,0 +1,11 @@ +1 5 1 +3 1 3 +5 6 5 +NULL 2 6 +NULL 3 12 +NULL 4 11 +NULL 33 31 +NULL 66 32 +NULL 67 33 +NULL 68 34 +NULL 69 35 diff --git a/test/static/executor/expected_right_join.txt b/test/static/executor/expected_right_join.txt new file mode 100644 index 0000000..380ede1 --- /dev/null +++ b/test/static/executor/expected_right_join.txt @@ -0,0 +1,5 @@ +1 3 3 +5 1 1 +6 5 5 +NULL NULL 2 +NULL NULL 4 diff --git a/test/static/executor/test_data/books.csv b/test/static/executor/test_data/books.csv new file mode 100644 index 0000000..244d833 --- /dev/null +++ b/test/static/executor/test_data/books.csv @@ -0,0 +1,4 @@ +id:int,price:int +1,55 +2,66 +3,77 diff --git a/test/static/executor/test_data/departments.csv b/test/static/executor/test_data/departments.csv new file mode 100644 index 0000000..49afd56 --- /dev/null +++ b/test/static/executor/test_data/departments.csv @@ -0,0 +1,6 @@ +id:int +1 +2 +3 +4 +5 diff --git a/test/static/executor/test_data/departments_1000.csv b/test/static/executor/test_data/departments_1000.csv new file mode 100644 index 0000000..14dcc8c --- /dev/null +++ b/test/static/executor/test_data/departments_1000.csv @@ -0,0 +1,1001 @@ +id:int +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 +432 +433 +434 +435 +436 +437 +438 +439 +440 +441 +442 +443 +444 +445 +446 +447 +448 +449 +450 +451 +452 +453 +454 +455 +456 +457 +458 +459 +460 +461 +462 +463 +464 +465 +466 +467 +468 +469 +470 +471 +472 +473 +474 +475 +476 +477 +478 +479 +480 +481 +482 +483 +484 +485 +486 +487 +488 +489 +490 +491 +492 +493 +494 +495 +496 +497 +498 +499 +500 +501 +502 +503 +504 +505 +506 +507 +508 +509 +510 +511 +512 +513 +514 +515 +516 +517 +518 +519 +520 +521 +522 +523 +524 +525 +526 +527 +528 +529 +530 +531 +532 +533 +534 +535 +536 +537 +538 +539 +540 +541 +542 +543 +544 +545 +546 +547 +548 +549 +550 +551 +552 +553 +554 +555 +556 +557 +558 +559 +560 +561 +562 +563 +564 +565 +566 +567 +568 +569 +570 +571 +572 +573 +574 +575 +576 +577 +578 +579 +580 +581 +582 +583 +584 +585 +586 +587 +588 +589 +590 +591 +592 +593 +594 +595 +596 +597 +598 +599 +600 +601 +602 +603 +604 +605 +606 +607 +608 +609 +610 +611 +612 +613 +614 +615 +616 +617 +618 +619 +620 +621 +622 +623 +624 +625 +626 +627 +628 +629 +630 +631 +632 +633 +634 +635 +636 +637 +638 +639 +640 +641 +642 +643 +644 +645 +646 +647 +648 +649 +650 +651 +652 +653 +654 +655 +656 +657 +658 +659 +660 +661 +662 +663 +664 +665 +666 +667 +668 +669 +670 +671 +672 +673 +674 +675 +676 +677 +678 +679 +680 +681 +682 +683 +684 +685 +686 +687 +688 +689 +690 +691 +692 +693 +694 +695 +696 +697 +698 +699 +700 +701 +702 +703 +704 +705 +706 +707 +708 +709 +710 +711 +712 +713 +714 +715 +716 +717 +718 +719 +720 +721 +722 +723 +724 +725 +726 +727 +728 +729 +730 +731 +732 +733 +734 +735 +736 +737 +738 +739 +740 +741 +742 +743 +744 +745 +746 +747 +748 +749 +750 +751 +752 +753 +754 +755 +756 +757 +758 +759 +760 +761 +762 +763 +764 +765 +766 +767 +768 +769 +770 +771 +772 +773 +774 +775 +776 +777 +778 +779 +780 +781 +782 +783 +784 +785 +786 +787 +788 +789 +790 +791 +792 +793 +794 +795 +796 +797 +798 +799 +800 +801 +802 +803 +804 +805 +806 +807 +808 +809 +810 +811 +812 +813 +814 +815 +816 +817 +818 +819 +820 +821 +822 +823 +824 +825 +826 +827 +828 +829 +830 +831 +832 +833 +834 +835 +836 +837 +838 +839 +840 +841 +842 +843 +844 +845 +846 +847 +848 +849 +850 +851 +852 +853 +854 +855 +856 +857 +858 +859 +860 +861 +862 +863 +864 +865 +866 +867 +868 +869 +870 +871 +872 +873 +874 +875 +876 +877 +878 +879 +880 +881 +882 +883 +884 +885 +886 +887 +888 +889 +890 +891 +892 +893 +894 +895 +896 +897 +898 +899 +900 +901 +902 +903 +904 +905 +906 +907 +908 +909 +910 +911 +912 +913 +914 +915 +916 +917 +918 +919 +920 +921 +922 +923 +924 +925 +926 +927 +928 +929 +930 +931 +932 +933 +934 +935 +936 +937 +938 +939 +940 +941 +942 +943 +944 +945 +946 +947 +948 +949 +950 +951 +952 +953 +954 +955 +956 +957 +958 +959 +960 +961 +962 +963 +964 +965 +966 +967 +968 +969 +970 +971 +972 +973 +974 +975 +976 +977 +978 +979 +980 +981 +982 +983 +984 +985 +986 +987 +988 +989 +990 +991 +992 +993 +994 +995 +996 +997 +998 +999 +1000 diff --git a/test/static/executor/test_data/departments_16000.csv b/test/static/executor/test_data/departments_16000.csv new file mode 100644 index 0000000..1b181a1 --- /dev/null +++ b/test/static/executor/test_data/departments_16000.csv @@ -0,0 +1,16001 @@ +id:int +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 +432 +433 +434 +435 +436 +437 +438 +439 +440 +441 +442 +443 +444 +445 +446 +447 +448 +449 +450 +451 +452 +453 +454 +455 +456 +457 +458 +459 +460 +461 +462 +463 +464 +465 +466 +467 +468 +469 +470 +471 +472 +473 +474 +475 +476 +477 +478 +479 +480 +481 +482 +483 +484 +485 +486 +487 +488 +489 +490 +491 +492 +493 +494 +495 +496 +497 +498 +499 +500 +501 +502 +503 +504 +505 +506 +507 +508 +509 +510 +511 +512 +513 +514 +515 +516 +517 +518 +519 +520 +521 +522 +523 +524 +525 +526 +527 +528 +529 +530 +531 +532 +533 +534 +535 +536 +537 +538 +539 +540 +541 +542 +543 +544 +545 +546 +547 +548 +549 +550 +551 +552 +553 +554 +555 +556 +557 +558 +559 +560 +561 +562 +563 +564 +565 +566 +567 +568 +569 +570 +571 +572 +573 +574 +575 +576 +577 +578 +579 +580 +581 +582 +583 +584 +585 +586 +587 +588 +589 +590 +591 +592 +593 +594 +595 +596 +597 +598 +599 +600 +601 +602 +603 +604 +605 +606 +607 +608 +609 +610 +611 +612 +613 +614 +615 +616 +617 +618 +619 +620 +621 +622 +623 +624 +625 +626 +627 +628 +629 +630 +631 +632 +633 +634 +635 +636 +637 +638 +639 +640 +641 +642 +643 +644 +645 +646 +647 +648 +649 +650 +651 +652 +653 +654 +655 +656 +657 +658 +659 +660 +661 +662 +663 +664 +665 +666 +667 +668 +669 +670 +671 +672 +673 +674 +675 +676 +677 +678 +679 +680 +681 +682 +683 +684 +685 +686 +687 +688 +689 +690 +691 +692 +693 +694 +695 +696 +697 +698 +699 +700 +701 +702 +703 +704 +705 +706 +707 +708 +709 +710 +711 +712 +713 +714 +715 +716 +717 +718 +719 +720 +721 +722 +723 +724 +725 +726 +727 +728 +729 +730 +731 +732 +733 +734 +735 +736 +737 +738 +739 +740 +741 +742 +743 +744 +745 +746 +747 +748 +749 +750 +751 +752 +753 +754 +755 +756 +757 +758 +759 +760 +761 +762 +763 +764 +765 +766 +767 +768 +769 +770 +771 +772 +773 +774 +775 +776 +777 +778 +779 +780 +781 +782 +783 +784 +785 +786 +787 +788 +789 +790 +791 +792 +793 +794 +795 +796 +797 +798 +799 +800 +801 +802 +803 +804 +805 +806 +807 +808 +809 +810 +811 +812 +813 +814 +815 +816 +817 +818 +819 +820 +821 +822 +823 +824 +825 +826 +827 +828 +829 +830 +831 +832 +833 +834 +835 +836 +837 +838 +839 +840 +841 +842 +843 +844 +845 +846 +847 +848 +849 +850 +851 +852 +853 +854 +855 +856 +857 +858 +859 +860 +861 +862 +863 +864 +865 +866 +867 +868 +869 +870 +871 +872 +873 +874 +875 +876 +877 +878 +879 +880 +881 +882 +883 +884 +885 +886 +887 +888 +889 +890 +891 +892 +893 +894 +895 +896 +897 +898 +899 +900 +901 +902 +903 +904 +905 +906 +907 +908 +909 +910 +911 +912 +913 +914 +915 +916 +917 +918 +919 +920 +921 +922 +923 +924 +925 +926 +927 +928 +929 +930 +931 +932 +933 +934 +935 +936 +937 +938 +939 +940 +941 +942 +943 +944 +945 +946 +947 +948 +949 +950 +951 +952 +953 +954 +955 +956 +957 +958 +959 +960 +961 +962 +963 +964 +965 +966 +967 +968 +969 +970 +971 +972 +973 +974 +975 +976 +977 +978 +979 +980 +981 +982 +983 +984 +985 +986 +987 +988 +989 +990 +991 +992 +993 +994 +995 +996 +997 +998 +999 +1000 +1001 +1002 +1003 +1004 +1005 +1006 +1007 +1008 +1009 +1010 +1011 +1012 +1013 +1014 +1015 +1016 +1017 +1018 +1019 +1020 +1021 +1022 +1023 +1024 +1025 +1026 +1027 +1028 +1029 +1030 +1031 +1032 +1033 +1034 +1035 +1036 +1037 +1038 +1039 +1040 +1041 +1042 +1043 +1044 +1045 +1046 +1047 +1048 +1049 +1050 +1051 +1052 +1053 +1054 +1055 +1056 +1057 +1058 +1059 +1060 +1061 +1062 +1063 +1064 +1065 +1066 +1067 +1068 +1069 +1070 +1071 +1072 +1073 +1074 +1075 +1076 +1077 +1078 +1079 +1080 +1081 +1082 +1083 +1084 +1085 +1086 +1087 +1088 +1089 +1090 +1091 +1092 +1093 +1094 +1095 +1096 +1097 +1098 +1099 +1100 +1101 +1102 +1103 +1104 +1105 +1106 +1107 +1108 +1109 +1110 +1111 +1112 +1113 +1114 +1115 +1116 +1117 +1118 +1119 +1120 +1121 +1122 +1123 +1124 +1125 +1126 +1127 +1128 +1129 +1130 +1131 +1132 +1133 +1134 +1135 +1136 +1137 +1138 +1139 +1140 +1141 +1142 +1143 +1144 +1145 +1146 +1147 +1148 +1149 +1150 +1151 +1152 +1153 +1154 +1155 +1156 +1157 +1158 +1159 +1160 +1161 +1162 +1163 +1164 +1165 +1166 +1167 +1168 +1169 +1170 +1171 +1172 +1173 +1174 +1175 +1176 +1177 +1178 +1179 +1180 +1181 +1182 +1183 +1184 +1185 +1186 +1187 +1188 +1189 +1190 +1191 +1192 +1193 +1194 +1195 +1196 +1197 +1198 +1199 +1200 +1201 +1202 +1203 +1204 +1205 +1206 +1207 +1208 +1209 +1210 +1211 +1212 +1213 +1214 +1215 +1216 +1217 +1218 +1219 +1220 +1221 +1222 +1223 +1224 +1225 +1226 +1227 +1228 +1229 +1230 +1231 +1232 +1233 +1234 +1235 +1236 +1237 +1238 +1239 +1240 +1241 +1242 +1243 +1244 +1245 +1246 +1247 +1248 +1249 +1250 +1251 +1252 +1253 +1254 +1255 +1256 +1257 +1258 +1259 +1260 +1261 +1262 +1263 +1264 +1265 +1266 +1267 +1268 +1269 +1270 +1271 +1272 +1273 +1274 +1275 +1276 +1277 +1278 +1279 +1280 +1281 +1282 +1283 +1284 +1285 +1286 +1287 +1288 +1289 +1290 +1291 +1292 +1293 +1294 +1295 +1296 +1297 +1298 +1299 +1300 +1301 +1302 +1303 +1304 +1305 +1306 +1307 +1308 +1309 +1310 +1311 +1312 +1313 +1314 +1315 +1316 +1317 +1318 +1319 +1320 +1321 +1322 +1323 +1324 +1325 +1326 +1327 +1328 +1329 +1330 +1331 +1332 +1333 +1334 +1335 +1336 +1337 +1338 +1339 +1340 +1341 +1342 +1343 +1344 +1345 +1346 +1347 +1348 +1349 +1350 +1351 +1352 +1353 +1354 +1355 +1356 +1357 +1358 +1359 +1360 +1361 +1362 +1363 +1364 +1365 +1366 +1367 +1368 +1369 +1370 +1371 +1372 +1373 +1374 +1375 +1376 +1377 +1378 +1379 +1380 +1381 +1382 +1383 +1384 +1385 +1386 +1387 +1388 +1389 +1390 +1391 +1392 +1393 +1394 +1395 +1396 +1397 +1398 +1399 +1400 +1401 +1402 +1403 +1404 +1405 +1406 +1407 +1408 +1409 +1410 +1411 +1412 +1413 +1414 +1415 +1416 +1417 +1418 +1419 +1420 +1421 +1422 +1423 +1424 +1425 +1426 +1427 +1428 +1429 +1430 +1431 +1432 +1433 +1434 +1435 +1436 +1437 +1438 +1439 +1440 +1441 +1442 +1443 +1444 +1445 +1446 +1447 +1448 +1449 +1450 +1451 +1452 +1453 +1454 +1455 +1456 +1457 +1458 +1459 +1460 +1461 +1462 +1463 +1464 +1465 +1466 +1467 +1468 +1469 +1470 +1471 +1472 +1473 +1474 +1475 +1476 +1477 +1478 +1479 +1480 +1481 +1482 +1483 +1484 +1485 +1486 +1487 +1488 +1489 +1490 +1491 +1492 +1493 +1494 +1495 +1496 +1497 +1498 +1499 +1500 +1501 +1502 +1503 +1504 +1505 +1506 +1507 +1508 +1509 +1510 +1511 +1512 +1513 +1514 +1515 +1516 +1517 +1518 +1519 +1520 +1521 +1522 +1523 +1524 +1525 +1526 +1527 +1528 +1529 +1530 +1531 +1532 +1533 +1534 +1535 +1536 +1537 +1538 +1539 +1540 +1541 +1542 +1543 +1544 +1545 +1546 +1547 +1548 +1549 +1550 +1551 +1552 +1553 +1554 +1555 +1556 +1557 +1558 +1559 +1560 +1561 +1562 +1563 +1564 +1565 +1566 +1567 +1568 +1569 +1570 +1571 +1572 +1573 +1574 +1575 +1576 +1577 +1578 +1579 +1580 +1581 +1582 +1583 +1584 +1585 +1586 +1587 +1588 +1589 +1590 +1591 +1592 +1593 +1594 +1595 +1596 +1597 +1598 +1599 +1600 +1601 +1602 +1603 +1604 +1605 +1606 +1607 +1608 +1609 +1610 +1611 +1612 +1613 +1614 +1615 +1616 +1617 +1618 +1619 +1620 +1621 +1622 +1623 +1624 +1625 +1626 +1627 +1628 +1629 +1630 +1631 +1632 +1633 +1634 +1635 +1636 +1637 +1638 +1639 +1640 +1641 +1642 +1643 +1644 +1645 +1646 +1647 +1648 +1649 +1650 +1651 +1652 +1653 +1654 +1655 +1656 +1657 +1658 +1659 +1660 +1661 +1662 +1663 +1664 +1665 +1666 +1667 +1668 +1669 +1670 +1671 +1672 +1673 +1674 +1675 +1676 +1677 +1678 +1679 +1680 +1681 +1682 +1683 +1684 +1685 +1686 +1687 +1688 +1689 +1690 +1691 +1692 +1693 +1694 +1695 +1696 +1697 +1698 +1699 +1700 +1701 +1702 +1703 +1704 +1705 +1706 +1707 +1708 +1709 +1710 +1711 +1712 +1713 +1714 +1715 +1716 +1717 +1718 +1719 +1720 +1721 +1722 +1723 +1724 +1725 +1726 +1727 +1728 +1729 +1730 +1731 +1732 +1733 +1734 +1735 +1736 +1737 +1738 +1739 +1740 +1741 +1742 +1743 +1744 +1745 +1746 +1747 +1748 +1749 +1750 +1751 +1752 +1753 +1754 +1755 +1756 +1757 +1758 +1759 +1760 +1761 +1762 +1763 +1764 +1765 +1766 +1767 +1768 +1769 +1770 +1771 +1772 +1773 +1774 +1775 +1776 +1777 +1778 +1779 +1780 +1781 +1782 +1783 +1784 +1785 +1786 +1787 +1788 +1789 +1790 +1791 +1792 +1793 +1794 +1795 +1796 +1797 +1798 +1799 +1800 +1801 +1802 +1803 +1804 +1805 +1806 +1807 +1808 +1809 +1810 +1811 +1812 +1813 +1814 +1815 +1816 +1817 +1818 +1819 +1820 +1821 +1822 +1823 +1824 +1825 +1826 +1827 +1828 +1829 +1830 +1831 +1832 +1833 +1834 +1835 +1836 +1837 +1838 +1839 +1840 +1841 +1842 +1843 +1844 +1845 +1846 +1847 +1848 +1849 +1850 +1851 +1852 +1853 +1854 +1855 +1856 +1857 +1858 +1859 +1860 +1861 +1862 +1863 +1864 +1865 +1866 +1867 +1868 +1869 +1870 +1871 +1872 +1873 +1874 +1875 +1876 +1877 +1878 +1879 +1880 +1881 +1882 +1883 +1884 +1885 +1886 +1887 +1888 +1889 +1890 +1891 +1892 +1893 +1894 +1895 +1896 +1897 +1898 +1899 +1900 +1901 +1902 +1903 +1904 +1905 +1906 +1907 +1908 +1909 +1910 +1911 +1912 +1913 +1914 +1915 +1916 +1917 +1918 +1919 +1920 +1921 +1922 +1923 +1924 +1925 +1926 +1927 +1928 +1929 +1930 +1931 +1932 +1933 +1934 +1935 +1936 +1937 +1938 +1939 +1940 +1941 +1942 +1943 +1944 +1945 +1946 +1947 +1948 +1949 +1950 +1951 +1952 +1953 +1954 +1955 +1956 +1957 +1958 +1959 +1960 +1961 +1962 +1963 +1964 +1965 +1966 +1967 +1968 +1969 +1970 +1971 +1972 +1973 +1974 +1975 +1976 +1977 +1978 +1979 +1980 +1981 +1982 +1983 +1984 +1985 +1986 +1987 +1988 +1989 +1990 +1991 +1992 +1993 +1994 +1995 +1996 +1997 +1998 +1999 +2000 +2001 +2002 +2003 +2004 +2005 +2006 +2007 +2008 +2009 +2010 +2011 +2012 +2013 +2014 +2015 +2016 +2017 +2018 +2019 +2020 +2021 +2022 +2023 +2024 +2025 +2026 +2027 +2028 +2029 +2030 +2031 +2032 +2033 +2034 +2035 +2036 +2037 +2038 +2039 +2040 +2041 +2042 +2043 +2044 +2045 +2046 +2047 +2048 +2049 +2050 +2051 +2052 +2053 +2054 +2055 +2056 +2057 +2058 +2059 +2060 +2061 +2062 +2063 +2064 +2065 +2066 +2067 +2068 +2069 +2070 +2071 +2072 +2073 +2074 +2075 +2076 +2077 +2078 +2079 +2080 +2081 +2082 +2083 +2084 +2085 +2086 +2087 +2088 +2089 +2090 +2091 +2092 +2093 +2094 +2095 +2096 +2097 +2098 +2099 +2100 +2101 +2102 +2103 +2104 +2105 +2106 +2107 +2108 +2109 +2110 +2111 +2112 +2113 +2114 +2115 +2116 +2117 +2118 +2119 +2120 +2121 +2122 +2123 +2124 +2125 +2126 +2127 +2128 +2129 +2130 +2131 +2132 +2133 +2134 +2135 +2136 +2137 +2138 +2139 +2140 +2141 +2142 +2143 +2144 +2145 +2146 +2147 +2148 +2149 +2150 +2151 +2152 +2153 +2154 +2155 +2156 +2157 +2158 +2159 +2160 +2161 +2162 +2163 +2164 +2165 +2166 +2167 +2168 +2169 +2170 +2171 +2172 +2173 +2174 +2175 +2176 +2177 +2178 +2179 +2180 +2181 +2182 +2183 +2184 +2185 +2186 +2187 +2188 +2189 +2190 +2191 +2192 +2193 +2194 +2195 +2196 +2197 +2198 +2199 +2200 +2201 +2202 +2203 +2204 +2205 +2206 +2207 +2208 +2209 +2210 +2211 +2212 +2213 +2214 +2215 +2216 +2217 +2218 +2219 +2220 +2221 +2222 +2223 +2224 +2225 +2226 +2227 +2228 +2229 +2230 +2231 +2232 +2233 +2234 +2235 +2236 +2237 +2238 +2239 +2240 +2241 +2242 +2243 +2244 +2245 +2246 +2247 +2248 +2249 +2250 +2251 +2252 +2253 +2254 +2255 +2256 +2257 +2258 +2259 +2260 +2261 +2262 +2263 +2264 +2265 +2266 +2267 +2268 +2269 +2270 +2271 +2272 +2273 +2274 +2275 +2276 +2277 +2278 +2279 +2280 +2281 +2282 +2283 +2284 +2285 +2286 +2287 +2288 +2289 +2290 +2291 +2292 +2293 +2294 +2295 +2296 +2297 +2298 +2299 +2300 +2301 +2302 +2303 +2304 +2305 +2306 +2307 +2308 +2309 +2310 +2311 +2312 +2313 +2314 +2315 +2316 +2317 +2318 +2319 +2320 +2321 +2322 +2323 +2324 +2325 +2326 +2327 +2328 +2329 +2330 +2331 +2332 +2333 +2334 +2335 +2336 +2337 +2338 +2339 +2340 +2341 +2342 +2343 +2344 +2345 +2346 +2347 +2348 +2349 +2350 +2351 +2352 +2353 +2354 +2355 +2356 +2357 +2358 +2359 +2360 +2361 +2362 +2363 +2364 +2365 +2366 +2367 +2368 +2369 +2370 +2371 +2372 +2373 +2374 +2375 +2376 +2377 +2378 +2379 +2380 +2381 +2382 +2383 +2384 +2385 +2386 +2387 +2388 +2389 +2390 +2391 +2392 +2393 +2394 +2395 +2396 +2397 +2398 +2399 +2400 +2401 +2402 +2403 +2404 +2405 +2406 +2407 +2408 +2409 +2410 +2411 +2412 +2413 +2414 +2415 +2416 +2417 +2418 +2419 +2420 +2421 +2422 +2423 +2424 +2425 +2426 +2427 +2428 +2429 +2430 +2431 +2432 +2433 +2434 +2435 +2436 +2437 +2438 +2439 +2440 +2441 +2442 +2443 +2444 +2445 +2446 +2447 +2448 +2449 +2450 +2451 +2452 +2453 +2454 +2455 +2456 +2457 +2458 +2459 +2460 +2461 +2462 +2463 +2464 +2465 +2466 +2467 +2468 +2469 +2470 +2471 +2472 +2473 +2474 +2475 +2476 +2477 +2478 +2479 +2480 +2481 +2482 +2483 +2484 +2485 +2486 +2487 +2488 +2489 +2490 +2491 +2492 +2493 +2494 +2495 +2496 +2497 +2498 +2499 +2500 +2501 +2502 +2503 +2504 +2505 +2506 +2507 +2508 +2509 +2510 +2511 +2512 +2513 +2514 +2515 +2516 +2517 +2518 +2519 +2520 +2521 +2522 +2523 +2524 +2525 +2526 +2527 +2528 +2529 +2530 +2531 +2532 +2533 +2534 +2535 +2536 +2537 +2538 +2539 +2540 +2541 +2542 +2543 +2544 +2545 +2546 +2547 +2548 +2549 +2550 +2551 +2552 +2553 +2554 +2555 +2556 +2557 +2558 +2559 +2560 +2561 +2562 +2563 +2564 +2565 +2566 +2567 +2568 +2569 +2570 +2571 +2572 +2573 +2574 +2575 +2576 +2577 +2578 +2579 +2580 +2581 +2582 +2583 +2584 +2585 +2586 +2587 +2588 +2589 +2590 +2591 +2592 +2593 +2594 +2595 +2596 +2597 +2598 +2599 +2600 +2601 +2602 +2603 +2604 +2605 +2606 +2607 +2608 +2609 +2610 +2611 +2612 +2613 +2614 +2615 +2616 +2617 +2618 +2619 +2620 +2621 +2622 +2623 +2624 +2625 +2626 +2627 +2628 +2629 +2630 +2631 +2632 +2633 +2634 +2635 +2636 +2637 +2638 +2639 +2640 +2641 +2642 +2643 +2644 +2645 +2646 +2647 +2648 +2649 +2650 +2651 +2652 +2653 +2654 +2655 +2656 +2657 +2658 +2659 +2660 +2661 +2662 +2663 +2664 +2665 +2666 +2667 +2668 +2669 +2670 +2671 +2672 +2673 +2674 +2675 +2676 +2677 +2678 +2679 +2680 +2681 +2682 +2683 +2684 +2685 +2686 +2687 +2688 +2689 +2690 +2691 +2692 +2693 +2694 +2695 +2696 +2697 +2698 +2699 +2700 +2701 +2702 +2703 +2704 +2705 +2706 +2707 +2708 +2709 +2710 +2711 +2712 +2713 +2714 +2715 +2716 +2717 +2718 +2719 +2720 +2721 +2722 +2723 +2724 +2725 +2726 +2727 +2728 +2729 +2730 +2731 +2732 +2733 +2734 +2735 +2736 +2737 +2738 +2739 +2740 +2741 +2742 +2743 +2744 +2745 +2746 +2747 +2748 +2749 +2750 +2751 +2752 +2753 +2754 +2755 +2756 +2757 +2758 +2759 +2760 +2761 +2762 +2763 +2764 +2765 +2766 +2767 +2768 +2769 +2770 +2771 +2772 +2773 +2774 +2775 +2776 +2777 +2778 +2779 +2780 +2781 +2782 +2783 +2784 +2785 +2786 +2787 +2788 +2789 +2790 +2791 +2792 +2793 +2794 +2795 +2796 +2797 +2798 +2799 +2800 +2801 +2802 +2803 +2804 +2805 +2806 +2807 +2808 +2809 +2810 +2811 +2812 +2813 +2814 +2815 +2816 +2817 +2818 +2819 +2820 +2821 +2822 +2823 +2824 +2825 +2826 +2827 +2828 +2829 +2830 +2831 +2832 +2833 +2834 +2835 +2836 +2837 +2838 +2839 +2840 +2841 +2842 +2843 +2844 +2845 +2846 +2847 +2848 +2849 +2850 +2851 +2852 +2853 +2854 +2855 +2856 +2857 +2858 +2859 +2860 +2861 +2862 +2863 +2864 +2865 +2866 +2867 +2868 +2869 +2870 +2871 +2872 +2873 +2874 +2875 +2876 +2877 +2878 +2879 +2880 +2881 +2882 +2883 +2884 +2885 +2886 +2887 +2888 +2889 +2890 +2891 +2892 +2893 +2894 +2895 +2896 +2897 +2898 +2899 +2900 +2901 +2902 +2903 +2904 +2905 +2906 +2907 +2908 +2909 +2910 +2911 +2912 +2913 +2914 +2915 +2916 +2917 +2918 +2919 +2920 +2921 +2922 +2923 +2924 +2925 +2926 +2927 +2928 +2929 +2930 +2931 +2932 +2933 +2934 +2935 +2936 +2937 +2938 +2939 +2940 +2941 +2942 +2943 +2944 +2945 +2946 +2947 +2948 +2949 +2950 +2951 +2952 +2953 +2954 +2955 +2956 +2957 +2958 +2959 +2960 +2961 +2962 +2963 +2964 +2965 +2966 +2967 +2968 +2969 +2970 +2971 +2972 +2973 +2974 +2975 +2976 +2977 +2978 +2979 +2980 +2981 +2982 +2983 +2984 +2985 +2986 +2987 +2988 +2989 +2990 +2991 +2992 +2993 +2994 +2995 +2996 +2997 +2998 +2999 +3000 +3001 +3002 +3003 +3004 +3005 +3006 +3007 +3008 +3009 +3010 +3011 +3012 +3013 +3014 +3015 +3016 +3017 +3018 +3019 +3020 +3021 +3022 +3023 +3024 +3025 +3026 +3027 +3028 +3029 +3030 +3031 +3032 +3033 +3034 +3035 +3036 +3037 +3038 +3039 +3040 +3041 +3042 +3043 +3044 +3045 +3046 +3047 +3048 +3049 +3050 +3051 +3052 +3053 +3054 +3055 +3056 +3057 +3058 +3059 +3060 +3061 +3062 +3063 +3064 +3065 +3066 +3067 +3068 +3069 +3070 +3071 +3072 +3073 +3074 +3075 +3076 +3077 +3078 +3079 +3080 +3081 +3082 +3083 +3084 +3085 +3086 +3087 +3088 +3089 +3090 +3091 +3092 +3093 +3094 +3095 +3096 +3097 +3098 +3099 +3100 +3101 +3102 +3103 +3104 +3105 +3106 +3107 +3108 +3109 +3110 +3111 +3112 +3113 +3114 +3115 +3116 +3117 +3118 +3119 +3120 +3121 +3122 +3123 +3124 +3125 +3126 +3127 +3128 +3129 +3130 +3131 +3132 +3133 +3134 +3135 +3136 +3137 +3138 +3139 +3140 +3141 +3142 +3143 +3144 +3145 +3146 +3147 +3148 +3149 +3150 +3151 +3152 +3153 +3154 +3155 +3156 +3157 +3158 +3159 +3160 +3161 +3162 +3163 +3164 +3165 +3166 +3167 +3168 +3169 +3170 +3171 +3172 +3173 +3174 +3175 +3176 +3177 +3178 +3179 +3180 +3181 +3182 +3183 +3184 +3185 +3186 +3187 +3188 +3189 +3190 +3191 +3192 +3193 +3194 +3195 +3196 +3197 +3198 +3199 +3200 +3201 +3202 +3203 +3204 +3205 +3206 +3207 +3208 +3209 +3210 +3211 +3212 +3213 +3214 +3215 +3216 +3217 +3218 +3219 +3220 +3221 +3222 +3223 +3224 +3225 +3226 +3227 +3228 +3229 +3230 +3231 +3232 +3233 +3234 +3235 +3236 +3237 +3238 +3239 +3240 +3241 +3242 +3243 +3244 +3245 +3246 +3247 +3248 +3249 +3250 +3251 +3252 +3253 +3254 +3255 +3256 +3257 +3258 +3259 +3260 +3261 +3262 +3263 +3264 +3265 +3266 +3267 +3268 +3269 +3270 +3271 +3272 +3273 +3274 +3275 +3276 +3277 +3278 +3279 +3280 +3281 +3282 +3283 +3284 +3285 +3286 +3287 +3288 +3289 +3290 +3291 +3292 +3293 +3294 +3295 +3296 +3297 +3298 +3299 +3300 +3301 +3302 +3303 +3304 +3305 +3306 +3307 +3308 +3309 +3310 +3311 +3312 +3313 +3314 +3315 +3316 +3317 +3318 +3319 +3320 +3321 +3322 +3323 +3324 +3325 +3326 +3327 +3328 +3329 +3330 +3331 +3332 +3333 +3334 +3335 +3336 +3337 +3338 +3339 +3340 +3341 +3342 +3343 +3344 +3345 +3346 +3347 +3348 +3349 +3350 +3351 +3352 +3353 +3354 +3355 +3356 +3357 +3358 +3359 +3360 +3361 +3362 +3363 +3364 +3365 +3366 +3367 +3368 +3369 +3370 +3371 +3372 +3373 +3374 +3375 +3376 +3377 +3378 +3379 +3380 +3381 +3382 +3383 +3384 +3385 +3386 +3387 +3388 +3389 +3390 +3391 +3392 +3393 +3394 +3395 +3396 +3397 +3398 +3399 +3400 +3401 +3402 +3403 +3404 +3405 +3406 +3407 +3408 +3409 +3410 +3411 +3412 +3413 +3414 +3415 +3416 +3417 +3418 +3419 +3420 +3421 +3422 +3423 +3424 +3425 +3426 +3427 +3428 +3429 +3430 +3431 +3432 +3433 +3434 +3435 +3436 +3437 +3438 +3439 +3440 +3441 +3442 +3443 +3444 +3445 +3446 +3447 +3448 +3449 +3450 +3451 +3452 +3453 +3454 +3455 +3456 +3457 +3458 +3459 +3460 +3461 +3462 +3463 +3464 +3465 +3466 +3467 +3468 +3469 +3470 +3471 +3472 +3473 +3474 +3475 +3476 +3477 +3478 +3479 +3480 +3481 +3482 +3483 +3484 +3485 +3486 +3487 +3488 +3489 +3490 +3491 +3492 +3493 +3494 +3495 +3496 +3497 +3498 +3499 +3500 +3501 +3502 +3503 +3504 +3505 +3506 +3507 +3508 +3509 +3510 +3511 +3512 +3513 +3514 +3515 +3516 +3517 +3518 +3519 +3520 +3521 +3522 +3523 +3524 +3525 +3526 +3527 +3528 +3529 +3530 +3531 +3532 +3533 +3534 +3535 +3536 +3537 +3538 +3539 +3540 +3541 +3542 +3543 +3544 +3545 +3546 +3547 +3548 +3549 +3550 +3551 +3552 +3553 +3554 +3555 +3556 +3557 +3558 +3559 +3560 +3561 +3562 +3563 +3564 +3565 +3566 +3567 +3568 +3569 +3570 +3571 +3572 +3573 +3574 +3575 +3576 +3577 +3578 +3579 +3580 +3581 +3582 +3583 +3584 +3585 +3586 +3587 +3588 +3589 +3590 +3591 +3592 +3593 +3594 +3595 +3596 +3597 +3598 +3599 +3600 +3601 +3602 +3603 +3604 +3605 +3606 +3607 +3608 +3609 +3610 +3611 +3612 +3613 +3614 +3615 +3616 +3617 +3618 +3619 +3620 +3621 +3622 +3623 +3624 +3625 +3626 +3627 +3628 +3629 +3630 +3631 +3632 +3633 +3634 +3635 +3636 +3637 +3638 +3639 +3640 +3641 +3642 +3643 +3644 +3645 +3646 +3647 +3648 +3649 +3650 +3651 +3652 +3653 +3654 +3655 +3656 +3657 +3658 +3659 +3660 +3661 +3662 +3663 +3664 +3665 +3666 +3667 +3668 +3669 +3670 +3671 +3672 +3673 +3674 +3675 +3676 +3677 +3678 +3679 +3680 +3681 +3682 +3683 +3684 +3685 +3686 +3687 +3688 +3689 +3690 +3691 +3692 +3693 +3694 +3695 +3696 +3697 +3698 +3699 +3700 +3701 +3702 +3703 +3704 +3705 +3706 +3707 +3708 +3709 +3710 +3711 +3712 +3713 +3714 +3715 +3716 +3717 +3718 +3719 +3720 +3721 +3722 +3723 +3724 +3725 +3726 +3727 +3728 +3729 +3730 +3731 +3732 +3733 +3734 +3735 +3736 +3737 +3738 +3739 +3740 +3741 +3742 +3743 +3744 +3745 +3746 +3747 +3748 +3749 +3750 +3751 +3752 +3753 +3754 +3755 +3756 +3757 +3758 +3759 +3760 +3761 +3762 +3763 +3764 +3765 +3766 +3767 +3768 +3769 +3770 +3771 +3772 +3773 +3774 +3775 +3776 +3777 +3778 +3779 +3780 +3781 +3782 +3783 +3784 +3785 +3786 +3787 +3788 +3789 +3790 +3791 +3792 +3793 +3794 +3795 +3796 +3797 +3798 +3799 +3800 +3801 +3802 +3803 +3804 +3805 +3806 +3807 +3808 +3809 +3810 +3811 +3812 +3813 +3814 +3815 +3816 +3817 +3818 +3819 +3820 +3821 +3822 +3823 +3824 +3825 +3826 +3827 +3828 +3829 +3830 +3831 +3832 +3833 +3834 +3835 +3836 +3837 +3838 +3839 +3840 +3841 +3842 +3843 +3844 +3845 +3846 +3847 +3848 +3849 +3850 +3851 +3852 +3853 +3854 +3855 +3856 +3857 +3858 +3859 +3860 +3861 +3862 +3863 +3864 +3865 +3866 +3867 +3868 +3869 +3870 +3871 +3872 +3873 +3874 +3875 +3876 +3877 +3878 +3879 +3880 +3881 +3882 +3883 +3884 +3885 +3886 +3887 +3888 +3889 +3890 +3891 +3892 +3893 +3894 +3895 +3896 +3897 +3898 +3899 +3900 +3901 +3902 +3903 +3904 +3905 +3906 +3907 +3908 +3909 +3910 +3911 +3912 +3913 +3914 +3915 +3916 +3917 +3918 +3919 +3920 +3921 +3922 +3923 +3924 +3925 +3926 +3927 +3928 +3929 +3930 +3931 +3932 +3933 +3934 +3935 +3936 +3937 +3938 +3939 +3940 +3941 +3942 +3943 +3944 +3945 +3946 +3947 +3948 +3949 +3950 +3951 +3952 +3953 +3954 +3955 +3956 +3957 +3958 +3959 +3960 +3961 +3962 +3963 +3964 +3965 +3966 +3967 +3968 +3969 +3970 +3971 +3972 +3973 +3974 +3975 +3976 +3977 +3978 +3979 +3980 +3981 +3982 +3983 +3984 +3985 +3986 +3987 +3988 +3989 +3990 +3991 +3992 +3993 +3994 +3995 +3996 +3997 +3998 +3999 +4000 +4001 +4002 +4003 +4004 +4005 +4006 +4007 +4008 +4009 +4010 +4011 +4012 +4013 +4014 +4015 +4016 +4017 +4018 +4019 +4020 +4021 +4022 +4023 +4024 +4025 +4026 +4027 +4028 +4029 +4030 +4031 +4032 +4033 +4034 +4035 +4036 +4037 +4038 +4039 +4040 +4041 +4042 +4043 +4044 +4045 +4046 +4047 +4048 +4049 +4050 +4051 +4052 +4053 +4054 +4055 +4056 +4057 +4058 +4059 +4060 +4061 +4062 +4063 +4064 +4065 +4066 +4067 +4068 +4069 +4070 +4071 +4072 +4073 +4074 +4075 +4076 +4077 +4078 +4079 +4080 +4081 +4082 +4083 +4084 +4085 +4086 +4087 +4088 +4089 +4090 +4091 +4092 +4093 +4094 +4095 +4096 +4097 +4098 +4099 +4100 +4101 +4102 +4103 +4104 +4105 +4106 +4107 +4108 +4109 +4110 +4111 +4112 +4113 +4114 +4115 +4116 +4117 +4118 +4119 +4120 +4121 +4122 +4123 +4124 +4125 +4126 +4127 +4128 +4129 +4130 +4131 +4132 +4133 +4134 +4135 +4136 +4137 +4138 +4139 +4140 +4141 +4142 +4143 +4144 +4145 +4146 +4147 +4148 +4149 +4150 +4151 +4152 +4153 +4154 +4155 +4156 +4157 +4158 +4159 +4160 +4161 +4162 +4163 +4164 +4165 +4166 +4167 +4168 +4169 +4170 +4171 +4172 +4173 +4174 +4175 +4176 +4177 +4178 +4179 +4180 +4181 +4182 +4183 +4184 +4185 +4186 +4187 +4188 +4189 +4190 +4191 +4192 +4193 +4194 +4195 +4196 +4197 +4198 +4199 +4200 +4201 +4202 +4203 +4204 +4205 +4206 +4207 +4208 +4209 +4210 +4211 +4212 +4213 +4214 +4215 +4216 +4217 +4218 +4219 +4220 +4221 +4222 +4223 +4224 +4225 +4226 +4227 +4228 +4229 +4230 +4231 +4232 +4233 +4234 +4235 +4236 +4237 +4238 +4239 +4240 +4241 +4242 +4243 +4244 +4245 +4246 +4247 +4248 +4249 +4250 +4251 +4252 +4253 +4254 +4255 +4256 +4257 +4258 +4259 +4260 +4261 +4262 +4263 +4264 +4265 +4266 +4267 +4268 +4269 +4270 +4271 +4272 +4273 +4274 +4275 +4276 +4277 +4278 +4279 +4280 +4281 +4282 +4283 +4284 +4285 +4286 +4287 +4288 +4289 +4290 +4291 +4292 +4293 +4294 +4295 +4296 +4297 +4298 +4299 +4300 +4301 +4302 +4303 +4304 +4305 +4306 +4307 +4308 +4309 +4310 +4311 +4312 +4313 +4314 +4315 +4316 +4317 +4318 +4319 +4320 +4321 +4322 +4323 +4324 +4325 +4326 +4327 +4328 +4329 +4330 +4331 +4332 +4333 +4334 +4335 +4336 +4337 +4338 +4339 +4340 +4341 +4342 +4343 +4344 +4345 +4346 +4347 +4348 +4349 +4350 +4351 +4352 +4353 +4354 +4355 +4356 +4357 +4358 +4359 +4360 +4361 +4362 +4363 +4364 +4365 +4366 +4367 +4368 +4369 +4370 +4371 +4372 +4373 +4374 +4375 +4376 +4377 +4378 +4379 +4380 +4381 +4382 +4383 +4384 +4385 +4386 +4387 +4388 +4389 +4390 +4391 +4392 +4393 +4394 +4395 +4396 +4397 +4398 +4399 +4400 +4401 +4402 +4403 +4404 +4405 +4406 +4407 +4408 +4409 +4410 +4411 +4412 +4413 +4414 +4415 +4416 +4417 +4418 +4419 +4420 +4421 +4422 +4423 +4424 +4425 +4426 +4427 +4428 +4429 +4430 +4431 +4432 +4433 +4434 +4435 +4436 +4437 +4438 +4439 +4440 +4441 +4442 +4443 +4444 +4445 +4446 +4447 +4448 +4449 +4450 +4451 +4452 +4453 +4454 +4455 +4456 +4457 +4458 +4459 +4460 +4461 +4462 +4463 +4464 +4465 +4466 +4467 +4468 +4469 +4470 +4471 +4472 +4473 +4474 +4475 +4476 +4477 +4478 +4479 +4480 +4481 +4482 +4483 +4484 +4485 +4486 +4487 +4488 +4489 +4490 +4491 +4492 +4493 +4494 +4495 +4496 +4497 +4498 +4499 +4500 +4501 +4502 +4503 +4504 +4505 +4506 +4507 +4508 +4509 +4510 +4511 +4512 +4513 +4514 +4515 +4516 +4517 +4518 +4519 +4520 +4521 +4522 +4523 +4524 +4525 +4526 +4527 +4528 +4529 +4530 +4531 +4532 +4533 +4534 +4535 +4536 +4537 +4538 +4539 +4540 +4541 +4542 +4543 +4544 +4545 +4546 +4547 +4548 +4549 +4550 +4551 +4552 +4553 +4554 +4555 +4556 +4557 +4558 +4559 +4560 +4561 +4562 +4563 +4564 +4565 +4566 +4567 +4568 +4569 +4570 +4571 +4572 +4573 +4574 +4575 +4576 +4577 +4578 +4579 +4580 +4581 +4582 +4583 +4584 +4585 +4586 +4587 +4588 +4589 +4590 +4591 +4592 +4593 +4594 +4595 +4596 +4597 +4598 +4599 +4600 +4601 +4602 +4603 +4604 +4605 +4606 +4607 +4608 +4609 +4610 +4611 +4612 +4613 +4614 +4615 +4616 +4617 +4618 +4619 +4620 +4621 +4622 +4623 +4624 +4625 +4626 +4627 +4628 +4629 +4630 +4631 +4632 +4633 +4634 +4635 +4636 +4637 +4638 +4639 +4640 +4641 +4642 +4643 +4644 +4645 +4646 +4647 +4648 +4649 +4650 +4651 +4652 +4653 +4654 +4655 +4656 +4657 +4658 +4659 +4660 +4661 +4662 +4663 +4664 +4665 +4666 +4667 +4668 +4669 +4670 +4671 +4672 +4673 +4674 +4675 +4676 +4677 +4678 +4679 +4680 +4681 +4682 +4683 +4684 +4685 +4686 +4687 +4688 +4689 +4690 +4691 +4692 +4693 +4694 +4695 +4696 +4697 +4698 +4699 +4700 +4701 +4702 +4703 +4704 +4705 +4706 +4707 +4708 +4709 +4710 +4711 +4712 +4713 +4714 +4715 +4716 +4717 +4718 +4719 +4720 +4721 +4722 +4723 +4724 +4725 +4726 +4727 +4728 +4729 +4730 +4731 +4732 +4733 +4734 +4735 +4736 +4737 +4738 +4739 +4740 +4741 +4742 +4743 +4744 +4745 +4746 +4747 +4748 +4749 +4750 +4751 +4752 +4753 +4754 +4755 +4756 +4757 +4758 +4759 +4760 +4761 +4762 +4763 +4764 +4765 +4766 +4767 +4768 +4769 +4770 +4771 +4772 +4773 +4774 +4775 +4776 +4777 +4778 +4779 +4780 +4781 +4782 +4783 +4784 +4785 +4786 +4787 +4788 +4789 +4790 +4791 +4792 +4793 +4794 +4795 +4796 +4797 +4798 +4799 +4800 +4801 +4802 +4803 +4804 +4805 +4806 +4807 +4808 +4809 +4810 +4811 +4812 +4813 +4814 +4815 +4816 +4817 +4818 +4819 +4820 +4821 +4822 +4823 +4824 +4825 +4826 +4827 +4828 +4829 +4830 +4831 +4832 +4833 +4834 +4835 +4836 +4837 +4838 +4839 +4840 +4841 +4842 +4843 +4844 +4845 +4846 +4847 +4848 +4849 +4850 +4851 +4852 +4853 +4854 +4855 +4856 +4857 +4858 +4859 +4860 +4861 +4862 +4863 +4864 +4865 +4866 +4867 +4868 +4869 +4870 +4871 +4872 +4873 +4874 +4875 +4876 +4877 +4878 +4879 +4880 +4881 +4882 +4883 +4884 +4885 +4886 +4887 +4888 +4889 +4890 +4891 +4892 +4893 +4894 +4895 +4896 +4897 +4898 +4899 +4900 +4901 +4902 +4903 +4904 +4905 +4906 +4907 +4908 +4909 +4910 +4911 +4912 +4913 +4914 +4915 +4916 +4917 +4918 +4919 +4920 +4921 +4922 +4923 +4924 +4925 +4926 +4927 +4928 +4929 +4930 +4931 +4932 +4933 +4934 +4935 +4936 +4937 +4938 +4939 +4940 +4941 +4942 +4943 +4944 +4945 +4946 +4947 +4948 +4949 +4950 +4951 +4952 +4953 +4954 +4955 +4956 +4957 +4958 +4959 +4960 +4961 +4962 +4963 +4964 +4965 +4966 +4967 +4968 +4969 +4970 +4971 +4972 +4973 +4974 +4975 +4976 +4977 +4978 +4979 +4980 +4981 +4982 +4983 +4984 +4985 +4986 +4987 +4988 +4989 +4990 +4991 +4992 +4993 +4994 +4995 +4996 +4997 +4998 +4999 +5000 +5001 +5002 +5003 +5004 +5005 +5006 +5007 +5008 +5009 +5010 +5011 +5012 +5013 +5014 +5015 +5016 +5017 +5018 +5019 +5020 +5021 +5022 +5023 +5024 +5025 +5026 +5027 +5028 +5029 +5030 +5031 +5032 +5033 +5034 +5035 +5036 +5037 +5038 +5039 +5040 +5041 +5042 +5043 +5044 +5045 +5046 +5047 +5048 +5049 +5050 +5051 +5052 +5053 +5054 +5055 +5056 +5057 +5058 +5059 +5060 +5061 +5062 +5063 +5064 +5065 +5066 +5067 +5068 +5069 +5070 +5071 +5072 +5073 +5074 +5075 +5076 +5077 +5078 +5079 +5080 +5081 +5082 +5083 +5084 +5085 +5086 +5087 +5088 +5089 +5090 +5091 +5092 +5093 +5094 +5095 +5096 +5097 +5098 +5099 +5100 +5101 +5102 +5103 +5104 +5105 +5106 +5107 +5108 +5109 +5110 +5111 +5112 +5113 +5114 +5115 +5116 +5117 +5118 +5119 +5120 +5121 +5122 +5123 +5124 +5125 +5126 +5127 +5128 +5129 +5130 +5131 +5132 +5133 +5134 +5135 +5136 +5137 +5138 +5139 +5140 +5141 +5142 +5143 +5144 +5145 +5146 +5147 +5148 +5149 +5150 +5151 +5152 +5153 +5154 +5155 +5156 +5157 +5158 +5159 +5160 +5161 +5162 +5163 +5164 +5165 +5166 +5167 +5168 +5169 +5170 +5171 +5172 +5173 +5174 +5175 +5176 +5177 +5178 +5179 +5180 +5181 +5182 +5183 +5184 +5185 +5186 +5187 +5188 +5189 +5190 +5191 +5192 +5193 +5194 +5195 +5196 +5197 +5198 +5199 +5200 +5201 +5202 +5203 +5204 +5205 +5206 +5207 +5208 +5209 +5210 +5211 +5212 +5213 +5214 +5215 +5216 +5217 +5218 +5219 +5220 +5221 +5222 +5223 +5224 +5225 +5226 +5227 +5228 +5229 +5230 +5231 +5232 +5233 +5234 +5235 +5236 +5237 +5238 +5239 +5240 +5241 +5242 +5243 +5244 +5245 +5246 +5247 +5248 +5249 +5250 +5251 +5252 +5253 +5254 +5255 +5256 +5257 +5258 +5259 +5260 +5261 +5262 +5263 +5264 +5265 +5266 +5267 +5268 +5269 +5270 +5271 +5272 +5273 +5274 +5275 +5276 +5277 +5278 +5279 +5280 +5281 +5282 +5283 +5284 +5285 +5286 +5287 +5288 +5289 +5290 +5291 +5292 +5293 +5294 +5295 +5296 +5297 +5298 +5299 +5300 +5301 +5302 +5303 +5304 +5305 +5306 +5307 +5308 +5309 +5310 +5311 +5312 +5313 +5314 +5315 +5316 +5317 +5318 +5319 +5320 +5321 +5322 +5323 +5324 +5325 +5326 +5327 +5328 +5329 +5330 +5331 +5332 +5333 +5334 +5335 +5336 +5337 +5338 +5339 +5340 +5341 +5342 +5343 +5344 +5345 +5346 +5347 +5348 +5349 +5350 +5351 +5352 +5353 +5354 +5355 +5356 +5357 +5358 +5359 +5360 +5361 +5362 +5363 +5364 +5365 +5366 +5367 +5368 +5369 +5370 +5371 +5372 +5373 +5374 +5375 +5376 +5377 +5378 +5379 +5380 +5381 +5382 +5383 +5384 +5385 +5386 +5387 +5388 +5389 +5390 +5391 +5392 +5393 +5394 +5395 +5396 +5397 +5398 +5399 +5400 +5401 +5402 +5403 +5404 +5405 +5406 +5407 +5408 +5409 +5410 +5411 +5412 +5413 +5414 +5415 +5416 +5417 +5418 +5419 +5420 +5421 +5422 +5423 +5424 +5425 +5426 +5427 +5428 +5429 +5430 +5431 +5432 +5433 +5434 +5435 +5436 +5437 +5438 +5439 +5440 +5441 +5442 +5443 +5444 +5445 +5446 +5447 +5448 +5449 +5450 +5451 +5452 +5453 +5454 +5455 +5456 +5457 +5458 +5459 +5460 +5461 +5462 +5463 +5464 +5465 +5466 +5467 +5468 +5469 +5470 +5471 +5472 +5473 +5474 +5475 +5476 +5477 +5478 +5479 +5480 +5481 +5482 +5483 +5484 +5485 +5486 +5487 +5488 +5489 +5490 +5491 +5492 +5493 +5494 +5495 +5496 +5497 +5498 +5499 +5500 +5501 +5502 +5503 +5504 +5505 +5506 +5507 +5508 +5509 +5510 +5511 +5512 +5513 +5514 +5515 +5516 +5517 +5518 +5519 +5520 +5521 +5522 +5523 +5524 +5525 +5526 +5527 +5528 +5529 +5530 +5531 +5532 +5533 +5534 +5535 +5536 +5537 +5538 +5539 +5540 +5541 +5542 +5543 +5544 +5545 +5546 +5547 +5548 +5549 +5550 +5551 +5552 +5553 +5554 +5555 +5556 +5557 +5558 +5559 +5560 +5561 +5562 +5563 +5564 +5565 +5566 +5567 +5568 +5569 +5570 +5571 +5572 +5573 +5574 +5575 +5576 +5577 +5578 +5579 +5580 +5581 +5582 +5583 +5584 +5585 +5586 +5587 +5588 +5589 +5590 +5591 +5592 +5593 +5594 +5595 +5596 +5597 +5598 +5599 +5600 +5601 +5602 +5603 +5604 +5605 +5606 +5607 +5608 +5609 +5610 +5611 +5612 +5613 +5614 +5615 +5616 +5617 +5618 +5619 +5620 +5621 +5622 +5623 +5624 +5625 +5626 +5627 +5628 +5629 +5630 +5631 +5632 +5633 +5634 +5635 +5636 +5637 +5638 +5639 +5640 +5641 +5642 +5643 +5644 +5645 +5646 +5647 +5648 +5649 +5650 +5651 +5652 +5653 +5654 +5655 +5656 +5657 +5658 +5659 +5660 +5661 +5662 +5663 +5664 +5665 +5666 +5667 +5668 +5669 +5670 +5671 +5672 +5673 +5674 +5675 +5676 +5677 +5678 +5679 +5680 +5681 +5682 +5683 +5684 +5685 +5686 +5687 +5688 +5689 +5690 +5691 +5692 +5693 +5694 +5695 +5696 +5697 +5698 +5699 +5700 +5701 +5702 +5703 +5704 +5705 +5706 +5707 +5708 +5709 +5710 +5711 +5712 +5713 +5714 +5715 +5716 +5717 +5718 +5719 +5720 +5721 +5722 +5723 +5724 +5725 +5726 +5727 +5728 +5729 +5730 +5731 +5732 +5733 +5734 +5735 +5736 +5737 +5738 +5739 +5740 +5741 +5742 +5743 +5744 +5745 +5746 +5747 +5748 +5749 +5750 +5751 +5752 +5753 +5754 +5755 +5756 +5757 +5758 +5759 +5760 +5761 +5762 +5763 +5764 +5765 +5766 +5767 +5768 +5769 +5770 +5771 +5772 +5773 +5774 +5775 +5776 +5777 +5778 +5779 +5780 +5781 +5782 +5783 +5784 +5785 +5786 +5787 +5788 +5789 +5790 +5791 +5792 +5793 +5794 +5795 +5796 +5797 +5798 +5799 +5800 +5801 +5802 +5803 +5804 +5805 +5806 +5807 +5808 +5809 +5810 +5811 +5812 +5813 +5814 +5815 +5816 +5817 +5818 +5819 +5820 +5821 +5822 +5823 +5824 +5825 +5826 +5827 +5828 +5829 +5830 +5831 +5832 +5833 +5834 +5835 +5836 +5837 +5838 +5839 +5840 +5841 +5842 +5843 +5844 +5845 +5846 +5847 +5848 +5849 +5850 +5851 +5852 +5853 +5854 +5855 +5856 +5857 +5858 +5859 +5860 +5861 +5862 +5863 +5864 +5865 +5866 +5867 +5868 +5869 +5870 +5871 +5872 +5873 +5874 +5875 +5876 +5877 +5878 +5879 +5880 +5881 +5882 +5883 +5884 +5885 +5886 +5887 +5888 +5889 +5890 +5891 +5892 +5893 +5894 +5895 +5896 +5897 +5898 +5899 +5900 +5901 +5902 +5903 +5904 +5905 +5906 +5907 +5908 +5909 +5910 +5911 +5912 +5913 +5914 +5915 +5916 +5917 +5918 +5919 +5920 +5921 +5922 +5923 +5924 +5925 +5926 +5927 +5928 +5929 +5930 +5931 +5932 +5933 +5934 +5935 +5936 +5937 +5938 +5939 +5940 +5941 +5942 +5943 +5944 +5945 +5946 +5947 +5948 +5949 +5950 +5951 +5952 +5953 +5954 +5955 +5956 +5957 +5958 +5959 +5960 +5961 +5962 +5963 +5964 +5965 +5966 +5967 +5968 +5969 +5970 +5971 +5972 +5973 +5974 +5975 +5976 +5977 +5978 +5979 +5980 +5981 +5982 +5983 +5984 +5985 +5986 +5987 +5988 +5989 +5990 +5991 +5992 +5993 +5994 +5995 +5996 +5997 +5998 +5999 +6000 +6001 +6002 +6003 +6004 +6005 +6006 +6007 +6008 +6009 +6010 +6011 +6012 +6013 +6014 +6015 +6016 +6017 +6018 +6019 +6020 +6021 +6022 +6023 +6024 +6025 +6026 +6027 +6028 +6029 +6030 +6031 +6032 +6033 +6034 +6035 +6036 +6037 +6038 +6039 +6040 +6041 +6042 +6043 +6044 +6045 +6046 +6047 +6048 +6049 +6050 +6051 +6052 +6053 +6054 +6055 +6056 +6057 +6058 +6059 +6060 +6061 +6062 +6063 +6064 +6065 +6066 +6067 +6068 +6069 +6070 +6071 +6072 +6073 +6074 +6075 +6076 +6077 +6078 +6079 +6080 +6081 +6082 +6083 +6084 +6085 +6086 +6087 +6088 +6089 +6090 +6091 +6092 +6093 +6094 +6095 +6096 +6097 +6098 +6099 +6100 +6101 +6102 +6103 +6104 +6105 +6106 +6107 +6108 +6109 +6110 +6111 +6112 +6113 +6114 +6115 +6116 +6117 +6118 +6119 +6120 +6121 +6122 +6123 +6124 +6125 +6126 +6127 +6128 +6129 +6130 +6131 +6132 +6133 +6134 +6135 +6136 +6137 +6138 +6139 +6140 +6141 +6142 +6143 +6144 +6145 +6146 +6147 +6148 +6149 +6150 +6151 +6152 +6153 +6154 +6155 +6156 +6157 +6158 +6159 +6160 +6161 +6162 +6163 +6164 +6165 +6166 +6167 +6168 +6169 +6170 +6171 +6172 +6173 +6174 +6175 +6176 +6177 +6178 +6179 +6180 +6181 +6182 +6183 +6184 +6185 +6186 +6187 +6188 +6189 +6190 +6191 +6192 +6193 +6194 +6195 +6196 +6197 +6198 +6199 +6200 +6201 +6202 +6203 +6204 +6205 +6206 +6207 +6208 +6209 +6210 +6211 +6212 +6213 +6214 +6215 +6216 +6217 +6218 +6219 +6220 +6221 +6222 +6223 +6224 +6225 +6226 +6227 +6228 +6229 +6230 +6231 +6232 +6233 +6234 +6235 +6236 +6237 +6238 +6239 +6240 +6241 +6242 +6243 +6244 +6245 +6246 +6247 +6248 +6249 +6250 +6251 +6252 +6253 +6254 +6255 +6256 +6257 +6258 +6259 +6260 +6261 +6262 +6263 +6264 +6265 +6266 +6267 +6268 +6269 +6270 +6271 +6272 +6273 +6274 +6275 +6276 +6277 +6278 +6279 +6280 +6281 +6282 +6283 +6284 +6285 +6286 +6287 +6288 +6289 +6290 +6291 +6292 +6293 +6294 +6295 +6296 +6297 +6298 +6299 +6300 +6301 +6302 +6303 +6304 +6305 +6306 +6307 +6308 +6309 +6310 +6311 +6312 +6313 +6314 +6315 +6316 +6317 +6318 +6319 +6320 +6321 +6322 +6323 +6324 +6325 +6326 +6327 +6328 +6329 +6330 +6331 +6332 +6333 +6334 +6335 +6336 +6337 +6338 +6339 +6340 +6341 +6342 +6343 +6344 +6345 +6346 +6347 +6348 +6349 +6350 +6351 +6352 +6353 +6354 +6355 +6356 +6357 +6358 +6359 +6360 +6361 +6362 +6363 +6364 +6365 +6366 +6367 +6368 +6369 +6370 +6371 +6372 +6373 +6374 +6375 +6376 +6377 +6378 +6379 +6380 +6381 +6382 +6383 +6384 +6385 +6386 +6387 +6388 +6389 +6390 +6391 +6392 +6393 +6394 +6395 +6396 +6397 +6398 +6399 +6400 +6401 +6402 +6403 +6404 +6405 +6406 +6407 +6408 +6409 +6410 +6411 +6412 +6413 +6414 +6415 +6416 +6417 +6418 +6419 +6420 +6421 +6422 +6423 +6424 +6425 +6426 +6427 +6428 +6429 +6430 +6431 +6432 +6433 +6434 +6435 +6436 +6437 +6438 +6439 +6440 +6441 +6442 +6443 +6444 +6445 +6446 +6447 +6448 +6449 +6450 +6451 +6452 +6453 +6454 +6455 +6456 +6457 +6458 +6459 +6460 +6461 +6462 +6463 +6464 +6465 +6466 +6467 +6468 +6469 +6470 +6471 +6472 +6473 +6474 +6475 +6476 +6477 +6478 +6479 +6480 +6481 +6482 +6483 +6484 +6485 +6486 +6487 +6488 +6489 +6490 +6491 +6492 +6493 +6494 +6495 +6496 +6497 +6498 +6499 +6500 +6501 +6502 +6503 +6504 +6505 +6506 +6507 +6508 +6509 +6510 +6511 +6512 +6513 +6514 +6515 +6516 +6517 +6518 +6519 +6520 +6521 +6522 +6523 +6524 +6525 +6526 +6527 +6528 +6529 +6530 +6531 +6532 +6533 +6534 +6535 +6536 +6537 +6538 +6539 +6540 +6541 +6542 +6543 +6544 +6545 +6546 +6547 +6548 +6549 +6550 +6551 +6552 +6553 +6554 +6555 +6556 +6557 +6558 +6559 +6560 +6561 +6562 +6563 +6564 +6565 +6566 +6567 +6568 +6569 +6570 +6571 +6572 +6573 +6574 +6575 +6576 +6577 +6578 +6579 +6580 +6581 +6582 +6583 +6584 +6585 +6586 +6587 +6588 +6589 +6590 +6591 +6592 +6593 +6594 +6595 +6596 +6597 +6598 +6599 +6600 +6601 +6602 +6603 +6604 +6605 +6606 +6607 +6608 +6609 +6610 +6611 +6612 +6613 +6614 +6615 +6616 +6617 +6618 +6619 +6620 +6621 +6622 +6623 +6624 +6625 +6626 +6627 +6628 +6629 +6630 +6631 +6632 +6633 +6634 +6635 +6636 +6637 +6638 +6639 +6640 +6641 +6642 +6643 +6644 +6645 +6646 +6647 +6648 +6649 +6650 +6651 +6652 +6653 +6654 +6655 +6656 +6657 +6658 +6659 +6660 +6661 +6662 +6663 +6664 +6665 +6666 +6667 +6668 +6669 +6670 +6671 +6672 +6673 +6674 +6675 +6676 +6677 +6678 +6679 +6680 +6681 +6682 +6683 +6684 +6685 +6686 +6687 +6688 +6689 +6690 +6691 +6692 +6693 +6694 +6695 +6696 +6697 +6698 +6699 +6700 +6701 +6702 +6703 +6704 +6705 +6706 +6707 +6708 +6709 +6710 +6711 +6712 +6713 +6714 +6715 +6716 +6717 +6718 +6719 +6720 +6721 +6722 +6723 +6724 +6725 +6726 +6727 +6728 +6729 +6730 +6731 +6732 +6733 +6734 +6735 +6736 +6737 +6738 +6739 +6740 +6741 +6742 +6743 +6744 +6745 +6746 +6747 +6748 +6749 +6750 +6751 +6752 +6753 +6754 +6755 +6756 +6757 +6758 +6759 +6760 +6761 +6762 +6763 +6764 +6765 +6766 +6767 +6768 +6769 +6770 +6771 +6772 +6773 +6774 +6775 +6776 +6777 +6778 +6779 +6780 +6781 +6782 +6783 +6784 +6785 +6786 +6787 +6788 +6789 +6790 +6791 +6792 +6793 +6794 +6795 +6796 +6797 +6798 +6799 +6800 +6801 +6802 +6803 +6804 +6805 +6806 +6807 +6808 +6809 +6810 +6811 +6812 +6813 +6814 +6815 +6816 +6817 +6818 +6819 +6820 +6821 +6822 +6823 +6824 +6825 +6826 +6827 +6828 +6829 +6830 +6831 +6832 +6833 +6834 +6835 +6836 +6837 +6838 +6839 +6840 +6841 +6842 +6843 +6844 +6845 +6846 +6847 +6848 +6849 +6850 +6851 +6852 +6853 +6854 +6855 +6856 +6857 +6858 +6859 +6860 +6861 +6862 +6863 +6864 +6865 +6866 +6867 +6868 +6869 +6870 +6871 +6872 +6873 +6874 +6875 +6876 +6877 +6878 +6879 +6880 +6881 +6882 +6883 +6884 +6885 +6886 +6887 +6888 +6889 +6890 +6891 +6892 +6893 +6894 +6895 +6896 +6897 +6898 +6899 +6900 +6901 +6902 +6903 +6904 +6905 +6906 +6907 +6908 +6909 +6910 +6911 +6912 +6913 +6914 +6915 +6916 +6917 +6918 +6919 +6920 +6921 +6922 +6923 +6924 +6925 +6926 +6927 +6928 +6929 +6930 +6931 +6932 +6933 +6934 +6935 +6936 +6937 +6938 +6939 +6940 +6941 +6942 +6943 +6944 +6945 +6946 +6947 +6948 +6949 +6950 +6951 +6952 +6953 +6954 +6955 +6956 +6957 +6958 +6959 +6960 +6961 +6962 +6963 +6964 +6965 +6966 +6967 +6968 +6969 +6970 +6971 +6972 +6973 +6974 +6975 +6976 +6977 +6978 +6979 +6980 +6981 +6982 +6983 +6984 +6985 +6986 +6987 +6988 +6989 +6990 +6991 +6992 +6993 +6994 +6995 +6996 +6997 +6998 +6999 +7000 +7001 +7002 +7003 +7004 +7005 +7006 +7007 +7008 +7009 +7010 +7011 +7012 +7013 +7014 +7015 +7016 +7017 +7018 +7019 +7020 +7021 +7022 +7023 +7024 +7025 +7026 +7027 +7028 +7029 +7030 +7031 +7032 +7033 +7034 +7035 +7036 +7037 +7038 +7039 +7040 +7041 +7042 +7043 +7044 +7045 +7046 +7047 +7048 +7049 +7050 +7051 +7052 +7053 +7054 +7055 +7056 +7057 +7058 +7059 +7060 +7061 +7062 +7063 +7064 +7065 +7066 +7067 +7068 +7069 +7070 +7071 +7072 +7073 +7074 +7075 +7076 +7077 +7078 +7079 +7080 +7081 +7082 +7083 +7084 +7085 +7086 +7087 +7088 +7089 +7090 +7091 +7092 +7093 +7094 +7095 +7096 +7097 +7098 +7099 +7100 +7101 +7102 +7103 +7104 +7105 +7106 +7107 +7108 +7109 +7110 +7111 +7112 +7113 +7114 +7115 +7116 +7117 +7118 +7119 +7120 +7121 +7122 +7123 +7124 +7125 +7126 +7127 +7128 +7129 +7130 +7131 +7132 +7133 +7134 +7135 +7136 +7137 +7138 +7139 +7140 +7141 +7142 +7143 +7144 +7145 +7146 +7147 +7148 +7149 +7150 +7151 +7152 +7153 +7154 +7155 +7156 +7157 +7158 +7159 +7160 +7161 +7162 +7163 +7164 +7165 +7166 +7167 +7168 +7169 +7170 +7171 +7172 +7173 +7174 +7175 +7176 +7177 +7178 +7179 +7180 +7181 +7182 +7183 +7184 +7185 +7186 +7187 +7188 +7189 +7190 +7191 +7192 +7193 +7194 +7195 +7196 +7197 +7198 +7199 +7200 +7201 +7202 +7203 +7204 +7205 +7206 +7207 +7208 +7209 +7210 +7211 +7212 +7213 +7214 +7215 +7216 +7217 +7218 +7219 +7220 +7221 +7222 +7223 +7224 +7225 +7226 +7227 +7228 +7229 +7230 +7231 +7232 +7233 +7234 +7235 +7236 +7237 +7238 +7239 +7240 +7241 +7242 +7243 +7244 +7245 +7246 +7247 +7248 +7249 +7250 +7251 +7252 +7253 +7254 +7255 +7256 +7257 +7258 +7259 +7260 +7261 +7262 +7263 +7264 +7265 +7266 +7267 +7268 +7269 +7270 +7271 +7272 +7273 +7274 +7275 +7276 +7277 +7278 +7279 +7280 +7281 +7282 +7283 +7284 +7285 +7286 +7287 +7288 +7289 +7290 +7291 +7292 +7293 +7294 +7295 +7296 +7297 +7298 +7299 +7300 +7301 +7302 +7303 +7304 +7305 +7306 +7307 +7308 +7309 +7310 +7311 +7312 +7313 +7314 +7315 +7316 +7317 +7318 +7319 +7320 +7321 +7322 +7323 +7324 +7325 +7326 +7327 +7328 +7329 +7330 +7331 +7332 +7333 +7334 +7335 +7336 +7337 +7338 +7339 +7340 +7341 +7342 +7343 +7344 +7345 +7346 +7347 +7348 +7349 +7350 +7351 +7352 +7353 +7354 +7355 +7356 +7357 +7358 +7359 +7360 +7361 +7362 +7363 +7364 +7365 +7366 +7367 +7368 +7369 +7370 +7371 +7372 +7373 +7374 +7375 +7376 +7377 +7378 +7379 +7380 +7381 +7382 +7383 +7384 +7385 +7386 +7387 +7388 +7389 +7390 +7391 +7392 +7393 +7394 +7395 +7396 +7397 +7398 +7399 +7400 +7401 +7402 +7403 +7404 +7405 +7406 +7407 +7408 +7409 +7410 +7411 +7412 +7413 +7414 +7415 +7416 +7417 +7418 +7419 +7420 +7421 +7422 +7423 +7424 +7425 +7426 +7427 +7428 +7429 +7430 +7431 +7432 +7433 +7434 +7435 +7436 +7437 +7438 +7439 +7440 +7441 +7442 +7443 +7444 +7445 +7446 +7447 +7448 +7449 +7450 +7451 +7452 +7453 +7454 +7455 +7456 +7457 +7458 +7459 +7460 +7461 +7462 +7463 +7464 +7465 +7466 +7467 +7468 +7469 +7470 +7471 +7472 +7473 +7474 +7475 +7476 +7477 +7478 +7479 +7480 +7481 +7482 +7483 +7484 +7485 +7486 +7487 +7488 +7489 +7490 +7491 +7492 +7493 +7494 +7495 +7496 +7497 +7498 +7499 +7500 +7501 +7502 +7503 +7504 +7505 +7506 +7507 +7508 +7509 +7510 +7511 +7512 +7513 +7514 +7515 +7516 +7517 +7518 +7519 +7520 +7521 +7522 +7523 +7524 +7525 +7526 +7527 +7528 +7529 +7530 +7531 +7532 +7533 +7534 +7535 +7536 +7537 +7538 +7539 +7540 +7541 +7542 +7543 +7544 +7545 +7546 +7547 +7548 +7549 +7550 +7551 +7552 +7553 +7554 +7555 +7556 +7557 +7558 +7559 +7560 +7561 +7562 +7563 +7564 +7565 +7566 +7567 +7568 +7569 +7570 +7571 +7572 +7573 +7574 +7575 +7576 +7577 +7578 +7579 +7580 +7581 +7582 +7583 +7584 +7585 +7586 +7587 +7588 +7589 +7590 +7591 +7592 +7593 +7594 +7595 +7596 +7597 +7598 +7599 +7600 +7601 +7602 +7603 +7604 +7605 +7606 +7607 +7608 +7609 +7610 +7611 +7612 +7613 +7614 +7615 +7616 +7617 +7618 +7619 +7620 +7621 +7622 +7623 +7624 +7625 +7626 +7627 +7628 +7629 +7630 +7631 +7632 +7633 +7634 +7635 +7636 +7637 +7638 +7639 +7640 +7641 +7642 +7643 +7644 +7645 +7646 +7647 +7648 +7649 +7650 +7651 +7652 +7653 +7654 +7655 +7656 +7657 +7658 +7659 +7660 +7661 +7662 +7663 +7664 +7665 +7666 +7667 +7668 +7669 +7670 +7671 +7672 +7673 +7674 +7675 +7676 +7677 +7678 +7679 +7680 +7681 +7682 +7683 +7684 +7685 +7686 +7687 +7688 +7689 +7690 +7691 +7692 +7693 +7694 +7695 +7696 +7697 +7698 +7699 +7700 +7701 +7702 +7703 +7704 +7705 +7706 +7707 +7708 +7709 +7710 +7711 +7712 +7713 +7714 +7715 +7716 +7717 +7718 +7719 +7720 +7721 +7722 +7723 +7724 +7725 +7726 +7727 +7728 +7729 +7730 +7731 +7732 +7733 +7734 +7735 +7736 +7737 +7738 +7739 +7740 +7741 +7742 +7743 +7744 +7745 +7746 +7747 +7748 +7749 +7750 +7751 +7752 +7753 +7754 +7755 +7756 +7757 +7758 +7759 +7760 +7761 +7762 +7763 +7764 +7765 +7766 +7767 +7768 +7769 +7770 +7771 +7772 +7773 +7774 +7775 +7776 +7777 +7778 +7779 +7780 +7781 +7782 +7783 +7784 +7785 +7786 +7787 +7788 +7789 +7790 +7791 +7792 +7793 +7794 +7795 +7796 +7797 +7798 +7799 +7800 +7801 +7802 +7803 +7804 +7805 +7806 +7807 +7808 +7809 +7810 +7811 +7812 +7813 +7814 +7815 +7816 +7817 +7818 +7819 +7820 +7821 +7822 +7823 +7824 +7825 +7826 +7827 +7828 +7829 +7830 +7831 +7832 +7833 +7834 +7835 +7836 +7837 +7838 +7839 +7840 +7841 +7842 +7843 +7844 +7845 +7846 +7847 +7848 +7849 +7850 +7851 +7852 +7853 +7854 +7855 +7856 +7857 +7858 +7859 +7860 +7861 +7862 +7863 +7864 +7865 +7866 +7867 +7868 +7869 +7870 +7871 +7872 +7873 +7874 +7875 +7876 +7877 +7878 +7879 +7880 +7881 +7882 +7883 +7884 +7885 +7886 +7887 +7888 +7889 +7890 +7891 +7892 +7893 +7894 +7895 +7896 +7897 +7898 +7899 +7900 +7901 +7902 +7903 +7904 +7905 +7906 +7907 +7908 +7909 +7910 +7911 +7912 +7913 +7914 +7915 +7916 +7917 +7918 +7919 +7920 +7921 +7922 +7923 +7924 +7925 +7926 +7927 +7928 +7929 +7930 +7931 +7932 +7933 +7934 +7935 +7936 +7937 +7938 +7939 +7940 +7941 +7942 +7943 +7944 +7945 +7946 +7947 +7948 +7949 +7950 +7951 +7952 +7953 +7954 +7955 +7956 +7957 +7958 +7959 +7960 +7961 +7962 +7963 +7964 +7965 +7966 +7967 +7968 +7969 +7970 +7971 +7972 +7973 +7974 +7975 +7976 +7977 +7978 +7979 +7980 +7981 +7982 +7983 +7984 +7985 +7986 +7987 +7988 +7989 +7990 +7991 +7992 +7993 +7994 +7995 +7996 +7997 +7998 +7999 +8000 +8001 +8002 +8003 +8004 +8005 +8006 +8007 +8008 +8009 +8010 +8011 +8012 +8013 +8014 +8015 +8016 +8017 +8018 +8019 +8020 +8021 +8022 +8023 +8024 +8025 +8026 +8027 +8028 +8029 +8030 +8031 +8032 +8033 +8034 +8035 +8036 +8037 +8038 +8039 +8040 +8041 +8042 +8043 +8044 +8045 +8046 +8047 +8048 +8049 +8050 +8051 +8052 +8053 +8054 +8055 +8056 +8057 +8058 +8059 +8060 +8061 +8062 +8063 +8064 +8065 +8066 +8067 +8068 +8069 +8070 +8071 +8072 +8073 +8074 +8075 +8076 +8077 +8078 +8079 +8080 +8081 +8082 +8083 +8084 +8085 +8086 +8087 +8088 +8089 +8090 +8091 +8092 +8093 +8094 +8095 +8096 +8097 +8098 +8099 +8100 +8101 +8102 +8103 +8104 +8105 +8106 +8107 +8108 +8109 +8110 +8111 +8112 +8113 +8114 +8115 +8116 +8117 +8118 +8119 +8120 +8121 +8122 +8123 +8124 +8125 +8126 +8127 +8128 +8129 +8130 +8131 +8132 +8133 +8134 +8135 +8136 +8137 +8138 +8139 +8140 +8141 +8142 +8143 +8144 +8145 +8146 +8147 +8148 +8149 +8150 +8151 +8152 +8153 +8154 +8155 +8156 +8157 +8158 +8159 +8160 +8161 +8162 +8163 +8164 +8165 +8166 +8167 +8168 +8169 +8170 +8171 +8172 +8173 +8174 +8175 +8176 +8177 +8178 +8179 +8180 +8181 +8182 +8183 +8184 +8185 +8186 +8187 +8188 +8189 +8190 +8191 +8192 +8193 +8194 +8195 +8196 +8197 +8198 +8199 +8200 +8201 +8202 +8203 +8204 +8205 +8206 +8207 +8208 +8209 +8210 +8211 +8212 +8213 +8214 +8215 +8216 +8217 +8218 +8219 +8220 +8221 +8222 +8223 +8224 +8225 +8226 +8227 +8228 +8229 +8230 +8231 +8232 +8233 +8234 +8235 +8236 +8237 +8238 +8239 +8240 +8241 +8242 +8243 +8244 +8245 +8246 +8247 +8248 +8249 +8250 +8251 +8252 +8253 +8254 +8255 +8256 +8257 +8258 +8259 +8260 +8261 +8262 +8263 +8264 +8265 +8266 +8267 +8268 +8269 +8270 +8271 +8272 +8273 +8274 +8275 +8276 +8277 +8278 +8279 +8280 +8281 +8282 +8283 +8284 +8285 +8286 +8287 +8288 +8289 +8290 +8291 +8292 +8293 +8294 +8295 +8296 +8297 +8298 +8299 +8300 +8301 +8302 +8303 +8304 +8305 +8306 +8307 +8308 +8309 +8310 +8311 +8312 +8313 +8314 +8315 +8316 +8317 +8318 +8319 +8320 +8321 +8322 +8323 +8324 +8325 +8326 +8327 +8328 +8329 +8330 +8331 +8332 +8333 +8334 +8335 +8336 +8337 +8338 +8339 +8340 +8341 +8342 +8343 +8344 +8345 +8346 +8347 +8348 +8349 +8350 +8351 +8352 +8353 +8354 +8355 +8356 +8357 +8358 +8359 +8360 +8361 +8362 +8363 +8364 +8365 +8366 +8367 +8368 +8369 +8370 +8371 +8372 +8373 +8374 +8375 +8376 +8377 +8378 +8379 +8380 +8381 +8382 +8383 +8384 +8385 +8386 +8387 +8388 +8389 +8390 +8391 +8392 +8393 +8394 +8395 +8396 +8397 +8398 +8399 +8400 +8401 +8402 +8403 +8404 +8405 +8406 +8407 +8408 +8409 +8410 +8411 +8412 +8413 +8414 +8415 +8416 +8417 +8418 +8419 +8420 +8421 +8422 +8423 +8424 +8425 +8426 +8427 +8428 +8429 +8430 +8431 +8432 +8433 +8434 +8435 +8436 +8437 +8438 +8439 +8440 +8441 +8442 +8443 +8444 +8445 +8446 +8447 +8448 +8449 +8450 +8451 +8452 +8453 +8454 +8455 +8456 +8457 +8458 +8459 +8460 +8461 +8462 +8463 +8464 +8465 +8466 +8467 +8468 +8469 +8470 +8471 +8472 +8473 +8474 +8475 +8476 +8477 +8478 +8479 +8480 +8481 +8482 +8483 +8484 +8485 +8486 +8487 +8488 +8489 +8490 +8491 +8492 +8493 +8494 +8495 +8496 +8497 +8498 +8499 +8500 +8501 +8502 +8503 +8504 +8505 +8506 +8507 +8508 +8509 +8510 +8511 +8512 +8513 +8514 +8515 +8516 +8517 +8518 +8519 +8520 +8521 +8522 +8523 +8524 +8525 +8526 +8527 +8528 +8529 +8530 +8531 +8532 +8533 +8534 +8535 +8536 +8537 +8538 +8539 +8540 +8541 +8542 +8543 +8544 +8545 +8546 +8547 +8548 +8549 +8550 +8551 +8552 +8553 +8554 +8555 +8556 +8557 +8558 +8559 +8560 +8561 +8562 +8563 +8564 +8565 +8566 +8567 +8568 +8569 +8570 +8571 +8572 +8573 +8574 +8575 +8576 +8577 +8578 +8579 +8580 +8581 +8582 +8583 +8584 +8585 +8586 +8587 +8588 +8589 +8590 +8591 +8592 +8593 +8594 +8595 +8596 +8597 +8598 +8599 +8600 +8601 +8602 +8603 +8604 +8605 +8606 +8607 +8608 +8609 +8610 +8611 +8612 +8613 +8614 +8615 +8616 +8617 +8618 +8619 +8620 +8621 +8622 +8623 +8624 +8625 +8626 +8627 +8628 +8629 +8630 +8631 +8632 +8633 +8634 +8635 +8636 +8637 +8638 +8639 +8640 +8641 +8642 +8643 +8644 +8645 +8646 +8647 +8648 +8649 +8650 +8651 +8652 +8653 +8654 +8655 +8656 +8657 +8658 +8659 +8660 +8661 +8662 +8663 +8664 +8665 +8666 +8667 +8668 +8669 +8670 +8671 +8672 +8673 +8674 +8675 +8676 +8677 +8678 +8679 +8680 +8681 +8682 +8683 +8684 +8685 +8686 +8687 +8688 +8689 +8690 +8691 +8692 +8693 +8694 +8695 +8696 +8697 +8698 +8699 +8700 +8701 +8702 +8703 +8704 +8705 +8706 +8707 +8708 +8709 +8710 +8711 +8712 +8713 +8714 +8715 +8716 +8717 +8718 +8719 +8720 +8721 +8722 +8723 +8724 +8725 +8726 +8727 +8728 +8729 +8730 +8731 +8732 +8733 +8734 +8735 +8736 +8737 +8738 +8739 +8740 +8741 +8742 +8743 +8744 +8745 +8746 +8747 +8748 +8749 +8750 +8751 +8752 +8753 +8754 +8755 +8756 +8757 +8758 +8759 +8760 +8761 +8762 +8763 +8764 +8765 +8766 +8767 +8768 +8769 +8770 +8771 +8772 +8773 +8774 +8775 +8776 +8777 +8778 +8779 +8780 +8781 +8782 +8783 +8784 +8785 +8786 +8787 +8788 +8789 +8790 +8791 +8792 +8793 +8794 +8795 +8796 +8797 +8798 +8799 +8800 +8801 +8802 +8803 +8804 +8805 +8806 +8807 +8808 +8809 +8810 +8811 +8812 +8813 +8814 +8815 +8816 +8817 +8818 +8819 +8820 +8821 +8822 +8823 +8824 +8825 +8826 +8827 +8828 +8829 +8830 +8831 +8832 +8833 +8834 +8835 +8836 +8837 +8838 +8839 +8840 +8841 +8842 +8843 +8844 +8845 +8846 +8847 +8848 +8849 +8850 +8851 +8852 +8853 +8854 +8855 +8856 +8857 +8858 +8859 +8860 +8861 +8862 +8863 +8864 +8865 +8866 +8867 +8868 +8869 +8870 +8871 +8872 +8873 +8874 +8875 +8876 +8877 +8878 +8879 +8880 +8881 +8882 +8883 +8884 +8885 +8886 +8887 +8888 +8889 +8890 +8891 +8892 +8893 +8894 +8895 +8896 +8897 +8898 +8899 +8900 +8901 +8902 +8903 +8904 +8905 +8906 +8907 +8908 +8909 +8910 +8911 +8912 +8913 +8914 +8915 +8916 +8917 +8918 +8919 +8920 +8921 +8922 +8923 +8924 +8925 +8926 +8927 +8928 +8929 +8930 +8931 +8932 +8933 +8934 +8935 +8936 +8937 +8938 +8939 +8940 +8941 +8942 +8943 +8944 +8945 +8946 +8947 +8948 +8949 +8950 +8951 +8952 +8953 +8954 +8955 +8956 +8957 +8958 +8959 +8960 +8961 +8962 +8963 +8964 +8965 +8966 +8967 +8968 +8969 +8970 +8971 +8972 +8973 +8974 +8975 +8976 +8977 +8978 +8979 +8980 +8981 +8982 +8983 +8984 +8985 +8986 +8987 +8988 +8989 +8990 +8991 +8992 +8993 +8994 +8995 +8996 +8997 +8998 +8999 +9000 +9001 +9002 +9003 +9004 +9005 +9006 +9007 +9008 +9009 +9010 +9011 +9012 +9013 +9014 +9015 +9016 +9017 +9018 +9019 +9020 +9021 +9022 +9023 +9024 +9025 +9026 +9027 +9028 +9029 +9030 +9031 +9032 +9033 +9034 +9035 +9036 +9037 +9038 +9039 +9040 +9041 +9042 +9043 +9044 +9045 +9046 +9047 +9048 +9049 +9050 +9051 +9052 +9053 +9054 +9055 +9056 +9057 +9058 +9059 +9060 +9061 +9062 +9063 +9064 +9065 +9066 +9067 +9068 +9069 +9070 +9071 +9072 +9073 +9074 +9075 +9076 +9077 +9078 +9079 +9080 +9081 +9082 +9083 +9084 +9085 +9086 +9087 +9088 +9089 +9090 +9091 +9092 +9093 +9094 +9095 +9096 +9097 +9098 +9099 +9100 +9101 +9102 +9103 +9104 +9105 +9106 +9107 +9108 +9109 +9110 +9111 +9112 +9113 +9114 +9115 +9116 +9117 +9118 +9119 +9120 +9121 +9122 +9123 +9124 +9125 +9126 +9127 +9128 +9129 +9130 +9131 +9132 +9133 +9134 +9135 +9136 +9137 +9138 +9139 +9140 +9141 +9142 +9143 +9144 +9145 +9146 +9147 +9148 +9149 +9150 +9151 +9152 +9153 +9154 +9155 +9156 +9157 +9158 +9159 +9160 +9161 +9162 +9163 +9164 +9165 +9166 +9167 +9168 +9169 +9170 +9171 +9172 +9173 +9174 +9175 +9176 +9177 +9178 +9179 +9180 +9181 +9182 +9183 +9184 +9185 +9186 +9187 +9188 +9189 +9190 +9191 +9192 +9193 +9194 +9195 +9196 +9197 +9198 +9199 +9200 +9201 +9202 +9203 +9204 +9205 +9206 +9207 +9208 +9209 +9210 +9211 +9212 +9213 +9214 +9215 +9216 +9217 +9218 +9219 +9220 +9221 +9222 +9223 +9224 +9225 +9226 +9227 +9228 +9229 +9230 +9231 +9232 +9233 +9234 +9235 +9236 +9237 +9238 +9239 +9240 +9241 +9242 +9243 +9244 +9245 +9246 +9247 +9248 +9249 +9250 +9251 +9252 +9253 +9254 +9255 +9256 +9257 +9258 +9259 +9260 +9261 +9262 +9263 +9264 +9265 +9266 +9267 +9268 +9269 +9270 +9271 +9272 +9273 +9274 +9275 +9276 +9277 +9278 +9279 +9280 +9281 +9282 +9283 +9284 +9285 +9286 +9287 +9288 +9289 +9290 +9291 +9292 +9293 +9294 +9295 +9296 +9297 +9298 +9299 +9300 +9301 +9302 +9303 +9304 +9305 +9306 +9307 +9308 +9309 +9310 +9311 +9312 +9313 +9314 +9315 +9316 +9317 +9318 +9319 +9320 +9321 +9322 +9323 +9324 +9325 +9326 +9327 +9328 +9329 +9330 +9331 +9332 +9333 +9334 +9335 +9336 +9337 +9338 +9339 +9340 +9341 +9342 +9343 +9344 +9345 +9346 +9347 +9348 +9349 +9350 +9351 +9352 +9353 +9354 +9355 +9356 +9357 +9358 +9359 +9360 +9361 +9362 +9363 +9364 +9365 +9366 +9367 +9368 +9369 +9370 +9371 +9372 +9373 +9374 +9375 +9376 +9377 +9378 +9379 +9380 +9381 +9382 +9383 +9384 +9385 +9386 +9387 +9388 +9389 +9390 +9391 +9392 +9393 +9394 +9395 +9396 +9397 +9398 +9399 +9400 +9401 +9402 +9403 +9404 +9405 +9406 +9407 +9408 +9409 +9410 +9411 +9412 +9413 +9414 +9415 +9416 +9417 +9418 +9419 +9420 +9421 +9422 +9423 +9424 +9425 +9426 +9427 +9428 +9429 +9430 +9431 +9432 +9433 +9434 +9435 +9436 +9437 +9438 +9439 +9440 +9441 +9442 +9443 +9444 +9445 +9446 +9447 +9448 +9449 +9450 +9451 +9452 +9453 +9454 +9455 +9456 +9457 +9458 +9459 +9460 +9461 +9462 +9463 +9464 +9465 +9466 +9467 +9468 +9469 +9470 +9471 +9472 +9473 +9474 +9475 +9476 +9477 +9478 +9479 +9480 +9481 +9482 +9483 +9484 +9485 +9486 +9487 +9488 +9489 +9490 +9491 +9492 +9493 +9494 +9495 +9496 +9497 +9498 +9499 +9500 +9501 +9502 +9503 +9504 +9505 +9506 +9507 +9508 +9509 +9510 +9511 +9512 +9513 +9514 +9515 +9516 +9517 +9518 +9519 +9520 +9521 +9522 +9523 +9524 +9525 +9526 +9527 +9528 +9529 +9530 +9531 +9532 +9533 +9534 +9535 +9536 +9537 +9538 +9539 +9540 +9541 +9542 +9543 +9544 +9545 +9546 +9547 +9548 +9549 +9550 +9551 +9552 +9553 +9554 +9555 +9556 +9557 +9558 +9559 +9560 +9561 +9562 +9563 +9564 +9565 +9566 +9567 +9568 +9569 +9570 +9571 +9572 +9573 +9574 +9575 +9576 +9577 +9578 +9579 +9580 +9581 +9582 +9583 +9584 +9585 +9586 +9587 +9588 +9589 +9590 +9591 +9592 +9593 +9594 +9595 +9596 +9597 +9598 +9599 +9600 +9601 +9602 +9603 +9604 +9605 +9606 +9607 +9608 +9609 +9610 +9611 +9612 +9613 +9614 +9615 +9616 +9617 +9618 +9619 +9620 +9621 +9622 +9623 +9624 +9625 +9626 +9627 +9628 +9629 +9630 +9631 +9632 +9633 +9634 +9635 +9636 +9637 +9638 +9639 +9640 +9641 +9642 +9643 +9644 +9645 +9646 +9647 +9648 +9649 +9650 +9651 +9652 +9653 +9654 +9655 +9656 +9657 +9658 +9659 +9660 +9661 +9662 +9663 +9664 +9665 +9666 +9667 +9668 +9669 +9670 +9671 +9672 +9673 +9674 +9675 +9676 +9677 +9678 +9679 +9680 +9681 +9682 +9683 +9684 +9685 +9686 +9687 +9688 +9689 +9690 +9691 +9692 +9693 +9694 +9695 +9696 +9697 +9698 +9699 +9700 +9701 +9702 +9703 +9704 +9705 +9706 +9707 +9708 +9709 +9710 +9711 +9712 +9713 +9714 +9715 +9716 +9717 +9718 +9719 +9720 +9721 +9722 +9723 +9724 +9725 +9726 +9727 +9728 +9729 +9730 +9731 +9732 +9733 +9734 +9735 +9736 +9737 +9738 +9739 +9740 +9741 +9742 +9743 +9744 +9745 +9746 +9747 +9748 +9749 +9750 +9751 +9752 +9753 +9754 +9755 +9756 +9757 +9758 +9759 +9760 +9761 +9762 +9763 +9764 +9765 +9766 +9767 +9768 +9769 +9770 +9771 +9772 +9773 +9774 +9775 +9776 +9777 +9778 +9779 +9780 +9781 +9782 +9783 +9784 +9785 +9786 +9787 +9788 +9789 +9790 +9791 +9792 +9793 +9794 +9795 +9796 +9797 +9798 +9799 +9800 +9801 +9802 +9803 +9804 +9805 +9806 +9807 +9808 +9809 +9810 +9811 +9812 +9813 +9814 +9815 +9816 +9817 +9818 +9819 +9820 +9821 +9822 +9823 +9824 +9825 +9826 +9827 +9828 +9829 +9830 +9831 +9832 +9833 +9834 +9835 +9836 +9837 +9838 +9839 +9840 +9841 +9842 +9843 +9844 +9845 +9846 +9847 +9848 +9849 +9850 +9851 +9852 +9853 +9854 +9855 +9856 +9857 +9858 +9859 +9860 +9861 +9862 +9863 +9864 +9865 +9866 +9867 +9868 +9869 +9870 +9871 +9872 +9873 +9874 +9875 +9876 +9877 +9878 +9879 +9880 +9881 +9882 +9883 +9884 +9885 +9886 +9887 +9888 +9889 +9890 +9891 +9892 +9893 +9894 +9895 +9896 +9897 +9898 +9899 +9900 +9901 +9902 +9903 +9904 +9905 +9906 +9907 +9908 +9909 +9910 +9911 +9912 +9913 +9914 +9915 +9916 +9917 +9918 +9919 +9920 +9921 +9922 +9923 +9924 +9925 +9926 +9927 +9928 +9929 +9930 +9931 +9932 +9933 +9934 +9935 +9936 +9937 +9938 +9939 +9940 +9941 +9942 +9943 +9944 +9945 +9946 +9947 +9948 +9949 +9950 +9951 +9952 +9953 +9954 +9955 +9956 +9957 +9958 +9959 +9960 +9961 +9962 +9963 +9964 +9965 +9966 +9967 +9968 +9969 +9970 +9971 +9972 +9973 +9974 +9975 +9976 +9977 +9978 +9979 +9980 +9981 +9982 +9983 +9984 +9985 +9986 +9987 +9988 +9989 +9990 +9991 +9992 +9993 +9994 +9995 +9996 +9997 +9998 +9999 +10000 +10001 +10002 +10003 +10004 +10005 +10006 +10007 +10008 +10009 +10010 +10011 +10012 +10013 +10014 +10015 +10016 +10017 +10018 +10019 +10020 +10021 +10022 +10023 +10024 +10025 +10026 +10027 +10028 +10029 +10030 +10031 +10032 +10033 +10034 +10035 +10036 +10037 +10038 +10039 +10040 +10041 +10042 +10043 +10044 +10045 +10046 +10047 +10048 +10049 +10050 +10051 +10052 +10053 +10054 +10055 +10056 +10057 +10058 +10059 +10060 +10061 +10062 +10063 +10064 +10065 +10066 +10067 +10068 +10069 +10070 +10071 +10072 +10073 +10074 +10075 +10076 +10077 +10078 +10079 +10080 +10081 +10082 +10083 +10084 +10085 +10086 +10087 +10088 +10089 +10090 +10091 +10092 +10093 +10094 +10095 +10096 +10097 +10098 +10099 +10100 +10101 +10102 +10103 +10104 +10105 +10106 +10107 +10108 +10109 +10110 +10111 +10112 +10113 +10114 +10115 +10116 +10117 +10118 +10119 +10120 +10121 +10122 +10123 +10124 +10125 +10126 +10127 +10128 +10129 +10130 +10131 +10132 +10133 +10134 +10135 +10136 +10137 +10138 +10139 +10140 +10141 +10142 +10143 +10144 +10145 +10146 +10147 +10148 +10149 +10150 +10151 +10152 +10153 +10154 +10155 +10156 +10157 +10158 +10159 +10160 +10161 +10162 +10163 +10164 +10165 +10166 +10167 +10168 +10169 +10170 +10171 +10172 +10173 +10174 +10175 +10176 +10177 +10178 +10179 +10180 +10181 +10182 +10183 +10184 +10185 +10186 +10187 +10188 +10189 +10190 +10191 +10192 +10193 +10194 +10195 +10196 +10197 +10198 +10199 +10200 +10201 +10202 +10203 +10204 +10205 +10206 +10207 +10208 +10209 +10210 +10211 +10212 +10213 +10214 +10215 +10216 +10217 +10218 +10219 +10220 +10221 +10222 +10223 +10224 +10225 +10226 +10227 +10228 +10229 +10230 +10231 +10232 +10233 +10234 +10235 +10236 +10237 +10238 +10239 +10240 +10241 +10242 +10243 +10244 +10245 +10246 +10247 +10248 +10249 +10250 +10251 +10252 +10253 +10254 +10255 +10256 +10257 +10258 +10259 +10260 +10261 +10262 +10263 +10264 +10265 +10266 +10267 +10268 +10269 +10270 +10271 +10272 +10273 +10274 +10275 +10276 +10277 +10278 +10279 +10280 +10281 +10282 +10283 +10284 +10285 +10286 +10287 +10288 +10289 +10290 +10291 +10292 +10293 +10294 +10295 +10296 +10297 +10298 +10299 +10300 +10301 +10302 +10303 +10304 +10305 +10306 +10307 +10308 +10309 +10310 +10311 +10312 +10313 +10314 +10315 +10316 +10317 +10318 +10319 +10320 +10321 +10322 +10323 +10324 +10325 +10326 +10327 +10328 +10329 +10330 +10331 +10332 +10333 +10334 +10335 +10336 +10337 +10338 +10339 +10340 +10341 +10342 +10343 +10344 +10345 +10346 +10347 +10348 +10349 +10350 +10351 +10352 +10353 +10354 +10355 +10356 +10357 +10358 +10359 +10360 +10361 +10362 +10363 +10364 +10365 +10366 +10367 +10368 +10369 +10370 +10371 +10372 +10373 +10374 +10375 +10376 +10377 +10378 +10379 +10380 +10381 +10382 +10383 +10384 +10385 +10386 +10387 +10388 +10389 +10390 +10391 +10392 +10393 +10394 +10395 +10396 +10397 +10398 +10399 +10400 +10401 +10402 +10403 +10404 +10405 +10406 +10407 +10408 +10409 +10410 +10411 +10412 +10413 +10414 +10415 +10416 +10417 +10418 +10419 +10420 +10421 +10422 +10423 +10424 +10425 +10426 +10427 +10428 +10429 +10430 +10431 +10432 +10433 +10434 +10435 +10436 +10437 +10438 +10439 +10440 +10441 +10442 +10443 +10444 +10445 +10446 +10447 +10448 +10449 +10450 +10451 +10452 +10453 +10454 +10455 +10456 +10457 +10458 +10459 +10460 +10461 +10462 +10463 +10464 +10465 +10466 +10467 +10468 +10469 +10470 +10471 +10472 +10473 +10474 +10475 +10476 +10477 +10478 +10479 +10480 +10481 +10482 +10483 +10484 +10485 +10486 +10487 +10488 +10489 +10490 +10491 +10492 +10493 +10494 +10495 +10496 +10497 +10498 +10499 +10500 +10501 +10502 +10503 +10504 +10505 +10506 +10507 +10508 +10509 +10510 +10511 +10512 +10513 +10514 +10515 +10516 +10517 +10518 +10519 +10520 +10521 +10522 +10523 +10524 +10525 +10526 +10527 +10528 +10529 +10530 +10531 +10532 +10533 +10534 +10535 +10536 +10537 +10538 +10539 +10540 +10541 +10542 +10543 +10544 +10545 +10546 +10547 +10548 +10549 +10550 +10551 +10552 +10553 +10554 +10555 +10556 +10557 +10558 +10559 +10560 +10561 +10562 +10563 +10564 +10565 +10566 +10567 +10568 +10569 +10570 +10571 +10572 +10573 +10574 +10575 +10576 +10577 +10578 +10579 +10580 +10581 +10582 +10583 +10584 +10585 +10586 +10587 +10588 +10589 +10590 +10591 +10592 +10593 +10594 +10595 +10596 +10597 +10598 +10599 +10600 +10601 +10602 +10603 +10604 +10605 +10606 +10607 +10608 +10609 +10610 +10611 +10612 +10613 +10614 +10615 +10616 +10617 +10618 +10619 +10620 +10621 +10622 +10623 +10624 +10625 +10626 +10627 +10628 +10629 +10630 +10631 +10632 +10633 +10634 +10635 +10636 +10637 +10638 +10639 +10640 +10641 +10642 +10643 +10644 +10645 +10646 +10647 +10648 +10649 +10650 +10651 +10652 +10653 +10654 +10655 +10656 +10657 +10658 +10659 +10660 +10661 +10662 +10663 +10664 +10665 +10666 +10667 +10668 +10669 +10670 +10671 +10672 +10673 +10674 +10675 +10676 +10677 +10678 +10679 +10680 +10681 +10682 +10683 +10684 +10685 +10686 +10687 +10688 +10689 +10690 +10691 +10692 +10693 +10694 +10695 +10696 +10697 +10698 +10699 +10700 +10701 +10702 +10703 +10704 +10705 +10706 +10707 +10708 +10709 +10710 +10711 +10712 +10713 +10714 +10715 +10716 +10717 +10718 +10719 +10720 +10721 +10722 +10723 +10724 +10725 +10726 +10727 +10728 +10729 +10730 +10731 +10732 +10733 +10734 +10735 +10736 +10737 +10738 +10739 +10740 +10741 +10742 +10743 +10744 +10745 +10746 +10747 +10748 +10749 +10750 +10751 +10752 +10753 +10754 +10755 +10756 +10757 +10758 +10759 +10760 +10761 +10762 +10763 +10764 +10765 +10766 +10767 +10768 +10769 +10770 +10771 +10772 +10773 +10774 +10775 +10776 +10777 +10778 +10779 +10780 +10781 +10782 +10783 +10784 +10785 +10786 +10787 +10788 +10789 +10790 +10791 +10792 +10793 +10794 +10795 +10796 +10797 +10798 +10799 +10800 +10801 +10802 +10803 +10804 +10805 +10806 +10807 +10808 +10809 +10810 +10811 +10812 +10813 +10814 +10815 +10816 +10817 +10818 +10819 +10820 +10821 +10822 +10823 +10824 +10825 +10826 +10827 +10828 +10829 +10830 +10831 +10832 +10833 +10834 +10835 +10836 +10837 +10838 +10839 +10840 +10841 +10842 +10843 +10844 +10845 +10846 +10847 +10848 +10849 +10850 +10851 +10852 +10853 +10854 +10855 +10856 +10857 +10858 +10859 +10860 +10861 +10862 +10863 +10864 +10865 +10866 +10867 +10868 +10869 +10870 +10871 +10872 +10873 +10874 +10875 +10876 +10877 +10878 +10879 +10880 +10881 +10882 +10883 +10884 +10885 +10886 +10887 +10888 +10889 +10890 +10891 +10892 +10893 +10894 +10895 +10896 +10897 +10898 +10899 +10900 +10901 +10902 +10903 +10904 +10905 +10906 +10907 +10908 +10909 +10910 +10911 +10912 +10913 +10914 +10915 +10916 +10917 +10918 +10919 +10920 +10921 +10922 +10923 +10924 +10925 +10926 +10927 +10928 +10929 +10930 +10931 +10932 +10933 +10934 +10935 +10936 +10937 +10938 +10939 +10940 +10941 +10942 +10943 +10944 +10945 +10946 +10947 +10948 +10949 +10950 +10951 +10952 +10953 +10954 +10955 +10956 +10957 +10958 +10959 +10960 +10961 +10962 +10963 +10964 +10965 +10966 +10967 +10968 +10969 +10970 +10971 +10972 +10973 +10974 +10975 +10976 +10977 +10978 +10979 +10980 +10981 +10982 +10983 +10984 +10985 +10986 +10987 +10988 +10989 +10990 +10991 +10992 +10993 +10994 +10995 +10996 +10997 +10998 +10999 +11000 +11001 +11002 +11003 +11004 +11005 +11006 +11007 +11008 +11009 +11010 +11011 +11012 +11013 +11014 +11015 +11016 +11017 +11018 +11019 +11020 +11021 +11022 +11023 +11024 +11025 +11026 +11027 +11028 +11029 +11030 +11031 +11032 +11033 +11034 +11035 +11036 +11037 +11038 +11039 +11040 +11041 +11042 +11043 +11044 +11045 +11046 +11047 +11048 +11049 +11050 +11051 +11052 +11053 +11054 +11055 +11056 +11057 +11058 +11059 +11060 +11061 +11062 +11063 +11064 +11065 +11066 +11067 +11068 +11069 +11070 +11071 +11072 +11073 +11074 +11075 +11076 +11077 +11078 +11079 +11080 +11081 +11082 +11083 +11084 +11085 +11086 +11087 +11088 +11089 +11090 +11091 +11092 +11093 +11094 +11095 +11096 +11097 +11098 +11099 +11100 +11101 +11102 +11103 +11104 +11105 +11106 +11107 +11108 +11109 +11110 +11111 +11112 +11113 +11114 +11115 +11116 +11117 +11118 +11119 +11120 +11121 +11122 +11123 +11124 +11125 +11126 +11127 +11128 +11129 +11130 +11131 +11132 +11133 +11134 +11135 +11136 +11137 +11138 +11139 +11140 +11141 +11142 +11143 +11144 +11145 +11146 +11147 +11148 +11149 +11150 +11151 +11152 +11153 +11154 +11155 +11156 +11157 +11158 +11159 +11160 +11161 +11162 +11163 +11164 +11165 +11166 +11167 +11168 +11169 +11170 +11171 +11172 +11173 +11174 +11175 +11176 +11177 +11178 +11179 +11180 +11181 +11182 +11183 +11184 +11185 +11186 +11187 +11188 +11189 +11190 +11191 +11192 +11193 +11194 +11195 +11196 +11197 +11198 +11199 +11200 +11201 +11202 +11203 +11204 +11205 +11206 +11207 +11208 +11209 +11210 +11211 +11212 +11213 +11214 +11215 +11216 +11217 +11218 +11219 +11220 +11221 +11222 +11223 +11224 +11225 +11226 +11227 +11228 +11229 +11230 +11231 +11232 +11233 +11234 +11235 +11236 +11237 +11238 +11239 +11240 +11241 +11242 +11243 +11244 +11245 +11246 +11247 +11248 +11249 +11250 +11251 +11252 +11253 +11254 +11255 +11256 +11257 +11258 +11259 +11260 +11261 +11262 +11263 +11264 +11265 +11266 +11267 +11268 +11269 +11270 +11271 +11272 +11273 +11274 +11275 +11276 +11277 +11278 +11279 +11280 +11281 +11282 +11283 +11284 +11285 +11286 +11287 +11288 +11289 +11290 +11291 +11292 +11293 +11294 +11295 +11296 +11297 +11298 +11299 +11300 +11301 +11302 +11303 +11304 +11305 +11306 +11307 +11308 +11309 +11310 +11311 +11312 +11313 +11314 +11315 +11316 +11317 +11318 +11319 +11320 +11321 +11322 +11323 +11324 +11325 +11326 +11327 +11328 +11329 +11330 +11331 +11332 +11333 +11334 +11335 +11336 +11337 +11338 +11339 +11340 +11341 +11342 +11343 +11344 +11345 +11346 +11347 +11348 +11349 +11350 +11351 +11352 +11353 +11354 +11355 +11356 +11357 +11358 +11359 +11360 +11361 +11362 +11363 +11364 +11365 +11366 +11367 +11368 +11369 +11370 +11371 +11372 +11373 +11374 +11375 +11376 +11377 +11378 +11379 +11380 +11381 +11382 +11383 +11384 +11385 +11386 +11387 +11388 +11389 +11390 +11391 +11392 +11393 +11394 +11395 +11396 +11397 +11398 +11399 +11400 +11401 +11402 +11403 +11404 +11405 +11406 +11407 +11408 +11409 +11410 +11411 +11412 +11413 +11414 +11415 +11416 +11417 +11418 +11419 +11420 +11421 +11422 +11423 +11424 +11425 +11426 +11427 +11428 +11429 +11430 +11431 +11432 +11433 +11434 +11435 +11436 +11437 +11438 +11439 +11440 +11441 +11442 +11443 +11444 +11445 +11446 +11447 +11448 +11449 +11450 +11451 +11452 +11453 +11454 +11455 +11456 +11457 +11458 +11459 +11460 +11461 +11462 +11463 +11464 +11465 +11466 +11467 +11468 +11469 +11470 +11471 +11472 +11473 +11474 +11475 +11476 +11477 +11478 +11479 +11480 +11481 +11482 +11483 +11484 +11485 +11486 +11487 +11488 +11489 +11490 +11491 +11492 +11493 +11494 +11495 +11496 +11497 +11498 +11499 +11500 +11501 +11502 +11503 +11504 +11505 +11506 +11507 +11508 +11509 +11510 +11511 +11512 +11513 +11514 +11515 +11516 +11517 +11518 +11519 +11520 +11521 +11522 +11523 +11524 +11525 +11526 +11527 +11528 +11529 +11530 +11531 +11532 +11533 +11534 +11535 +11536 +11537 +11538 +11539 +11540 +11541 +11542 +11543 +11544 +11545 +11546 +11547 +11548 +11549 +11550 +11551 +11552 +11553 +11554 +11555 +11556 +11557 +11558 +11559 +11560 +11561 +11562 +11563 +11564 +11565 +11566 +11567 +11568 +11569 +11570 +11571 +11572 +11573 +11574 +11575 +11576 +11577 +11578 +11579 +11580 +11581 +11582 +11583 +11584 +11585 +11586 +11587 +11588 +11589 +11590 +11591 +11592 +11593 +11594 +11595 +11596 +11597 +11598 +11599 +11600 +11601 +11602 +11603 +11604 +11605 +11606 +11607 +11608 +11609 +11610 +11611 +11612 +11613 +11614 +11615 +11616 +11617 +11618 +11619 +11620 +11621 +11622 +11623 +11624 +11625 +11626 +11627 +11628 +11629 +11630 +11631 +11632 +11633 +11634 +11635 +11636 +11637 +11638 +11639 +11640 +11641 +11642 +11643 +11644 +11645 +11646 +11647 +11648 +11649 +11650 +11651 +11652 +11653 +11654 +11655 +11656 +11657 +11658 +11659 +11660 +11661 +11662 +11663 +11664 +11665 +11666 +11667 +11668 +11669 +11670 +11671 +11672 +11673 +11674 +11675 +11676 +11677 +11678 +11679 +11680 +11681 +11682 +11683 +11684 +11685 +11686 +11687 +11688 +11689 +11690 +11691 +11692 +11693 +11694 +11695 +11696 +11697 +11698 +11699 +11700 +11701 +11702 +11703 +11704 +11705 +11706 +11707 +11708 +11709 +11710 +11711 +11712 +11713 +11714 +11715 +11716 +11717 +11718 +11719 +11720 +11721 +11722 +11723 +11724 +11725 +11726 +11727 +11728 +11729 +11730 +11731 +11732 +11733 +11734 +11735 +11736 +11737 +11738 +11739 +11740 +11741 +11742 +11743 +11744 +11745 +11746 +11747 +11748 +11749 +11750 +11751 +11752 +11753 +11754 +11755 +11756 +11757 +11758 +11759 +11760 +11761 +11762 +11763 +11764 +11765 +11766 +11767 +11768 +11769 +11770 +11771 +11772 +11773 +11774 +11775 +11776 +11777 +11778 +11779 +11780 +11781 +11782 +11783 +11784 +11785 +11786 +11787 +11788 +11789 +11790 +11791 +11792 +11793 +11794 +11795 +11796 +11797 +11798 +11799 +11800 +11801 +11802 +11803 +11804 +11805 +11806 +11807 +11808 +11809 +11810 +11811 +11812 +11813 +11814 +11815 +11816 +11817 +11818 +11819 +11820 +11821 +11822 +11823 +11824 +11825 +11826 +11827 +11828 +11829 +11830 +11831 +11832 +11833 +11834 +11835 +11836 +11837 +11838 +11839 +11840 +11841 +11842 +11843 +11844 +11845 +11846 +11847 +11848 +11849 +11850 +11851 +11852 +11853 +11854 +11855 +11856 +11857 +11858 +11859 +11860 +11861 +11862 +11863 +11864 +11865 +11866 +11867 +11868 +11869 +11870 +11871 +11872 +11873 +11874 +11875 +11876 +11877 +11878 +11879 +11880 +11881 +11882 +11883 +11884 +11885 +11886 +11887 +11888 +11889 +11890 +11891 +11892 +11893 +11894 +11895 +11896 +11897 +11898 +11899 +11900 +11901 +11902 +11903 +11904 +11905 +11906 +11907 +11908 +11909 +11910 +11911 +11912 +11913 +11914 +11915 +11916 +11917 +11918 +11919 +11920 +11921 +11922 +11923 +11924 +11925 +11926 +11927 +11928 +11929 +11930 +11931 +11932 +11933 +11934 +11935 +11936 +11937 +11938 +11939 +11940 +11941 +11942 +11943 +11944 +11945 +11946 +11947 +11948 +11949 +11950 +11951 +11952 +11953 +11954 +11955 +11956 +11957 +11958 +11959 +11960 +11961 +11962 +11963 +11964 +11965 +11966 +11967 +11968 +11969 +11970 +11971 +11972 +11973 +11974 +11975 +11976 +11977 +11978 +11979 +11980 +11981 +11982 +11983 +11984 +11985 +11986 +11987 +11988 +11989 +11990 +11991 +11992 +11993 +11994 +11995 +11996 +11997 +11998 +11999 +12000 +12001 +12002 +12003 +12004 +12005 +12006 +12007 +12008 +12009 +12010 +12011 +12012 +12013 +12014 +12015 +12016 +12017 +12018 +12019 +12020 +12021 +12022 +12023 +12024 +12025 +12026 +12027 +12028 +12029 +12030 +12031 +12032 +12033 +12034 +12035 +12036 +12037 +12038 +12039 +12040 +12041 +12042 +12043 +12044 +12045 +12046 +12047 +12048 +12049 +12050 +12051 +12052 +12053 +12054 +12055 +12056 +12057 +12058 +12059 +12060 +12061 +12062 +12063 +12064 +12065 +12066 +12067 +12068 +12069 +12070 +12071 +12072 +12073 +12074 +12075 +12076 +12077 +12078 +12079 +12080 +12081 +12082 +12083 +12084 +12085 +12086 +12087 +12088 +12089 +12090 +12091 +12092 +12093 +12094 +12095 +12096 +12097 +12098 +12099 +12100 +12101 +12102 +12103 +12104 +12105 +12106 +12107 +12108 +12109 +12110 +12111 +12112 +12113 +12114 +12115 +12116 +12117 +12118 +12119 +12120 +12121 +12122 +12123 +12124 +12125 +12126 +12127 +12128 +12129 +12130 +12131 +12132 +12133 +12134 +12135 +12136 +12137 +12138 +12139 +12140 +12141 +12142 +12143 +12144 +12145 +12146 +12147 +12148 +12149 +12150 +12151 +12152 +12153 +12154 +12155 +12156 +12157 +12158 +12159 +12160 +12161 +12162 +12163 +12164 +12165 +12166 +12167 +12168 +12169 +12170 +12171 +12172 +12173 +12174 +12175 +12176 +12177 +12178 +12179 +12180 +12181 +12182 +12183 +12184 +12185 +12186 +12187 +12188 +12189 +12190 +12191 +12192 +12193 +12194 +12195 +12196 +12197 +12198 +12199 +12200 +12201 +12202 +12203 +12204 +12205 +12206 +12207 +12208 +12209 +12210 +12211 +12212 +12213 +12214 +12215 +12216 +12217 +12218 +12219 +12220 +12221 +12222 +12223 +12224 +12225 +12226 +12227 +12228 +12229 +12230 +12231 +12232 +12233 +12234 +12235 +12236 +12237 +12238 +12239 +12240 +12241 +12242 +12243 +12244 +12245 +12246 +12247 +12248 +12249 +12250 +12251 +12252 +12253 +12254 +12255 +12256 +12257 +12258 +12259 +12260 +12261 +12262 +12263 +12264 +12265 +12266 +12267 +12268 +12269 +12270 +12271 +12272 +12273 +12274 +12275 +12276 +12277 +12278 +12279 +12280 +12281 +12282 +12283 +12284 +12285 +12286 +12287 +12288 +12289 +12290 +12291 +12292 +12293 +12294 +12295 +12296 +12297 +12298 +12299 +12300 +12301 +12302 +12303 +12304 +12305 +12306 +12307 +12308 +12309 +12310 +12311 +12312 +12313 +12314 +12315 +12316 +12317 +12318 +12319 +12320 +12321 +12322 +12323 +12324 +12325 +12326 +12327 +12328 +12329 +12330 +12331 +12332 +12333 +12334 +12335 +12336 +12337 +12338 +12339 +12340 +12341 +12342 +12343 +12344 +12345 +12346 +12347 +12348 +12349 +12350 +12351 +12352 +12353 +12354 +12355 +12356 +12357 +12358 +12359 +12360 +12361 +12362 +12363 +12364 +12365 +12366 +12367 +12368 +12369 +12370 +12371 +12372 +12373 +12374 +12375 +12376 +12377 +12378 +12379 +12380 +12381 +12382 +12383 +12384 +12385 +12386 +12387 +12388 +12389 +12390 +12391 +12392 +12393 +12394 +12395 +12396 +12397 +12398 +12399 +12400 +12401 +12402 +12403 +12404 +12405 +12406 +12407 +12408 +12409 +12410 +12411 +12412 +12413 +12414 +12415 +12416 +12417 +12418 +12419 +12420 +12421 +12422 +12423 +12424 +12425 +12426 +12427 +12428 +12429 +12430 +12431 +12432 +12433 +12434 +12435 +12436 +12437 +12438 +12439 +12440 +12441 +12442 +12443 +12444 +12445 +12446 +12447 +12448 +12449 +12450 +12451 +12452 +12453 +12454 +12455 +12456 +12457 +12458 +12459 +12460 +12461 +12462 +12463 +12464 +12465 +12466 +12467 +12468 +12469 +12470 +12471 +12472 +12473 +12474 +12475 +12476 +12477 +12478 +12479 +12480 +12481 +12482 +12483 +12484 +12485 +12486 +12487 +12488 +12489 +12490 +12491 +12492 +12493 +12494 +12495 +12496 +12497 +12498 +12499 +12500 +12501 +12502 +12503 +12504 +12505 +12506 +12507 +12508 +12509 +12510 +12511 +12512 +12513 +12514 +12515 +12516 +12517 +12518 +12519 +12520 +12521 +12522 +12523 +12524 +12525 +12526 +12527 +12528 +12529 +12530 +12531 +12532 +12533 +12534 +12535 +12536 +12537 +12538 +12539 +12540 +12541 +12542 +12543 +12544 +12545 +12546 +12547 +12548 +12549 +12550 +12551 +12552 +12553 +12554 +12555 +12556 +12557 +12558 +12559 +12560 +12561 +12562 +12563 +12564 +12565 +12566 +12567 +12568 +12569 +12570 +12571 +12572 +12573 +12574 +12575 +12576 +12577 +12578 +12579 +12580 +12581 +12582 +12583 +12584 +12585 +12586 +12587 +12588 +12589 +12590 +12591 +12592 +12593 +12594 +12595 +12596 +12597 +12598 +12599 +12600 +12601 +12602 +12603 +12604 +12605 +12606 +12607 +12608 +12609 +12610 +12611 +12612 +12613 +12614 +12615 +12616 +12617 +12618 +12619 +12620 +12621 +12622 +12623 +12624 +12625 +12626 +12627 +12628 +12629 +12630 +12631 +12632 +12633 +12634 +12635 +12636 +12637 +12638 +12639 +12640 +12641 +12642 +12643 +12644 +12645 +12646 +12647 +12648 +12649 +12650 +12651 +12652 +12653 +12654 +12655 +12656 +12657 +12658 +12659 +12660 +12661 +12662 +12663 +12664 +12665 +12666 +12667 +12668 +12669 +12670 +12671 +12672 +12673 +12674 +12675 +12676 +12677 +12678 +12679 +12680 +12681 +12682 +12683 +12684 +12685 +12686 +12687 +12688 +12689 +12690 +12691 +12692 +12693 +12694 +12695 +12696 +12697 +12698 +12699 +12700 +12701 +12702 +12703 +12704 +12705 +12706 +12707 +12708 +12709 +12710 +12711 +12712 +12713 +12714 +12715 +12716 +12717 +12718 +12719 +12720 +12721 +12722 +12723 +12724 +12725 +12726 +12727 +12728 +12729 +12730 +12731 +12732 +12733 +12734 +12735 +12736 +12737 +12738 +12739 +12740 +12741 +12742 +12743 +12744 +12745 +12746 +12747 +12748 +12749 +12750 +12751 +12752 +12753 +12754 +12755 +12756 +12757 +12758 +12759 +12760 +12761 +12762 +12763 +12764 +12765 +12766 +12767 +12768 +12769 +12770 +12771 +12772 +12773 +12774 +12775 +12776 +12777 +12778 +12779 +12780 +12781 +12782 +12783 +12784 +12785 +12786 +12787 +12788 +12789 +12790 +12791 +12792 +12793 +12794 +12795 +12796 +12797 +12798 +12799 +12800 +12801 +12802 +12803 +12804 +12805 +12806 +12807 +12808 +12809 +12810 +12811 +12812 +12813 +12814 +12815 +12816 +12817 +12818 +12819 +12820 +12821 +12822 +12823 +12824 +12825 +12826 +12827 +12828 +12829 +12830 +12831 +12832 +12833 +12834 +12835 +12836 +12837 +12838 +12839 +12840 +12841 +12842 +12843 +12844 +12845 +12846 +12847 +12848 +12849 +12850 +12851 +12852 +12853 +12854 +12855 +12856 +12857 +12858 +12859 +12860 +12861 +12862 +12863 +12864 +12865 +12866 +12867 +12868 +12869 +12870 +12871 +12872 +12873 +12874 +12875 +12876 +12877 +12878 +12879 +12880 +12881 +12882 +12883 +12884 +12885 +12886 +12887 +12888 +12889 +12890 +12891 +12892 +12893 +12894 +12895 +12896 +12897 +12898 +12899 +12900 +12901 +12902 +12903 +12904 +12905 +12906 +12907 +12908 +12909 +12910 +12911 +12912 +12913 +12914 +12915 +12916 +12917 +12918 +12919 +12920 +12921 +12922 +12923 +12924 +12925 +12926 +12927 +12928 +12929 +12930 +12931 +12932 +12933 +12934 +12935 +12936 +12937 +12938 +12939 +12940 +12941 +12942 +12943 +12944 +12945 +12946 +12947 +12948 +12949 +12950 +12951 +12952 +12953 +12954 +12955 +12956 +12957 +12958 +12959 +12960 +12961 +12962 +12963 +12964 +12965 +12966 +12967 +12968 +12969 +12970 +12971 +12972 +12973 +12974 +12975 +12976 +12977 +12978 +12979 +12980 +12981 +12982 +12983 +12984 +12985 +12986 +12987 +12988 +12989 +12990 +12991 +12992 +12993 +12994 +12995 +12996 +12997 +12998 +12999 +13000 +13001 +13002 +13003 +13004 +13005 +13006 +13007 +13008 +13009 +13010 +13011 +13012 +13013 +13014 +13015 +13016 +13017 +13018 +13019 +13020 +13021 +13022 +13023 +13024 +13025 +13026 +13027 +13028 +13029 +13030 +13031 +13032 +13033 +13034 +13035 +13036 +13037 +13038 +13039 +13040 +13041 +13042 +13043 +13044 +13045 +13046 +13047 +13048 +13049 +13050 +13051 +13052 +13053 +13054 +13055 +13056 +13057 +13058 +13059 +13060 +13061 +13062 +13063 +13064 +13065 +13066 +13067 +13068 +13069 +13070 +13071 +13072 +13073 +13074 +13075 +13076 +13077 +13078 +13079 +13080 +13081 +13082 +13083 +13084 +13085 +13086 +13087 +13088 +13089 +13090 +13091 +13092 +13093 +13094 +13095 +13096 +13097 +13098 +13099 +13100 +13101 +13102 +13103 +13104 +13105 +13106 +13107 +13108 +13109 +13110 +13111 +13112 +13113 +13114 +13115 +13116 +13117 +13118 +13119 +13120 +13121 +13122 +13123 +13124 +13125 +13126 +13127 +13128 +13129 +13130 +13131 +13132 +13133 +13134 +13135 +13136 +13137 +13138 +13139 +13140 +13141 +13142 +13143 +13144 +13145 +13146 +13147 +13148 +13149 +13150 +13151 +13152 +13153 +13154 +13155 +13156 +13157 +13158 +13159 +13160 +13161 +13162 +13163 +13164 +13165 +13166 +13167 +13168 +13169 +13170 +13171 +13172 +13173 +13174 +13175 +13176 +13177 +13178 +13179 +13180 +13181 +13182 +13183 +13184 +13185 +13186 +13187 +13188 +13189 +13190 +13191 +13192 +13193 +13194 +13195 +13196 +13197 +13198 +13199 +13200 +13201 +13202 +13203 +13204 +13205 +13206 +13207 +13208 +13209 +13210 +13211 +13212 +13213 +13214 +13215 +13216 +13217 +13218 +13219 +13220 +13221 +13222 +13223 +13224 +13225 +13226 +13227 +13228 +13229 +13230 +13231 +13232 +13233 +13234 +13235 +13236 +13237 +13238 +13239 +13240 +13241 +13242 +13243 +13244 +13245 +13246 +13247 +13248 +13249 +13250 +13251 +13252 +13253 +13254 +13255 +13256 +13257 +13258 +13259 +13260 +13261 +13262 +13263 +13264 +13265 +13266 +13267 +13268 +13269 +13270 +13271 +13272 +13273 +13274 +13275 +13276 +13277 +13278 +13279 +13280 +13281 +13282 +13283 +13284 +13285 +13286 +13287 +13288 +13289 +13290 +13291 +13292 +13293 +13294 +13295 +13296 +13297 +13298 +13299 +13300 +13301 +13302 +13303 +13304 +13305 +13306 +13307 +13308 +13309 +13310 +13311 +13312 +13313 +13314 +13315 +13316 +13317 +13318 +13319 +13320 +13321 +13322 +13323 +13324 +13325 +13326 +13327 +13328 +13329 +13330 +13331 +13332 +13333 +13334 +13335 +13336 +13337 +13338 +13339 +13340 +13341 +13342 +13343 +13344 +13345 +13346 +13347 +13348 +13349 +13350 +13351 +13352 +13353 +13354 +13355 +13356 +13357 +13358 +13359 +13360 +13361 +13362 +13363 +13364 +13365 +13366 +13367 +13368 +13369 +13370 +13371 +13372 +13373 +13374 +13375 +13376 +13377 +13378 +13379 +13380 +13381 +13382 +13383 +13384 +13385 +13386 +13387 +13388 +13389 +13390 +13391 +13392 +13393 +13394 +13395 +13396 +13397 +13398 +13399 +13400 +13401 +13402 +13403 +13404 +13405 +13406 +13407 +13408 +13409 +13410 +13411 +13412 +13413 +13414 +13415 +13416 +13417 +13418 +13419 +13420 +13421 +13422 +13423 +13424 +13425 +13426 +13427 +13428 +13429 +13430 +13431 +13432 +13433 +13434 +13435 +13436 +13437 +13438 +13439 +13440 +13441 +13442 +13443 +13444 +13445 +13446 +13447 +13448 +13449 +13450 +13451 +13452 +13453 +13454 +13455 +13456 +13457 +13458 +13459 +13460 +13461 +13462 +13463 +13464 +13465 +13466 +13467 +13468 +13469 +13470 +13471 +13472 +13473 +13474 +13475 +13476 +13477 +13478 +13479 +13480 +13481 +13482 +13483 +13484 +13485 +13486 +13487 +13488 +13489 +13490 +13491 +13492 +13493 +13494 +13495 +13496 +13497 +13498 +13499 +13500 +13501 +13502 +13503 +13504 +13505 +13506 +13507 +13508 +13509 +13510 +13511 +13512 +13513 +13514 +13515 +13516 +13517 +13518 +13519 +13520 +13521 +13522 +13523 +13524 +13525 +13526 +13527 +13528 +13529 +13530 +13531 +13532 +13533 +13534 +13535 +13536 +13537 +13538 +13539 +13540 +13541 +13542 +13543 +13544 +13545 +13546 +13547 +13548 +13549 +13550 +13551 +13552 +13553 +13554 +13555 +13556 +13557 +13558 +13559 +13560 +13561 +13562 +13563 +13564 +13565 +13566 +13567 +13568 +13569 +13570 +13571 +13572 +13573 +13574 +13575 +13576 +13577 +13578 +13579 +13580 +13581 +13582 +13583 +13584 +13585 +13586 +13587 +13588 +13589 +13590 +13591 +13592 +13593 +13594 +13595 +13596 +13597 +13598 +13599 +13600 +13601 +13602 +13603 +13604 +13605 +13606 +13607 +13608 +13609 +13610 +13611 +13612 +13613 +13614 +13615 +13616 +13617 +13618 +13619 +13620 +13621 +13622 +13623 +13624 +13625 +13626 +13627 +13628 +13629 +13630 +13631 +13632 +13633 +13634 +13635 +13636 +13637 +13638 +13639 +13640 +13641 +13642 +13643 +13644 +13645 +13646 +13647 +13648 +13649 +13650 +13651 +13652 +13653 +13654 +13655 +13656 +13657 +13658 +13659 +13660 +13661 +13662 +13663 +13664 +13665 +13666 +13667 +13668 +13669 +13670 +13671 +13672 +13673 +13674 +13675 +13676 +13677 +13678 +13679 +13680 +13681 +13682 +13683 +13684 +13685 +13686 +13687 +13688 +13689 +13690 +13691 +13692 +13693 +13694 +13695 +13696 +13697 +13698 +13699 +13700 +13701 +13702 +13703 +13704 +13705 +13706 +13707 +13708 +13709 +13710 +13711 +13712 +13713 +13714 +13715 +13716 +13717 +13718 +13719 +13720 +13721 +13722 +13723 +13724 +13725 +13726 +13727 +13728 +13729 +13730 +13731 +13732 +13733 +13734 +13735 +13736 +13737 +13738 +13739 +13740 +13741 +13742 +13743 +13744 +13745 +13746 +13747 +13748 +13749 +13750 +13751 +13752 +13753 +13754 +13755 +13756 +13757 +13758 +13759 +13760 +13761 +13762 +13763 +13764 +13765 +13766 +13767 +13768 +13769 +13770 +13771 +13772 +13773 +13774 +13775 +13776 +13777 +13778 +13779 +13780 +13781 +13782 +13783 +13784 +13785 +13786 +13787 +13788 +13789 +13790 +13791 +13792 +13793 +13794 +13795 +13796 +13797 +13798 +13799 +13800 +13801 +13802 +13803 +13804 +13805 +13806 +13807 +13808 +13809 +13810 +13811 +13812 +13813 +13814 +13815 +13816 +13817 +13818 +13819 +13820 +13821 +13822 +13823 +13824 +13825 +13826 +13827 +13828 +13829 +13830 +13831 +13832 +13833 +13834 +13835 +13836 +13837 +13838 +13839 +13840 +13841 +13842 +13843 +13844 +13845 +13846 +13847 +13848 +13849 +13850 +13851 +13852 +13853 +13854 +13855 +13856 +13857 +13858 +13859 +13860 +13861 +13862 +13863 +13864 +13865 +13866 +13867 +13868 +13869 +13870 +13871 +13872 +13873 +13874 +13875 +13876 +13877 +13878 +13879 +13880 +13881 +13882 +13883 +13884 +13885 +13886 +13887 +13888 +13889 +13890 +13891 +13892 +13893 +13894 +13895 +13896 +13897 +13898 +13899 +13900 +13901 +13902 +13903 +13904 +13905 +13906 +13907 +13908 +13909 +13910 +13911 +13912 +13913 +13914 +13915 +13916 +13917 +13918 +13919 +13920 +13921 +13922 +13923 +13924 +13925 +13926 +13927 +13928 +13929 +13930 +13931 +13932 +13933 +13934 +13935 +13936 +13937 +13938 +13939 +13940 +13941 +13942 +13943 +13944 +13945 +13946 +13947 +13948 +13949 +13950 +13951 +13952 +13953 +13954 +13955 +13956 +13957 +13958 +13959 +13960 +13961 +13962 +13963 +13964 +13965 +13966 +13967 +13968 +13969 +13970 +13971 +13972 +13973 +13974 +13975 +13976 +13977 +13978 +13979 +13980 +13981 +13982 +13983 +13984 +13985 +13986 +13987 +13988 +13989 +13990 +13991 +13992 +13993 +13994 +13995 +13996 +13997 +13998 +13999 +14000 +14001 +14002 +14003 +14004 +14005 +14006 +14007 +14008 +14009 +14010 +14011 +14012 +14013 +14014 +14015 +14016 +14017 +14018 +14019 +14020 +14021 +14022 +14023 +14024 +14025 +14026 +14027 +14028 +14029 +14030 +14031 +14032 +14033 +14034 +14035 +14036 +14037 +14038 +14039 +14040 +14041 +14042 +14043 +14044 +14045 +14046 +14047 +14048 +14049 +14050 +14051 +14052 +14053 +14054 +14055 +14056 +14057 +14058 +14059 +14060 +14061 +14062 +14063 +14064 +14065 +14066 +14067 +14068 +14069 +14070 +14071 +14072 +14073 +14074 +14075 +14076 +14077 +14078 +14079 +14080 +14081 +14082 +14083 +14084 +14085 +14086 +14087 +14088 +14089 +14090 +14091 +14092 +14093 +14094 +14095 +14096 +14097 +14098 +14099 +14100 +14101 +14102 +14103 +14104 +14105 +14106 +14107 +14108 +14109 +14110 +14111 +14112 +14113 +14114 +14115 +14116 +14117 +14118 +14119 +14120 +14121 +14122 +14123 +14124 +14125 +14126 +14127 +14128 +14129 +14130 +14131 +14132 +14133 +14134 +14135 +14136 +14137 +14138 +14139 +14140 +14141 +14142 +14143 +14144 +14145 +14146 +14147 +14148 +14149 +14150 +14151 +14152 +14153 +14154 +14155 +14156 +14157 +14158 +14159 +14160 +14161 +14162 +14163 +14164 +14165 +14166 +14167 +14168 +14169 +14170 +14171 +14172 +14173 +14174 +14175 +14176 +14177 +14178 +14179 +14180 +14181 +14182 +14183 +14184 +14185 +14186 +14187 +14188 +14189 +14190 +14191 +14192 +14193 +14194 +14195 +14196 +14197 +14198 +14199 +14200 +14201 +14202 +14203 +14204 +14205 +14206 +14207 +14208 +14209 +14210 +14211 +14212 +14213 +14214 +14215 +14216 +14217 +14218 +14219 +14220 +14221 +14222 +14223 +14224 +14225 +14226 +14227 +14228 +14229 +14230 +14231 +14232 +14233 +14234 +14235 +14236 +14237 +14238 +14239 +14240 +14241 +14242 +14243 +14244 +14245 +14246 +14247 +14248 +14249 +14250 +14251 +14252 +14253 +14254 +14255 +14256 +14257 +14258 +14259 +14260 +14261 +14262 +14263 +14264 +14265 +14266 +14267 +14268 +14269 +14270 +14271 +14272 +14273 +14274 +14275 +14276 +14277 +14278 +14279 +14280 +14281 +14282 +14283 +14284 +14285 +14286 +14287 +14288 +14289 +14290 +14291 +14292 +14293 +14294 +14295 +14296 +14297 +14298 +14299 +14300 +14301 +14302 +14303 +14304 +14305 +14306 +14307 +14308 +14309 +14310 +14311 +14312 +14313 +14314 +14315 +14316 +14317 +14318 +14319 +14320 +14321 +14322 +14323 +14324 +14325 +14326 +14327 +14328 +14329 +14330 +14331 +14332 +14333 +14334 +14335 +14336 +14337 +14338 +14339 +14340 +14341 +14342 +14343 +14344 +14345 +14346 +14347 +14348 +14349 +14350 +14351 +14352 +14353 +14354 +14355 +14356 +14357 +14358 +14359 +14360 +14361 +14362 +14363 +14364 +14365 +14366 +14367 +14368 +14369 +14370 +14371 +14372 +14373 +14374 +14375 +14376 +14377 +14378 +14379 +14380 +14381 +14382 +14383 +14384 +14385 +14386 +14387 +14388 +14389 +14390 +14391 +14392 +14393 +14394 +14395 +14396 +14397 +14398 +14399 +14400 +14401 +14402 +14403 +14404 +14405 +14406 +14407 +14408 +14409 +14410 +14411 +14412 +14413 +14414 +14415 +14416 +14417 +14418 +14419 +14420 +14421 +14422 +14423 +14424 +14425 +14426 +14427 +14428 +14429 +14430 +14431 +14432 +14433 +14434 +14435 +14436 +14437 +14438 +14439 +14440 +14441 +14442 +14443 +14444 +14445 +14446 +14447 +14448 +14449 +14450 +14451 +14452 +14453 +14454 +14455 +14456 +14457 +14458 +14459 +14460 +14461 +14462 +14463 +14464 +14465 +14466 +14467 +14468 +14469 +14470 +14471 +14472 +14473 +14474 +14475 +14476 +14477 +14478 +14479 +14480 +14481 +14482 +14483 +14484 +14485 +14486 +14487 +14488 +14489 +14490 +14491 +14492 +14493 +14494 +14495 +14496 +14497 +14498 +14499 +14500 +14501 +14502 +14503 +14504 +14505 +14506 +14507 +14508 +14509 +14510 +14511 +14512 +14513 +14514 +14515 +14516 +14517 +14518 +14519 +14520 +14521 +14522 +14523 +14524 +14525 +14526 +14527 +14528 +14529 +14530 +14531 +14532 +14533 +14534 +14535 +14536 +14537 +14538 +14539 +14540 +14541 +14542 +14543 +14544 +14545 +14546 +14547 +14548 +14549 +14550 +14551 +14552 +14553 +14554 +14555 +14556 +14557 +14558 +14559 +14560 +14561 +14562 +14563 +14564 +14565 +14566 +14567 +14568 +14569 +14570 +14571 +14572 +14573 +14574 +14575 +14576 +14577 +14578 +14579 +14580 +14581 +14582 +14583 +14584 +14585 +14586 +14587 +14588 +14589 +14590 +14591 +14592 +14593 +14594 +14595 +14596 +14597 +14598 +14599 +14600 +14601 +14602 +14603 +14604 +14605 +14606 +14607 +14608 +14609 +14610 +14611 +14612 +14613 +14614 +14615 +14616 +14617 +14618 +14619 +14620 +14621 +14622 +14623 +14624 +14625 +14626 +14627 +14628 +14629 +14630 +14631 +14632 +14633 +14634 +14635 +14636 +14637 +14638 +14639 +14640 +14641 +14642 +14643 +14644 +14645 +14646 +14647 +14648 +14649 +14650 +14651 +14652 +14653 +14654 +14655 +14656 +14657 +14658 +14659 +14660 +14661 +14662 +14663 +14664 +14665 +14666 +14667 +14668 +14669 +14670 +14671 +14672 +14673 +14674 +14675 +14676 +14677 +14678 +14679 +14680 +14681 +14682 +14683 +14684 +14685 +14686 +14687 +14688 +14689 +14690 +14691 +14692 +14693 +14694 +14695 +14696 +14697 +14698 +14699 +14700 +14701 +14702 +14703 +14704 +14705 +14706 +14707 +14708 +14709 +14710 +14711 +14712 +14713 +14714 +14715 +14716 +14717 +14718 +14719 +14720 +14721 +14722 +14723 +14724 +14725 +14726 +14727 +14728 +14729 +14730 +14731 +14732 +14733 +14734 +14735 +14736 +14737 +14738 +14739 +14740 +14741 +14742 +14743 +14744 +14745 +14746 +14747 +14748 +14749 +14750 +14751 +14752 +14753 +14754 +14755 +14756 +14757 +14758 +14759 +14760 +14761 +14762 +14763 +14764 +14765 +14766 +14767 +14768 +14769 +14770 +14771 +14772 +14773 +14774 +14775 +14776 +14777 +14778 +14779 +14780 +14781 +14782 +14783 +14784 +14785 +14786 +14787 +14788 +14789 +14790 +14791 +14792 +14793 +14794 +14795 +14796 +14797 +14798 +14799 +14800 +14801 +14802 +14803 +14804 +14805 +14806 +14807 +14808 +14809 +14810 +14811 +14812 +14813 +14814 +14815 +14816 +14817 +14818 +14819 +14820 +14821 +14822 +14823 +14824 +14825 +14826 +14827 +14828 +14829 +14830 +14831 +14832 +14833 +14834 +14835 +14836 +14837 +14838 +14839 +14840 +14841 +14842 +14843 +14844 +14845 +14846 +14847 +14848 +14849 +14850 +14851 +14852 +14853 +14854 +14855 +14856 +14857 +14858 +14859 +14860 +14861 +14862 +14863 +14864 +14865 +14866 +14867 +14868 +14869 +14870 +14871 +14872 +14873 +14874 +14875 +14876 +14877 +14878 +14879 +14880 +14881 +14882 +14883 +14884 +14885 +14886 +14887 +14888 +14889 +14890 +14891 +14892 +14893 +14894 +14895 +14896 +14897 +14898 +14899 +14900 +14901 +14902 +14903 +14904 +14905 +14906 +14907 +14908 +14909 +14910 +14911 +14912 +14913 +14914 +14915 +14916 +14917 +14918 +14919 +14920 +14921 +14922 +14923 +14924 +14925 +14926 +14927 +14928 +14929 +14930 +14931 +14932 +14933 +14934 +14935 +14936 +14937 +14938 +14939 +14940 +14941 +14942 +14943 +14944 +14945 +14946 +14947 +14948 +14949 +14950 +14951 +14952 +14953 +14954 +14955 +14956 +14957 +14958 +14959 +14960 +14961 +14962 +14963 +14964 +14965 +14966 +14967 +14968 +14969 +14970 +14971 +14972 +14973 +14974 +14975 +14976 +14977 +14978 +14979 +14980 +14981 +14982 +14983 +14984 +14985 +14986 +14987 +14988 +14989 +14990 +14991 +14992 +14993 +14994 +14995 +14996 +14997 +14998 +14999 +15000 +15001 +15002 +15003 +15004 +15005 +15006 +15007 +15008 +15009 +15010 +15011 +15012 +15013 +15014 +15015 +15016 +15017 +15018 +15019 +15020 +15021 +15022 +15023 +15024 +15025 +15026 +15027 +15028 +15029 +15030 +15031 +15032 +15033 +15034 +15035 +15036 +15037 +15038 +15039 +15040 +15041 +15042 +15043 +15044 +15045 +15046 +15047 +15048 +15049 +15050 +15051 +15052 +15053 +15054 +15055 +15056 +15057 +15058 +15059 +15060 +15061 +15062 +15063 +15064 +15065 +15066 +15067 +15068 +15069 +15070 +15071 +15072 +15073 +15074 +15075 +15076 +15077 +15078 +15079 +15080 +15081 +15082 +15083 +15084 +15085 +15086 +15087 +15088 +15089 +15090 +15091 +15092 +15093 +15094 +15095 +15096 +15097 +15098 +15099 +15100 +15101 +15102 +15103 +15104 +15105 +15106 +15107 +15108 +15109 +15110 +15111 +15112 +15113 +15114 +15115 +15116 +15117 +15118 +15119 +15120 +15121 +15122 +15123 +15124 +15125 +15126 +15127 +15128 +15129 +15130 +15131 +15132 +15133 +15134 +15135 +15136 +15137 +15138 +15139 +15140 +15141 +15142 +15143 +15144 +15145 +15146 +15147 +15148 +15149 +15150 +15151 +15152 +15153 +15154 +15155 +15156 +15157 +15158 +15159 +15160 +15161 +15162 +15163 +15164 +15165 +15166 +15167 +15168 +15169 +15170 +15171 +15172 +15173 +15174 +15175 +15176 +15177 +15178 +15179 +15180 +15181 +15182 +15183 +15184 +15185 +15186 +15187 +15188 +15189 +15190 +15191 +15192 +15193 +15194 +15195 +15196 +15197 +15198 +15199 +15200 +15201 +15202 +15203 +15204 +15205 +15206 +15207 +15208 +15209 +15210 +15211 +15212 +15213 +15214 +15215 +15216 +15217 +15218 +15219 +15220 +15221 +15222 +15223 +15224 +15225 +15226 +15227 +15228 +15229 +15230 +15231 +15232 +15233 +15234 +15235 +15236 +15237 +15238 +15239 +15240 +15241 +15242 +15243 +15244 +15245 +15246 +15247 +15248 +15249 +15250 +15251 +15252 +15253 +15254 +15255 +15256 +15257 +15258 +15259 +15260 +15261 +15262 +15263 +15264 +15265 +15266 +15267 +15268 +15269 +15270 +15271 +15272 +15273 +15274 +15275 +15276 +15277 +15278 +15279 +15280 +15281 +15282 +15283 +15284 +15285 +15286 +15287 +15288 +15289 +15290 +15291 +15292 +15293 +15294 +15295 +15296 +15297 +15298 +15299 +15300 +15301 +15302 +15303 +15304 +15305 +15306 +15307 +15308 +15309 +15310 +15311 +15312 +15313 +15314 +15315 +15316 +15317 +15318 +15319 +15320 +15321 +15322 +15323 +15324 +15325 +15326 +15327 +15328 +15329 +15330 +15331 +15332 +15333 +15334 +15335 +15336 +15337 +15338 +15339 +15340 +15341 +15342 +15343 +15344 +15345 +15346 +15347 +15348 +15349 +15350 +15351 +15352 +15353 +15354 +15355 +15356 +15357 +15358 +15359 +15360 +15361 +15362 +15363 +15364 +15365 +15366 +15367 +15368 +15369 +15370 +15371 +15372 +15373 +15374 +15375 +15376 +15377 +15378 +15379 +15380 +15381 +15382 +15383 +15384 +15385 +15386 +15387 +15388 +15389 +15390 +15391 +15392 +15393 +15394 +15395 +15396 +15397 +15398 +15399 +15400 +15401 +15402 +15403 +15404 +15405 +15406 +15407 +15408 +15409 +15410 +15411 +15412 +15413 +15414 +15415 +15416 +15417 +15418 +15419 +15420 +15421 +15422 +15423 +15424 +15425 +15426 +15427 +15428 +15429 +15430 +15431 +15432 +15433 +15434 +15435 +15436 +15437 +15438 +15439 +15440 +15441 +15442 +15443 +15444 +15445 +15446 +15447 +15448 +15449 +15450 +15451 +15452 +15453 +15454 +15455 +15456 +15457 +15458 +15459 +15460 +15461 +15462 +15463 +15464 +15465 +15466 +15467 +15468 +15469 +15470 +15471 +15472 +15473 +15474 +15475 +15476 +15477 +15478 +15479 +15480 +15481 +15482 +15483 +15484 +15485 +15486 +15487 +15488 +15489 +15490 +15491 +15492 +15493 +15494 +15495 +15496 +15497 +15498 +15499 +15500 +15501 +15502 +15503 +15504 +15505 +15506 +15507 +15508 +15509 +15510 +15511 +15512 +15513 +15514 +15515 +15516 +15517 +15518 +15519 +15520 +15521 +15522 +15523 +15524 +15525 +15526 +15527 +15528 +15529 +15530 +15531 +15532 +15533 +15534 +15535 +15536 +15537 +15538 +15539 +15540 +15541 +15542 +15543 +15544 +15545 +15546 +15547 +15548 +15549 +15550 +15551 +15552 +15553 +15554 +15555 +15556 +15557 +15558 +15559 +15560 +15561 +15562 +15563 +15564 +15565 +15566 +15567 +15568 +15569 +15570 +15571 +15572 +15573 +15574 +15575 +15576 +15577 +15578 +15579 +15580 +15581 +15582 +15583 +15584 +15585 +15586 +15587 +15588 +15589 +15590 +15591 +15592 +15593 +15594 +15595 +15596 +15597 +15598 +15599 +15600 +15601 +15602 +15603 +15604 +15605 +15606 +15607 +15608 +15609 +15610 +15611 +15612 +15613 +15614 +15615 +15616 +15617 +15618 +15619 +15620 +15621 +15622 +15623 +15624 +15625 +15626 +15627 +15628 +15629 +15630 +15631 +15632 +15633 +15634 +15635 +15636 +15637 +15638 +15639 +15640 +15641 +15642 +15643 +15644 +15645 +15646 +15647 +15648 +15649 +15650 +15651 +15652 +15653 +15654 +15655 +15656 +15657 +15658 +15659 +15660 +15661 +15662 +15663 +15664 +15665 +15666 +15667 +15668 +15669 +15670 +15671 +15672 +15673 +15674 +15675 +15676 +15677 +15678 +15679 +15680 +15681 +15682 +15683 +15684 +15685 +15686 +15687 +15688 +15689 +15690 +15691 +15692 +15693 +15694 +15695 +15696 +15697 +15698 +15699 +15700 +15701 +15702 +15703 +15704 +15705 +15706 +15707 +15708 +15709 +15710 +15711 +15712 +15713 +15714 +15715 +15716 +15717 +15718 +15719 +15720 +15721 +15722 +15723 +15724 +15725 +15726 +15727 +15728 +15729 +15730 +15731 +15732 +15733 +15734 +15735 +15736 +15737 +15738 +15739 +15740 +15741 +15742 +15743 +15744 +15745 +15746 +15747 +15748 +15749 +15750 +15751 +15752 +15753 +15754 +15755 +15756 +15757 +15758 +15759 +15760 +15761 +15762 +15763 +15764 +15765 +15766 +15767 +15768 +15769 +15770 +15771 +15772 +15773 +15774 +15775 +15776 +15777 +15778 +15779 +15780 +15781 +15782 +15783 +15784 +15785 +15786 +15787 +15788 +15789 +15790 +15791 +15792 +15793 +15794 +15795 +15796 +15797 +15798 +15799 +15800 +15801 +15802 +15803 +15804 +15805 +15806 +15807 +15808 +15809 +15810 +15811 +15812 +15813 +15814 +15815 +15816 +15817 +15818 +15819 +15820 +15821 +15822 +15823 +15824 +15825 +15826 +15827 +15828 +15829 +15830 +15831 +15832 +15833 +15834 +15835 +15836 +15837 +15838 +15839 +15840 +15841 +15842 +15843 +15844 +15845 +15846 +15847 +15848 +15849 +15850 +15851 +15852 +15853 +15854 +15855 +15856 +15857 +15858 +15859 +15860 +15861 +15862 +15863 +15864 +15865 +15866 +15867 +15868 +15869 +15870 +15871 +15872 +15873 +15874 +15875 +15876 +15877 +15878 +15879 +15880 +15881 +15882 +15883 +15884 +15885 +15886 +15887 +15888 +15889 +15890 +15891 +15892 +15893 +15894 +15895 +15896 +15897 +15898 +15899 +15900 +15901 +15902 +15903 +15904 +15905 +15906 +15907 +15908 +15909 +15910 +15911 +15912 +15913 +15914 +15915 +15916 +15917 +15918 +15919 +15920 +15921 +15922 +15923 +15924 +15925 +15926 +15927 +15928 +15929 +15930 +15931 +15932 +15933 +15934 +15935 +15936 +15937 +15938 +15939 +15940 +15941 +15942 +15943 +15944 +15945 +15946 +15947 +15948 +15949 +15950 +15951 +15952 +15953 +15954 +15955 +15956 +15957 +15958 +15959 +15960 +15961 +15962 +15963 +15964 +15965 +15966 +15967 +15968 +15969 +15970 +15971 +15972 +15973 +15974 +15975 +15976 +15977 +15978 +15979 +15980 +15981 +15982 +15983 +15984 +15985 +15986 +15987 +15988 +15989 +15990 +15991 +15992 +15993 +15994 +15995 +15996 +15997 +15998 +15999 +16000 diff --git a/test/static/executor/test_data/departments_2000.csv b/test/static/executor/test_data/departments_2000.csv new file mode 100644 index 0000000..44c9617 --- /dev/null +++ b/test/static/executor/test_data/departments_2000.csv @@ -0,0 +1,2001 @@ +id:int +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 +432 +433 +434 +435 +436 +437 +438 +439 +440 +441 +442 +443 +444 +445 +446 +447 +448 +449 +450 +451 +452 +453 +454 +455 +456 +457 +458 +459 +460 +461 +462 +463 +464 +465 +466 +467 +468 +469 +470 +471 +472 +473 +474 +475 +476 +477 +478 +479 +480 +481 +482 +483 +484 +485 +486 +487 +488 +489 +490 +491 +492 +493 +494 +495 +496 +497 +498 +499 +500 +501 +502 +503 +504 +505 +506 +507 +508 +509 +510 +511 +512 +513 +514 +515 +516 +517 +518 +519 +520 +521 +522 +523 +524 +525 +526 +527 +528 +529 +530 +531 +532 +533 +534 +535 +536 +537 +538 +539 +540 +541 +542 +543 +544 +545 +546 +547 +548 +549 +550 +551 +552 +553 +554 +555 +556 +557 +558 +559 +560 +561 +562 +563 +564 +565 +566 +567 +568 +569 +570 +571 +572 +573 +574 +575 +576 +577 +578 +579 +580 +581 +582 +583 +584 +585 +586 +587 +588 +589 +590 +591 +592 +593 +594 +595 +596 +597 +598 +599 +600 +601 +602 +603 +604 +605 +606 +607 +608 +609 +610 +611 +612 +613 +614 +615 +616 +617 +618 +619 +620 +621 +622 +623 +624 +625 +626 +627 +628 +629 +630 +631 +632 +633 +634 +635 +636 +637 +638 +639 +640 +641 +642 +643 +644 +645 +646 +647 +648 +649 +650 +651 +652 +653 +654 +655 +656 +657 +658 +659 +660 +661 +662 +663 +664 +665 +666 +667 +668 +669 +670 +671 +672 +673 +674 +675 +676 +677 +678 +679 +680 +681 +682 +683 +684 +685 +686 +687 +688 +689 +690 +691 +692 +693 +694 +695 +696 +697 +698 +699 +700 +701 +702 +703 +704 +705 +706 +707 +708 +709 +710 +711 +712 +713 +714 +715 +716 +717 +718 +719 +720 +721 +722 +723 +724 +725 +726 +727 +728 +729 +730 +731 +732 +733 +734 +735 +736 +737 +738 +739 +740 +741 +742 +743 +744 +745 +746 +747 +748 +749 +750 +751 +752 +753 +754 +755 +756 +757 +758 +759 +760 +761 +762 +763 +764 +765 +766 +767 +768 +769 +770 +771 +772 +773 +774 +775 +776 +777 +778 +779 +780 +781 +782 +783 +784 +785 +786 +787 +788 +789 +790 +791 +792 +793 +794 +795 +796 +797 +798 +799 +800 +801 +802 +803 +804 +805 +806 +807 +808 +809 +810 +811 +812 +813 +814 +815 +816 +817 +818 +819 +820 +821 +822 +823 +824 +825 +826 +827 +828 +829 +830 +831 +832 +833 +834 +835 +836 +837 +838 +839 +840 +841 +842 +843 +844 +845 +846 +847 +848 +849 +850 +851 +852 +853 +854 +855 +856 +857 +858 +859 +860 +861 +862 +863 +864 +865 +866 +867 +868 +869 +870 +871 +872 +873 +874 +875 +876 +877 +878 +879 +880 +881 +882 +883 +884 +885 +886 +887 +888 +889 +890 +891 +892 +893 +894 +895 +896 +897 +898 +899 +900 +901 +902 +903 +904 +905 +906 +907 +908 +909 +910 +911 +912 +913 +914 +915 +916 +917 +918 +919 +920 +921 +922 +923 +924 +925 +926 +927 +928 +929 +930 +931 +932 +933 +934 +935 +936 +937 +938 +939 +940 +941 +942 +943 +944 +945 +946 +947 +948 +949 +950 +951 +952 +953 +954 +955 +956 +957 +958 +959 +960 +961 +962 +963 +964 +965 +966 +967 +968 +969 +970 +971 +972 +973 +974 +975 +976 +977 +978 +979 +980 +981 +982 +983 +984 +985 +986 +987 +988 +989 +990 +991 +992 +993 +994 +995 +996 +997 +998 +999 +1000 +1001 +1002 +1003 +1004 +1005 +1006 +1007 +1008 +1009 +1010 +1011 +1012 +1013 +1014 +1015 +1016 +1017 +1018 +1019 +1020 +1021 +1022 +1023 +1024 +1025 +1026 +1027 +1028 +1029 +1030 +1031 +1032 +1033 +1034 +1035 +1036 +1037 +1038 +1039 +1040 +1041 +1042 +1043 +1044 +1045 +1046 +1047 +1048 +1049 +1050 +1051 +1052 +1053 +1054 +1055 +1056 +1057 +1058 +1059 +1060 +1061 +1062 +1063 +1064 +1065 +1066 +1067 +1068 +1069 +1070 +1071 +1072 +1073 +1074 +1075 +1076 +1077 +1078 +1079 +1080 +1081 +1082 +1083 +1084 +1085 +1086 +1087 +1088 +1089 +1090 +1091 +1092 +1093 +1094 +1095 +1096 +1097 +1098 +1099 +1100 +1101 +1102 +1103 +1104 +1105 +1106 +1107 +1108 +1109 +1110 +1111 +1112 +1113 +1114 +1115 +1116 +1117 +1118 +1119 +1120 +1121 +1122 +1123 +1124 +1125 +1126 +1127 +1128 +1129 +1130 +1131 +1132 +1133 +1134 +1135 +1136 +1137 +1138 +1139 +1140 +1141 +1142 +1143 +1144 +1145 +1146 +1147 +1148 +1149 +1150 +1151 +1152 +1153 +1154 +1155 +1156 +1157 +1158 +1159 +1160 +1161 +1162 +1163 +1164 +1165 +1166 +1167 +1168 +1169 +1170 +1171 +1172 +1173 +1174 +1175 +1176 +1177 +1178 +1179 +1180 +1181 +1182 +1183 +1184 +1185 +1186 +1187 +1188 +1189 +1190 +1191 +1192 +1193 +1194 +1195 +1196 +1197 +1198 +1199 +1200 +1201 +1202 +1203 +1204 +1205 +1206 +1207 +1208 +1209 +1210 +1211 +1212 +1213 +1214 +1215 +1216 +1217 +1218 +1219 +1220 +1221 +1222 +1223 +1224 +1225 +1226 +1227 +1228 +1229 +1230 +1231 +1232 +1233 +1234 +1235 +1236 +1237 +1238 +1239 +1240 +1241 +1242 +1243 +1244 +1245 +1246 +1247 +1248 +1249 +1250 +1251 +1252 +1253 +1254 +1255 +1256 +1257 +1258 +1259 +1260 +1261 +1262 +1263 +1264 +1265 +1266 +1267 +1268 +1269 +1270 +1271 +1272 +1273 +1274 +1275 +1276 +1277 +1278 +1279 +1280 +1281 +1282 +1283 +1284 +1285 +1286 +1287 +1288 +1289 +1290 +1291 +1292 +1293 +1294 +1295 +1296 +1297 +1298 +1299 +1300 +1301 +1302 +1303 +1304 +1305 +1306 +1307 +1308 +1309 +1310 +1311 +1312 +1313 +1314 +1315 +1316 +1317 +1318 +1319 +1320 +1321 +1322 +1323 +1324 +1325 +1326 +1327 +1328 +1329 +1330 +1331 +1332 +1333 +1334 +1335 +1336 +1337 +1338 +1339 +1340 +1341 +1342 +1343 +1344 +1345 +1346 +1347 +1348 +1349 +1350 +1351 +1352 +1353 +1354 +1355 +1356 +1357 +1358 +1359 +1360 +1361 +1362 +1363 +1364 +1365 +1366 +1367 +1368 +1369 +1370 +1371 +1372 +1373 +1374 +1375 +1376 +1377 +1378 +1379 +1380 +1381 +1382 +1383 +1384 +1385 +1386 +1387 +1388 +1389 +1390 +1391 +1392 +1393 +1394 +1395 +1396 +1397 +1398 +1399 +1400 +1401 +1402 +1403 +1404 +1405 +1406 +1407 +1408 +1409 +1410 +1411 +1412 +1413 +1414 +1415 +1416 +1417 +1418 +1419 +1420 +1421 +1422 +1423 +1424 +1425 +1426 +1427 +1428 +1429 +1430 +1431 +1432 +1433 +1434 +1435 +1436 +1437 +1438 +1439 +1440 +1441 +1442 +1443 +1444 +1445 +1446 +1447 +1448 +1449 +1450 +1451 +1452 +1453 +1454 +1455 +1456 +1457 +1458 +1459 +1460 +1461 +1462 +1463 +1464 +1465 +1466 +1467 +1468 +1469 +1470 +1471 +1472 +1473 +1474 +1475 +1476 +1477 +1478 +1479 +1480 +1481 +1482 +1483 +1484 +1485 +1486 +1487 +1488 +1489 +1490 +1491 +1492 +1493 +1494 +1495 +1496 +1497 +1498 +1499 +1500 +1501 +1502 +1503 +1504 +1505 +1506 +1507 +1508 +1509 +1510 +1511 +1512 +1513 +1514 +1515 +1516 +1517 +1518 +1519 +1520 +1521 +1522 +1523 +1524 +1525 +1526 +1527 +1528 +1529 +1530 +1531 +1532 +1533 +1534 +1535 +1536 +1537 +1538 +1539 +1540 +1541 +1542 +1543 +1544 +1545 +1546 +1547 +1548 +1549 +1550 +1551 +1552 +1553 +1554 +1555 +1556 +1557 +1558 +1559 +1560 +1561 +1562 +1563 +1564 +1565 +1566 +1567 +1568 +1569 +1570 +1571 +1572 +1573 +1574 +1575 +1576 +1577 +1578 +1579 +1580 +1581 +1582 +1583 +1584 +1585 +1586 +1587 +1588 +1589 +1590 +1591 +1592 +1593 +1594 +1595 +1596 +1597 +1598 +1599 +1600 +1601 +1602 +1603 +1604 +1605 +1606 +1607 +1608 +1609 +1610 +1611 +1612 +1613 +1614 +1615 +1616 +1617 +1618 +1619 +1620 +1621 +1622 +1623 +1624 +1625 +1626 +1627 +1628 +1629 +1630 +1631 +1632 +1633 +1634 +1635 +1636 +1637 +1638 +1639 +1640 +1641 +1642 +1643 +1644 +1645 +1646 +1647 +1648 +1649 +1650 +1651 +1652 +1653 +1654 +1655 +1656 +1657 +1658 +1659 +1660 +1661 +1662 +1663 +1664 +1665 +1666 +1667 +1668 +1669 +1670 +1671 +1672 +1673 +1674 +1675 +1676 +1677 +1678 +1679 +1680 +1681 +1682 +1683 +1684 +1685 +1686 +1687 +1688 +1689 +1690 +1691 +1692 +1693 +1694 +1695 +1696 +1697 +1698 +1699 +1700 +1701 +1702 +1703 +1704 +1705 +1706 +1707 +1708 +1709 +1710 +1711 +1712 +1713 +1714 +1715 +1716 +1717 +1718 +1719 +1720 +1721 +1722 +1723 +1724 +1725 +1726 +1727 +1728 +1729 +1730 +1731 +1732 +1733 +1734 +1735 +1736 +1737 +1738 +1739 +1740 +1741 +1742 +1743 +1744 +1745 +1746 +1747 +1748 +1749 +1750 +1751 +1752 +1753 +1754 +1755 +1756 +1757 +1758 +1759 +1760 +1761 +1762 +1763 +1764 +1765 +1766 +1767 +1768 +1769 +1770 +1771 +1772 +1773 +1774 +1775 +1776 +1777 +1778 +1779 +1780 +1781 +1782 +1783 +1784 +1785 +1786 +1787 +1788 +1789 +1790 +1791 +1792 +1793 +1794 +1795 +1796 +1797 +1798 +1799 +1800 +1801 +1802 +1803 +1804 +1805 +1806 +1807 +1808 +1809 +1810 +1811 +1812 +1813 +1814 +1815 +1816 +1817 +1818 +1819 +1820 +1821 +1822 +1823 +1824 +1825 +1826 +1827 +1828 +1829 +1830 +1831 +1832 +1833 +1834 +1835 +1836 +1837 +1838 +1839 +1840 +1841 +1842 +1843 +1844 +1845 +1846 +1847 +1848 +1849 +1850 +1851 +1852 +1853 +1854 +1855 +1856 +1857 +1858 +1859 +1860 +1861 +1862 +1863 +1864 +1865 +1866 +1867 +1868 +1869 +1870 +1871 +1872 +1873 +1874 +1875 +1876 +1877 +1878 +1879 +1880 +1881 +1882 +1883 +1884 +1885 +1886 +1887 +1888 +1889 +1890 +1891 +1892 +1893 +1894 +1895 +1896 +1897 +1898 +1899 +1900 +1901 +1902 +1903 +1904 +1905 +1906 +1907 +1908 +1909 +1910 +1911 +1912 +1913 +1914 +1915 +1916 +1917 +1918 +1919 +1920 +1921 +1922 +1923 +1924 +1925 +1926 +1927 +1928 +1929 +1930 +1931 +1932 +1933 +1934 +1935 +1936 +1937 +1938 +1939 +1940 +1941 +1942 +1943 +1944 +1945 +1946 +1947 +1948 +1949 +1950 +1951 +1952 +1953 +1954 +1955 +1956 +1957 +1958 +1959 +1960 +1961 +1962 +1963 +1964 +1965 +1966 +1967 +1968 +1969 +1970 +1971 +1972 +1973 +1974 +1975 +1976 +1977 +1978 +1979 +1980 +1981 +1982 +1983 +1984 +1985 +1986 +1987 +1988 +1989 +1990 +1991 +1992 +1993 +1994 +1995 +1996 +1997 +1998 +1999 +2000 diff --git a/test/static/executor/test_data/departments_4000.csv b/test/static/executor/test_data/departments_4000.csv new file mode 100644 index 0000000..8c9b3d1 --- /dev/null +++ b/test/static/executor/test_data/departments_4000.csv @@ -0,0 +1,4001 @@ +id:int +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 +432 +433 +434 +435 +436 +437 +438 +439 +440 +441 +442 +443 +444 +445 +446 +447 +448 +449 +450 +451 +452 +453 +454 +455 +456 +457 +458 +459 +460 +461 +462 +463 +464 +465 +466 +467 +468 +469 +470 +471 +472 +473 +474 +475 +476 +477 +478 +479 +480 +481 +482 +483 +484 +485 +486 +487 +488 +489 +490 +491 +492 +493 +494 +495 +496 +497 +498 +499 +500 +501 +502 +503 +504 +505 +506 +507 +508 +509 +510 +511 +512 +513 +514 +515 +516 +517 +518 +519 +520 +521 +522 +523 +524 +525 +526 +527 +528 +529 +530 +531 +532 +533 +534 +535 +536 +537 +538 +539 +540 +541 +542 +543 +544 +545 +546 +547 +548 +549 +550 +551 +552 +553 +554 +555 +556 +557 +558 +559 +560 +561 +562 +563 +564 +565 +566 +567 +568 +569 +570 +571 +572 +573 +574 +575 +576 +577 +578 +579 +580 +581 +582 +583 +584 +585 +586 +587 +588 +589 +590 +591 +592 +593 +594 +595 +596 +597 +598 +599 +600 +601 +602 +603 +604 +605 +606 +607 +608 +609 +610 +611 +612 +613 +614 +615 +616 +617 +618 +619 +620 +621 +622 +623 +624 +625 +626 +627 +628 +629 +630 +631 +632 +633 +634 +635 +636 +637 +638 +639 +640 +641 +642 +643 +644 +645 +646 +647 +648 +649 +650 +651 +652 +653 +654 +655 +656 +657 +658 +659 +660 +661 +662 +663 +664 +665 +666 +667 +668 +669 +670 +671 +672 +673 +674 +675 +676 +677 +678 +679 +680 +681 +682 +683 +684 +685 +686 +687 +688 +689 +690 +691 +692 +693 +694 +695 +696 +697 +698 +699 +700 +701 +702 +703 +704 +705 +706 +707 +708 +709 +710 +711 +712 +713 +714 +715 +716 +717 +718 +719 +720 +721 +722 +723 +724 +725 +726 +727 +728 +729 +730 +731 +732 +733 +734 +735 +736 +737 +738 +739 +740 +741 +742 +743 +744 +745 +746 +747 +748 +749 +750 +751 +752 +753 +754 +755 +756 +757 +758 +759 +760 +761 +762 +763 +764 +765 +766 +767 +768 +769 +770 +771 +772 +773 +774 +775 +776 +777 +778 +779 +780 +781 +782 +783 +784 +785 +786 +787 +788 +789 +790 +791 +792 +793 +794 +795 +796 +797 +798 +799 +800 +801 +802 +803 +804 +805 +806 +807 +808 +809 +810 +811 +812 +813 +814 +815 +816 +817 +818 +819 +820 +821 +822 +823 +824 +825 +826 +827 +828 +829 +830 +831 +832 +833 +834 +835 +836 +837 +838 +839 +840 +841 +842 +843 +844 +845 +846 +847 +848 +849 +850 +851 +852 +853 +854 +855 +856 +857 +858 +859 +860 +861 +862 +863 +864 +865 +866 +867 +868 +869 +870 +871 +872 +873 +874 +875 +876 +877 +878 +879 +880 +881 +882 +883 +884 +885 +886 +887 +888 +889 +890 +891 +892 +893 +894 +895 +896 +897 +898 +899 +900 +901 +902 +903 +904 +905 +906 +907 +908 +909 +910 +911 +912 +913 +914 +915 +916 +917 +918 +919 +920 +921 +922 +923 +924 +925 +926 +927 +928 +929 +930 +931 +932 +933 +934 +935 +936 +937 +938 +939 +940 +941 +942 +943 +944 +945 +946 +947 +948 +949 +950 +951 +952 +953 +954 +955 +956 +957 +958 +959 +960 +961 +962 +963 +964 +965 +966 +967 +968 +969 +970 +971 +972 +973 +974 +975 +976 +977 +978 +979 +980 +981 +982 +983 +984 +985 +986 +987 +988 +989 +990 +991 +992 +993 +994 +995 +996 +997 +998 +999 +1000 +1001 +1002 +1003 +1004 +1005 +1006 +1007 +1008 +1009 +1010 +1011 +1012 +1013 +1014 +1015 +1016 +1017 +1018 +1019 +1020 +1021 +1022 +1023 +1024 +1025 +1026 +1027 +1028 +1029 +1030 +1031 +1032 +1033 +1034 +1035 +1036 +1037 +1038 +1039 +1040 +1041 +1042 +1043 +1044 +1045 +1046 +1047 +1048 +1049 +1050 +1051 +1052 +1053 +1054 +1055 +1056 +1057 +1058 +1059 +1060 +1061 +1062 +1063 +1064 +1065 +1066 +1067 +1068 +1069 +1070 +1071 +1072 +1073 +1074 +1075 +1076 +1077 +1078 +1079 +1080 +1081 +1082 +1083 +1084 +1085 +1086 +1087 +1088 +1089 +1090 +1091 +1092 +1093 +1094 +1095 +1096 +1097 +1098 +1099 +1100 +1101 +1102 +1103 +1104 +1105 +1106 +1107 +1108 +1109 +1110 +1111 +1112 +1113 +1114 +1115 +1116 +1117 +1118 +1119 +1120 +1121 +1122 +1123 +1124 +1125 +1126 +1127 +1128 +1129 +1130 +1131 +1132 +1133 +1134 +1135 +1136 +1137 +1138 +1139 +1140 +1141 +1142 +1143 +1144 +1145 +1146 +1147 +1148 +1149 +1150 +1151 +1152 +1153 +1154 +1155 +1156 +1157 +1158 +1159 +1160 +1161 +1162 +1163 +1164 +1165 +1166 +1167 +1168 +1169 +1170 +1171 +1172 +1173 +1174 +1175 +1176 +1177 +1178 +1179 +1180 +1181 +1182 +1183 +1184 +1185 +1186 +1187 +1188 +1189 +1190 +1191 +1192 +1193 +1194 +1195 +1196 +1197 +1198 +1199 +1200 +1201 +1202 +1203 +1204 +1205 +1206 +1207 +1208 +1209 +1210 +1211 +1212 +1213 +1214 +1215 +1216 +1217 +1218 +1219 +1220 +1221 +1222 +1223 +1224 +1225 +1226 +1227 +1228 +1229 +1230 +1231 +1232 +1233 +1234 +1235 +1236 +1237 +1238 +1239 +1240 +1241 +1242 +1243 +1244 +1245 +1246 +1247 +1248 +1249 +1250 +1251 +1252 +1253 +1254 +1255 +1256 +1257 +1258 +1259 +1260 +1261 +1262 +1263 +1264 +1265 +1266 +1267 +1268 +1269 +1270 +1271 +1272 +1273 +1274 +1275 +1276 +1277 +1278 +1279 +1280 +1281 +1282 +1283 +1284 +1285 +1286 +1287 +1288 +1289 +1290 +1291 +1292 +1293 +1294 +1295 +1296 +1297 +1298 +1299 +1300 +1301 +1302 +1303 +1304 +1305 +1306 +1307 +1308 +1309 +1310 +1311 +1312 +1313 +1314 +1315 +1316 +1317 +1318 +1319 +1320 +1321 +1322 +1323 +1324 +1325 +1326 +1327 +1328 +1329 +1330 +1331 +1332 +1333 +1334 +1335 +1336 +1337 +1338 +1339 +1340 +1341 +1342 +1343 +1344 +1345 +1346 +1347 +1348 +1349 +1350 +1351 +1352 +1353 +1354 +1355 +1356 +1357 +1358 +1359 +1360 +1361 +1362 +1363 +1364 +1365 +1366 +1367 +1368 +1369 +1370 +1371 +1372 +1373 +1374 +1375 +1376 +1377 +1378 +1379 +1380 +1381 +1382 +1383 +1384 +1385 +1386 +1387 +1388 +1389 +1390 +1391 +1392 +1393 +1394 +1395 +1396 +1397 +1398 +1399 +1400 +1401 +1402 +1403 +1404 +1405 +1406 +1407 +1408 +1409 +1410 +1411 +1412 +1413 +1414 +1415 +1416 +1417 +1418 +1419 +1420 +1421 +1422 +1423 +1424 +1425 +1426 +1427 +1428 +1429 +1430 +1431 +1432 +1433 +1434 +1435 +1436 +1437 +1438 +1439 +1440 +1441 +1442 +1443 +1444 +1445 +1446 +1447 +1448 +1449 +1450 +1451 +1452 +1453 +1454 +1455 +1456 +1457 +1458 +1459 +1460 +1461 +1462 +1463 +1464 +1465 +1466 +1467 +1468 +1469 +1470 +1471 +1472 +1473 +1474 +1475 +1476 +1477 +1478 +1479 +1480 +1481 +1482 +1483 +1484 +1485 +1486 +1487 +1488 +1489 +1490 +1491 +1492 +1493 +1494 +1495 +1496 +1497 +1498 +1499 +1500 +1501 +1502 +1503 +1504 +1505 +1506 +1507 +1508 +1509 +1510 +1511 +1512 +1513 +1514 +1515 +1516 +1517 +1518 +1519 +1520 +1521 +1522 +1523 +1524 +1525 +1526 +1527 +1528 +1529 +1530 +1531 +1532 +1533 +1534 +1535 +1536 +1537 +1538 +1539 +1540 +1541 +1542 +1543 +1544 +1545 +1546 +1547 +1548 +1549 +1550 +1551 +1552 +1553 +1554 +1555 +1556 +1557 +1558 +1559 +1560 +1561 +1562 +1563 +1564 +1565 +1566 +1567 +1568 +1569 +1570 +1571 +1572 +1573 +1574 +1575 +1576 +1577 +1578 +1579 +1580 +1581 +1582 +1583 +1584 +1585 +1586 +1587 +1588 +1589 +1590 +1591 +1592 +1593 +1594 +1595 +1596 +1597 +1598 +1599 +1600 +1601 +1602 +1603 +1604 +1605 +1606 +1607 +1608 +1609 +1610 +1611 +1612 +1613 +1614 +1615 +1616 +1617 +1618 +1619 +1620 +1621 +1622 +1623 +1624 +1625 +1626 +1627 +1628 +1629 +1630 +1631 +1632 +1633 +1634 +1635 +1636 +1637 +1638 +1639 +1640 +1641 +1642 +1643 +1644 +1645 +1646 +1647 +1648 +1649 +1650 +1651 +1652 +1653 +1654 +1655 +1656 +1657 +1658 +1659 +1660 +1661 +1662 +1663 +1664 +1665 +1666 +1667 +1668 +1669 +1670 +1671 +1672 +1673 +1674 +1675 +1676 +1677 +1678 +1679 +1680 +1681 +1682 +1683 +1684 +1685 +1686 +1687 +1688 +1689 +1690 +1691 +1692 +1693 +1694 +1695 +1696 +1697 +1698 +1699 +1700 +1701 +1702 +1703 +1704 +1705 +1706 +1707 +1708 +1709 +1710 +1711 +1712 +1713 +1714 +1715 +1716 +1717 +1718 +1719 +1720 +1721 +1722 +1723 +1724 +1725 +1726 +1727 +1728 +1729 +1730 +1731 +1732 +1733 +1734 +1735 +1736 +1737 +1738 +1739 +1740 +1741 +1742 +1743 +1744 +1745 +1746 +1747 +1748 +1749 +1750 +1751 +1752 +1753 +1754 +1755 +1756 +1757 +1758 +1759 +1760 +1761 +1762 +1763 +1764 +1765 +1766 +1767 +1768 +1769 +1770 +1771 +1772 +1773 +1774 +1775 +1776 +1777 +1778 +1779 +1780 +1781 +1782 +1783 +1784 +1785 +1786 +1787 +1788 +1789 +1790 +1791 +1792 +1793 +1794 +1795 +1796 +1797 +1798 +1799 +1800 +1801 +1802 +1803 +1804 +1805 +1806 +1807 +1808 +1809 +1810 +1811 +1812 +1813 +1814 +1815 +1816 +1817 +1818 +1819 +1820 +1821 +1822 +1823 +1824 +1825 +1826 +1827 +1828 +1829 +1830 +1831 +1832 +1833 +1834 +1835 +1836 +1837 +1838 +1839 +1840 +1841 +1842 +1843 +1844 +1845 +1846 +1847 +1848 +1849 +1850 +1851 +1852 +1853 +1854 +1855 +1856 +1857 +1858 +1859 +1860 +1861 +1862 +1863 +1864 +1865 +1866 +1867 +1868 +1869 +1870 +1871 +1872 +1873 +1874 +1875 +1876 +1877 +1878 +1879 +1880 +1881 +1882 +1883 +1884 +1885 +1886 +1887 +1888 +1889 +1890 +1891 +1892 +1893 +1894 +1895 +1896 +1897 +1898 +1899 +1900 +1901 +1902 +1903 +1904 +1905 +1906 +1907 +1908 +1909 +1910 +1911 +1912 +1913 +1914 +1915 +1916 +1917 +1918 +1919 +1920 +1921 +1922 +1923 +1924 +1925 +1926 +1927 +1928 +1929 +1930 +1931 +1932 +1933 +1934 +1935 +1936 +1937 +1938 +1939 +1940 +1941 +1942 +1943 +1944 +1945 +1946 +1947 +1948 +1949 +1950 +1951 +1952 +1953 +1954 +1955 +1956 +1957 +1958 +1959 +1960 +1961 +1962 +1963 +1964 +1965 +1966 +1967 +1968 +1969 +1970 +1971 +1972 +1973 +1974 +1975 +1976 +1977 +1978 +1979 +1980 +1981 +1982 +1983 +1984 +1985 +1986 +1987 +1988 +1989 +1990 +1991 +1992 +1993 +1994 +1995 +1996 +1997 +1998 +1999 +2000 +2001 +2002 +2003 +2004 +2005 +2006 +2007 +2008 +2009 +2010 +2011 +2012 +2013 +2014 +2015 +2016 +2017 +2018 +2019 +2020 +2021 +2022 +2023 +2024 +2025 +2026 +2027 +2028 +2029 +2030 +2031 +2032 +2033 +2034 +2035 +2036 +2037 +2038 +2039 +2040 +2041 +2042 +2043 +2044 +2045 +2046 +2047 +2048 +2049 +2050 +2051 +2052 +2053 +2054 +2055 +2056 +2057 +2058 +2059 +2060 +2061 +2062 +2063 +2064 +2065 +2066 +2067 +2068 +2069 +2070 +2071 +2072 +2073 +2074 +2075 +2076 +2077 +2078 +2079 +2080 +2081 +2082 +2083 +2084 +2085 +2086 +2087 +2088 +2089 +2090 +2091 +2092 +2093 +2094 +2095 +2096 +2097 +2098 +2099 +2100 +2101 +2102 +2103 +2104 +2105 +2106 +2107 +2108 +2109 +2110 +2111 +2112 +2113 +2114 +2115 +2116 +2117 +2118 +2119 +2120 +2121 +2122 +2123 +2124 +2125 +2126 +2127 +2128 +2129 +2130 +2131 +2132 +2133 +2134 +2135 +2136 +2137 +2138 +2139 +2140 +2141 +2142 +2143 +2144 +2145 +2146 +2147 +2148 +2149 +2150 +2151 +2152 +2153 +2154 +2155 +2156 +2157 +2158 +2159 +2160 +2161 +2162 +2163 +2164 +2165 +2166 +2167 +2168 +2169 +2170 +2171 +2172 +2173 +2174 +2175 +2176 +2177 +2178 +2179 +2180 +2181 +2182 +2183 +2184 +2185 +2186 +2187 +2188 +2189 +2190 +2191 +2192 +2193 +2194 +2195 +2196 +2197 +2198 +2199 +2200 +2201 +2202 +2203 +2204 +2205 +2206 +2207 +2208 +2209 +2210 +2211 +2212 +2213 +2214 +2215 +2216 +2217 +2218 +2219 +2220 +2221 +2222 +2223 +2224 +2225 +2226 +2227 +2228 +2229 +2230 +2231 +2232 +2233 +2234 +2235 +2236 +2237 +2238 +2239 +2240 +2241 +2242 +2243 +2244 +2245 +2246 +2247 +2248 +2249 +2250 +2251 +2252 +2253 +2254 +2255 +2256 +2257 +2258 +2259 +2260 +2261 +2262 +2263 +2264 +2265 +2266 +2267 +2268 +2269 +2270 +2271 +2272 +2273 +2274 +2275 +2276 +2277 +2278 +2279 +2280 +2281 +2282 +2283 +2284 +2285 +2286 +2287 +2288 +2289 +2290 +2291 +2292 +2293 +2294 +2295 +2296 +2297 +2298 +2299 +2300 +2301 +2302 +2303 +2304 +2305 +2306 +2307 +2308 +2309 +2310 +2311 +2312 +2313 +2314 +2315 +2316 +2317 +2318 +2319 +2320 +2321 +2322 +2323 +2324 +2325 +2326 +2327 +2328 +2329 +2330 +2331 +2332 +2333 +2334 +2335 +2336 +2337 +2338 +2339 +2340 +2341 +2342 +2343 +2344 +2345 +2346 +2347 +2348 +2349 +2350 +2351 +2352 +2353 +2354 +2355 +2356 +2357 +2358 +2359 +2360 +2361 +2362 +2363 +2364 +2365 +2366 +2367 +2368 +2369 +2370 +2371 +2372 +2373 +2374 +2375 +2376 +2377 +2378 +2379 +2380 +2381 +2382 +2383 +2384 +2385 +2386 +2387 +2388 +2389 +2390 +2391 +2392 +2393 +2394 +2395 +2396 +2397 +2398 +2399 +2400 +2401 +2402 +2403 +2404 +2405 +2406 +2407 +2408 +2409 +2410 +2411 +2412 +2413 +2414 +2415 +2416 +2417 +2418 +2419 +2420 +2421 +2422 +2423 +2424 +2425 +2426 +2427 +2428 +2429 +2430 +2431 +2432 +2433 +2434 +2435 +2436 +2437 +2438 +2439 +2440 +2441 +2442 +2443 +2444 +2445 +2446 +2447 +2448 +2449 +2450 +2451 +2452 +2453 +2454 +2455 +2456 +2457 +2458 +2459 +2460 +2461 +2462 +2463 +2464 +2465 +2466 +2467 +2468 +2469 +2470 +2471 +2472 +2473 +2474 +2475 +2476 +2477 +2478 +2479 +2480 +2481 +2482 +2483 +2484 +2485 +2486 +2487 +2488 +2489 +2490 +2491 +2492 +2493 +2494 +2495 +2496 +2497 +2498 +2499 +2500 +2501 +2502 +2503 +2504 +2505 +2506 +2507 +2508 +2509 +2510 +2511 +2512 +2513 +2514 +2515 +2516 +2517 +2518 +2519 +2520 +2521 +2522 +2523 +2524 +2525 +2526 +2527 +2528 +2529 +2530 +2531 +2532 +2533 +2534 +2535 +2536 +2537 +2538 +2539 +2540 +2541 +2542 +2543 +2544 +2545 +2546 +2547 +2548 +2549 +2550 +2551 +2552 +2553 +2554 +2555 +2556 +2557 +2558 +2559 +2560 +2561 +2562 +2563 +2564 +2565 +2566 +2567 +2568 +2569 +2570 +2571 +2572 +2573 +2574 +2575 +2576 +2577 +2578 +2579 +2580 +2581 +2582 +2583 +2584 +2585 +2586 +2587 +2588 +2589 +2590 +2591 +2592 +2593 +2594 +2595 +2596 +2597 +2598 +2599 +2600 +2601 +2602 +2603 +2604 +2605 +2606 +2607 +2608 +2609 +2610 +2611 +2612 +2613 +2614 +2615 +2616 +2617 +2618 +2619 +2620 +2621 +2622 +2623 +2624 +2625 +2626 +2627 +2628 +2629 +2630 +2631 +2632 +2633 +2634 +2635 +2636 +2637 +2638 +2639 +2640 +2641 +2642 +2643 +2644 +2645 +2646 +2647 +2648 +2649 +2650 +2651 +2652 +2653 +2654 +2655 +2656 +2657 +2658 +2659 +2660 +2661 +2662 +2663 +2664 +2665 +2666 +2667 +2668 +2669 +2670 +2671 +2672 +2673 +2674 +2675 +2676 +2677 +2678 +2679 +2680 +2681 +2682 +2683 +2684 +2685 +2686 +2687 +2688 +2689 +2690 +2691 +2692 +2693 +2694 +2695 +2696 +2697 +2698 +2699 +2700 +2701 +2702 +2703 +2704 +2705 +2706 +2707 +2708 +2709 +2710 +2711 +2712 +2713 +2714 +2715 +2716 +2717 +2718 +2719 +2720 +2721 +2722 +2723 +2724 +2725 +2726 +2727 +2728 +2729 +2730 +2731 +2732 +2733 +2734 +2735 +2736 +2737 +2738 +2739 +2740 +2741 +2742 +2743 +2744 +2745 +2746 +2747 +2748 +2749 +2750 +2751 +2752 +2753 +2754 +2755 +2756 +2757 +2758 +2759 +2760 +2761 +2762 +2763 +2764 +2765 +2766 +2767 +2768 +2769 +2770 +2771 +2772 +2773 +2774 +2775 +2776 +2777 +2778 +2779 +2780 +2781 +2782 +2783 +2784 +2785 +2786 +2787 +2788 +2789 +2790 +2791 +2792 +2793 +2794 +2795 +2796 +2797 +2798 +2799 +2800 +2801 +2802 +2803 +2804 +2805 +2806 +2807 +2808 +2809 +2810 +2811 +2812 +2813 +2814 +2815 +2816 +2817 +2818 +2819 +2820 +2821 +2822 +2823 +2824 +2825 +2826 +2827 +2828 +2829 +2830 +2831 +2832 +2833 +2834 +2835 +2836 +2837 +2838 +2839 +2840 +2841 +2842 +2843 +2844 +2845 +2846 +2847 +2848 +2849 +2850 +2851 +2852 +2853 +2854 +2855 +2856 +2857 +2858 +2859 +2860 +2861 +2862 +2863 +2864 +2865 +2866 +2867 +2868 +2869 +2870 +2871 +2872 +2873 +2874 +2875 +2876 +2877 +2878 +2879 +2880 +2881 +2882 +2883 +2884 +2885 +2886 +2887 +2888 +2889 +2890 +2891 +2892 +2893 +2894 +2895 +2896 +2897 +2898 +2899 +2900 +2901 +2902 +2903 +2904 +2905 +2906 +2907 +2908 +2909 +2910 +2911 +2912 +2913 +2914 +2915 +2916 +2917 +2918 +2919 +2920 +2921 +2922 +2923 +2924 +2925 +2926 +2927 +2928 +2929 +2930 +2931 +2932 +2933 +2934 +2935 +2936 +2937 +2938 +2939 +2940 +2941 +2942 +2943 +2944 +2945 +2946 +2947 +2948 +2949 +2950 +2951 +2952 +2953 +2954 +2955 +2956 +2957 +2958 +2959 +2960 +2961 +2962 +2963 +2964 +2965 +2966 +2967 +2968 +2969 +2970 +2971 +2972 +2973 +2974 +2975 +2976 +2977 +2978 +2979 +2980 +2981 +2982 +2983 +2984 +2985 +2986 +2987 +2988 +2989 +2990 +2991 +2992 +2993 +2994 +2995 +2996 +2997 +2998 +2999 +3000 +3001 +3002 +3003 +3004 +3005 +3006 +3007 +3008 +3009 +3010 +3011 +3012 +3013 +3014 +3015 +3016 +3017 +3018 +3019 +3020 +3021 +3022 +3023 +3024 +3025 +3026 +3027 +3028 +3029 +3030 +3031 +3032 +3033 +3034 +3035 +3036 +3037 +3038 +3039 +3040 +3041 +3042 +3043 +3044 +3045 +3046 +3047 +3048 +3049 +3050 +3051 +3052 +3053 +3054 +3055 +3056 +3057 +3058 +3059 +3060 +3061 +3062 +3063 +3064 +3065 +3066 +3067 +3068 +3069 +3070 +3071 +3072 +3073 +3074 +3075 +3076 +3077 +3078 +3079 +3080 +3081 +3082 +3083 +3084 +3085 +3086 +3087 +3088 +3089 +3090 +3091 +3092 +3093 +3094 +3095 +3096 +3097 +3098 +3099 +3100 +3101 +3102 +3103 +3104 +3105 +3106 +3107 +3108 +3109 +3110 +3111 +3112 +3113 +3114 +3115 +3116 +3117 +3118 +3119 +3120 +3121 +3122 +3123 +3124 +3125 +3126 +3127 +3128 +3129 +3130 +3131 +3132 +3133 +3134 +3135 +3136 +3137 +3138 +3139 +3140 +3141 +3142 +3143 +3144 +3145 +3146 +3147 +3148 +3149 +3150 +3151 +3152 +3153 +3154 +3155 +3156 +3157 +3158 +3159 +3160 +3161 +3162 +3163 +3164 +3165 +3166 +3167 +3168 +3169 +3170 +3171 +3172 +3173 +3174 +3175 +3176 +3177 +3178 +3179 +3180 +3181 +3182 +3183 +3184 +3185 +3186 +3187 +3188 +3189 +3190 +3191 +3192 +3193 +3194 +3195 +3196 +3197 +3198 +3199 +3200 +3201 +3202 +3203 +3204 +3205 +3206 +3207 +3208 +3209 +3210 +3211 +3212 +3213 +3214 +3215 +3216 +3217 +3218 +3219 +3220 +3221 +3222 +3223 +3224 +3225 +3226 +3227 +3228 +3229 +3230 +3231 +3232 +3233 +3234 +3235 +3236 +3237 +3238 +3239 +3240 +3241 +3242 +3243 +3244 +3245 +3246 +3247 +3248 +3249 +3250 +3251 +3252 +3253 +3254 +3255 +3256 +3257 +3258 +3259 +3260 +3261 +3262 +3263 +3264 +3265 +3266 +3267 +3268 +3269 +3270 +3271 +3272 +3273 +3274 +3275 +3276 +3277 +3278 +3279 +3280 +3281 +3282 +3283 +3284 +3285 +3286 +3287 +3288 +3289 +3290 +3291 +3292 +3293 +3294 +3295 +3296 +3297 +3298 +3299 +3300 +3301 +3302 +3303 +3304 +3305 +3306 +3307 +3308 +3309 +3310 +3311 +3312 +3313 +3314 +3315 +3316 +3317 +3318 +3319 +3320 +3321 +3322 +3323 +3324 +3325 +3326 +3327 +3328 +3329 +3330 +3331 +3332 +3333 +3334 +3335 +3336 +3337 +3338 +3339 +3340 +3341 +3342 +3343 +3344 +3345 +3346 +3347 +3348 +3349 +3350 +3351 +3352 +3353 +3354 +3355 +3356 +3357 +3358 +3359 +3360 +3361 +3362 +3363 +3364 +3365 +3366 +3367 +3368 +3369 +3370 +3371 +3372 +3373 +3374 +3375 +3376 +3377 +3378 +3379 +3380 +3381 +3382 +3383 +3384 +3385 +3386 +3387 +3388 +3389 +3390 +3391 +3392 +3393 +3394 +3395 +3396 +3397 +3398 +3399 +3400 +3401 +3402 +3403 +3404 +3405 +3406 +3407 +3408 +3409 +3410 +3411 +3412 +3413 +3414 +3415 +3416 +3417 +3418 +3419 +3420 +3421 +3422 +3423 +3424 +3425 +3426 +3427 +3428 +3429 +3430 +3431 +3432 +3433 +3434 +3435 +3436 +3437 +3438 +3439 +3440 +3441 +3442 +3443 +3444 +3445 +3446 +3447 +3448 +3449 +3450 +3451 +3452 +3453 +3454 +3455 +3456 +3457 +3458 +3459 +3460 +3461 +3462 +3463 +3464 +3465 +3466 +3467 +3468 +3469 +3470 +3471 +3472 +3473 +3474 +3475 +3476 +3477 +3478 +3479 +3480 +3481 +3482 +3483 +3484 +3485 +3486 +3487 +3488 +3489 +3490 +3491 +3492 +3493 +3494 +3495 +3496 +3497 +3498 +3499 +3500 +3501 +3502 +3503 +3504 +3505 +3506 +3507 +3508 +3509 +3510 +3511 +3512 +3513 +3514 +3515 +3516 +3517 +3518 +3519 +3520 +3521 +3522 +3523 +3524 +3525 +3526 +3527 +3528 +3529 +3530 +3531 +3532 +3533 +3534 +3535 +3536 +3537 +3538 +3539 +3540 +3541 +3542 +3543 +3544 +3545 +3546 +3547 +3548 +3549 +3550 +3551 +3552 +3553 +3554 +3555 +3556 +3557 +3558 +3559 +3560 +3561 +3562 +3563 +3564 +3565 +3566 +3567 +3568 +3569 +3570 +3571 +3572 +3573 +3574 +3575 +3576 +3577 +3578 +3579 +3580 +3581 +3582 +3583 +3584 +3585 +3586 +3587 +3588 +3589 +3590 +3591 +3592 +3593 +3594 +3595 +3596 +3597 +3598 +3599 +3600 +3601 +3602 +3603 +3604 +3605 +3606 +3607 +3608 +3609 +3610 +3611 +3612 +3613 +3614 +3615 +3616 +3617 +3618 +3619 +3620 +3621 +3622 +3623 +3624 +3625 +3626 +3627 +3628 +3629 +3630 +3631 +3632 +3633 +3634 +3635 +3636 +3637 +3638 +3639 +3640 +3641 +3642 +3643 +3644 +3645 +3646 +3647 +3648 +3649 +3650 +3651 +3652 +3653 +3654 +3655 +3656 +3657 +3658 +3659 +3660 +3661 +3662 +3663 +3664 +3665 +3666 +3667 +3668 +3669 +3670 +3671 +3672 +3673 +3674 +3675 +3676 +3677 +3678 +3679 +3680 +3681 +3682 +3683 +3684 +3685 +3686 +3687 +3688 +3689 +3690 +3691 +3692 +3693 +3694 +3695 +3696 +3697 +3698 +3699 +3700 +3701 +3702 +3703 +3704 +3705 +3706 +3707 +3708 +3709 +3710 +3711 +3712 +3713 +3714 +3715 +3716 +3717 +3718 +3719 +3720 +3721 +3722 +3723 +3724 +3725 +3726 +3727 +3728 +3729 +3730 +3731 +3732 +3733 +3734 +3735 +3736 +3737 +3738 +3739 +3740 +3741 +3742 +3743 +3744 +3745 +3746 +3747 +3748 +3749 +3750 +3751 +3752 +3753 +3754 +3755 +3756 +3757 +3758 +3759 +3760 +3761 +3762 +3763 +3764 +3765 +3766 +3767 +3768 +3769 +3770 +3771 +3772 +3773 +3774 +3775 +3776 +3777 +3778 +3779 +3780 +3781 +3782 +3783 +3784 +3785 +3786 +3787 +3788 +3789 +3790 +3791 +3792 +3793 +3794 +3795 +3796 +3797 +3798 +3799 +3800 +3801 +3802 +3803 +3804 +3805 +3806 +3807 +3808 +3809 +3810 +3811 +3812 +3813 +3814 +3815 +3816 +3817 +3818 +3819 +3820 +3821 +3822 +3823 +3824 +3825 +3826 +3827 +3828 +3829 +3830 +3831 +3832 +3833 +3834 +3835 +3836 +3837 +3838 +3839 +3840 +3841 +3842 +3843 +3844 +3845 +3846 +3847 +3848 +3849 +3850 +3851 +3852 +3853 +3854 +3855 +3856 +3857 +3858 +3859 +3860 +3861 +3862 +3863 +3864 +3865 +3866 +3867 +3868 +3869 +3870 +3871 +3872 +3873 +3874 +3875 +3876 +3877 +3878 +3879 +3880 +3881 +3882 +3883 +3884 +3885 +3886 +3887 +3888 +3889 +3890 +3891 +3892 +3893 +3894 +3895 +3896 +3897 +3898 +3899 +3900 +3901 +3902 +3903 +3904 +3905 +3906 +3907 +3908 +3909 +3910 +3911 +3912 +3913 +3914 +3915 +3916 +3917 +3918 +3919 +3920 +3921 +3922 +3923 +3924 +3925 +3926 +3927 +3928 +3929 +3930 +3931 +3932 +3933 +3934 +3935 +3936 +3937 +3938 +3939 +3940 +3941 +3942 +3943 +3944 +3945 +3946 +3947 +3948 +3949 +3950 +3951 +3952 +3953 +3954 +3955 +3956 +3957 +3958 +3959 +3960 +3961 +3962 +3963 +3964 +3965 +3966 +3967 +3968 +3969 +3970 +3971 +3972 +3973 +3974 +3975 +3976 +3977 +3978 +3979 +3980 +3981 +3982 +3983 +3984 +3985 +3986 +3987 +3988 +3989 +3990 +3991 +3992 +3993 +3994 +3995 +3996 +3997 +3998 +3999 +4000 diff --git a/test/static/executor/test_data/departments_500.csv b/test/static/executor/test_data/departments_500.csv new file mode 100644 index 0000000..14dcc8c --- /dev/null +++ b/test/static/executor/test_data/departments_500.csv @@ -0,0 +1,1001 @@ +id:int +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 +432 +433 +434 +435 +436 +437 +438 +439 +440 +441 +442 +443 +444 +445 +446 +447 +448 +449 +450 +451 +452 +453 +454 +455 +456 +457 +458 +459 +460 +461 +462 +463 +464 +465 +466 +467 +468 +469 +470 +471 +472 +473 +474 +475 +476 +477 +478 +479 +480 +481 +482 +483 +484 +485 +486 +487 +488 +489 +490 +491 +492 +493 +494 +495 +496 +497 +498 +499 +500 +501 +502 +503 +504 +505 +506 +507 +508 +509 +510 +511 +512 +513 +514 +515 +516 +517 +518 +519 +520 +521 +522 +523 +524 +525 +526 +527 +528 +529 +530 +531 +532 +533 +534 +535 +536 +537 +538 +539 +540 +541 +542 +543 +544 +545 +546 +547 +548 +549 +550 +551 +552 +553 +554 +555 +556 +557 +558 +559 +560 +561 +562 +563 +564 +565 +566 +567 +568 +569 +570 +571 +572 +573 +574 +575 +576 +577 +578 +579 +580 +581 +582 +583 +584 +585 +586 +587 +588 +589 +590 +591 +592 +593 +594 +595 +596 +597 +598 +599 +600 +601 +602 +603 +604 +605 +606 +607 +608 +609 +610 +611 +612 +613 +614 +615 +616 +617 +618 +619 +620 +621 +622 +623 +624 +625 +626 +627 +628 +629 +630 +631 +632 +633 +634 +635 +636 +637 +638 +639 +640 +641 +642 +643 +644 +645 +646 +647 +648 +649 +650 +651 +652 +653 +654 +655 +656 +657 +658 +659 +660 +661 +662 +663 +664 +665 +666 +667 +668 +669 +670 +671 +672 +673 +674 +675 +676 +677 +678 +679 +680 +681 +682 +683 +684 +685 +686 +687 +688 +689 +690 +691 +692 +693 +694 +695 +696 +697 +698 +699 +700 +701 +702 +703 +704 +705 +706 +707 +708 +709 +710 +711 +712 +713 +714 +715 +716 +717 +718 +719 +720 +721 +722 +723 +724 +725 +726 +727 +728 +729 +730 +731 +732 +733 +734 +735 +736 +737 +738 +739 +740 +741 +742 +743 +744 +745 +746 +747 +748 +749 +750 +751 +752 +753 +754 +755 +756 +757 +758 +759 +760 +761 +762 +763 +764 +765 +766 +767 +768 +769 +770 +771 +772 +773 +774 +775 +776 +777 +778 +779 +780 +781 +782 +783 +784 +785 +786 +787 +788 +789 +790 +791 +792 +793 +794 +795 +796 +797 +798 +799 +800 +801 +802 +803 +804 +805 +806 +807 +808 +809 +810 +811 +812 +813 +814 +815 +816 +817 +818 +819 +820 +821 +822 +823 +824 +825 +826 +827 +828 +829 +830 +831 +832 +833 +834 +835 +836 +837 +838 +839 +840 +841 +842 +843 +844 +845 +846 +847 +848 +849 +850 +851 +852 +853 +854 +855 +856 +857 +858 +859 +860 +861 +862 +863 +864 +865 +866 +867 +868 +869 +870 +871 +872 +873 +874 +875 +876 +877 +878 +879 +880 +881 +882 +883 +884 +885 +886 +887 +888 +889 +890 +891 +892 +893 +894 +895 +896 +897 +898 +899 +900 +901 +902 +903 +904 +905 +906 +907 +908 +909 +910 +911 +912 +913 +914 +915 +916 +917 +918 +919 +920 +921 +922 +923 +924 +925 +926 +927 +928 +929 +930 +931 +932 +933 +934 +935 +936 +937 +938 +939 +940 +941 +942 +943 +944 +945 +946 +947 +948 +949 +950 +951 +952 +953 +954 +955 +956 +957 +958 +959 +960 +961 +962 +963 +964 +965 +966 +967 +968 +969 +970 +971 +972 +973 +974 +975 +976 +977 +978 +979 +980 +981 +982 +983 +984 +985 +986 +987 +988 +989 +990 +991 +992 +993 +994 +995 +996 +997 +998 +999 +1000 diff --git a/test/static/executor/test_data/departments_8000.csv b/test/static/executor/test_data/departments_8000.csv new file mode 100644 index 0000000..df7c787 --- /dev/null +++ b/test/static/executor/test_data/departments_8000.csv @@ -0,0 +1,8001 @@ +id:int +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 +432 +433 +434 +435 +436 +437 +438 +439 +440 +441 +442 +443 +444 +445 +446 +447 +448 +449 +450 +451 +452 +453 +454 +455 +456 +457 +458 +459 +460 +461 +462 +463 +464 +465 +466 +467 +468 +469 +470 +471 +472 +473 +474 +475 +476 +477 +478 +479 +480 +481 +482 +483 +484 +485 +486 +487 +488 +489 +490 +491 +492 +493 +494 +495 +496 +497 +498 +499 +500 +501 +502 +503 +504 +505 +506 +507 +508 +509 +510 +511 +512 +513 +514 +515 +516 +517 +518 +519 +520 +521 +522 +523 +524 +525 +526 +527 +528 +529 +530 +531 +532 +533 +534 +535 +536 +537 +538 +539 +540 +541 +542 +543 +544 +545 +546 +547 +548 +549 +550 +551 +552 +553 +554 +555 +556 +557 +558 +559 +560 +561 +562 +563 +564 +565 +566 +567 +568 +569 +570 +571 +572 +573 +574 +575 +576 +577 +578 +579 +580 +581 +582 +583 +584 +585 +586 +587 +588 +589 +590 +591 +592 +593 +594 +595 +596 +597 +598 +599 +600 +601 +602 +603 +604 +605 +606 +607 +608 +609 +610 +611 +612 +613 +614 +615 +616 +617 +618 +619 +620 +621 +622 +623 +624 +625 +626 +627 +628 +629 +630 +631 +632 +633 +634 +635 +636 +637 +638 +639 +640 +641 +642 +643 +644 +645 +646 +647 +648 +649 +650 +651 +652 +653 +654 +655 +656 +657 +658 +659 +660 +661 +662 +663 +664 +665 +666 +667 +668 +669 +670 +671 +672 +673 +674 +675 +676 +677 +678 +679 +680 +681 +682 +683 +684 +685 +686 +687 +688 +689 +690 +691 +692 +693 +694 +695 +696 +697 +698 +699 +700 +701 +702 +703 +704 +705 +706 +707 +708 +709 +710 +711 +712 +713 +714 +715 +716 +717 +718 +719 +720 +721 +722 +723 +724 +725 +726 +727 +728 +729 +730 +731 +732 +733 +734 +735 +736 +737 +738 +739 +740 +741 +742 +743 +744 +745 +746 +747 +748 +749 +750 +751 +752 +753 +754 +755 +756 +757 +758 +759 +760 +761 +762 +763 +764 +765 +766 +767 +768 +769 +770 +771 +772 +773 +774 +775 +776 +777 +778 +779 +780 +781 +782 +783 +784 +785 +786 +787 +788 +789 +790 +791 +792 +793 +794 +795 +796 +797 +798 +799 +800 +801 +802 +803 +804 +805 +806 +807 +808 +809 +810 +811 +812 +813 +814 +815 +816 +817 +818 +819 +820 +821 +822 +823 +824 +825 +826 +827 +828 +829 +830 +831 +832 +833 +834 +835 +836 +837 +838 +839 +840 +841 +842 +843 +844 +845 +846 +847 +848 +849 +850 +851 +852 +853 +854 +855 +856 +857 +858 +859 +860 +861 +862 +863 +864 +865 +866 +867 +868 +869 +870 +871 +872 +873 +874 +875 +876 +877 +878 +879 +880 +881 +882 +883 +884 +885 +886 +887 +888 +889 +890 +891 +892 +893 +894 +895 +896 +897 +898 +899 +900 +901 +902 +903 +904 +905 +906 +907 +908 +909 +910 +911 +912 +913 +914 +915 +916 +917 +918 +919 +920 +921 +922 +923 +924 +925 +926 +927 +928 +929 +930 +931 +932 +933 +934 +935 +936 +937 +938 +939 +940 +941 +942 +943 +944 +945 +946 +947 +948 +949 +950 +951 +952 +953 +954 +955 +956 +957 +958 +959 +960 +961 +962 +963 +964 +965 +966 +967 +968 +969 +970 +971 +972 +973 +974 +975 +976 +977 +978 +979 +980 +981 +982 +983 +984 +985 +986 +987 +988 +989 +990 +991 +992 +993 +994 +995 +996 +997 +998 +999 +1000 +1001 +1002 +1003 +1004 +1005 +1006 +1007 +1008 +1009 +1010 +1011 +1012 +1013 +1014 +1015 +1016 +1017 +1018 +1019 +1020 +1021 +1022 +1023 +1024 +1025 +1026 +1027 +1028 +1029 +1030 +1031 +1032 +1033 +1034 +1035 +1036 +1037 +1038 +1039 +1040 +1041 +1042 +1043 +1044 +1045 +1046 +1047 +1048 +1049 +1050 +1051 +1052 +1053 +1054 +1055 +1056 +1057 +1058 +1059 +1060 +1061 +1062 +1063 +1064 +1065 +1066 +1067 +1068 +1069 +1070 +1071 +1072 +1073 +1074 +1075 +1076 +1077 +1078 +1079 +1080 +1081 +1082 +1083 +1084 +1085 +1086 +1087 +1088 +1089 +1090 +1091 +1092 +1093 +1094 +1095 +1096 +1097 +1098 +1099 +1100 +1101 +1102 +1103 +1104 +1105 +1106 +1107 +1108 +1109 +1110 +1111 +1112 +1113 +1114 +1115 +1116 +1117 +1118 +1119 +1120 +1121 +1122 +1123 +1124 +1125 +1126 +1127 +1128 +1129 +1130 +1131 +1132 +1133 +1134 +1135 +1136 +1137 +1138 +1139 +1140 +1141 +1142 +1143 +1144 +1145 +1146 +1147 +1148 +1149 +1150 +1151 +1152 +1153 +1154 +1155 +1156 +1157 +1158 +1159 +1160 +1161 +1162 +1163 +1164 +1165 +1166 +1167 +1168 +1169 +1170 +1171 +1172 +1173 +1174 +1175 +1176 +1177 +1178 +1179 +1180 +1181 +1182 +1183 +1184 +1185 +1186 +1187 +1188 +1189 +1190 +1191 +1192 +1193 +1194 +1195 +1196 +1197 +1198 +1199 +1200 +1201 +1202 +1203 +1204 +1205 +1206 +1207 +1208 +1209 +1210 +1211 +1212 +1213 +1214 +1215 +1216 +1217 +1218 +1219 +1220 +1221 +1222 +1223 +1224 +1225 +1226 +1227 +1228 +1229 +1230 +1231 +1232 +1233 +1234 +1235 +1236 +1237 +1238 +1239 +1240 +1241 +1242 +1243 +1244 +1245 +1246 +1247 +1248 +1249 +1250 +1251 +1252 +1253 +1254 +1255 +1256 +1257 +1258 +1259 +1260 +1261 +1262 +1263 +1264 +1265 +1266 +1267 +1268 +1269 +1270 +1271 +1272 +1273 +1274 +1275 +1276 +1277 +1278 +1279 +1280 +1281 +1282 +1283 +1284 +1285 +1286 +1287 +1288 +1289 +1290 +1291 +1292 +1293 +1294 +1295 +1296 +1297 +1298 +1299 +1300 +1301 +1302 +1303 +1304 +1305 +1306 +1307 +1308 +1309 +1310 +1311 +1312 +1313 +1314 +1315 +1316 +1317 +1318 +1319 +1320 +1321 +1322 +1323 +1324 +1325 +1326 +1327 +1328 +1329 +1330 +1331 +1332 +1333 +1334 +1335 +1336 +1337 +1338 +1339 +1340 +1341 +1342 +1343 +1344 +1345 +1346 +1347 +1348 +1349 +1350 +1351 +1352 +1353 +1354 +1355 +1356 +1357 +1358 +1359 +1360 +1361 +1362 +1363 +1364 +1365 +1366 +1367 +1368 +1369 +1370 +1371 +1372 +1373 +1374 +1375 +1376 +1377 +1378 +1379 +1380 +1381 +1382 +1383 +1384 +1385 +1386 +1387 +1388 +1389 +1390 +1391 +1392 +1393 +1394 +1395 +1396 +1397 +1398 +1399 +1400 +1401 +1402 +1403 +1404 +1405 +1406 +1407 +1408 +1409 +1410 +1411 +1412 +1413 +1414 +1415 +1416 +1417 +1418 +1419 +1420 +1421 +1422 +1423 +1424 +1425 +1426 +1427 +1428 +1429 +1430 +1431 +1432 +1433 +1434 +1435 +1436 +1437 +1438 +1439 +1440 +1441 +1442 +1443 +1444 +1445 +1446 +1447 +1448 +1449 +1450 +1451 +1452 +1453 +1454 +1455 +1456 +1457 +1458 +1459 +1460 +1461 +1462 +1463 +1464 +1465 +1466 +1467 +1468 +1469 +1470 +1471 +1472 +1473 +1474 +1475 +1476 +1477 +1478 +1479 +1480 +1481 +1482 +1483 +1484 +1485 +1486 +1487 +1488 +1489 +1490 +1491 +1492 +1493 +1494 +1495 +1496 +1497 +1498 +1499 +1500 +1501 +1502 +1503 +1504 +1505 +1506 +1507 +1508 +1509 +1510 +1511 +1512 +1513 +1514 +1515 +1516 +1517 +1518 +1519 +1520 +1521 +1522 +1523 +1524 +1525 +1526 +1527 +1528 +1529 +1530 +1531 +1532 +1533 +1534 +1535 +1536 +1537 +1538 +1539 +1540 +1541 +1542 +1543 +1544 +1545 +1546 +1547 +1548 +1549 +1550 +1551 +1552 +1553 +1554 +1555 +1556 +1557 +1558 +1559 +1560 +1561 +1562 +1563 +1564 +1565 +1566 +1567 +1568 +1569 +1570 +1571 +1572 +1573 +1574 +1575 +1576 +1577 +1578 +1579 +1580 +1581 +1582 +1583 +1584 +1585 +1586 +1587 +1588 +1589 +1590 +1591 +1592 +1593 +1594 +1595 +1596 +1597 +1598 +1599 +1600 +1601 +1602 +1603 +1604 +1605 +1606 +1607 +1608 +1609 +1610 +1611 +1612 +1613 +1614 +1615 +1616 +1617 +1618 +1619 +1620 +1621 +1622 +1623 +1624 +1625 +1626 +1627 +1628 +1629 +1630 +1631 +1632 +1633 +1634 +1635 +1636 +1637 +1638 +1639 +1640 +1641 +1642 +1643 +1644 +1645 +1646 +1647 +1648 +1649 +1650 +1651 +1652 +1653 +1654 +1655 +1656 +1657 +1658 +1659 +1660 +1661 +1662 +1663 +1664 +1665 +1666 +1667 +1668 +1669 +1670 +1671 +1672 +1673 +1674 +1675 +1676 +1677 +1678 +1679 +1680 +1681 +1682 +1683 +1684 +1685 +1686 +1687 +1688 +1689 +1690 +1691 +1692 +1693 +1694 +1695 +1696 +1697 +1698 +1699 +1700 +1701 +1702 +1703 +1704 +1705 +1706 +1707 +1708 +1709 +1710 +1711 +1712 +1713 +1714 +1715 +1716 +1717 +1718 +1719 +1720 +1721 +1722 +1723 +1724 +1725 +1726 +1727 +1728 +1729 +1730 +1731 +1732 +1733 +1734 +1735 +1736 +1737 +1738 +1739 +1740 +1741 +1742 +1743 +1744 +1745 +1746 +1747 +1748 +1749 +1750 +1751 +1752 +1753 +1754 +1755 +1756 +1757 +1758 +1759 +1760 +1761 +1762 +1763 +1764 +1765 +1766 +1767 +1768 +1769 +1770 +1771 +1772 +1773 +1774 +1775 +1776 +1777 +1778 +1779 +1780 +1781 +1782 +1783 +1784 +1785 +1786 +1787 +1788 +1789 +1790 +1791 +1792 +1793 +1794 +1795 +1796 +1797 +1798 +1799 +1800 +1801 +1802 +1803 +1804 +1805 +1806 +1807 +1808 +1809 +1810 +1811 +1812 +1813 +1814 +1815 +1816 +1817 +1818 +1819 +1820 +1821 +1822 +1823 +1824 +1825 +1826 +1827 +1828 +1829 +1830 +1831 +1832 +1833 +1834 +1835 +1836 +1837 +1838 +1839 +1840 +1841 +1842 +1843 +1844 +1845 +1846 +1847 +1848 +1849 +1850 +1851 +1852 +1853 +1854 +1855 +1856 +1857 +1858 +1859 +1860 +1861 +1862 +1863 +1864 +1865 +1866 +1867 +1868 +1869 +1870 +1871 +1872 +1873 +1874 +1875 +1876 +1877 +1878 +1879 +1880 +1881 +1882 +1883 +1884 +1885 +1886 +1887 +1888 +1889 +1890 +1891 +1892 +1893 +1894 +1895 +1896 +1897 +1898 +1899 +1900 +1901 +1902 +1903 +1904 +1905 +1906 +1907 +1908 +1909 +1910 +1911 +1912 +1913 +1914 +1915 +1916 +1917 +1918 +1919 +1920 +1921 +1922 +1923 +1924 +1925 +1926 +1927 +1928 +1929 +1930 +1931 +1932 +1933 +1934 +1935 +1936 +1937 +1938 +1939 +1940 +1941 +1942 +1943 +1944 +1945 +1946 +1947 +1948 +1949 +1950 +1951 +1952 +1953 +1954 +1955 +1956 +1957 +1958 +1959 +1960 +1961 +1962 +1963 +1964 +1965 +1966 +1967 +1968 +1969 +1970 +1971 +1972 +1973 +1974 +1975 +1976 +1977 +1978 +1979 +1980 +1981 +1982 +1983 +1984 +1985 +1986 +1987 +1988 +1989 +1990 +1991 +1992 +1993 +1994 +1995 +1996 +1997 +1998 +1999 +2000 +2001 +2002 +2003 +2004 +2005 +2006 +2007 +2008 +2009 +2010 +2011 +2012 +2013 +2014 +2015 +2016 +2017 +2018 +2019 +2020 +2021 +2022 +2023 +2024 +2025 +2026 +2027 +2028 +2029 +2030 +2031 +2032 +2033 +2034 +2035 +2036 +2037 +2038 +2039 +2040 +2041 +2042 +2043 +2044 +2045 +2046 +2047 +2048 +2049 +2050 +2051 +2052 +2053 +2054 +2055 +2056 +2057 +2058 +2059 +2060 +2061 +2062 +2063 +2064 +2065 +2066 +2067 +2068 +2069 +2070 +2071 +2072 +2073 +2074 +2075 +2076 +2077 +2078 +2079 +2080 +2081 +2082 +2083 +2084 +2085 +2086 +2087 +2088 +2089 +2090 +2091 +2092 +2093 +2094 +2095 +2096 +2097 +2098 +2099 +2100 +2101 +2102 +2103 +2104 +2105 +2106 +2107 +2108 +2109 +2110 +2111 +2112 +2113 +2114 +2115 +2116 +2117 +2118 +2119 +2120 +2121 +2122 +2123 +2124 +2125 +2126 +2127 +2128 +2129 +2130 +2131 +2132 +2133 +2134 +2135 +2136 +2137 +2138 +2139 +2140 +2141 +2142 +2143 +2144 +2145 +2146 +2147 +2148 +2149 +2150 +2151 +2152 +2153 +2154 +2155 +2156 +2157 +2158 +2159 +2160 +2161 +2162 +2163 +2164 +2165 +2166 +2167 +2168 +2169 +2170 +2171 +2172 +2173 +2174 +2175 +2176 +2177 +2178 +2179 +2180 +2181 +2182 +2183 +2184 +2185 +2186 +2187 +2188 +2189 +2190 +2191 +2192 +2193 +2194 +2195 +2196 +2197 +2198 +2199 +2200 +2201 +2202 +2203 +2204 +2205 +2206 +2207 +2208 +2209 +2210 +2211 +2212 +2213 +2214 +2215 +2216 +2217 +2218 +2219 +2220 +2221 +2222 +2223 +2224 +2225 +2226 +2227 +2228 +2229 +2230 +2231 +2232 +2233 +2234 +2235 +2236 +2237 +2238 +2239 +2240 +2241 +2242 +2243 +2244 +2245 +2246 +2247 +2248 +2249 +2250 +2251 +2252 +2253 +2254 +2255 +2256 +2257 +2258 +2259 +2260 +2261 +2262 +2263 +2264 +2265 +2266 +2267 +2268 +2269 +2270 +2271 +2272 +2273 +2274 +2275 +2276 +2277 +2278 +2279 +2280 +2281 +2282 +2283 +2284 +2285 +2286 +2287 +2288 +2289 +2290 +2291 +2292 +2293 +2294 +2295 +2296 +2297 +2298 +2299 +2300 +2301 +2302 +2303 +2304 +2305 +2306 +2307 +2308 +2309 +2310 +2311 +2312 +2313 +2314 +2315 +2316 +2317 +2318 +2319 +2320 +2321 +2322 +2323 +2324 +2325 +2326 +2327 +2328 +2329 +2330 +2331 +2332 +2333 +2334 +2335 +2336 +2337 +2338 +2339 +2340 +2341 +2342 +2343 +2344 +2345 +2346 +2347 +2348 +2349 +2350 +2351 +2352 +2353 +2354 +2355 +2356 +2357 +2358 +2359 +2360 +2361 +2362 +2363 +2364 +2365 +2366 +2367 +2368 +2369 +2370 +2371 +2372 +2373 +2374 +2375 +2376 +2377 +2378 +2379 +2380 +2381 +2382 +2383 +2384 +2385 +2386 +2387 +2388 +2389 +2390 +2391 +2392 +2393 +2394 +2395 +2396 +2397 +2398 +2399 +2400 +2401 +2402 +2403 +2404 +2405 +2406 +2407 +2408 +2409 +2410 +2411 +2412 +2413 +2414 +2415 +2416 +2417 +2418 +2419 +2420 +2421 +2422 +2423 +2424 +2425 +2426 +2427 +2428 +2429 +2430 +2431 +2432 +2433 +2434 +2435 +2436 +2437 +2438 +2439 +2440 +2441 +2442 +2443 +2444 +2445 +2446 +2447 +2448 +2449 +2450 +2451 +2452 +2453 +2454 +2455 +2456 +2457 +2458 +2459 +2460 +2461 +2462 +2463 +2464 +2465 +2466 +2467 +2468 +2469 +2470 +2471 +2472 +2473 +2474 +2475 +2476 +2477 +2478 +2479 +2480 +2481 +2482 +2483 +2484 +2485 +2486 +2487 +2488 +2489 +2490 +2491 +2492 +2493 +2494 +2495 +2496 +2497 +2498 +2499 +2500 +2501 +2502 +2503 +2504 +2505 +2506 +2507 +2508 +2509 +2510 +2511 +2512 +2513 +2514 +2515 +2516 +2517 +2518 +2519 +2520 +2521 +2522 +2523 +2524 +2525 +2526 +2527 +2528 +2529 +2530 +2531 +2532 +2533 +2534 +2535 +2536 +2537 +2538 +2539 +2540 +2541 +2542 +2543 +2544 +2545 +2546 +2547 +2548 +2549 +2550 +2551 +2552 +2553 +2554 +2555 +2556 +2557 +2558 +2559 +2560 +2561 +2562 +2563 +2564 +2565 +2566 +2567 +2568 +2569 +2570 +2571 +2572 +2573 +2574 +2575 +2576 +2577 +2578 +2579 +2580 +2581 +2582 +2583 +2584 +2585 +2586 +2587 +2588 +2589 +2590 +2591 +2592 +2593 +2594 +2595 +2596 +2597 +2598 +2599 +2600 +2601 +2602 +2603 +2604 +2605 +2606 +2607 +2608 +2609 +2610 +2611 +2612 +2613 +2614 +2615 +2616 +2617 +2618 +2619 +2620 +2621 +2622 +2623 +2624 +2625 +2626 +2627 +2628 +2629 +2630 +2631 +2632 +2633 +2634 +2635 +2636 +2637 +2638 +2639 +2640 +2641 +2642 +2643 +2644 +2645 +2646 +2647 +2648 +2649 +2650 +2651 +2652 +2653 +2654 +2655 +2656 +2657 +2658 +2659 +2660 +2661 +2662 +2663 +2664 +2665 +2666 +2667 +2668 +2669 +2670 +2671 +2672 +2673 +2674 +2675 +2676 +2677 +2678 +2679 +2680 +2681 +2682 +2683 +2684 +2685 +2686 +2687 +2688 +2689 +2690 +2691 +2692 +2693 +2694 +2695 +2696 +2697 +2698 +2699 +2700 +2701 +2702 +2703 +2704 +2705 +2706 +2707 +2708 +2709 +2710 +2711 +2712 +2713 +2714 +2715 +2716 +2717 +2718 +2719 +2720 +2721 +2722 +2723 +2724 +2725 +2726 +2727 +2728 +2729 +2730 +2731 +2732 +2733 +2734 +2735 +2736 +2737 +2738 +2739 +2740 +2741 +2742 +2743 +2744 +2745 +2746 +2747 +2748 +2749 +2750 +2751 +2752 +2753 +2754 +2755 +2756 +2757 +2758 +2759 +2760 +2761 +2762 +2763 +2764 +2765 +2766 +2767 +2768 +2769 +2770 +2771 +2772 +2773 +2774 +2775 +2776 +2777 +2778 +2779 +2780 +2781 +2782 +2783 +2784 +2785 +2786 +2787 +2788 +2789 +2790 +2791 +2792 +2793 +2794 +2795 +2796 +2797 +2798 +2799 +2800 +2801 +2802 +2803 +2804 +2805 +2806 +2807 +2808 +2809 +2810 +2811 +2812 +2813 +2814 +2815 +2816 +2817 +2818 +2819 +2820 +2821 +2822 +2823 +2824 +2825 +2826 +2827 +2828 +2829 +2830 +2831 +2832 +2833 +2834 +2835 +2836 +2837 +2838 +2839 +2840 +2841 +2842 +2843 +2844 +2845 +2846 +2847 +2848 +2849 +2850 +2851 +2852 +2853 +2854 +2855 +2856 +2857 +2858 +2859 +2860 +2861 +2862 +2863 +2864 +2865 +2866 +2867 +2868 +2869 +2870 +2871 +2872 +2873 +2874 +2875 +2876 +2877 +2878 +2879 +2880 +2881 +2882 +2883 +2884 +2885 +2886 +2887 +2888 +2889 +2890 +2891 +2892 +2893 +2894 +2895 +2896 +2897 +2898 +2899 +2900 +2901 +2902 +2903 +2904 +2905 +2906 +2907 +2908 +2909 +2910 +2911 +2912 +2913 +2914 +2915 +2916 +2917 +2918 +2919 +2920 +2921 +2922 +2923 +2924 +2925 +2926 +2927 +2928 +2929 +2930 +2931 +2932 +2933 +2934 +2935 +2936 +2937 +2938 +2939 +2940 +2941 +2942 +2943 +2944 +2945 +2946 +2947 +2948 +2949 +2950 +2951 +2952 +2953 +2954 +2955 +2956 +2957 +2958 +2959 +2960 +2961 +2962 +2963 +2964 +2965 +2966 +2967 +2968 +2969 +2970 +2971 +2972 +2973 +2974 +2975 +2976 +2977 +2978 +2979 +2980 +2981 +2982 +2983 +2984 +2985 +2986 +2987 +2988 +2989 +2990 +2991 +2992 +2993 +2994 +2995 +2996 +2997 +2998 +2999 +3000 +3001 +3002 +3003 +3004 +3005 +3006 +3007 +3008 +3009 +3010 +3011 +3012 +3013 +3014 +3015 +3016 +3017 +3018 +3019 +3020 +3021 +3022 +3023 +3024 +3025 +3026 +3027 +3028 +3029 +3030 +3031 +3032 +3033 +3034 +3035 +3036 +3037 +3038 +3039 +3040 +3041 +3042 +3043 +3044 +3045 +3046 +3047 +3048 +3049 +3050 +3051 +3052 +3053 +3054 +3055 +3056 +3057 +3058 +3059 +3060 +3061 +3062 +3063 +3064 +3065 +3066 +3067 +3068 +3069 +3070 +3071 +3072 +3073 +3074 +3075 +3076 +3077 +3078 +3079 +3080 +3081 +3082 +3083 +3084 +3085 +3086 +3087 +3088 +3089 +3090 +3091 +3092 +3093 +3094 +3095 +3096 +3097 +3098 +3099 +3100 +3101 +3102 +3103 +3104 +3105 +3106 +3107 +3108 +3109 +3110 +3111 +3112 +3113 +3114 +3115 +3116 +3117 +3118 +3119 +3120 +3121 +3122 +3123 +3124 +3125 +3126 +3127 +3128 +3129 +3130 +3131 +3132 +3133 +3134 +3135 +3136 +3137 +3138 +3139 +3140 +3141 +3142 +3143 +3144 +3145 +3146 +3147 +3148 +3149 +3150 +3151 +3152 +3153 +3154 +3155 +3156 +3157 +3158 +3159 +3160 +3161 +3162 +3163 +3164 +3165 +3166 +3167 +3168 +3169 +3170 +3171 +3172 +3173 +3174 +3175 +3176 +3177 +3178 +3179 +3180 +3181 +3182 +3183 +3184 +3185 +3186 +3187 +3188 +3189 +3190 +3191 +3192 +3193 +3194 +3195 +3196 +3197 +3198 +3199 +3200 +3201 +3202 +3203 +3204 +3205 +3206 +3207 +3208 +3209 +3210 +3211 +3212 +3213 +3214 +3215 +3216 +3217 +3218 +3219 +3220 +3221 +3222 +3223 +3224 +3225 +3226 +3227 +3228 +3229 +3230 +3231 +3232 +3233 +3234 +3235 +3236 +3237 +3238 +3239 +3240 +3241 +3242 +3243 +3244 +3245 +3246 +3247 +3248 +3249 +3250 +3251 +3252 +3253 +3254 +3255 +3256 +3257 +3258 +3259 +3260 +3261 +3262 +3263 +3264 +3265 +3266 +3267 +3268 +3269 +3270 +3271 +3272 +3273 +3274 +3275 +3276 +3277 +3278 +3279 +3280 +3281 +3282 +3283 +3284 +3285 +3286 +3287 +3288 +3289 +3290 +3291 +3292 +3293 +3294 +3295 +3296 +3297 +3298 +3299 +3300 +3301 +3302 +3303 +3304 +3305 +3306 +3307 +3308 +3309 +3310 +3311 +3312 +3313 +3314 +3315 +3316 +3317 +3318 +3319 +3320 +3321 +3322 +3323 +3324 +3325 +3326 +3327 +3328 +3329 +3330 +3331 +3332 +3333 +3334 +3335 +3336 +3337 +3338 +3339 +3340 +3341 +3342 +3343 +3344 +3345 +3346 +3347 +3348 +3349 +3350 +3351 +3352 +3353 +3354 +3355 +3356 +3357 +3358 +3359 +3360 +3361 +3362 +3363 +3364 +3365 +3366 +3367 +3368 +3369 +3370 +3371 +3372 +3373 +3374 +3375 +3376 +3377 +3378 +3379 +3380 +3381 +3382 +3383 +3384 +3385 +3386 +3387 +3388 +3389 +3390 +3391 +3392 +3393 +3394 +3395 +3396 +3397 +3398 +3399 +3400 +3401 +3402 +3403 +3404 +3405 +3406 +3407 +3408 +3409 +3410 +3411 +3412 +3413 +3414 +3415 +3416 +3417 +3418 +3419 +3420 +3421 +3422 +3423 +3424 +3425 +3426 +3427 +3428 +3429 +3430 +3431 +3432 +3433 +3434 +3435 +3436 +3437 +3438 +3439 +3440 +3441 +3442 +3443 +3444 +3445 +3446 +3447 +3448 +3449 +3450 +3451 +3452 +3453 +3454 +3455 +3456 +3457 +3458 +3459 +3460 +3461 +3462 +3463 +3464 +3465 +3466 +3467 +3468 +3469 +3470 +3471 +3472 +3473 +3474 +3475 +3476 +3477 +3478 +3479 +3480 +3481 +3482 +3483 +3484 +3485 +3486 +3487 +3488 +3489 +3490 +3491 +3492 +3493 +3494 +3495 +3496 +3497 +3498 +3499 +3500 +3501 +3502 +3503 +3504 +3505 +3506 +3507 +3508 +3509 +3510 +3511 +3512 +3513 +3514 +3515 +3516 +3517 +3518 +3519 +3520 +3521 +3522 +3523 +3524 +3525 +3526 +3527 +3528 +3529 +3530 +3531 +3532 +3533 +3534 +3535 +3536 +3537 +3538 +3539 +3540 +3541 +3542 +3543 +3544 +3545 +3546 +3547 +3548 +3549 +3550 +3551 +3552 +3553 +3554 +3555 +3556 +3557 +3558 +3559 +3560 +3561 +3562 +3563 +3564 +3565 +3566 +3567 +3568 +3569 +3570 +3571 +3572 +3573 +3574 +3575 +3576 +3577 +3578 +3579 +3580 +3581 +3582 +3583 +3584 +3585 +3586 +3587 +3588 +3589 +3590 +3591 +3592 +3593 +3594 +3595 +3596 +3597 +3598 +3599 +3600 +3601 +3602 +3603 +3604 +3605 +3606 +3607 +3608 +3609 +3610 +3611 +3612 +3613 +3614 +3615 +3616 +3617 +3618 +3619 +3620 +3621 +3622 +3623 +3624 +3625 +3626 +3627 +3628 +3629 +3630 +3631 +3632 +3633 +3634 +3635 +3636 +3637 +3638 +3639 +3640 +3641 +3642 +3643 +3644 +3645 +3646 +3647 +3648 +3649 +3650 +3651 +3652 +3653 +3654 +3655 +3656 +3657 +3658 +3659 +3660 +3661 +3662 +3663 +3664 +3665 +3666 +3667 +3668 +3669 +3670 +3671 +3672 +3673 +3674 +3675 +3676 +3677 +3678 +3679 +3680 +3681 +3682 +3683 +3684 +3685 +3686 +3687 +3688 +3689 +3690 +3691 +3692 +3693 +3694 +3695 +3696 +3697 +3698 +3699 +3700 +3701 +3702 +3703 +3704 +3705 +3706 +3707 +3708 +3709 +3710 +3711 +3712 +3713 +3714 +3715 +3716 +3717 +3718 +3719 +3720 +3721 +3722 +3723 +3724 +3725 +3726 +3727 +3728 +3729 +3730 +3731 +3732 +3733 +3734 +3735 +3736 +3737 +3738 +3739 +3740 +3741 +3742 +3743 +3744 +3745 +3746 +3747 +3748 +3749 +3750 +3751 +3752 +3753 +3754 +3755 +3756 +3757 +3758 +3759 +3760 +3761 +3762 +3763 +3764 +3765 +3766 +3767 +3768 +3769 +3770 +3771 +3772 +3773 +3774 +3775 +3776 +3777 +3778 +3779 +3780 +3781 +3782 +3783 +3784 +3785 +3786 +3787 +3788 +3789 +3790 +3791 +3792 +3793 +3794 +3795 +3796 +3797 +3798 +3799 +3800 +3801 +3802 +3803 +3804 +3805 +3806 +3807 +3808 +3809 +3810 +3811 +3812 +3813 +3814 +3815 +3816 +3817 +3818 +3819 +3820 +3821 +3822 +3823 +3824 +3825 +3826 +3827 +3828 +3829 +3830 +3831 +3832 +3833 +3834 +3835 +3836 +3837 +3838 +3839 +3840 +3841 +3842 +3843 +3844 +3845 +3846 +3847 +3848 +3849 +3850 +3851 +3852 +3853 +3854 +3855 +3856 +3857 +3858 +3859 +3860 +3861 +3862 +3863 +3864 +3865 +3866 +3867 +3868 +3869 +3870 +3871 +3872 +3873 +3874 +3875 +3876 +3877 +3878 +3879 +3880 +3881 +3882 +3883 +3884 +3885 +3886 +3887 +3888 +3889 +3890 +3891 +3892 +3893 +3894 +3895 +3896 +3897 +3898 +3899 +3900 +3901 +3902 +3903 +3904 +3905 +3906 +3907 +3908 +3909 +3910 +3911 +3912 +3913 +3914 +3915 +3916 +3917 +3918 +3919 +3920 +3921 +3922 +3923 +3924 +3925 +3926 +3927 +3928 +3929 +3930 +3931 +3932 +3933 +3934 +3935 +3936 +3937 +3938 +3939 +3940 +3941 +3942 +3943 +3944 +3945 +3946 +3947 +3948 +3949 +3950 +3951 +3952 +3953 +3954 +3955 +3956 +3957 +3958 +3959 +3960 +3961 +3962 +3963 +3964 +3965 +3966 +3967 +3968 +3969 +3970 +3971 +3972 +3973 +3974 +3975 +3976 +3977 +3978 +3979 +3980 +3981 +3982 +3983 +3984 +3985 +3986 +3987 +3988 +3989 +3990 +3991 +3992 +3993 +3994 +3995 +3996 +3997 +3998 +3999 +4000 +4001 +4002 +4003 +4004 +4005 +4006 +4007 +4008 +4009 +4010 +4011 +4012 +4013 +4014 +4015 +4016 +4017 +4018 +4019 +4020 +4021 +4022 +4023 +4024 +4025 +4026 +4027 +4028 +4029 +4030 +4031 +4032 +4033 +4034 +4035 +4036 +4037 +4038 +4039 +4040 +4041 +4042 +4043 +4044 +4045 +4046 +4047 +4048 +4049 +4050 +4051 +4052 +4053 +4054 +4055 +4056 +4057 +4058 +4059 +4060 +4061 +4062 +4063 +4064 +4065 +4066 +4067 +4068 +4069 +4070 +4071 +4072 +4073 +4074 +4075 +4076 +4077 +4078 +4079 +4080 +4081 +4082 +4083 +4084 +4085 +4086 +4087 +4088 +4089 +4090 +4091 +4092 +4093 +4094 +4095 +4096 +4097 +4098 +4099 +4100 +4101 +4102 +4103 +4104 +4105 +4106 +4107 +4108 +4109 +4110 +4111 +4112 +4113 +4114 +4115 +4116 +4117 +4118 +4119 +4120 +4121 +4122 +4123 +4124 +4125 +4126 +4127 +4128 +4129 +4130 +4131 +4132 +4133 +4134 +4135 +4136 +4137 +4138 +4139 +4140 +4141 +4142 +4143 +4144 +4145 +4146 +4147 +4148 +4149 +4150 +4151 +4152 +4153 +4154 +4155 +4156 +4157 +4158 +4159 +4160 +4161 +4162 +4163 +4164 +4165 +4166 +4167 +4168 +4169 +4170 +4171 +4172 +4173 +4174 +4175 +4176 +4177 +4178 +4179 +4180 +4181 +4182 +4183 +4184 +4185 +4186 +4187 +4188 +4189 +4190 +4191 +4192 +4193 +4194 +4195 +4196 +4197 +4198 +4199 +4200 +4201 +4202 +4203 +4204 +4205 +4206 +4207 +4208 +4209 +4210 +4211 +4212 +4213 +4214 +4215 +4216 +4217 +4218 +4219 +4220 +4221 +4222 +4223 +4224 +4225 +4226 +4227 +4228 +4229 +4230 +4231 +4232 +4233 +4234 +4235 +4236 +4237 +4238 +4239 +4240 +4241 +4242 +4243 +4244 +4245 +4246 +4247 +4248 +4249 +4250 +4251 +4252 +4253 +4254 +4255 +4256 +4257 +4258 +4259 +4260 +4261 +4262 +4263 +4264 +4265 +4266 +4267 +4268 +4269 +4270 +4271 +4272 +4273 +4274 +4275 +4276 +4277 +4278 +4279 +4280 +4281 +4282 +4283 +4284 +4285 +4286 +4287 +4288 +4289 +4290 +4291 +4292 +4293 +4294 +4295 +4296 +4297 +4298 +4299 +4300 +4301 +4302 +4303 +4304 +4305 +4306 +4307 +4308 +4309 +4310 +4311 +4312 +4313 +4314 +4315 +4316 +4317 +4318 +4319 +4320 +4321 +4322 +4323 +4324 +4325 +4326 +4327 +4328 +4329 +4330 +4331 +4332 +4333 +4334 +4335 +4336 +4337 +4338 +4339 +4340 +4341 +4342 +4343 +4344 +4345 +4346 +4347 +4348 +4349 +4350 +4351 +4352 +4353 +4354 +4355 +4356 +4357 +4358 +4359 +4360 +4361 +4362 +4363 +4364 +4365 +4366 +4367 +4368 +4369 +4370 +4371 +4372 +4373 +4374 +4375 +4376 +4377 +4378 +4379 +4380 +4381 +4382 +4383 +4384 +4385 +4386 +4387 +4388 +4389 +4390 +4391 +4392 +4393 +4394 +4395 +4396 +4397 +4398 +4399 +4400 +4401 +4402 +4403 +4404 +4405 +4406 +4407 +4408 +4409 +4410 +4411 +4412 +4413 +4414 +4415 +4416 +4417 +4418 +4419 +4420 +4421 +4422 +4423 +4424 +4425 +4426 +4427 +4428 +4429 +4430 +4431 +4432 +4433 +4434 +4435 +4436 +4437 +4438 +4439 +4440 +4441 +4442 +4443 +4444 +4445 +4446 +4447 +4448 +4449 +4450 +4451 +4452 +4453 +4454 +4455 +4456 +4457 +4458 +4459 +4460 +4461 +4462 +4463 +4464 +4465 +4466 +4467 +4468 +4469 +4470 +4471 +4472 +4473 +4474 +4475 +4476 +4477 +4478 +4479 +4480 +4481 +4482 +4483 +4484 +4485 +4486 +4487 +4488 +4489 +4490 +4491 +4492 +4493 +4494 +4495 +4496 +4497 +4498 +4499 +4500 +4501 +4502 +4503 +4504 +4505 +4506 +4507 +4508 +4509 +4510 +4511 +4512 +4513 +4514 +4515 +4516 +4517 +4518 +4519 +4520 +4521 +4522 +4523 +4524 +4525 +4526 +4527 +4528 +4529 +4530 +4531 +4532 +4533 +4534 +4535 +4536 +4537 +4538 +4539 +4540 +4541 +4542 +4543 +4544 +4545 +4546 +4547 +4548 +4549 +4550 +4551 +4552 +4553 +4554 +4555 +4556 +4557 +4558 +4559 +4560 +4561 +4562 +4563 +4564 +4565 +4566 +4567 +4568 +4569 +4570 +4571 +4572 +4573 +4574 +4575 +4576 +4577 +4578 +4579 +4580 +4581 +4582 +4583 +4584 +4585 +4586 +4587 +4588 +4589 +4590 +4591 +4592 +4593 +4594 +4595 +4596 +4597 +4598 +4599 +4600 +4601 +4602 +4603 +4604 +4605 +4606 +4607 +4608 +4609 +4610 +4611 +4612 +4613 +4614 +4615 +4616 +4617 +4618 +4619 +4620 +4621 +4622 +4623 +4624 +4625 +4626 +4627 +4628 +4629 +4630 +4631 +4632 +4633 +4634 +4635 +4636 +4637 +4638 +4639 +4640 +4641 +4642 +4643 +4644 +4645 +4646 +4647 +4648 +4649 +4650 +4651 +4652 +4653 +4654 +4655 +4656 +4657 +4658 +4659 +4660 +4661 +4662 +4663 +4664 +4665 +4666 +4667 +4668 +4669 +4670 +4671 +4672 +4673 +4674 +4675 +4676 +4677 +4678 +4679 +4680 +4681 +4682 +4683 +4684 +4685 +4686 +4687 +4688 +4689 +4690 +4691 +4692 +4693 +4694 +4695 +4696 +4697 +4698 +4699 +4700 +4701 +4702 +4703 +4704 +4705 +4706 +4707 +4708 +4709 +4710 +4711 +4712 +4713 +4714 +4715 +4716 +4717 +4718 +4719 +4720 +4721 +4722 +4723 +4724 +4725 +4726 +4727 +4728 +4729 +4730 +4731 +4732 +4733 +4734 +4735 +4736 +4737 +4738 +4739 +4740 +4741 +4742 +4743 +4744 +4745 +4746 +4747 +4748 +4749 +4750 +4751 +4752 +4753 +4754 +4755 +4756 +4757 +4758 +4759 +4760 +4761 +4762 +4763 +4764 +4765 +4766 +4767 +4768 +4769 +4770 +4771 +4772 +4773 +4774 +4775 +4776 +4777 +4778 +4779 +4780 +4781 +4782 +4783 +4784 +4785 +4786 +4787 +4788 +4789 +4790 +4791 +4792 +4793 +4794 +4795 +4796 +4797 +4798 +4799 +4800 +4801 +4802 +4803 +4804 +4805 +4806 +4807 +4808 +4809 +4810 +4811 +4812 +4813 +4814 +4815 +4816 +4817 +4818 +4819 +4820 +4821 +4822 +4823 +4824 +4825 +4826 +4827 +4828 +4829 +4830 +4831 +4832 +4833 +4834 +4835 +4836 +4837 +4838 +4839 +4840 +4841 +4842 +4843 +4844 +4845 +4846 +4847 +4848 +4849 +4850 +4851 +4852 +4853 +4854 +4855 +4856 +4857 +4858 +4859 +4860 +4861 +4862 +4863 +4864 +4865 +4866 +4867 +4868 +4869 +4870 +4871 +4872 +4873 +4874 +4875 +4876 +4877 +4878 +4879 +4880 +4881 +4882 +4883 +4884 +4885 +4886 +4887 +4888 +4889 +4890 +4891 +4892 +4893 +4894 +4895 +4896 +4897 +4898 +4899 +4900 +4901 +4902 +4903 +4904 +4905 +4906 +4907 +4908 +4909 +4910 +4911 +4912 +4913 +4914 +4915 +4916 +4917 +4918 +4919 +4920 +4921 +4922 +4923 +4924 +4925 +4926 +4927 +4928 +4929 +4930 +4931 +4932 +4933 +4934 +4935 +4936 +4937 +4938 +4939 +4940 +4941 +4942 +4943 +4944 +4945 +4946 +4947 +4948 +4949 +4950 +4951 +4952 +4953 +4954 +4955 +4956 +4957 +4958 +4959 +4960 +4961 +4962 +4963 +4964 +4965 +4966 +4967 +4968 +4969 +4970 +4971 +4972 +4973 +4974 +4975 +4976 +4977 +4978 +4979 +4980 +4981 +4982 +4983 +4984 +4985 +4986 +4987 +4988 +4989 +4990 +4991 +4992 +4993 +4994 +4995 +4996 +4997 +4998 +4999 +5000 +5001 +5002 +5003 +5004 +5005 +5006 +5007 +5008 +5009 +5010 +5011 +5012 +5013 +5014 +5015 +5016 +5017 +5018 +5019 +5020 +5021 +5022 +5023 +5024 +5025 +5026 +5027 +5028 +5029 +5030 +5031 +5032 +5033 +5034 +5035 +5036 +5037 +5038 +5039 +5040 +5041 +5042 +5043 +5044 +5045 +5046 +5047 +5048 +5049 +5050 +5051 +5052 +5053 +5054 +5055 +5056 +5057 +5058 +5059 +5060 +5061 +5062 +5063 +5064 +5065 +5066 +5067 +5068 +5069 +5070 +5071 +5072 +5073 +5074 +5075 +5076 +5077 +5078 +5079 +5080 +5081 +5082 +5083 +5084 +5085 +5086 +5087 +5088 +5089 +5090 +5091 +5092 +5093 +5094 +5095 +5096 +5097 +5098 +5099 +5100 +5101 +5102 +5103 +5104 +5105 +5106 +5107 +5108 +5109 +5110 +5111 +5112 +5113 +5114 +5115 +5116 +5117 +5118 +5119 +5120 +5121 +5122 +5123 +5124 +5125 +5126 +5127 +5128 +5129 +5130 +5131 +5132 +5133 +5134 +5135 +5136 +5137 +5138 +5139 +5140 +5141 +5142 +5143 +5144 +5145 +5146 +5147 +5148 +5149 +5150 +5151 +5152 +5153 +5154 +5155 +5156 +5157 +5158 +5159 +5160 +5161 +5162 +5163 +5164 +5165 +5166 +5167 +5168 +5169 +5170 +5171 +5172 +5173 +5174 +5175 +5176 +5177 +5178 +5179 +5180 +5181 +5182 +5183 +5184 +5185 +5186 +5187 +5188 +5189 +5190 +5191 +5192 +5193 +5194 +5195 +5196 +5197 +5198 +5199 +5200 +5201 +5202 +5203 +5204 +5205 +5206 +5207 +5208 +5209 +5210 +5211 +5212 +5213 +5214 +5215 +5216 +5217 +5218 +5219 +5220 +5221 +5222 +5223 +5224 +5225 +5226 +5227 +5228 +5229 +5230 +5231 +5232 +5233 +5234 +5235 +5236 +5237 +5238 +5239 +5240 +5241 +5242 +5243 +5244 +5245 +5246 +5247 +5248 +5249 +5250 +5251 +5252 +5253 +5254 +5255 +5256 +5257 +5258 +5259 +5260 +5261 +5262 +5263 +5264 +5265 +5266 +5267 +5268 +5269 +5270 +5271 +5272 +5273 +5274 +5275 +5276 +5277 +5278 +5279 +5280 +5281 +5282 +5283 +5284 +5285 +5286 +5287 +5288 +5289 +5290 +5291 +5292 +5293 +5294 +5295 +5296 +5297 +5298 +5299 +5300 +5301 +5302 +5303 +5304 +5305 +5306 +5307 +5308 +5309 +5310 +5311 +5312 +5313 +5314 +5315 +5316 +5317 +5318 +5319 +5320 +5321 +5322 +5323 +5324 +5325 +5326 +5327 +5328 +5329 +5330 +5331 +5332 +5333 +5334 +5335 +5336 +5337 +5338 +5339 +5340 +5341 +5342 +5343 +5344 +5345 +5346 +5347 +5348 +5349 +5350 +5351 +5352 +5353 +5354 +5355 +5356 +5357 +5358 +5359 +5360 +5361 +5362 +5363 +5364 +5365 +5366 +5367 +5368 +5369 +5370 +5371 +5372 +5373 +5374 +5375 +5376 +5377 +5378 +5379 +5380 +5381 +5382 +5383 +5384 +5385 +5386 +5387 +5388 +5389 +5390 +5391 +5392 +5393 +5394 +5395 +5396 +5397 +5398 +5399 +5400 +5401 +5402 +5403 +5404 +5405 +5406 +5407 +5408 +5409 +5410 +5411 +5412 +5413 +5414 +5415 +5416 +5417 +5418 +5419 +5420 +5421 +5422 +5423 +5424 +5425 +5426 +5427 +5428 +5429 +5430 +5431 +5432 +5433 +5434 +5435 +5436 +5437 +5438 +5439 +5440 +5441 +5442 +5443 +5444 +5445 +5446 +5447 +5448 +5449 +5450 +5451 +5452 +5453 +5454 +5455 +5456 +5457 +5458 +5459 +5460 +5461 +5462 +5463 +5464 +5465 +5466 +5467 +5468 +5469 +5470 +5471 +5472 +5473 +5474 +5475 +5476 +5477 +5478 +5479 +5480 +5481 +5482 +5483 +5484 +5485 +5486 +5487 +5488 +5489 +5490 +5491 +5492 +5493 +5494 +5495 +5496 +5497 +5498 +5499 +5500 +5501 +5502 +5503 +5504 +5505 +5506 +5507 +5508 +5509 +5510 +5511 +5512 +5513 +5514 +5515 +5516 +5517 +5518 +5519 +5520 +5521 +5522 +5523 +5524 +5525 +5526 +5527 +5528 +5529 +5530 +5531 +5532 +5533 +5534 +5535 +5536 +5537 +5538 +5539 +5540 +5541 +5542 +5543 +5544 +5545 +5546 +5547 +5548 +5549 +5550 +5551 +5552 +5553 +5554 +5555 +5556 +5557 +5558 +5559 +5560 +5561 +5562 +5563 +5564 +5565 +5566 +5567 +5568 +5569 +5570 +5571 +5572 +5573 +5574 +5575 +5576 +5577 +5578 +5579 +5580 +5581 +5582 +5583 +5584 +5585 +5586 +5587 +5588 +5589 +5590 +5591 +5592 +5593 +5594 +5595 +5596 +5597 +5598 +5599 +5600 +5601 +5602 +5603 +5604 +5605 +5606 +5607 +5608 +5609 +5610 +5611 +5612 +5613 +5614 +5615 +5616 +5617 +5618 +5619 +5620 +5621 +5622 +5623 +5624 +5625 +5626 +5627 +5628 +5629 +5630 +5631 +5632 +5633 +5634 +5635 +5636 +5637 +5638 +5639 +5640 +5641 +5642 +5643 +5644 +5645 +5646 +5647 +5648 +5649 +5650 +5651 +5652 +5653 +5654 +5655 +5656 +5657 +5658 +5659 +5660 +5661 +5662 +5663 +5664 +5665 +5666 +5667 +5668 +5669 +5670 +5671 +5672 +5673 +5674 +5675 +5676 +5677 +5678 +5679 +5680 +5681 +5682 +5683 +5684 +5685 +5686 +5687 +5688 +5689 +5690 +5691 +5692 +5693 +5694 +5695 +5696 +5697 +5698 +5699 +5700 +5701 +5702 +5703 +5704 +5705 +5706 +5707 +5708 +5709 +5710 +5711 +5712 +5713 +5714 +5715 +5716 +5717 +5718 +5719 +5720 +5721 +5722 +5723 +5724 +5725 +5726 +5727 +5728 +5729 +5730 +5731 +5732 +5733 +5734 +5735 +5736 +5737 +5738 +5739 +5740 +5741 +5742 +5743 +5744 +5745 +5746 +5747 +5748 +5749 +5750 +5751 +5752 +5753 +5754 +5755 +5756 +5757 +5758 +5759 +5760 +5761 +5762 +5763 +5764 +5765 +5766 +5767 +5768 +5769 +5770 +5771 +5772 +5773 +5774 +5775 +5776 +5777 +5778 +5779 +5780 +5781 +5782 +5783 +5784 +5785 +5786 +5787 +5788 +5789 +5790 +5791 +5792 +5793 +5794 +5795 +5796 +5797 +5798 +5799 +5800 +5801 +5802 +5803 +5804 +5805 +5806 +5807 +5808 +5809 +5810 +5811 +5812 +5813 +5814 +5815 +5816 +5817 +5818 +5819 +5820 +5821 +5822 +5823 +5824 +5825 +5826 +5827 +5828 +5829 +5830 +5831 +5832 +5833 +5834 +5835 +5836 +5837 +5838 +5839 +5840 +5841 +5842 +5843 +5844 +5845 +5846 +5847 +5848 +5849 +5850 +5851 +5852 +5853 +5854 +5855 +5856 +5857 +5858 +5859 +5860 +5861 +5862 +5863 +5864 +5865 +5866 +5867 +5868 +5869 +5870 +5871 +5872 +5873 +5874 +5875 +5876 +5877 +5878 +5879 +5880 +5881 +5882 +5883 +5884 +5885 +5886 +5887 +5888 +5889 +5890 +5891 +5892 +5893 +5894 +5895 +5896 +5897 +5898 +5899 +5900 +5901 +5902 +5903 +5904 +5905 +5906 +5907 +5908 +5909 +5910 +5911 +5912 +5913 +5914 +5915 +5916 +5917 +5918 +5919 +5920 +5921 +5922 +5923 +5924 +5925 +5926 +5927 +5928 +5929 +5930 +5931 +5932 +5933 +5934 +5935 +5936 +5937 +5938 +5939 +5940 +5941 +5942 +5943 +5944 +5945 +5946 +5947 +5948 +5949 +5950 +5951 +5952 +5953 +5954 +5955 +5956 +5957 +5958 +5959 +5960 +5961 +5962 +5963 +5964 +5965 +5966 +5967 +5968 +5969 +5970 +5971 +5972 +5973 +5974 +5975 +5976 +5977 +5978 +5979 +5980 +5981 +5982 +5983 +5984 +5985 +5986 +5987 +5988 +5989 +5990 +5991 +5992 +5993 +5994 +5995 +5996 +5997 +5998 +5999 +6000 +6001 +6002 +6003 +6004 +6005 +6006 +6007 +6008 +6009 +6010 +6011 +6012 +6013 +6014 +6015 +6016 +6017 +6018 +6019 +6020 +6021 +6022 +6023 +6024 +6025 +6026 +6027 +6028 +6029 +6030 +6031 +6032 +6033 +6034 +6035 +6036 +6037 +6038 +6039 +6040 +6041 +6042 +6043 +6044 +6045 +6046 +6047 +6048 +6049 +6050 +6051 +6052 +6053 +6054 +6055 +6056 +6057 +6058 +6059 +6060 +6061 +6062 +6063 +6064 +6065 +6066 +6067 +6068 +6069 +6070 +6071 +6072 +6073 +6074 +6075 +6076 +6077 +6078 +6079 +6080 +6081 +6082 +6083 +6084 +6085 +6086 +6087 +6088 +6089 +6090 +6091 +6092 +6093 +6094 +6095 +6096 +6097 +6098 +6099 +6100 +6101 +6102 +6103 +6104 +6105 +6106 +6107 +6108 +6109 +6110 +6111 +6112 +6113 +6114 +6115 +6116 +6117 +6118 +6119 +6120 +6121 +6122 +6123 +6124 +6125 +6126 +6127 +6128 +6129 +6130 +6131 +6132 +6133 +6134 +6135 +6136 +6137 +6138 +6139 +6140 +6141 +6142 +6143 +6144 +6145 +6146 +6147 +6148 +6149 +6150 +6151 +6152 +6153 +6154 +6155 +6156 +6157 +6158 +6159 +6160 +6161 +6162 +6163 +6164 +6165 +6166 +6167 +6168 +6169 +6170 +6171 +6172 +6173 +6174 +6175 +6176 +6177 +6178 +6179 +6180 +6181 +6182 +6183 +6184 +6185 +6186 +6187 +6188 +6189 +6190 +6191 +6192 +6193 +6194 +6195 +6196 +6197 +6198 +6199 +6200 +6201 +6202 +6203 +6204 +6205 +6206 +6207 +6208 +6209 +6210 +6211 +6212 +6213 +6214 +6215 +6216 +6217 +6218 +6219 +6220 +6221 +6222 +6223 +6224 +6225 +6226 +6227 +6228 +6229 +6230 +6231 +6232 +6233 +6234 +6235 +6236 +6237 +6238 +6239 +6240 +6241 +6242 +6243 +6244 +6245 +6246 +6247 +6248 +6249 +6250 +6251 +6252 +6253 +6254 +6255 +6256 +6257 +6258 +6259 +6260 +6261 +6262 +6263 +6264 +6265 +6266 +6267 +6268 +6269 +6270 +6271 +6272 +6273 +6274 +6275 +6276 +6277 +6278 +6279 +6280 +6281 +6282 +6283 +6284 +6285 +6286 +6287 +6288 +6289 +6290 +6291 +6292 +6293 +6294 +6295 +6296 +6297 +6298 +6299 +6300 +6301 +6302 +6303 +6304 +6305 +6306 +6307 +6308 +6309 +6310 +6311 +6312 +6313 +6314 +6315 +6316 +6317 +6318 +6319 +6320 +6321 +6322 +6323 +6324 +6325 +6326 +6327 +6328 +6329 +6330 +6331 +6332 +6333 +6334 +6335 +6336 +6337 +6338 +6339 +6340 +6341 +6342 +6343 +6344 +6345 +6346 +6347 +6348 +6349 +6350 +6351 +6352 +6353 +6354 +6355 +6356 +6357 +6358 +6359 +6360 +6361 +6362 +6363 +6364 +6365 +6366 +6367 +6368 +6369 +6370 +6371 +6372 +6373 +6374 +6375 +6376 +6377 +6378 +6379 +6380 +6381 +6382 +6383 +6384 +6385 +6386 +6387 +6388 +6389 +6390 +6391 +6392 +6393 +6394 +6395 +6396 +6397 +6398 +6399 +6400 +6401 +6402 +6403 +6404 +6405 +6406 +6407 +6408 +6409 +6410 +6411 +6412 +6413 +6414 +6415 +6416 +6417 +6418 +6419 +6420 +6421 +6422 +6423 +6424 +6425 +6426 +6427 +6428 +6429 +6430 +6431 +6432 +6433 +6434 +6435 +6436 +6437 +6438 +6439 +6440 +6441 +6442 +6443 +6444 +6445 +6446 +6447 +6448 +6449 +6450 +6451 +6452 +6453 +6454 +6455 +6456 +6457 +6458 +6459 +6460 +6461 +6462 +6463 +6464 +6465 +6466 +6467 +6468 +6469 +6470 +6471 +6472 +6473 +6474 +6475 +6476 +6477 +6478 +6479 +6480 +6481 +6482 +6483 +6484 +6485 +6486 +6487 +6488 +6489 +6490 +6491 +6492 +6493 +6494 +6495 +6496 +6497 +6498 +6499 +6500 +6501 +6502 +6503 +6504 +6505 +6506 +6507 +6508 +6509 +6510 +6511 +6512 +6513 +6514 +6515 +6516 +6517 +6518 +6519 +6520 +6521 +6522 +6523 +6524 +6525 +6526 +6527 +6528 +6529 +6530 +6531 +6532 +6533 +6534 +6535 +6536 +6537 +6538 +6539 +6540 +6541 +6542 +6543 +6544 +6545 +6546 +6547 +6548 +6549 +6550 +6551 +6552 +6553 +6554 +6555 +6556 +6557 +6558 +6559 +6560 +6561 +6562 +6563 +6564 +6565 +6566 +6567 +6568 +6569 +6570 +6571 +6572 +6573 +6574 +6575 +6576 +6577 +6578 +6579 +6580 +6581 +6582 +6583 +6584 +6585 +6586 +6587 +6588 +6589 +6590 +6591 +6592 +6593 +6594 +6595 +6596 +6597 +6598 +6599 +6600 +6601 +6602 +6603 +6604 +6605 +6606 +6607 +6608 +6609 +6610 +6611 +6612 +6613 +6614 +6615 +6616 +6617 +6618 +6619 +6620 +6621 +6622 +6623 +6624 +6625 +6626 +6627 +6628 +6629 +6630 +6631 +6632 +6633 +6634 +6635 +6636 +6637 +6638 +6639 +6640 +6641 +6642 +6643 +6644 +6645 +6646 +6647 +6648 +6649 +6650 +6651 +6652 +6653 +6654 +6655 +6656 +6657 +6658 +6659 +6660 +6661 +6662 +6663 +6664 +6665 +6666 +6667 +6668 +6669 +6670 +6671 +6672 +6673 +6674 +6675 +6676 +6677 +6678 +6679 +6680 +6681 +6682 +6683 +6684 +6685 +6686 +6687 +6688 +6689 +6690 +6691 +6692 +6693 +6694 +6695 +6696 +6697 +6698 +6699 +6700 +6701 +6702 +6703 +6704 +6705 +6706 +6707 +6708 +6709 +6710 +6711 +6712 +6713 +6714 +6715 +6716 +6717 +6718 +6719 +6720 +6721 +6722 +6723 +6724 +6725 +6726 +6727 +6728 +6729 +6730 +6731 +6732 +6733 +6734 +6735 +6736 +6737 +6738 +6739 +6740 +6741 +6742 +6743 +6744 +6745 +6746 +6747 +6748 +6749 +6750 +6751 +6752 +6753 +6754 +6755 +6756 +6757 +6758 +6759 +6760 +6761 +6762 +6763 +6764 +6765 +6766 +6767 +6768 +6769 +6770 +6771 +6772 +6773 +6774 +6775 +6776 +6777 +6778 +6779 +6780 +6781 +6782 +6783 +6784 +6785 +6786 +6787 +6788 +6789 +6790 +6791 +6792 +6793 +6794 +6795 +6796 +6797 +6798 +6799 +6800 +6801 +6802 +6803 +6804 +6805 +6806 +6807 +6808 +6809 +6810 +6811 +6812 +6813 +6814 +6815 +6816 +6817 +6818 +6819 +6820 +6821 +6822 +6823 +6824 +6825 +6826 +6827 +6828 +6829 +6830 +6831 +6832 +6833 +6834 +6835 +6836 +6837 +6838 +6839 +6840 +6841 +6842 +6843 +6844 +6845 +6846 +6847 +6848 +6849 +6850 +6851 +6852 +6853 +6854 +6855 +6856 +6857 +6858 +6859 +6860 +6861 +6862 +6863 +6864 +6865 +6866 +6867 +6868 +6869 +6870 +6871 +6872 +6873 +6874 +6875 +6876 +6877 +6878 +6879 +6880 +6881 +6882 +6883 +6884 +6885 +6886 +6887 +6888 +6889 +6890 +6891 +6892 +6893 +6894 +6895 +6896 +6897 +6898 +6899 +6900 +6901 +6902 +6903 +6904 +6905 +6906 +6907 +6908 +6909 +6910 +6911 +6912 +6913 +6914 +6915 +6916 +6917 +6918 +6919 +6920 +6921 +6922 +6923 +6924 +6925 +6926 +6927 +6928 +6929 +6930 +6931 +6932 +6933 +6934 +6935 +6936 +6937 +6938 +6939 +6940 +6941 +6942 +6943 +6944 +6945 +6946 +6947 +6948 +6949 +6950 +6951 +6952 +6953 +6954 +6955 +6956 +6957 +6958 +6959 +6960 +6961 +6962 +6963 +6964 +6965 +6966 +6967 +6968 +6969 +6970 +6971 +6972 +6973 +6974 +6975 +6976 +6977 +6978 +6979 +6980 +6981 +6982 +6983 +6984 +6985 +6986 +6987 +6988 +6989 +6990 +6991 +6992 +6993 +6994 +6995 +6996 +6997 +6998 +6999 +7000 +7001 +7002 +7003 +7004 +7005 +7006 +7007 +7008 +7009 +7010 +7011 +7012 +7013 +7014 +7015 +7016 +7017 +7018 +7019 +7020 +7021 +7022 +7023 +7024 +7025 +7026 +7027 +7028 +7029 +7030 +7031 +7032 +7033 +7034 +7035 +7036 +7037 +7038 +7039 +7040 +7041 +7042 +7043 +7044 +7045 +7046 +7047 +7048 +7049 +7050 +7051 +7052 +7053 +7054 +7055 +7056 +7057 +7058 +7059 +7060 +7061 +7062 +7063 +7064 +7065 +7066 +7067 +7068 +7069 +7070 +7071 +7072 +7073 +7074 +7075 +7076 +7077 +7078 +7079 +7080 +7081 +7082 +7083 +7084 +7085 +7086 +7087 +7088 +7089 +7090 +7091 +7092 +7093 +7094 +7095 +7096 +7097 +7098 +7099 +7100 +7101 +7102 +7103 +7104 +7105 +7106 +7107 +7108 +7109 +7110 +7111 +7112 +7113 +7114 +7115 +7116 +7117 +7118 +7119 +7120 +7121 +7122 +7123 +7124 +7125 +7126 +7127 +7128 +7129 +7130 +7131 +7132 +7133 +7134 +7135 +7136 +7137 +7138 +7139 +7140 +7141 +7142 +7143 +7144 +7145 +7146 +7147 +7148 +7149 +7150 +7151 +7152 +7153 +7154 +7155 +7156 +7157 +7158 +7159 +7160 +7161 +7162 +7163 +7164 +7165 +7166 +7167 +7168 +7169 +7170 +7171 +7172 +7173 +7174 +7175 +7176 +7177 +7178 +7179 +7180 +7181 +7182 +7183 +7184 +7185 +7186 +7187 +7188 +7189 +7190 +7191 +7192 +7193 +7194 +7195 +7196 +7197 +7198 +7199 +7200 +7201 +7202 +7203 +7204 +7205 +7206 +7207 +7208 +7209 +7210 +7211 +7212 +7213 +7214 +7215 +7216 +7217 +7218 +7219 +7220 +7221 +7222 +7223 +7224 +7225 +7226 +7227 +7228 +7229 +7230 +7231 +7232 +7233 +7234 +7235 +7236 +7237 +7238 +7239 +7240 +7241 +7242 +7243 +7244 +7245 +7246 +7247 +7248 +7249 +7250 +7251 +7252 +7253 +7254 +7255 +7256 +7257 +7258 +7259 +7260 +7261 +7262 +7263 +7264 +7265 +7266 +7267 +7268 +7269 +7270 +7271 +7272 +7273 +7274 +7275 +7276 +7277 +7278 +7279 +7280 +7281 +7282 +7283 +7284 +7285 +7286 +7287 +7288 +7289 +7290 +7291 +7292 +7293 +7294 +7295 +7296 +7297 +7298 +7299 +7300 +7301 +7302 +7303 +7304 +7305 +7306 +7307 +7308 +7309 +7310 +7311 +7312 +7313 +7314 +7315 +7316 +7317 +7318 +7319 +7320 +7321 +7322 +7323 +7324 +7325 +7326 +7327 +7328 +7329 +7330 +7331 +7332 +7333 +7334 +7335 +7336 +7337 +7338 +7339 +7340 +7341 +7342 +7343 +7344 +7345 +7346 +7347 +7348 +7349 +7350 +7351 +7352 +7353 +7354 +7355 +7356 +7357 +7358 +7359 +7360 +7361 +7362 +7363 +7364 +7365 +7366 +7367 +7368 +7369 +7370 +7371 +7372 +7373 +7374 +7375 +7376 +7377 +7378 +7379 +7380 +7381 +7382 +7383 +7384 +7385 +7386 +7387 +7388 +7389 +7390 +7391 +7392 +7393 +7394 +7395 +7396 +7397 +7398 +7399 +7400 +7401 +7402 +7403 +7404 +7405 +7406 +7407 +7408 +7409 +7410 +7411 +7412 +7413 +7414 +7415 +7416 +7417 +7418 +7419 +7420 +7421 +7422 +7423 +7424 +7425 +7426 +7427 +7428 +7429 +7430 +7431 +7432 +7433 +7434 +7435 +7436 +7437 +7438 +7439 +7440 +7441 +7442 +7443 +7444 +7445 +7446 +7447 +7448 +7449 +7450 +7451 +7452 +7453 +7454 +7455 +7456 +7457 +7458 +7459 +7460 +7461 +7462 +7463 +7464 +7465 +7466 +7467 +7468 +7469 +7470 +7471 +7472 +7473 +7474 +7475 +7476 +7477 +7478 +7479 +7480 +7481 +7482 +7483 +7484 +7485 +7486 +7487 +7488 +7489 +7490 +7491 +7492 +7493 +7494 +7495 +7496 +7497 +7498 +7499 +7500 +7501 +7502 +7503 +7504 +7505 +7506 +7507 +7508 +7509 +7510 +7511 +7512 +7513 +7514 +7515 +7516 +7517 +7518 +7519 +7520 +7521 +7522 +7523 +7524 +7525 +7526 +7527 +7528 +7529 +7530 +7531 +7532 +7533 +7534 +7535 +7536 +7537 +7538 +7539 +7540 +7541 +7542 +7543 +7544 +7545 +7546 +7547 +7548 +7549 +7550 +7551 +7552 +7553 +7554 +7555 +7556 +7557 +7558 +7559 +7560 +7561 +7562 +7563 +7564 +7565 +7566 +7567 +7568 +7569 +7570 +7571 +7572 +7573 +7574 +7575 +7576 +7577 +7578 +7579 +7580 +7581 +7582 +7583 +7584 +7585 +7586 +7587 +7588 +7589 +7590 +7591 +7592 +7593 +7594 +7595 +7596 +7597 +7598 +7599 +7600 +7601 +7602 +7603 +7604 +7605 +7606 +7607 +7608 +7609 +7610 +7611 +7612 +7613 +7614 +7615 +7616 +7617 +7618 +7619 +7620 +7621 +7622 +7623 +7624 +7625 +7626 +7627 +7628 +7629 +7630 +7631 +7632 +7633 +7634 +7635 +7636 +7637 +7638 +7639 +7640 +7641 +7642 +7643 +7644 +7645 +7646 +7647 +7648 +7649 +7650 +7651 +7652 +7653 +7654 +7655 +7656 +7657 +7658 +7659 +7660 +7661 +7662 +7663 +7664 +7665 +7666 +7667 +7668 +7669 +7670 +7671 +7672 +7673 +7674 +7675 +7676 +7677 +7678 +7679 +7680 +7681 +7682 +7683 +7684 +7685 +7686 +7687 +7688 +7689 +7690 +7691 +7692 +7693 +7694 +7695 +7696 +7697 +7698 +7699 +7700 +7701 +7702 +7703 +7704 +7705 +7706 +7707 +7708 +7709 +7710 +7711 +7712 +7713 +7714 +7715 +7716 +7717 +7718 +7719 +7720 +7721 +7722 +7723 +7724 +7725 +7726 +7727 +7728 +7729 +7730 +7731 +7732 +7733 +7734 +7735 +7736 +7737 +7738 +7739 +7740 +7741 +7742 +7743 +7744 +7745 +7746 +7747 +7748 +7749 +7750 +7751 +7752 +7753 +7754 +7755 +7756 +7757 +7758 +7759 +7760 +7761 +7762 +7763 +7764 +7765 +7766 +7767 +7768 +7769 +7770 +7771 +7772 +7773 +7774 +7775 +7776 +7777 +7778 +7779 +7780 +7781 +7782 +7783 +7784 +7785 +7786 +7787 +7788 +7789 +7790 +7791 +7792 +7793 +7794 +7795 +7796 +7797 +7798 +7799 +7800 +7801 +7802 +7803 +7804 +7805 +7806 +7807 +7808 +7809 +7810 +7811 +7812 +7813 +7814 +7815 +7816 +7817 +7818 +7819 +7820 +7821 +7822 +7823 +7824 +7825 +7826 +7827 +7828 +7829 +7830 +7831 +7832 +7833 +7834 +7835 +7836 +7837 +7838 +7839 +7840 +7841 +7842 +7843 +7844 +7845 +7846 +7847 +7848 +7849 +7850 +7851 +7852 +7853 +7854 +7855 +7856 +7857 +7858 +7859 +7860 +7861 +7862 +7863 +7864 +7865 +7866 +7867 +7868 +7869 +7870 +7871 +7872 +7873 +7874 +7875 +7876 +7877 +7878 +7879 +7880 +7881 +7882 +7883 +7884 +7885 +7886 +7887 +7888 +7889 +7890 +7891 +7892 +7893 +7894 +7895 +7896 +7897 +7898 +7899 +7900 +7901 +7902 +7903 +7904 +7905 +7906 +7907 +7908 +7909 +7910 +7911 +7912 +7913 +7914 +7915 +7916 +7917 +7918 +7919 +7920 +7921 +7922 +7923 +7924 +7925 +7926 +7927 +7928 +7929 +7930 +7931 +7932 +7933 +7934 +7935 +7936 +7937 +7938 +7939 +7940 +7941 +7942 +7943 +7944 +7945 +7946 +7947 +7948 +7949 +7950 +7951 +7952 +7953 +7954 +7955 +7956 +7957 +7958 +7959 +7960 +7961 +7962 +7963 +7964 +7965 +7966 +7967 +7968 +7969 +7970 +7971 +7972 +7973 +7974 +7975 +7976 +7977 +7978 +7979 +7980 +7981 +7982 +7983 +7984 +7985 +7986 +7987 +7988 +7989 +7990 +7991 +7992 +7993 +7994 +7995 +7996 +7997 +7998 +7999 +8000 diff --git a/test/static/executor/test_data/employees.csv b/test/static/executor/test_data/employees.csv new file mode 100644 index 0000000..fa1dfce --- /dev/null +++ b/test/static/executor/test_data/employees.csv @@ -0,0 +1,12 @@ +id:int,department_id:int +1,3 +2,6 +3,12 +4,11 +5,1 +6,5 +33,31 +66,32 +67,33 +68,34 +69,35 diff --git a/test/static/executor/test_data/employees_200.csv b/test/static/executor/test_data/employees_200.csv new file mode 100644 index 0000000..9bff65f --- /dev/null +++ b/test/static/executor/test_data/employees_200.csv @@ -0,0 +1,201 @@ +id:int,department_id:int +1 902 +2 258 +3 602 +4 479 +5 165 +6 564 +7 7 +8 699 +9 828 +10 197 +11 427 +12 923 +13 52 +14 748 +15 204 +16 169 +17 510 +18 897 +19 16 +20 478 +21 249 +22 816 +23 750 +24 580 +25 995 +26 623 +27 759 +28 566 +29 551 +30 715 +31 144 +32 343 +33 772 +34 193 +35 391 +36 172 +37 786 +38 532 +39 125 +40 135 +41 266 +42 983 +43 541 +44 590 +45 38 +46 968 +47 911 +48 927 +49 847 +50 735 +51 363 +52 256 +53 831 +54 488 +55 347 +56 932 +57 675 +58 640 +59 631 +60 478 +61 205 +62 224 +63 514 +64 616 +65 705 +66 177 +67 451 +68 230 +69 966 +70 134 +71 251 +72 182 +73 407 +74 747 +75 199 +76 551 +77 326 +78 425 +79 243 +80 629 +81 769 +82 425 +83 300 +84 721 +85 77 +86 283 +87 191 +88 974 +89 770 +90 539 +91 64 +92 88 +93 188 +94 406 +95 15 +96 864 +97 541 +98 325 +99 903 +100 534 +101 636 +102 761 +103 11 +104 266 +105 669 +106 457 +107 990 +108 561 +109 919 +110 623 +111 763 +112 591 +113 130 +114 186 +115 69 +116 323 +117 10 +118 4 +119 458 +120 235 +121 185 +122 368 +123 416 +124 879 +125 61 +126 570 +127 342 +128 340 +129 369 +130 99 +131 718 +132 728 +133 216 +134 682 +135 316 +136 706 +137 42 +138 3 +139 319 +140 142 +141 383 +142 596 +143 446 +144 660 +145 602 +146 305 +147 426 +148 11 +149 808 +150 722 +151 8 +152 200 +153 607 +154 556 +155 17 +156 378 +157 348 +158 40 +159 37 +160 644 +161 916 +162 880 +163 26 +164 922 +165 822 +166 486 +167 984 +168 787 +169 115 +170 679 +171 95 +172 838 +173 507 +174 749 +175 170 +176 460 +177 273 +178 575 +179 498 +180 814 +181 102 +182 434 +183 130 +184 255 +185 665 +186 202 +187 761 +188 852 +189 422 +190 435 +191 410 +192 347 +193 108 +194 783 +195 107 +196 206 +197 634 +198 131 +199 894 +200 9 diff --git a/test/static/executor/test_data/users.csv b/test/static/executor/test_data/users.csv new file mode 100644 index 0000000..3820d04 --- /dev/null +++ b/test/static/executor/test_data/users.csv @@ -0,0 +1,18 @@ +id:int,age:int +1,33 +2,64 +3,123 +4,11 +5,1 +6,5 +7,88 +8,64 +8,64 +10,22 +11,64 +12,64 +13,33 +14,64 +15,443 +16,21 +17,18 diff --git a/test/static/parser/expected.dot b/test/static/parser/expected.dot new file mode 100644 index 0000000..614fdce --- /dev/null +++ b/test/static/parser/expected.dot @@ -0,0 +1,5 @@ +digraph G { rankdir=BT; "π users.id" +"σ users.age > 18" -> "π users.id" +"σ users.age > 18" +"users" -> "σ users.age > 18" +"users" } diff --git a/test/static/parser/expected_arithmetical.dot b/test/static/parser/expected_arithmetical.dot new file mode 100644 index 0000000..e01c1f1 --- /dev/null +++ b/test/static/parser/expected_arithmetical.dot @@ -0,0 +1,3 @@ +digraph G { rankdir=BT; "π 1 + 2 - 3 + 4 + 5 - 6" +"_EMPTY_TABLE_" -> "π 1 + 2 - 3 + 4 + 5 - 6" +"_EMPTY_TABLE_" } diff --git a/test/static/parser/expected_join.dot b/test/static/parser/expected_join.dot new file mode 100644 index 0000000..c3daabb --- /dev/null +++ b/test/static/parser/expected_join.dot @@ -0,0 +1,5 @@ +digraph G { rankdir=BT; "crossjoin_users_books"[label="×"] +"users" -> "crossjoin_users_books" +"books" -> "crossjoin_users_books" +"users" +"books" } diff --git a/test/static/parser/expected_outer_join.dot b/test/static/parser/expected_outer_join.dot new file mode 100644 index 0000000..cd130ae --- /dev/null +++ b/test/static/parser/expected_outer_join.dot @@ -0,0 +1,5 @@ +digraph G { rankdir=BT; "join_users_books"[label="⟕\nON users.book = books.id"] +"users" -> "join_users_books" +"books" -> "join_users_books" +"users" +"books" }