mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-10-04 07:30:52 +00:00
Merge branch 'master' into refactor_databases_tmp_merge
This commit is contained in:
commit
444167cc1d
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -128,6 +128,9 @@
|
|||||||
[submodule "contrib/icu"]
|
[submodule "contrib/icu"]
|
||||||
path = contrib/icu
|
path = contrib/icu
|
||||||
url = https://github.com/unicode-org/icu.git
|
url = https://github.com/unicode-org/icu.git
|
||||||
|
[submodule "contrib/flatbuffers"]
|
||||||
|
path = contrib/flatbuffers
|
||||||
|
url = https://github.com/google/flatbuffers.git
|
||||||
[submodule "contrib/libc-headers"]
|
[submodule "contrib/libc-headers"]
|
||||||
path = contrib/libc-headers
|
path = contrib/libc-headers
|
||||||
url = https://github.com/ClickHouse-Extras/libc-headers.git
|
url = https://github.com/ClickHouse-Extras/libc-headers.git
|
||||||
|
@ -54,10 +54,12 @@ elseif(NOT MISSING_INTERNAL_PARQUET_LIBRARY AND NOT OS_FREEBSD)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(${USE_STATIC_LIBRARIES})
|
if(${USE_STATIC_LIBRARIES})
|
||||||
|
set(FLATBUFFERS_LIBRARY flatbuffers)
|
||||||
set(ARROW_LIBRARY arrow_static)
|
set(ARROW_LIBRARY arrow_static)
|
||||||
set(PARQUET_LIBRARY parquet_static)
|
set(PARQUET_LIBRARY parquet_static)
|
||||||
set(THRIFT_LIBRARY thrift_static)
|
set(THRIFT_LIBRARY thrift_static)
|
||||||
else()
|
else()
|
||||||
|
set(FLATBUFFERS_LIBRARY flatbuffers_shared)
|
||||||
set(ARROW_LIBRARY arrow_shared)
|
set(ARROW_LIBRARY arrow_shared)
|
||||||
set(PARQUET_LIBRARY parquet_shared)
|
set(PARQUET_LIBRARY parquet_shared)
|
||||||
if(USE_INTERNAL_PARQUET_LIBRARY_NATIVE_CMAKE)
|
if(USE_INTERNAL_PARQUET_LIBRARY_NATIVE_CMAKE)
|
||||||
@ -74,7 +76,7 @@ endif()
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(USE_PARQUET)
|
if(USE_PARQUET)
|
||||||
message(STATUS "Using Parquet: ${ARROW_LIBRARY}:${ARROW_INCLUDE_DIR} ; ${PARQUET_LIBRARY}:${PARQUET_INCLUDE_DIR} ; ${THRIFT_LIBRARY}")
|
message(STATUS "Using Parquet: ${ARROW_LIBRARY}:${ARROW_INCLUDE_DIR} ; ${PARQUET_LIBRARY}:${PARQUET_INCLUDE_DIR} ; ${THRIFT_LIBRARY} ; ${FLATBUFFERS_LIBRARY}")
|
||||||
else()
|
else()
|
||||||
message(STATUS "Building without Parquet support")
|
message(STATUS "Building without Parquet support")
|
||||||
endif()
|
endif()
|
||||||
|
2
contrib/CMakeLists.txt
vendored
2
contrib/CMakeLists.txt
vendored
@ -159,6 +159,8 @@ if (USE_INTERNAL_PARQUET_LIBRARY_NATIVE_CMAKE)
|
|||||||
set (ARROW_PARQUET ON CACHE INTERNAL "")
|
set (ARROW_PARQUET ON CACHE INTERNAL "")
|
||||||
set (ARROW_VERBOSE_THIRDPARTY_BUILD ON CACHE INTERNAL "")
|
set (ARROW_VERBOSE_THIRDPARTY_BUILD ON CACHE INTERNAL "")
|
||||||
set (ARROW_BUILD_SHARED 1 CACHE INTERNAL "")
|
set (ARROW_BUILD_SHARED 1 CACHE INTERNAL "")
|
||||||
|
set (ARROW_BUILD_UTILITIES OFF CACHE INTERNAL "")
|
||||||
|
set (ARROW_BUILD_INTEGRATION OFF CACHE INTERNAL "")
|
||||||
set (ARROW_BOOST_HEADER_ONLY ON CACHE INTERNAL "")
|
set (ARROW_BOOST_HEADER_ONLY ON CACHE INTERNAL "")
|
||||||
set (Boost_FOUND 1 CACHE INTERNAL "")
|
set (Boost_FOUND 1 CACHE INTERNAL "")
|
||||||
if (MAKE_STATIC_LIBRARIES)
|
if (MAKE_STATIC_LIBRARIES)
|
||||||
|
2
contrib/arrow
vendored
2
contrib/arrow
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 87ac6fddaf21d0b4ee8b8090533ff293db0da1b4
|
Subproject commit b789226ccb2124285792107c758bb3b40b3d082a
|
@ -1,46 +1,48 @@
|
|||||||
|
include(ExternalProject)
|
||||||
|
|
||||||
# === thrift
|
# === thrift
|
||||||
|
|
||||||
set(LIBRARY_DIR ${ClickHouse_SOURCE_DIR}/contrib/thrift/lib/cpp)
|
set(LIBRARY_DIR ${ClickHouse_SOURCE_DIR}/contrib/thrift/lib/cpp)
|
||||||
# contrib/thrift/lib/cpp/CMakeLists.txt
|
# contrib/thrift/lib/cpp/CMakeLists.txt
|
||||||
set(thriftcpp_SOURCES
|
set(thriftcpp_SOURCES
|
||||||
${LIBRARY_DIR}/src/thrift/TApplicationException.cpp
|
${LIBRARY_DIR}/src/thrift/TApplicationException.cpp
|
||||||
${LIBRARY_DIR}/src/thrift/TOutput.cpp
|
${LIBRARY_DIR}/src/thrift/TOutput.cpp
|
||||||
${LIBRARY_DIR}/src/thrift/async/TAsyncChannel.cpp
|
${LIBRARY_DIR}/src/thrift/async/TAsyncChannel.cpp
|
||||||
${LIBRARY_DIR}/src/thrift/async/TAsyncProtocolProcessor.cpp
|
${LIBRARY_DIR}/src/thrift/async/TAsyncProtocolProcessor.cpp
|
||||||
${LIBRARY_DIR}/src/thrift/async/TConcurrentClientSyncInfo.h
|
${LIBRARY_DIR}/src/thrift/async/TConcurrentClientSyncInfo.h
|
||||||
${LIBRARY_DIR}/src/thrift/async/TConcurrentClientSyncInfo.cpp
|
${LIBRARY_DIR}/src/thrift/async/TConcurrentClientSyncInfo.cpp
|
||||||
${LIBRARY_DIR}/src/thrift/concurrency/ThreadManager.cpp
|
${LIBRARY_DIR}/src/thrift/concurrency/ThreadManager.cpp
|
||||||
${LIBRARY_DIR}/src/thrift/concurrency/TimerManager.cpp
|
${LIBRARY_DIR}/src/thrift/concurrency/TimerManager.cpp
|
||||||
${LIBRARY_DIR}/src/thrift/concurrency/Util.cpp
|
${LIBRARY_DIR}/src/thrift/concurrency/Util.cpp
|
||||||
${LIBRARY_DIR}/src/thrift/processor/PeekProcessor.cpp
|
${LIBRARY_DIR}/src/thrift/processor/PeekProcessor.cpp
|
||||||
${LIBRARY_DIR}/src/thrift/protocol/TBase64Utils.cpp
|
${LIBRARY_DIR}/src/thrift/protocol/TBase64Utils.cpp
|
||||||
${LIBRARY_DIR}/src/thrift/protocol/TDebugProtocol.cpp
|
${LIBRARY_DIR}/src/thrift/protocol/TDebugProtocol.cpp
|
||||||
${LIBRARY_DIR}/src/thrift/protocol/TJSONProtocol.cpp
|
${LIBRARY_DIR}/src/thrift/protocol/TJSONProtocol.cpp
|
||||||
${LIBRARY_DIR}/src/thrift/protocol/TMultiplexedProtocol.cpp
|
${LIBRARY_DIR}/src/thrift/protocol/TMultiplexedProtocol.cpp
|
||||||
${LIBRARY_DIR}/src/thrift/protocol/TProtocol.cpp
|
${LIBRARY_DIR}/src/thrift/protocol/TProtocol.cpp
|
||||||
${LIBRARY_DIR}/src/thrift/transport/TTransportException.cpp
|
${LIBRARY_DIR}/src/thrift/transport/TTransportException.cpp
|
||||||
${LIBRARY_DIR}/src/thrift/transport/TFDTransport.cpp
|
${LIBRARY_DIR}/src/thrift/transport/TFDTransport.cpp
|
||||||
${LIBRARY_DIR}/src/thrift/transport/TSimpleFileTransport.cpp
|
${LIBRARY_DIR}/src/thrift/transport/TSimpleFileTransport.cpp
|
||||||
${LIBRARY_DIR}/src/thrift/transport/THttpTransport.cpp
|
${LIBRARY_DIR}/src/thrift/transport/THttpTransport.cpp
|
||||||
${LIBRARY_DIR}/src/thrift/transport/THttpClient.cpp
|
${LIBRARY_DIR}/src/thrift/transport/THttpClient.cpp
|
||||||
${LIBRARY_DIR}/src/thrift/transport/THttpServer.cpp
|
${LIBRARY_DIR}/src/thrift/transport/THttpServer.cpp
|
||||||
${LIBRARY_DIR}/src/thrift/transport/TSocket.cpp
|
${LIBRARY_DIR}/src/thrift/transport/TSocket.cpp
|
||||||
${LIBRARY_DIR}/src/thrift/transport/TSocketPool.cpp
|
${LIBRARY_DIR}/src/thrift/transport/TSocketPool.cpp
|
||||||
${LIBRARY_DIR}/src/thrift/transport/TServerSocket.cpp
|
${LIBRARY_DIR}/src/thrift/transport/TServerSocket.cpp
|
||||||
${LIBRARY_DIR}/src/thrift/transport/TTransportUtils.cpp
|
${LIBRARY_DIR}/src/thrift/transport/TTransportUtils.cpp
|
||||||
${LIBRARY_DIR}/src/thrift/transport/TBufferTransports.cpp
|
${LIBRARY_DIR}/src/thrift/transport/TBufferTransports.cpp
|
||||||
${LIBRARY_DIR}/src/thrift/server/TConnectedClient.cpp
|
${LIBRARY_DIR}/src/thrift/server/TConnectedClient.cpp
|
||||||
${LIBRARY_DIR}/src/thrift/server/TServerFramework.cpp
|
${LIBRARY_DIR}/src/thrift/server/TServerFramework.cpp
|
||||||
${LIBRARY_DIR}/src/thrift/server/TSimpleServer.cpp
|
${LIBRARY_DIR}/src/thrift/server/TSimpleServer.cpp
|
||||||
${LIBRARY_DIR}/src/thrift/server/TThreadPoolServer.cpp
|
${LIBRARY_DIR}/src/thrift/server/TThreadPoolServer.cpp
|
||||||
${LIBRARY_DIR}/src/thrift/server/TThreadedServer.cpp
|
${LIBRARY_DIR}/src/thrift/server/TThreadedServer.cpp
|
||||||
)
|
)
|
||||||
set( thriftcpp_threads_SOURCES
|
set(thriftcpp_threads_SOURCES
|
||||||
${LIBRARY_DIR}/src/thrift/concurrency/ThreadFactory.cpp
|
${LIBRARY_DIR}/src/thrift/concurrency/ThreadFactory.cpp
|
||||||
${LIBRARY_DIR}/src/thrift/concurrency/Thread.cpp
|
${LIBRARY_DIR}/src/thrift/concurrency/Thread.cpp
|
||||||
${LIBRARY_DIR}/src/thrift/concurrency/Monitor.cpp
|
${LIBRARY_DIR}/src/thrift/concurrency/Monitor.cpp
|
||||||
${LIBRARY_DIR}/src/thrift/concurrency/Mutex.cpp
|
${LIBRARY_DIR}/src/thrift/concurrency/Mutex.cpp
|
||||||
)
|
)
|
||||||
add_library(${THRIFT_LIBRARY} ${thriftcpp_SOURCES} ${thriftcpp_threads_SOURCES})
|
add_library(${THRIFT_LIBRARY} ${thriftcpp_SOURCES} ${thriftcpp_threads_SOURCES})
|
||||||
set_target_properties(${THRIFT_LIBRARY} PROPERTIES CXX_STANDARD 14) # REMOVE after https://github.com/apache/thrift/pull/1641
|
set_target_properties(${THRIFT_LIBRARY} PROPERTIES CXX_STANDARD 14) # REMOVE after https://github.com/apache/thrift/pull/1641
|
||||||
target_include_directories(${THRIFT_LIBRARY} SYSTEM PUBLIC ${ClickHouse_SOURCE_DIR}/contrib/thrift/lib/cpp/src PRIVATE ${Boost_INCLUDE_DIRS})
|
target_include_directories(${THRIFT_LIBRARY} SYSTEM PUBLIC ${ClickHouse_SOURCE_DIR}/contrib/thrift/lib/cpp/src PRIVATE ${Boost_INCLUDE_DIRS})
|
||||||
@ -70,22 +72,94 @@ add_custom_command(OUTPUT orc_proto.pb.h orc_proto.pb.cc
|
|||||||
--cpp_out="${CMAKE_CURRENT_BINARY_DIR}"
|
--cpp_out="${CMAKE_CURRENT_BINARY_DIR}"
|
||||||
"${PROTO_DIR}/orc_proto.proto")
|
"${PROTO_DIR}/orc_proto.proto")
|
||||||
|
|
||||||
|
|
||||||
|
# === flatbuffers
|
||||||
|
|
||||||
|
##############################################################
|
||||||
|
# fbs - Step 1: build flatbuffers lib and flatc compiler
|
||||||
|
##############################################################
|
||||||
|
set(FLATBUFFERS_SRC_DIR ${ClickHouse_SOURCE_DIR}/contrib/flatbuffers)
|
||||||
|
set(FLATBUFFERS_BINARY_DIR ${ClickHouse_BINARY_DIR}/contrib/flatbuffers)
|
||||||
|
set(FLATBUFFERS_INCLUDE_DIR ${FLATBUFFERS_SRC_DIR}/include)
|
||||||
|
set(FLATBUFFERS_COMPILER "${FLATBUFFERS_BINARY_DIR}/flatc")
|
||||||
|
|
||||||
|
# set flatbuffers CMake options
|
||||||
|
if (${USE_STATIC_LIBRARIES})
|
||||||
|
set(FLATBUFFERS_BUILD_FLATLIB ON CACHE BOOL "Enable the build of the flatbuffers library")
|
||||||
|
set(FLATBUFFERS_BUILD_SHAREDLIB OFF CACHE BOOL "Disable the build of the flatbuffers shared library")
|
||||||
|
else ()
|
||||||
|
set(FLATBUFFERS_BUILD_SHAREDLIB ON CACHE BOOL "Enable the build of the flatbuffers shared library")
|
||||||
|
set(FLATBUFFERS_BUILD_FLATLIB OFF CACHE BOOL "Disable the build of the flatbuffers library")
|
||||||
|
endif ()
|
||||||
|
set(FLATBUFFERS_BUILD_FLATC ON CACHE BOOL "Build flatbuffers compiler")
|
||||||
|
set(FLATBUFFERS_BUILD_TESTS OFF CACHE BOOL "Skip flatbuffers tests")
|
||||||
|
|
||||||
|
add_subdirectory(${FLATBUFFERS_SRC_DIR} "${FLATBUFFERS_BINARY_DIR}")
|
||||||
|
|
||||||
|
###################################
|
||||||
|
# fbs - Step 2: compile *.fbs files
|
||||||
|
###################################
|
||||||
|
set(ARROW_IPC_SRC_DIR ${ARROW_SRC_DIR}/arrow/ipc)
|
||||||
|
set(ARROW_FORMAT_SRC_DIR ${ARROW_SRC_DIR}/../../format)
|
||||||
|
|
||||||
|
set(ARROW_GENERATED_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/arrow_gen_headers)
|
||||||
|
set(FLATBUFFERS_COMPILED_OUT_DIR ${ARROW_GENERATED_INCLUDE_DIR}/arrow/ipc)
|
||||||
|
|
||||||
|
set(FBS_OUTPUT_FILES
|
||||||
|
"${FLATBUFFERS_COMPILED_OUT_DIR}/File_generated.h"
|
||||||
|
"${FLATBUFFERS_COMPILED_OUT_DIR}/Message_generated.h"
|
||||||
|
"${FLATBUFFERS_COMPILED_OUT_DIR}/feather_generated.h"
|
||||||
|
"${FLATBUFFERS_COMPILED_OUT_DIR}/Schema_generated.h"
|
||||||
|
"${FLATBUFFERS_COMPILED_OUT_DIR}/SparseTensor_generated.h"
|
||||||
|
"${FLATBUFFERS_COMPILED_OUT_DIR}/Tensor_generated.h")
|
||||||
|
|
||||||
|
set(FBS_SRC
|
||||||
|
${ARROW_FORMAT_SRC_DIR}/Message.fbs
|
||||||
|
${ARROW_FORMAT_SRC_DIR}/File.fbs
|
||||||
|
${ARROW_FORMAT_SRC_DIR}/Schema.fbs
|
||||||
|
${ARROW_FORMAT_SRC_DIR}/Tensor.fbs
|
||||||
|
${ARROW_FORMAT_SRC_DIR}/SparseTensor.fbs
|
||||||
|
${ARROW_IPC_SRC_DIR}/feather.fbs)
|
||||||
|
|
||||||
|
foreach (FIL ${FBS_SRC})
|
||||||
|
get_filename_component(ABS_FIL ${FIL} ABSOLUTE)
|
||||||
|
list(APPEND ABS_FBS_SRC ${ABS_FIL})
|
||||||
|
endforeach ()
|
||||||
|
|
||||||
|
message(STATUS "FLATBUFFERS_LIBRARY: ${FLATBUFFERS_LIBRARY}, FLATBUFFERS_COMPILER: ${FLATBUFFERS_COMPILER}")
|
||||||
|
message(STATUS "FLATBUFFERS_COMPILED_OUT_DIR: ${FLATBUFFERS_COMPILED_OUT_DIR}")
|
||||||
|
message(STATUS "flatc: ${FLATBUFFERS_COMPILER} -c -o ${FLATBUFFERS_COMPILED_OUT_DIR}/ ${ABS_FBS_SRC}")
|
||||||
|
|
||||||
|
add_custom_command(OUTPUT ${FBS_OUTPUT_FILES}
|
||||||
|
COMMAND ${FLATBUFFERS_COMPILER}
|
||||||
|
-c
|
||||||
|
-o
|
||||||
|
${FLATBUFFERS_COMPILED_OUT_DIR}/
|
||||||
|
${ABS_FBS_SRC}
|
||||||
|
DEPENDS flatc ${ABS_FBS_SRC}
|
||||||
|
COMMENT "Running flatc compiler on ${ABS_FBS_SRC}"
|
||||||
|
VERBATIM)
|
||||||
|
|
||||||
|
add_custom_target(metadata_fbs DEPENDS ${FBS_OUTPUT_FILES})
|
||||||
|
add_dependencies(metadata_fbs flatc)
|
||||||
|
|
||||||
# arrow-cmake cmake file calling orc cmake subroutine which detects certain compiler features.
|
# arrow-cmake cmake file calling orc cmake subroutine which detects certain compiler features.
|
||||||
# Apple Clang compiler failed to compile this code without specifying c++11 standard.
|
# Apple Clang compiler failed to compile this code without specifying c++11 standard.
|
||||||
# As result these compiler features detected as absent. In result it failed to compile orc itself.
|
# As result these compiler features detected as absent. In result it failed to compile orc itself.
|
||||||
# In orc makefile there is code that sets flags, but arrow-cmake ignores these flags.
|
# In orc makefile there is code that sets flags, but arrow-cmake ignores these flags.
|
||||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
if (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
||||||
set (CXX11_FLAGS "-std=c++0x")
|
set(CXX11_FLAGS "-std=c++0x")
|
||||||
endif()
|
endif ()
|
||||||
|
|
||||||
include(${ClickHouse_SOURCE_DIR}/contrib/orc/cmake_modules/CheckSourceCompiles.cmake)
|
include(${ClickHouse_SOURCE_DIR}/contrib/orc/cmake_modules/CheckSourceCompiles.cmake)
|
||||||
include(orc_check.cmake)
|
include(orc_check.cmake)
|
||||||
configure_file("${ORC_INCLUDE_DIR}/orc/orc-config.hh.in" "${ORC_BUILD_INCLUDE_DIR}/orc/orc-config.hh")
|
configure_file("${ORC_INCLUDE_DIR}/orc/orc-config.hh.in" "${ORC_BUILD_INCLUDE_DIR}/orc/orc-config.hh")
|
||||||
configure_file("${ORC_SOURCE_SRC_DIR}/Adaptor.hh.in" "${ORC_BUILD_INCLUDE_DIR}/Adaptor.hh")
|
configure_file("${ORC_SOURCE_SRC_DIR}/Adaptor.hh.in" "${ORC_BUILD_INCLUDE_DIR}/Adaptor.hh")
|
||||||
|
|
||||||
|
|
||||||
set(ORC_SRCS
|
set(ORC_SRCS
|
||||||
${ARROW_SRC_DIR}/arrow/adapters/orc/adapter.cc
|
${ARROW_SRC_DIR}/arrow/adapters/orc/adapter.cc
|
||||||
|
${ARROW_SRC_DIR}/arrow/adapters/orc/adapter_util.cc
|
||||||
${ORC_SOURCE_SRC_DIR}/Exceptions.cc
|
${ORC_SOURCE_SRC_DIR}/Exceptions.cc
|
||||||
${ORC_SOURCE_SRC_DIR}/OrcFile.cc
|
${ORC_SOURCE_SRC_DIR}/OrcFile.cc
|
||||||
${ORC_SOURCE_SRC_DIR}/Reader.cc
|
${ORC_SOURCE_SRC_DIR}/Reader.cc
|
||||||
@ -119,126 +193,160 @@ set(ORC_SRCS
|
|||||||
# === arrow
|
# === arrow
|
||||||
|
|
||||||
set(LIBRARY_DIR ${ClickHouse_SOURCE_DIR}/contrib/arrow/cpp/src/arrow)
|
set(LIBRARY_DIR ${ClickHouse_SOURCE_DIR}/contrib/arrow/cpp/src/arrow)
|
||||||
|
|
||||||
|
configure_file("${LIBRARY_DIR}/util/config.h.cmake" "${CMAKE_CURRENT_SOURCE_DIR}/cpp/src/arrow/util/config.h")
|
||||||
|
|
||||||
# arrow/cpp/src/arrow/CMakeLists.txt
|
# arrow/cpp/src/arrow/CMakeLists.txt
|
||||||
set(ARROW_SRCS
|
set(ARROW_SRCS
|
||||||
${LIBRARY_DIR}/array.cc
|
${LIBRARY_DIR}/array.cc
|
||||||
|
${LIBRARY_DIR}/buffer.cc
|
||||||
|
${LIBRARY_DIR}/builder.cc
|
||||||
|
${LIBRARY_DIR}/compare.cc
|
||||||
|
${LIBRARY_DIR}/extension_type.cc
|
||||||
|
${LIBRARY_DIR}/memory_pool.cc
|
||||||
|
${LIBRARY_DIR}/pretty_print.cc
|
||||||
|
${LIBRARY_DIR}/record_batch.cc
|
||||||
|
${LIBRARY_DIR}/result.cc
|
||||||
|
${LIBRARY_DIR}/scalar.cc
|
||||||
|
${LIBRARY_DIR}/sparse_tensor.cc
|
||||||
|
${LIBRARY_DIR}/status.cc
|
||||||
|
${LIBRARY_DIR}/table_builder.cc
|
||||||
|
${LIBRARY_DIR}/table.cc
|
||||||
|
${LIBRARY_DIR}/tensor.cc
|
||||||
|
${LIBRARY_DIR}/type.cc
|
||||||
|
${LIBRARY_DIR}/visitor.cc
|
||||||
|
|
||||||
${LIBRARY_DIR}/builder.cc
|
${LIBRARY_DIR}/array/builder_adaptive.cc
|
||||||
${LIBRARY_DIR}/array/builder_adaptive.cc
|
${LIBRARY_DIR}/array/builder_base.cc
|
||||||
${LIBRARY_DIR}/array/builder_base.cc
|
${LIBRARY_DIR}/array/builder_binary.cc
|
||||||
${LIBRARY_DIR}/array/builder_binary.cc
|
${LIBRARY_DIR}/array/builder_decimal.cc
|
||||||
${LIBRARY_DIR}/array/builder_decimal.cc
|
${LIBRARY_DIR}/array/builder_dict.cc
|
||||||
${LIBRARY_DIR}/array/builder_dict.cc
|
${LIBRARY_DIR}/array/builder_nested.cc
|
||||||
${LIBRARY_DIR}/array/builder_nested.cc
|
${LIBRARY_DIR}/array/builder_primitive.cc
|
||||||
${LIBRARY_DIR}/array/builder_primitive.cc
|
${LIBRARY_DIR}/array/builder_union.cc
|
||||||
|
${LIBRARY_DIR}/array/concatenate.cc
|
||||||
|
${LIBRARY_DIR}/array/dict_internal.cc
|
||||||
|
${LIBRARY_DIR}/array/diff.cc
|
||||||
|
|
||||||
${LIBRARY_DIR}/buffer.cc
|
${LIBRARY_DIR}/csv/converter.cc
|
||||||
${LIBRARY_DIR}/compare.cc
|
${LIBRARY_DIR}/csv/chunker.cc
|
||||||
${LIBRARY_DIR}/memory_pool.cc
|
${LIBRARY_DIR}/csv/column_builder.cc
|
||||||
${LIBRARY_DIR}/pretty_print.cc
|
${LIBRARY_DIR}/csv/options.cc
|
||||||
${LIBRARY_DIR}/record_batch.cc
|
${LIBRARY_DIR}/csv/parser.cc
|
||||||
${LIBRARY_DIR}/status.cc
|
${LIBRARY_DIR}/csv/reader.cc
|
||||||
${LIBRARY_DIR}/table.cc
|
|
||||||
${LIBRARY_DIR}/table_builder.cc
|
|
||||||
${LIBRARY_DIR}/tensor.cc
|
|
||||||
${LIBRARY_DIR}/sparse_tensor.cc
|
|
||||||
${LIBRARY_DIR}/type.cc
|
|
||||||
${LIBRARY_DIR}/visitor.cc
|
|
||||||
|
|
||||||
${LIBRARY_DIR}/csv/converter.cc
|
${LIBRARY_DIR}/ipc/dictionary.cc
|
||||||
${LIBRARY_DIR}/csv/chunker.cc
|
${LIBRARY_DIR}/ipc/feather.cc
|
||||||
${LIBRARY_DIR}/csv/column-builder.cc
|
${LIBRARY_DIR}/ipc/message.cc
|
||||||
${LIBRARY_DIR}/csv/options.cc
|
${LIBRARY_DIR}/ipc/metadata_internal.cc
|
||||||
${LIBRARY_DIR}/csv/parser.cc
|
${LIBRARY_DIR}/ipc/options.cc
|
||||||
${LIBRARY_DIR}/csv/reader.cc
|
${LIBRARY_DIR}/ipc/reader.cc
|
||||||
|
${LIBRARY_DIR}/ipc/writer.cc
|
||||||
|
|
||||||
${LIBRARY_DIR}/io/buffered.cc
|
${LIBRARY_DIR}/io/buffered.cc
|
||||||
${LIBRARY_DIR}/io/compressed.cc
|
${LIBRARY_DIR}/io/compressed.cc
|
||||||
${LIBRARY_DIR}/io/file.cc
|
${LIBRARY_DIR}/io/file.cc
|
||||||
${LIBRARY_DIR}/io/interfaces.cc
|
${LIBRARY_DIR}/io/interfaces.cc
|
||||||
${LIBRARY_DIR}/io/memory.cc
|
${LIBRARY_DIR}/io/memory.cc
|
||||||
${LIBRARY_DIR}/io/readahead.cc
|
${LIBRARY_DIR}/io/readahead.cc
|
||||||
|
${LIBRARY_DIR}/io/slow.cc
|
||||||
|
|
||||||
${LIBRARY_DIR}/util/bit-util.cc
|
${LIBRARY_DIR}/util/basic_decimal.cc
|
||||||
${LIBRARY_DIR}/util/compression.cc
|
${LIBRARY_DIR}/util/bit_util.cc
|
||||||
${LIBRARY_DIR}/util/cpu-info.cc
|
${LIBRARY_DIR}/util/compression.cc
|
||||||
${LIBRARY_DIR}/util/decimal.cc
|
${LIBRARY_DIR}/util/compression_lz4.cc
|
||||||
${LIBRARY_DIR}/util/int-util.cc
|
${LIBRARY_DIR}/util/compression_snappy.cc
|
||||||
${LIBRARY_DIR}/util/io-util.cc
|
${LIBRARY_DIR}/util/compression_zlib.cc
|
||||||
${LIBRARY_DIR}/util/logging.cc
|
${LIBRARY_DIR}/util/compression_zstd.cc
|
||||||
${LIBRARY_DIR}/util/key_value_metadata.cc
|
${LIBRARY_DIR}/util/cpu_info.cc
|
||||||
${LIBRARY_DIR}/util/task-group.cc
|
${LIBRARY_DIR}/util/decimal.cc
|
||||||
${LIBRARY_DIR}/util/thread-pool.cc
|
${LIBRARY_DIR}/util/int_util.cc
|
||||||
${LIBRARY_DIR}/util/trie.cc
|
${LIBRARY_DIR}/util/io_util.cc
|
||||||
${LIBRARY_DIR}/util/utf8.cc
|
${LIBRARY_DIR}/util/key_value_metadata.cc
|
||||||
${ORC_SRCS}
|
${LIBRARY_DIR}/util/logging.cc
|
||||||
)
|
${LIBRARY_DIR}/util/memory.cc
|
||||||
|
${LIBRARY_DIR}/util/string_builder.cc
|
||||||
|
${LIBRARY_DIR}/util/string.cc
|
||||||
|
${LIBRARY_DIR}/util/task_group.cc
|
||||||
|
${LIBRARY_DIR}/util/thread_pool.cc
|
||||||
|
${LIBRARY_DIR}/util/trie.cc
|
||||||
|
${LIBRARY_DIR}/util/utf8.cc
|
||||||
|
|
||||||
|
${LIBRARY_DIR}/vendored/base64.cpp
|
||||||
|
${ORC_SRCS}
|
||||||
|
)
|
||||||
|
|
||||||
set(ARROW_SRCS ${ARROW_SRCS}
|
set(ARROW_SRCS ${ARROW_SRCS}
|
||||||
${LIBRARY_DIR}/compute/context.cc
|
${LIBRARY_DIR}/compute/context.cc
|
||||||
${LIBRARY_DIR}/compute/kernels/boolean.cc
|
${LIBRARY_DIR}/compute/kernels/boolean.cc
|
||||||
${LIBRARY_DIR}/compute/kernels/cast.cc
|
${LIBRARY_DIR}/compute/kernels/cast.cc
|
||||||
${LIBRARY_DIR}/compute/kernels/hash.cc
|
${LIBRARY_DIR}/compute/kernels/hash.cc
|
||||||
${LIBRARY_DIR}/compute/kernels/util-internal.cc
|
${LIBRARY_DIR}/compute/kernels/util_internal.cc
|
||||||
)
|
)
|
||||||
|
|
||||||
if (LZ4_INCLUDE_DIR AND LZ4_LIBRARY)
|
if (LZ4_INCLUDE_DIR AND LZ4_LIBRARY)
|
||||||
set(ARROW_WITH_LZ4 1)
|
set(ARROW_WITH_LZ4 1)
|
||||||
endif()
|
endif ()
|
||||||
|
|
||||||
if(SNAPPY_INCLUDE_DIR AND SNAPPY_LIBRARY)
|
if (SNAPPY_INCLUDE_DIR AND SNAPPY_LIBRARY)
|
||||||
set(ARROW_WITH_SNAPPY 1)
|
set(ARROW_WITH_SNAPPY 1)
|
||||||
endif()
|
endif ()
|
||||||
|
|
||||||
if(ZLIB_INCLUDE_DIR AND ZLIB_LIBRARIES)
|
if (ZLIB_INCLUDE_DIR AND ZLIB_LIBRARIES)
|
||||||
set(ARROW_WITH_ZLIB 1)
|
set(ARROW_WITH_ZLIB 1)
|
||||||
endif()
|
endif ()
|
||||||
|
|
||||||
if (ZSTD_INCLUDE_DIR AND ZSTD_LIBRARY)
|
if (ZSTD_INCLUDE_DIR AND ZSTD_LIBRARY)
|
||||||
set(ARROW_WITH_ZSTD 1)
|
set(ARROW_WITH_ZSTD 1)
|
||||||
endif()
|
endif ()
|
||||||
|
|
||||||
if (ARROW_WITH_LZ4)
|
if (ARROW_WITH_LZ4)
|
||||||
add_definitions(-DARROW_WITH_LZ4)
|
add_definitions(-DARROW_WITH_LZ4)
|
||||||
SET(ARROW_SRCS ${LIBRARY_DIR}/util/compression_lz4.cc ${ARROW_SRCS})
|
SET(ARROW_SRCS ${LIBRARY_DIR}/util/compression_lz4.cc ${ARROW_SRCS})
|
||||||
endif()
|
endif ()
|
||||||
|
|
||||||
if (ARROW_WITH_SNAPPY)
|
if (ARROW_WITH_SNAPPY)
|
||||||
add_definitions(-DARROW_WITH_SNAPPY)
|
add_definitions(-DARROW_WITH_SNAPPY)
|
||||||
SET(ARROW_SRCS ${LIBRARY_DIR}/util/compression_snappy.cc ${ARROW_SRCS})
|
SET(ARROW_SRCS ${LIBRARY_DIR}/util/compression_snappy.cc ${ARROW_SRCS})
|
||||||
endif()
|
endif ()
|
||||||
|
|
||||||
if (ARROW_WITH_ZLIB)
|
if (ARROW_WITH_ZLIB)
|
||||||
add_definitions(-DARROW_WITH_ZLIB)
|
add_definitions(-DARROW_WITH_ZLIB)
|
||||||
SET(ARROW_SRCS ${LIBRARY_DIR}/util/compression_zlib.cc ${ARROW_SRCS})
|
SET(ARROW_SRCS ${LIBRARY_DIR}/util/compression_zlib.cc ${ARROW_SRCS})
|
||||||
endif()
|
endif ()
|
||||||
|
|
||||||
if (ARROW_WITH_ZSTD)
|
if (ARROW_WITH_ZSTD)
|
||||||
add_definitions(-DARROW_WITH_ZSTD)
|
add_definitions(-DARROW_WITH_ZSTD)
|
||||||
SET(ARROW_SRCS ${LIBRARY_DIR}/util/compression_zstd.cc ${ARROW_SRCS})
|
SET(ARROW_SRCS ${LIBRARY_DIR}/util/compression_zstd.cc ${ARROW_SRCS})
|
||||||
endif()
|
endif ()
|
||||||
|
|
||||||
|
|
||||||
add_library(${ARROW_LIBRARY} ${ARROW_SRCS})
|
add_library(${ARROW_LIBRARY} ${ARROW_SRCS})
|
||||||
|
|
||||||
|
# Arrow dependencies
|
||||||
|
add_dependencies(${ARROW_LIBRARY} ${FLATBUFFERS_LIBRARY} metadata_fbs)
|
||||||
|
|
||||||
|
target_link_libraries(${ARROW_LIBRARY} PRIVATE boost_system_internal boost_filesystem_internal boost_regex_internal)
|
||||||
|
target_link_libraries(${ARROW_LIBRARY} PRIVATE ${FLATBUFFERS_LIBRARY})
|
||||||
|
|
||||||
if (USE_INTERNAL_PROTOBUF_LIBRARY)
|
if (USE_INTERNAL_PROTOBUF_LIBRARY)
|
||||||
add_dependencies(${ARROW_LIBRARY} protoc)
|
add_dependencies(${ARROW_LIBRARY} protoc)
|
||||||
endif()
|
endif ()
|
||||||
|
|
||||||
target_include_directories(${ARROW_LIBRARY} SYSTEM PUBLIC ${ClickHouse_SOURCE_DIR}/contrib/arrow/cpp/src PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/cpp/src ${Boost_INCLUDE_DIRS})
|
target_include_directories(${ARROW_LIBRARY} SYSTEM PUBLIC ${ClickHouse_SOURCE_DIR}/contrib/arrow/cpp/src PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/cpp/src ${Boost_INCLUDE_DIRS})
|
||||||
target_link_libraries(${ARROW_LIBRARY} PRIVATE ${DOUBLE_CONVERSION_LIBRARIES} ${Protobuf_LIBRARY})
|
target_link_libraries(${ARROW_LIBRARY} PRIVATE ${DOUBLE_CONVERSION_LIBRARIES} ${Protobuf_LIBRARY})
|
||||||
if (ARROW_WITH_LZ4)
|
if (ARROW_WITH_LZ4)
|
||||||
target_link_libraries(${ARROW_LIBRARY} PRIVATE ${LZ4_LIBRARY})
|
target_link_libraries(${ARROW_LIBRARY} PRIVATE ${LZ4_LIBRARY})
|
||||||
endif()
|
endif ()
|
||||||
if (ARROW_WITH_SNAPPY)
|
if (ARROW_WITH_SNAPPY)
|
||||||
target_link_libraries(${ARROW_LIBRARY} PRIVATE ${SNAPPY_LIBRARY})
|
target_link_libraries(${ARROW_LIBRARY} PRIVATE ${SNAPPY_LIBRARY})
|
||||||
endif()
|
endif ()
|
||||||
if (ARROW_WITH_ZLIB)
|
if (ARROW_WITH_ZLIB)
|
||||||
target_link_libraries(${ARROW_LIBRARY} PRIVATE ${ZLIB_LIBRARIES})
|
target_link_libraries(${ARROW_LIBRARY} PRIVATE ${ZLIB_LIBRARIES})
|
||||||
endif()
|
endif ()
|
||||||
if (ARROW_WITH_ZSTD)
|
if (ARROW_WITH_ZSTD)
|
||||||
target_link_libraries(${ARROW_LIBRARY} PRIVATE ${ZSTD_LIBRARY})
|
target_link_libraries(${ARROW_LIBRARY} PRIVATE ${ZSTD_LIBRARY})
|
||||||
endif()
|
endif ()
|
||||||
|
|
||||||
target_include_directories(${ARROW_LIBRARY} PRIVATE SYSTEM ${ORC_INCLUDE_DIR})
|
target_include_directories(${ARROW_LIBRARY} PRIVATE SYSTEM ${ORC_INCLUDE_DIR})
|
||||||
target_include_directories(${ARROW_LIBRARY} PRIVATE SYSTEM ${ORC_SOURCE_SRC_DIR})
|
target_include_directories(${ARROW_LIBRARY} PRIVATE SYSTEM ${ORC_SOURCE_SRC_DIR})
|
||||||
@ -248,52 +356,56 @@ target_include_directories(${ARROW_LIBRARY} PRIVATE SYSTEM ${ORC_BUILD_SRC_DIR})
|
|||||||
target_include_directories(${ARROW_LIBRARY} PRIVATE SYSTEM ${ORC_BUILD_INCLUDE_DIR})
|
target_include_directories(${ARROW_LIBRARY} PRIVATE SYSTEM ${ORC_BUILD_INCLUDE_DIR})
|
||||||
target_include_directories(${ARROW_LIBRARY} PRIVATE SYSTEM ${ORC_ADDITION_SOURCE_DIR})
|
target_include_directories(${ARROW_LIBRARY} PRIVATE SYSTEM ${ORC_ADDITION_SOURCE_DIR})
|
||||||
target_include_directories(${ARROW_LIBRARY} PRIVATE SYSTEM ${ARROW_SRC_DIR})
|
target_include_directories(${ARROW_LIBRARY} PRIVATE SYSTEM ${ARROW_SRC_DIR})
|
||||||
|
target_include_directories(${ARROW_LIBRARY} PRIVATE SYSTEM ${FLATBUFFERS_INCLUDE_DIR})
|
||||||
|
target_include_directories(${ARROW_LIBRARY} PRIVATE SYSTEM ${ARROW_GENERATED_INCLUDE_DIR})
|
||||||
|
|
||||||
# === parquet
|
# === parquet
|
||||||
|
|
||||||
set(LIBRARY_DIR ${ClickHouse_SOURCE_DIR}/contrib/arrow/cpp/src/parquet)
|
set(LIBRARY_DIR ${ClickHouse_SOURCE_DIR}/contrib/arrow/cpp/src/parquet)
|
||||||
# arrow/cpp/src/parquet/CMakeLists.txt
|
# arrow/cpp/src/parquet/CMakeLists.txt
|
||||||
set(PARQUET_SRCS
|
set(PARQUET_SRCS
|
||||||
${LIBRARY_DIR}/arrow/reader.cc
|
${LIBRARY_DIR}/arrow/reader.cc
|
||||||
${LIBRARY_DIR}/arrow/record_reader.cc
|
${LIBRARY_DIR}/arrow/reader_internal.cc
|
||||||
${LIBRARY_DIR}/arrow/schema.cc
|
${LIBRARY_DIR}/arrow/schema.cc
|
||||||
${LIBRARY_DIR}/arrow/writer.cc
|
${LIBRARY_DIR}/arrow/writer.cc
|
||||||
${LIBRARY_DIR}/bloom_filter.cc
|
${LIBRARY_DIR}/bloom_filter.cc
|
||||||
${LIBRARY_DIR}/column_reader.cc
|
${LIBRARY_DIR}/column_reader.cc
|
||||||
${LIBRARY_DIR}/column_scanner.cc
|
${LIBRARY_DIR}/column_scanner.cc
|
||||||
${LIBRARY_DIR}/column_writer.cc
|
${LIBRARY_DIR}/column_writer.cc
|
||||||
${LIBRARY_DIR}/file_reader.cc
|
${LIBRARY_DIR}/deprecated_io.cc
|
||||||
${LIBRARY_DIR}/file_writer.cc
|
${LIBRARY_DIR}/encoding.cc
|
||||||
${LIBRARY_DIR}/metadata.cc
|
${LIBRARY_DIR}/file_reader.cc
|
||||||
${LIBRARY_DIR}/murmur3.cc
|
${LIBRARY_DIR}/file_writer.cc
|
||||||
${LIBRARY_DIR}/printer.cc
|
${LIBRARY_DIR}/metadata.cc
|
||||||
${LIBRARY_DIR}/schema.cc
|
${LIBRARY_DIR}/murmur3.cc
|
||||||
${LIBRARY_DIR}/statistics.cc
|
${LIBRARY_DIR}/platform.cc
|
||||||
${LIBRARY_DIR}/types.cc
|
${LIBRARY_DIR}/printer.cc
|
||||||
${LIBRARY_DIR}/util/comparison.cc
|
${LIBRARY_DIR}/properties.cc
|
||||||
${LIBRARY_DIR}/util/memory.cc
|
${LIBRARY_DIR}/schema.cc
|
||||||
)
|
${LIBRARY_DIR}/statistics.cc
|
||||||
|
${LIBRARY_DIR}/types.cc
|
||||||
|
)
|
||||||
#list(TRANSFORM PARQUET_SRCS PREPEND ${LIBRARY_DIR}/) # cmake 3.12
|
#list(TRANSFORM PARQUET_SRCS PREPEND ${LIBRARY_DIR}/) # cmake 3.12
|
||||||
list(APPEND PARQUET_SRCS
|
list(APPEND PARQUET_SRCS
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/cpp/src/parquet/parquet_constants.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/cpp/src/parquet/parquet_constants.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/cpp/src/parquet/parquet_types.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/cpp/src/parquet/parquet_types.cpp
|
||||||
)
|
)
|
||||||
add_library(${PARQUET_LIBRARY} ${PARQUET_SRCS})
|
add_library(${PARQUET_LIBRARY} ${PARQUET_SRCS})
|
||||||
target_include_directories(${PARQUET_LIBRARY} SYSTEM PUBLIC ${ClickHouse_SOURCE_DIR}/contrib/arrow/cpp/src ${CMAKE_CURRENT_SOURCE_DIR}/cpp/src)
|
target_include_directories(${PARQUET_LIBRARY} SYSTEM PUBLIC ${ClickHouse_SOURCE_DIR}/contrib/arrow/cpp/src ${CMAKE_CURRENT_SOURCE_DIR}/cpp/src)
|
||||||
include(${ClickHouse_SOURCE_DIR}/contrib/thrift/build/cmake/ConfigureChecks.cmake) # makes config.h
|
include(${ClickHouse_SOURCE_DIR}/contrib/thrift/build/cmake/ConfigureChecks.cmake) # makes config.h
|
||||||
target_link_libraries(${PARQUET_LIBRARY} PUBLIC ${ARROW_LIBRARY} PRIVATE ${THRIFT_LIBRARY} ${Boost_REGEX_LIBRARY})
|
target_link_libraries(${PARQUET_LIBRARY} PUBLIC ${ARROW_LIBRARY} PRIVATE ${THRIFT_LIBRARY} ${Boost_REGEX_LIBRARY})
|
||||||
target_include_directories(${PARQUET_LIBRARY} PRIVATE ${Boost_INCLUDE_DIRS})
|
target_include_directories(${PARQUET_LIBRARY} PRIVATE ${Boost_INCLUDE_DIRS})
|
||||||
|
|
||||||
if(SANITIZE STREQUAL "undefined")
|
if (SANITIZE STREQUAL "undefined")
|
||||||
target_compile_options(${PARQUET_LIBRARY} PRIVATE -fno-sanitize=undefined)
|
target_compile_options(${PARQUET_LIBRARY} PRIVATE -fno-sanitize=undefined)
|
||||||
target_compile_options(${ARROW_LIBRARY} PRIVATE -fno-sanitize=undefined)
|
target_compile_options(${ARROW_LIBRARY} PRIVATE -fno-sanitize=undefined)
|
||||||
endif()
|
endif ()
|
||||||
|
|
||||||
# === tools
|
# === tools
|
||||||
|
|
||||||
set(TOOLS_DIR ${ClickHouse_SOURCE_DIR}/contrib/arrow/cpp/tools/parquet)
|
set(TOOLS_DIR ${ClickHouse_SOURCE_DIR}/contrib/arrow/cpp/tools/parquet)
|
||||||
set(PARQUET_TOOLS parquet-dump-schema parquet-reader parquet-scan)
|
set(PARQUET_TOOLS parquet_dump_schema parquet_reader parquet_scan)
|
||||||
foreach(TOOL ${PARQUET_TOOLS})
|
foreach (TOOL ${PARQUET_TOOLS})
|
||||||
add_executable(${TOOL} ${TOOLS_DIR}/${TOOL}.cc)
|
add_executable(${TOOL} ${TOOLS_DIR}/${TOOL}.cc)
|
||||||
target_link_libraries(${TOOL} PRIVATE ${PARQUET_LIBRARY})
|
target_link_libraries(${TOOL} PRIVATE ${PARQUET_LIBRARY})
|
||||||
endforeach()
|
endforeach ()
|
||||||
|
24
contrib/arrow-cmake/cpp/src/arrow/util/config.h
Normal file
24
contrib/arrow-cmake/cpp/src/arrow/util/config.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
// or more contributor license agreements. See the NOTICE file
|
||||||
|
// distributed with this work for additional information
|
||||||
|
// regarding copyright ownership. The ASF licenses this file
|
||||||
|
// to you under the Apache License, Version 2.0 (the
|
||||||
|
// "License"); you may not use this file except in compliance
|
||||||
|
// with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing,
|
||||||
|
// software distributed under the License is distributed on an
|
||||||
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
// KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations
|
||||||
|
// under the License.
|
||||||
|
|
||||||
|
#define ARROW_VERSION_MAJOR
|
||||||
|
#define ARROW_VERSION_MINOR
|
||||||
|
#define ARROW_VERSION_PATCH
|
||||||
|
#define ARROW_VERSION ((ARROW_VERSION_MAJOR * 1000) + ARROW_VERSION_MINOR) * 1000 + ARROW_VERSION_PATCH
|
||||||
|
|
||||||
|
/* #undef DOUBLE_CONVERSION_HAS_CASE_INSENSIBILITY */
|
||||||
|
/* #undef GRPCPP_PP_INCLUDE */
|
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Autogenerated by Thrift Compiler (0.11.0)
|
* Autogenerated by Thrift Compiler (0.12.0)
|
||||||
*
|
*
|
||||||
* DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
* DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||||
* @generated
|
* @generated
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Autogenerated by Thrift Compiler (0.11.0)
|
* Autogenerated by Thrift Compiler (0.12.0)
|
||||||
*
|
*
|
||||||
* DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
* DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||||
* @generated
|
* @generated
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* Autogenerated by Thrift Compiler (0.11.0)
|
* Autogenerated by Thrift Compiler (0.12.0)
|
||||||
*
|
*
|
||||||
* DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
* DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
|
||||||
* @generated
|
* @generated
|
||||||
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
#include <thrift/stdcxx.h>
|
#include <thrift/stdcxx.h>
|
||||||
|
|
||||||
#include "parquet/util/windows_compatibility.h"
|
#include "parquet/windows_compatibility.h"
|
||||||
|
|
||||||
namespace parquet { namespace format {
|
namespace parquet { namespace format {
|
||||||
|
|
||||||
@ -161,6 +161,8 @@ class MilliSeconds;
|
|||||||
|
|
||||||
class MicroSeconds;
|
class MicroSeconds;
|
||||||
|
|
||||||
|
class NanoSeconds;
|
||||||
|
|
||||||
class TimeUnit;
|
class TimeUnit;
|
||||||
|
|
||||||
class TimestampType;
|
class TimestampType;
|
||||||
@ -215,14 +217,14 @@ class OffsetIndex;
|
|||||||
|
|
||||||
class ColumnIndex;
|
class ColumnIndex;
|
||||||
|
|
||||||
class FileMetaData;
|
|
||||||
|
|
||||||
class AesGcmV1;
|
class AesGcmV1;
|
||||||
|
|
||||||
class AesGcmCtrV1;
|
class AesGcmCtrV1;
|
||||||
|
|
||||||
class EncryptionAlgorithm;
|
class EncryptionAlgorithm;
|
||||||
|
|
||||||
|
class FileMetaData;
|
||||||
|
|
||||||
class FileCryptoMetaData;
|
class FileCryptoMetaData;
|
||||||
|
|
||||||
typedef struct _Statistics__isset {
|
typedef struct _Statistics__isset {
|
||||||
@ -629,10 +631,42 @@ void swap(MicroSeconds &a, MicroSeconds &b);
|
|||||||
|
|
||||||
std::ostream& operator<<(std::ostream& out, const MicroSeconds& obj);
|
std::ostream& operator<<(std::ostream& out, const MicroSeconds& obj);
|
||||||
|
|
||||||
|
|
||||||
|
class NanoSeconds : public virtual ::apache::thrift::TBase {
|
||||||
|
public:
|
||||||
|
|
||||||
|
NanoSeconds(const NanoSeconds&);
|
||||||
|
NanoSeconds& operator=(const NanoSeconds&);
|
||||||
|
NanoSeconds() {
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~NanoSeconds() throw();
|
||||||
|
|
||||||
|
bool operator == (const NanoSeconds & /* rhs */) const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool operator != (const NanoSeconds &rhs) const {
|
||||||
|
return !(*this == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator < (const NanoSeconds & ) const;
|
||||||
|
|
||||||
|
uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
|
||||||
|
uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;
|
||||||
|
|
||||||
|
virtual void printTo(std::ostream& out) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
void swap(NanoSeconds &a, NanoSeconds &b);
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& out, const NanoSeconds& obj);
|
||||||
|
|
||||||
typedef struct _TimeUnit__isset {
|
typedef struct _TimeUnit__isset {
|
||||||
_TimeUnit__isset() : MILLIS(false), MICROS(false) {}
|
_TimeUnit__isset() : MILLIS(false), MICROS(false), NANOS(false) {}
|
||||||
bool MILLIS :1;
|
bool MILLIS :1;
|
||||||
bool MICROS :1;
|
bool MICROS :1;
|
||||||
|
bool NANOS :1;
|
||||||
} _TimeUnit__isset;
|
} _TimeUnit__isset;
|
||||||
|
|
||||||
class TimeUnit : public virtual ::apache::thrift::TBase {
|
class TimeUnit : public virtual ::apache::thrift::TBase {
|
||||||
@ -646,6 +680,7 @@ class TimeUnit : public virtual ::apache::thrift::TBase {
|
|||||||
virtual ~TimeUnit() throw();
|
virtual ~TimeUnit() throw();
|
||||||
MilliSeconds MILLIS;
|
MilliSeconds MILLIS;
|
||||||
MicroSeconds MICROS;
|
MicroSeconds MICROS;
|
||||||
|
NanoSeconds NANOS;
|
||||||
|
|
||||||
_TimeUnit__isset __isset;
|
_TimeUnit__isset __isset;
|
||||||
|
|
||||||
@ -653,6 +688,8 @@ class TimeUnit : public virtual ::apache::thrift::TBase {
|
|||||||
|
|
||||||
void __set_MICROS(const MicroSeconds& val);
|
void __set_MICROS(const MicroSeconds& val);
|
||||||
|
|
||||||
|
void __set_NANOS(const NanoSeconds& val);
|
||||||
|
|
||||||
bool operator == (const TimeUnit & rhs) const
|
bool operator == (const TimeUnit & rhs) const
|
||||||
{
|
{
|
||||||
if (__isset.MILLIS != rhs.__isset.MILLIS)
|
if (__isset.MILLIS != rhs.__isset.MILLIS)
|
||||||
@ -663,6 +700,10 @@ class TimeUnit : public virtual ::apache::thrift::TBase {
|
|||||||
return false;
|
return false;
|
||||||
else if (__isset.MICROS && !(MICROS == rhs.MICROS))
|
else if (__isset.MICROS && !(MICROS == rhs.MICROS))
|
||||||
return false;
|
return false;
|
||||||
|
if (__isset.NANOS != rhs.__isset.NANOS)
|
||||||
|
return false;
|
||||||
|
else if (__isset.NANOS && !(NANOS == rhs.NANOS))
|
||||||
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool operator != (const TimeUnit &rhs) const {
|
bool operator != (const TimeUnit &rhs) const {
|
||||||
@ -867,7 +908,7 @@ void swap(BsonType &a, BsonType &b);
|
|||||||
std::ostream& operator<<(std::ostream& out, const BsonType& obj);
|
std::ostream& operator<<(std::ostream& out, const BsonType& obj);
|
||||||
|
|
||||||
typedef struct _LogicalType__isset {
|
typedef struct _LogicalType__isset {
|
||||||
_LogicalType__isset() : STRING(false), MAP(false), LIST(false), ENUM(false), DECIMAL(false), DATE(false), TIME(false), TIMESTAMP(false), INTEGER(false), UNKNOWN(false), JSON(false), BSON(false) {}
|
_LogicalType__isset() : STRING(false), MAP(false), LIST(false), ENUM(false), DECIMAL(false), DATE(false), TIME(false), TIMESTAMP(false), INTEGER(false), UNKNOWN(false), JSON(false), BSON(false), UUID(false) {}
|
||||||
bool STRING :1;
|
bool STRING :1;
|
||||||
bool MAP :1;
|
bool MAP :1;
|
||||||
bool LIST :1;
|
bool LIST :1;
|
||||||
@ -880,6 +921,7 @@ typedef struct _LogicalType__isset {
|
|||||||
bool UNKNOWN :1;
|
bool UNKNOWN :1;
|
||||||
bool JSON :1;
|
bool JSON :1;
|
||||||
bool BSON :1;
|
bool BSON :1;
|
||||||
|
bool UUID :1;
|
||||||
} _LogicalType__isset;
|
} _LogicalType__isset;
|
||||||
|
|
||||||
class LogicalType : public virtual ::apache::thrift::TBase {
|
class LogicalType : public virtual ::apache::thrift::TBase {
|
||||||
@ -903,6 +945,7 @@ class LogicalType : public virtual ::apache::thrift::TBase {
|
|||||||
NullType UNKNOWN;
|
NullType UNKNOWN;
|
||||||
JsonType JSON;
|
JsonType JSON;
|
||||||
BsonType BSON;
|
BsonType BSON;
|
||||||
|
UUIDType UUID;
|
||||||
|
|
||||||
_LogicalType__isset __isset;
|
_LogicalType__isset __isset;
|
||||||
|
|
||||||
@ -930,6 +973,8 @@ class LogicalType : public virtual ::apache::thrift::TBase {
|
|||||||
|
|
||||||
void __set_BSON(const BsonType& val);
|
void __set_BSON(const BsonType& val);
|
||||||
|
|
||||||
|
void __set_UUID(const UUIDType& val);
|
||||||
|
|
||||||
bool operator == (const LogicalType & rhs) const
|
bool operator == (const LogicalType & rhs) const
|
||||||
{
|
{
|
||||||
if (__isset.STRING != rhs.__isset.STRING)
|
if (__isset.STRING != rhs.__isset.STRING)
|
||||||
@ -980,6 +1025,10 @@ class LogicalType : public virtual ::apache::thrift::TBase {
|
|||||||
return false;
|
return false;
|
||||||
else if (__isset.BSON && !(BSON == rhs.BSON))
|
else if (__isset.BSON && !(BSON == rhs.BSON))
|
||||||
return false;
|
return false;
|
||||||
|
if (__isset.UUID != rhs.__isset.UUID)
|
||||||
|
return false;
|
||||||
|
else if (__isset.UUID && !(UUID == rhs.UUID))
|
||||||
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool operator != (const LogicalType &rhs) const {
|
bool operator != (const LogicalType &rhs) const {
|
||||||
@ -1722,8 +1771,8 @@ void swap(EncryptionWithFooterKey &a, EncryptionWithFooterKey &b);
|
|||||||
std::ostream& operator<<(std::ostream& out, const EncryptionWithFooterKey& obj);
|
std::ostream& operator<<(std::ostream& out, const EncryptionWithFooterKey& obj);
|
||||||
|
|
||||||
typedef struct _EncryptionWithColumnKey__isset {
|
typedef struct _EncryptionWithColumnKey__isset {
|
||||||
_EncryptionWithColumnKey__isset() : column_key_metadata(false) {}
|
_EncryptionWithColumnKey__isset() : key_metadata(false) {}
|
||||||
bool column_key_metadata :1;
|
bool key_metadata :1;
|
||||||
} _EncryptionWithColumnKey__isset;
|
} _EncryptionWithColumnKey__isset;
|
||||||
|
|
||||||
class EncryptionWithColumnKey : public virtual ::apache::thrift::TBase {
|
class EncryptionWithColumnKey : public virtual ::apache::thrift::TBase {
|
||||||
@ -1731,26 +1780,26 @@ class EncryptionWithColumnKey : public virtual ::apache::thrift::TBase {
|
|||||||
|
|
||||||
EncryptionWithColumnKey(const EncryptionWithColumnKey&);
|
EncryptionWithColumnKey(const EncryptionWithColumnKey&);
|
||||||
EncryptionWithColumnKey& operator=(const EncryptionWithColumnKey&);
|
EncryptionWithColumnKey& operator=(const EncryptionWithColumnKey&);
|
||||||
EncryptionWithColumnKey() : column_key_metadata() {
|
EncryptionWithColumnKey() : key_metadata() {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~EncryptionWithColumnKey() throw();
|
virtual ~EncryptionWithColumnKey() throw();
|
||||||
std::vector<std::string> path_in_schema;
|
std::vector<std::string> path_in_schema;
|
||||||
std::string column_key_metadata;
|
std::string key_metadata;
|
||||||
|
|
||||||
_EncryptionWithColumnKey__isset __isset;
|
_EncryptionWithColumnKey__isset __isset;
|
||||||
|
|
||||||
void __set_path_in_schema(const std::vector<std::string> & val);
|
void __set_path_in_schema(const std::vector<std::string> & val);
|
||||||
|
|
||||||
void __set_column_key_metadata(const std::string& val);
|
void __set_key_metadata(const std::string& val);
|
||||||
|
|
||||||
bool operator == (const EncryptionWithColumnKey & rhs) const
|
bool operator == (const EncryptionWithColumnKey & rhs) const
|
||||||
{
|
{
|
||||||
if (!(path_in_schema == rhs.path_in_schema))
|
if (!(path_in_schema == rhs.path_in_schema))
|
||||||
return false;
|
return false;
|
||||||
if (__isset.column_key_metadata != rhs.__isset.column_key_metadata)
|
if (__isset.key_metadata != rhs.__isset.key_metadata)
|
||||||
return false;
|
return false;
|
||||||
else if (__isset.column_key_metadata && !(column_key_metadata == rhs.column_key_metadata))
|
else if (__isset.key_metadata && !(key_metadata == rhs.key_metadata))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1823,14 +1872,15 @@ void swap(ColumnCryptoMetaData &a, ColumnCryptoMetaData &b);
|
|||||||
std::ostream& operator<<(std::ostream& out, const ColumnCryptoMetaData& obj);
|
std::ostream& operator<<(std::ostream& out, const ColumnCryptoMetaData& obj);
|
||||||
|
|
||||||
typedef struct _ColumnChunk__isset {
|
typedef struct _ColumnChunk__isset {
|
||||||
_ColumnChunk__isset() : file_path(false), meta_data(false), offset_index_offset(false), offset_index_length(false), column_index_offset(false), column_index_length(false), crypto_meta_data(false) {}
|
_ColumnChunk__isset() : file_path(false), meta_data(false), offset_index_offset(false), offset_index_length(false), column_index_offset(false), column_index_length(false), crypto_metadata(false), encrypted_column_metadata(false) {}
|
||||||
bool file_path :1;
|
bool file_path :1;
|
||||||
bool meta_data :1;
|
bool meta_data :1;
|
||||||
bool offset_index_offset :1;
|
bool offset_index_offset :1;
|
||||||
bool offset_index_length :1;
|
bool offset_index_length :1;
|
||||||
bool column_index_offset :1;
|
bool column_index_offset :1;
|
||||||
bool column_index_length :1;
|
bool column_index_length :1;
|
||||||
bool crypto_meta_data :1;
|
bool crypto_metadata :1;
|
||||||
|
bool encrypted_column_metadata :1;
|
||||||
} _ColumnChunk__isset;
|
} _ColumnChunk__isset;
|
||||||
|
|
||||||
class ColumnChunk : public virtual ::apache::thrift::TBase {
|
class ColumnChunk : public virtual ::apache::thrift::TBase {
|
||||||
@ -1838,7 +1888,7 @@ class ColumnChunk : public virtual ::apache::thrift::TBase {
|
|||||||
|
|
||||||
ColumnChunk(const ColumnChunk&);
|
ColumnChunk(const ColumnChunk&);
|
||||||
ColumnChunk& operator=(const ColumnChunk&);
|
ColumnChunk& operator=(const ColumnChunk&);
|
||||||
ColumnChunk() : file_path(), file_offset(0), offset_index_offset(0), offset_index_length(0), column_index_offset(0), column_index_length(0) {
|
ColumnChunk() : file_path(), file_offset(0), offset_index_offset(0), offset_index_length(0), column_index_offset(0), column_index_length(0), encrypted_column_metadata() {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~ColumnChunk() throw();
|
virtual ~ColumnChunk() throw();
|
||||||
@ -1849,7 +1899,8 @@ class ColumnChunk : public virtual ::apache::thrift::TBase {
|
|||||||
int32_t offset_index_length;
|
int32_t offset_index_length;
|
||||||
int64_t column_index_offset;
|
int64_t column_index_offset;
|
||||||
int32_t column_index_length;
|
int32_t column_index_length;
|
||||||
ColumnCryptoMetaData crypto_meta_data;
|
ColumnCryptoMetaData crypto_metadata;
|
||||||
|
std::string encrypted_column_metadata;
|
||||||
|
|
||||||
_ColumnChunk__isset __isset;
|
_ColumnChunk__isset __isset;
|
||||||
|
|
||||||
@ -1867,7 +1918,9 @@ class ColumnChunk : public virtual ::apache::thrift::TBase {
|
|||||||
|
|
||||||
void __set_column_index_length(const int32_t val);
|
void __set_column_index_length(const int32_t val);
|
||||||
|
|
||||||
void __set_crypto_meta_data(const ColumnCryptoMetaData& val);
|
void __set_crypto_metadata(const ColumnCryptoMetaData& val);
|
||||||
|
|
||||||
|
void __set_encrypted_column_metadata(const std::string& val);
|
||||||
|
|
||||||
bool operator == (const ColumnChunk & rhs) const
|
bool operator == (const ColumnChunk & rhs) const
|
||||||
{
|
{
|
||||||
@ -1897,9 +1950,13 @@ class ColumnChunk : public virtual ::apache::thrift::TBase {
|
|||||||
return false;
|
return false;
|
||||||
else if (__isset.column_index_length && !(column_index_length == rhs.column_index_length))
|
else if (__isset.column_index_length && !(column_index_length == rhs.column_index_length))
|
||||||
return false;
|
return false;
|
||||||
if (__isset.crypto_meta_data != rhs.__isset.crypto_meta_data)
|
if (__isset.crypto_metadata != rhs.__isset.crypto_metadata)
|
||||||
return false;
|
return false;
|
||||||
else if (__isset.crypto_meta_data && !(crypto_meta_data == rhs.crypto_meta_data))
|
else if (__isset.crypto_metadata && !(crypto_metadata == rhs.crypto_metadata))
|
||||||
|
return false;
|
||||||
|
if (__isset.encrypted_column_metadata != rhs.__isset.encrypted_column_metadata)
|
||||||
|
return false;
|
||||||
|
else if (__isset.encrypted_column_metadata && !(encrypted_column_metadata == rhs.encrypted_column_metadata))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1920,10 +1977,11 @@ void swap(ColumnChunk &a, ColumnChunk &b);
|
|||||||
std::ostream& operator<<(std::ostream& out, const ColumnChunk& obj);
|
std::ostream& operator<<(std::ostream& out, const ColumnChunk& obj);
|
||||||
|
|
||||||
typedef struct _RowGroup__isset {
|
typedef struct _RowGroup__isset {
|
||||||
_RowGroup__isset() : sorting_columns(false), file_offset(false), total_compressed_size(false) {}
|
_RowGroup__isset() : sorting_columns(false), file_offset(false), total_compressed_size(false), ordinal(false) {}
|
||||||
bool sorting_columns :1;
|
bool sorting_columns :1;
|
||||||
bool file_offset :1;
|
bool file_offset :1;
|
||||||
bool total_compressed_size :1;
|
bool total_compressed_size :1;
|
||||||
|
bool ordinal :1;
|
||||||
} _RowGroup__isset;
|
} _RowGroup__isset;
|
||||||
|
|
||||||
class RowGroup : public virtual ::apache::thrift::TBase {
|
class RowGroup : public virtual ::apache::thrift::TBase {
|
||||||
@ -1931,7 +1989,7 @@ class RowGroup : public virtual ::apache::thrift::TBase {
|
|||||||
|
|
||||||
RowGroup(const RowGroup&);
|
RowGroup(const RowGroup&);
|
||||||
RowGroup& operator=(const RowGroup&);
|
RowGroup& operator=(const RowGroup&);
|
||||||
RowGroup() : total_byte_size(0), num_rows(0), file_offset(0), total_compressed_size(0) {
|
RowGroup() : total_byte_size(0), num_rows(0), file_offset(0), total_compressed_size(0), ordinal(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~RowGroup() throw();
|
virtual ~RowGroup() throw();
|
||||||
@ -1941,6 +1999,7 @@ class RowGroup : public virtual ::apache::thrift::TBase {
|
|||||||
std::vector<SortingColumn> sorting_columns;
|
std::vector<SortingColumn> sorting_columns;
|
||||||
int64_t file_offset;
|
int64_t file_offset;
|
||||||
int64_t total_compressed_size;
|
int64_t total_compressed_size;
|
||||||
|
int16_t ordinal;
|
||||||
|
|
||||||
_RowGroup__isset __isset;
|
_RowGroup__isset __isset;
|
||||||
|
|
||||||
@ -1956,6 +2015,8 @@ class RowGroup : public virtual ::apache::thrift::TBase {
|
|||||||
|
|
||||||
void __set_total_compressed_size(const int64_t val);
|
void __set_total_compressed_size(const int64_t val);
|
||||||
|
|
||||||
|
void __set_ordinal(const int16_t val);
|
||||||
|
|
||||||
bool operator == (const RowGroup & rhs) const
|
bool operator == (const RowGroup & rhs) const
|
||||||
{
|
{
|
||||||
if (!(columns == rhs.columns))
|
if (!(columns == rhs.columns))
|
||||||
@ -1976,6 +2037,10 @@ class RowGroup : public virtual ::apache::thrift::TBase {
|
|||||||
return false;
|
return false;
|
||||||
else if (__isset.total_compressed_size && !(total_compressed_size == rhs.total_compressed_size))
|
else if (__isset.total_compressed_size && !(total_compressed_size == rhs.total_compressed_size))
|
||||||
return false;
|
return false;
|
||||||
|
if (__isset.ordinal != rhs.__isset.ordinal)
|
||||||
|
return false;
|
||||||
|
else if (__isset.ordinal && !(ordinal == rhs.ordinal))
|
||||||
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool operator != (const RowGroup &rhs) const {
|
bool operator != (const RowGroup &rhs) const {
|
||||||
@ -2215,90 +2280,11 @@ void swap(ColumnIndex &a, ColumnIndex &b);
|
|||||||
|
|
||||||
std::ostream& operator<<(std::ostream& out, const ColumnIndex& obj);
|
std::ostream& operator<<(std::ostream& out, const ColumnIndex& obj);
|
||||||
|
|
||||||
typedef struct _FileMetaData__isset {
|
|
||||||
_FileMetaData__isset() : key_value_metadata(false), created_by(false), column_orders(false) {}
|
|
||||||
bool key_value_metadata :1;
|
|
||||||
bool created_by :1;
|
|
||||||
bool column_orders :1;
|
|
||||||
} _FileMetaData__isset;
|
|
||||||
|
|
||||||
class FileMetaData : public virtual ::apache::thrift::TBase {
|
|
||||||
public:
|
|
||||||
|
|
||||||
FileMetaData(const FileMetaData&);
|
|
||||||
FileMetaData& operator=(const FileMetaData&);
|
|
||||||
FileMetaData() : version(0), num_rows(0), created_by() {
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~FileMetaData() throw();
|
|
||||||
int32_t version;
|
|
||||||
std::vector<SchemaElement> schema;
|
|
||||||
int64_t num_rows;
|
|
||||||
std::vector<RowGroup> row_groups;
|
|
||||||
std::vector<KeyValue> key_value_metadata;
|
|
||||||
std::string created_by;
|
|
||||||
std::vector<ColumnOrder> column_orders;
|
|
||||||
|
|
||||||
_FileMetaData__isset __isset;
|
|
||||||
|
|
||||||
void __set_version(const int32_t val);
|
|
||||||
|
|
||||||
void __set_schema(const std::vector<SchemaElement> & val);
|
|
||||||
|
|
||||||
void __set_num_rows(const int64_t val);
|
|
||||||
|
|
||||||
void __set_row_groups(const std::vector<RowGroup> & val);
|
|
||||||
|
|
||||||
void __set_key_value_metadata(const std::vector<KeyValue> & val);
|
|
||||||
|
|
||||||
void __set_created_by(const std::string& val);
|
|
||||||
|
|
||||||
void __set_column_orders(const std::vector<ColumnOrder> & val);
|
|
||||||
|
|
||||||
bool operator == (const FileMetaData & rhs) const
|
|
||||||
{
|
|
||||||
if (!(version == rhs.version))
|
|
||||||
return false;
|
|
||||||
if (!(schema == rhs.schema))
|
|
||||||
return false;
|
|
||||||
if (!(num_rows == rhs.num_rows))
|
|
||||||
return false;
|
|
||||||
if (!(row_groups == rhs.row_groups))
|
|
||||||
return false;
|
|
||||||
if (__isset.key_value_metadata != rhs.__isset.key_value_metadata)
|
|
||||||
return false;
|
|
||||||
else if (__isset.key_value_metadata && !(key_value_metadata == rhs.key_value_metadata))
|
|
||||||
return false;
|
|
||||||
if (__isset.created_by != rhs.__isset.created_by)
|
|
||||||
return false;
|
|
||||||
else if (__isset.created_by && !(created_by == rhs.created_by))
|
|
||||||
return false;
|
|
||||||
if (__isset.column_orders != rhs.__isset.column_orders)
|
|
||||||
return false;
|
|
||||||
else if (__isset.column_orders && !(column_orders == rhs.column_orders))
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool operator != (const FileMetaData &rhs) const {
|
|
||||||
return !(*this == rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator < (const FileMetaData & ) const;
|
|
||||||
|
|
||||||
uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
|
|
||||||
uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;
|
|
||||||
|
|
||||||
virtual void printTo(std::ostream& out) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
void swap(FileMetaData &a, FileMetaData &b);
|
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& out, const FileMetaData& obj);
|
|
||||||
|
|
||||||
typedef struct _AesGcmV1__isset {
|
typedef struct _AesGcmV1__isset {
|
||||||
_AesGcmV1__isset() : aad_metadata(false), iv_prefix(false) {}
|
_AesGcmV1__isset() : aad_prefix(false), aad_file_unique(false), supply_aad_prefix(false) {}
|
||||||
bool aad_metadata :1;
|
bool aad_prefix :1;
|
||||||
bool iv_prefix :1;
|
bool aad_file_unique :1;
|
||||||
|
bool supply_aad_prefix :1;
|
||||||
} _AesGcmV1__isset;
|
} _AesGcmV1__isset;
|
||||||
|
|
||||||
class AesGcmV1 : public virtual ::apache::thrift::TBase {
|
class AesGcmV1 : public virtual ::apache::thrift::TBase {
|
||||||
@ -2306,28 +2292,35 @@ class AesGcmV1 : public virtual ::apache::thrift::TBase {
|
|||||||
|
|
||||||
AesGcmV1(const AesGcmV1&);
|
AesGcmV1(const AesGcmV1&);
|
||||||
AesGcmV1& operator=(const AesGcmV1&);
|
AesGcmV1& operator=(const AesGcmV1&);
|
||||||
AesGcmV1() : aad_metadata(), iv_prefix() {
|
AesGcmV1() : aad_prefix(), aad_file_unique(), supply_aad_prefix(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~AesGcmV1() throw();
|
virtual ~AesGcmV1() throw();
|
||||||
std::string aad_metadata;
|
std::string aad_prefix;
|
||||||
std::string iv_prefix;
|
std::string aad_file_unique;
|
||||||
|
bool supply_aad_prefix;
|
||||||
|
|
||||||
_AesGcmV1__isset __isset;
|
_AesGcmV1__isset __isset;
|
||||||
|
|
||||||
void __set_aad_metadata(const std::string& val);
|
void __set_aad_prefix(const std::string& val);
|
||||||
|
|
||||||
void __set_iv_prefix(const std::string& val);
|
void __set_aad_file_unique(const std::string& val);
|
||||||
|
|
||||||
|
void __set_supply_aad_prefix(const bool val);
|
||||||
|
|
||||||
bool operator == (const AesGcmV1 & rhs) const
|
bool operator == (const AesGcmV1 & rhs) const
|
||||||
{
|
{
|
||||||
if (__isset.aad_metadata != rhs.__isset.aad_metadata)
|
if (__isset.aad_prefix != rhs.__isset.aad_prefix)
|
||||||
return false;
|
return false;
|
||||||
else if (__isset.aad_metadata && !(aad_metadata == rhs.aad_metadata))
|
else if (__isset.aad_prefix && !(aad_prefix == rhs.aad_prefix))
|
||||||
return false;
|
return false;
|
||||||
if (__isset.iv_prefix != rhs.__isset.iv_prefix)
|
if (__isset.aad_file_unique != rhs.__isset.aad_file_unique)
|
||||||
return false;
|
return false;
|
||||||
else if (__isset.iv_prefix && !(iv_prefix == rhs.iv_prefix))
|
else if (__isset.aad_file_unique && !(aad_file_unique == rhs.aad_file_unique))
|
||||||
|
return false;
|
||||||
|
if (__isset.supply_aad_prefix != rhs.__isset.supply_aad_prefix)
|
||||||
|
return false;
|
||||||
|
else if (__isset.supply_aad_prefix && !(supply_aad_prefix == rhs.supply_aad_prefix))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2348,10 +2341,10 @@ void swap(AesGcmV1 &a, AesGcmV1 &b);
|
|||||||
std::ostream& operator<<(std::ostream& out, const AesGcmV1& obj);
|
std::ostream& operator<<(std::ostream& out, const AesGcmV1& obj);
|
||||||
|
|
||||||
typedef struct _AesGcmCtrV1__isset {
|
typedef struct _AesGcmCtrV1__isset {
|
||||||
_AesGcmCtrV1__isset() : aad_metadata(false), gcm_iv_prefix(false), ctr_iv_prefix(false) {}
|
_AesGcmCtrV1__isset() : aad_prefix(false), aad_file_unique(false), supply_aad_prefix(false) {}
|
||||||
bool aad_metadata :1;
|
bool aad_prefix :1;
|
||||||
bool gcm_iv_prefix :1;
|
bool aad_file_unique :1;
|
||||||
bool ctr_iv_prefix :1;
|
bool supply_aad_prefix :1;
|
||||||
} _AesGcmCtrV1__isset;
|
} _AesGcmCtrV1__isset;
|
||||||
|
|
||||||
class AesGcmCtrV1 : public virtual ::apache::thrift::TBase {
|
class AesGcmCtrV1 : public virtual ::apache::thrift::TBase {
|
||||||
@ -2359,35 +2352,35 @@ class AesGcmCtrV1 : public virtual ::apache::thrift::TBase {
|
|||||||
|
|
||||||
AesGcmCtrV1(const AesGcmCtrV1&);
|
AesGcmCtrV1(const AesGcmCtrV1&);
|
||||||
AesGcmCtrV1& operator=(const AesGcmCtrV1&);
|
AesGcmCtrV1& operator=(const AesGcmCtrV1&);
|
||||||
AesGcmCtrV1() : aad_metadata(), gcm_iv_prefix(), ctr_iv_prefix() {
|
AesGcmCtrV1() : aad_prefix(), aad_file_unique(), supply_aad_prefix(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~AesGcmCtrV1() throw();
|
virtual ~AesGcmCtrV1() throw();
|
||||||
std::string aad_metadata;
|
std::string aad_prefix;
|
||||||
std::string gcm_iv_prefix;
|
std::string aad_file_unique;
|
||||||
std::string ctr_iv_prefix;
|
bool supply_aad_prefix;
|
||||||
|
|
||||||
_AesGcmCtrV1__isset __isset;
|
_AesGcmCtrV1__isset __isset;
|
||||||
|
|
||||||
void __set_aad_metadata(const std::string& val);
|
void __set_aad_prefix(const std::string& val);
|
||||||
|
|
||||||
void __set_gcm_iv_prefix(const std::string& val);
|
void __set_aad_file_unique(const std::string& val);
|
||||||
|
|
||||||
void __set_ctr_iv_prefix(const std::string& val);
|
void __set_supply_aad_prefix(const bool val);
|
||||||
|
|
||||||
bool operator == (const AesGcmCtrV1 & rhs) const
|
bool operator == (const AesGcmCtrV1 & rhs) const
|
||||||
{
|
{
|
||||||
if (__isset.aad_metadata != rhs.__isset.aad_metadata)
|
if (__isset.aad_prefix != rhs.__isset.aad_prefix)
|
||||||
return false;
|
return false;
|
||||||
else if (__isset.aad_metadata && !(aad_metadata == rhs.aad_metadata))
|
else if (__isset.aad_prefix && !(aad_prefix == rhs.aad_prefix))
|
||||||
return false;
|
return false;
|
||||||
if (__isset.gcm_iv_prefix != rhs.__isset.gcm_iv_prefix)
|
if (__isset.aad_file_unique != rhs.__isset.aad_file_unique)
|
||||||
return false;
|
return false;
|
||||||
else if (__isset.gcm_iv_prefix && !(gcm_iv_prefix == rhs.gcm_iv_prefix))
|
else if (__isset.aad_file_unique && !(aad_file_unique == rhs.aad_file_unique))
|
||||||
return false;
|
return false;
|
||||||
if (__isset.ctr_iv_prefix != rhs.__isset.ctr_iv_prefix)
|
if (__isset.supply_aad_prefix != rhs.__isset.supply_aad_prefix)
|
||||||
return false;
|
return false;
|
||||||
else if (__isset.ctr_iv_prefix && !(ctr_iv_prefix == rhs.ctr_iv_prefix))
|
else if (__isset.supply_aad_prefix && !(supply_aad_prefix == rhs.supply_aad_prefix))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -2459,9 +2452,105 @@ void swap(EncryptionAlgorithm &a, EncryptionAlgorithm &b);
|
|||||||
|
|
||||||
std::ostream& operator<<(std::ostream& out, const EncryptionAlgorithm& obj);
|
std::ostream& operator<<(std::ostream& out, const EncryptionAlgorithm& obj);
|
||||||
|
|
||||||
|
typedef struct _FileMetaData__isset {
|
||||||
|
_FileMetaData__isset() : key_value_metadata(false), created_by(false), column_orders(false), encryption_algorithm(false), footer_signing_key_metadata(false) {}
|
||||||
|
bool key_value_metadata :1;
|
||||||
|
bool created_by :1;
|
||||||
|
bool column_orders :1;
|
||||||
|
bool encryption_algorithm :1;
|
||||||
|
bool footer_signing_key_metadata :1;
|
||||||
|
} _FileMetaData__isset;
|
||||||
|
|
||||||
|
class FileMetaData : public virtual ::apache::thrift::TBase {
|
||||||
|
public:
|
||||||
|
|
||||||
|
FileMetaData(const FileMetaData&);
|
||||||
|
FileMetaData& operator=(const FileMetaData&);
|
||||||
|
FileMetaData() : version(0), num_rows(0), created_by(), footer_signing_key_metadata() {
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~FileMetaData() throw();
|
||||||
|
int32_t version;
|
||||||
|
std::vector<SchemaElement> schema;
|
||||||
|
int64_t num_rows;
|
||||||
|
std::vector<RowGroup> row_groups;
|
||||||
|
std::vector<KeyValue> key_value_metadata;
|
||||||
|
std::string created_by;
|
||||||
|
std::vector<ColumnOrder> column_orders;
|
||||||
|
EncryptionAlgorithm encryption_algorithm;
|
||||||
|
std::string footer_signing_key_metadata;
|
||||||
|
|
||||||
|
_FileMetaData__isset __isset;
|
||||||
|
|
||||||
|
void __set_version(const int32_t val);
|
||||||
|
|
||||||
|
void __set_schema(const std::vector<SchemaElement> & val);
|
||||||
|
|
||||||
|
void __set_num_rows(const int64_t val);
|
||||||
|
|
||||||
|
void __set_row_groups(const std::vector<RowGroup> & val);
|
||||||
|
|
||||||
|
void __set_key_value_metadata(const std::vector<KeyValue> & val);
|
||||||
|
|
||||||
|
void __set_created_by(const std::string& val);
|
||||||
|
|
||||||
|
void __set_column_orders(const std::vector<ColumnOrder> & val);
|
||||||
|
|
||||||
|
void __set_encryption_algorithm(const EncryptionAlgorithm& val);
|
||||||
|
|
||||||
|
void __set_footer_signing_key_metadata(const std::string& val);
|
||||||
|
|
||||||
|
bool operator == (const FileMetaData & rhs) const
|
||||||
|
{
|
||||||
|
if (!(version == rhs.version))
|
||||||
|
return false;
|
||||||
|
if (!(schema == rhs.schema))
|
||||||
|
return false;
|
||||||
|
if (!(num_rows == rhs.num_rows))
|
||||||
|
return false;
|
||||||
|
if (!(row_groups == rhs.row_groups))
|
||||||
|
return false;
|
||||||
|
if (__isset.key_value_metadata != rhs.__isset.key_value_metadata)
|
||||||
|
return false;
|
||||||
|
else if (__isset.key_value_metadata && !(key_value_metadata == rhs.key_value_metadata))
|
||||||
|
return false;
|
||||||
|
if (__isset.created_by != rhs.__isset.created_by)
|
||||||
|
return false;
|
||||||
|
else if (__isset.created_by && !(created_by == rhs.created_by))
|
||||||
|
return false;
|
||||||
|
if (__isset.column_orders != rhs.__isset.column_orders)
|
||||||
|
return false;
|
||||||
|
else if (__isset.column_orders && !(column_orders == rhs.column_orders))
|
||||||
|
return false;
|
||||||
|
if (__isset.encryption_algorithm != rhs.__isset.encryption_algorithm)
|
||||||
|
return false;
|
||||||
|
else if (__isset.encryption_algorithm && !(encryption_algorithm == rhs.encryption_algorithm))
|
||||||
|
return false;
|
||||||
|
if (__isset.footer_signing_key_metadata != rhs.__isset.footer_signing_key_metadata)
|
||||||
|
return false;
|
||||||
|
else if (__isset.footer_signing_key_metadata && !(footer_signing_key_metadata == rhs.footer_signing_key_metadata))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool operator != (const FileMetaData &rhs) const {
|
||||||
|
return !(*this == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator < (const FileMetaData & ) const;
|
||||||
|
|
||||||
|
uint32_t read(::apache::thrift::protocol::TProtocol* iprot);
|
||||||
|
uint32_t write(::apache::thrift::protocol::TProtocol* oprot) const;
|
||||||
|
|
||||||
|
virtual void printTo(std::ostream& out) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
void swap(FileMetaData &a, FileMetaData &b);
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& out, const FileMetaData& obj);
|
||||||
|
|
||||||
typedef struct _FileCryptoMetaData__isset {
|
typedef struct _FileCryptoMetaData__isset {
|
||||||
_FileCryptoMetaData__isset() : footer_key_metadata(false) {}
|
_FileCryptoMetaData__isset() : key_metadata(false) {}
|
||||||
bool footer_key_metadata :1;
|
bool key_metadata :1;
|
||||||
} _FileCryptoMetaData__isset;
|
} _FileCryptoMetaData__isset;
|
||||||
|
|
||||||
class FileCryptoMetaData : public virtual ::apache::thrift::TBase {
|
class FileCryptoMetaData : public virtual ::apache::thrift::TBase {
|
||||||
@ -2469,36 +2558,26 @@ class FileCryptoMetaData : public virtual ::apache::thrift::TBase {
|
|||||||
|
|
||||||
FileCryptoMetaData(const FileCryptoMetaData&);
|
FileCryptoMetaData(const FileCryptoMetaData&);
|
||||||
FileCryptoMetaData& operator=(const FileCryptoMetaData&);
|
FileCryptoMetaData& operator=(const FileCryptoMetaData&);
|
||||||
FileCryptoMetaData() : encrypted_footer(0), footer_key_metadata(), footer_offset(0) {
|
FileCryptoMetaData() : key_metadata() {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~FileCryptoMetaData() throw();
|
virtual ~FileCryptoMetaData() throw();
|
||||||
EncryptionAlgorithm encryption_algorithm;
|
EncryptionAlgorithm encryption_algorithm;
|
||||||
bool encrypted_footer;
|
std::string key_metadata;
|
||||||
std::string footer_key_metadata;
|
|
||||||
int64_t footer_offset;
|
|
||||||
|
|
||||||
_FileCryptoMetaData__isset __isset;
|
_FileCryptoMetaData__isset __isset;
|
||||||
|
|
||||||
void __set_encryption_algorithm(const EncryptionAlgorithm& val);
|
void __set_encryption_algorithm(const EncryptionAlgorithm& val);
|
||||||
|
|
||||||
void __set_encrypted_footer(const bool val);
|
void __set_key_metadata(const std::string& val);
|
||||||
|
|
||||||
void __set_footer_key_metadata(const std::string& val);
|
|
||||||
|
|
||||||
void __set_footer_offset(const int64_t val);
|
|
||||||
|
|
||||||
bool operator == (const FileCryptoMetaData & rhs) const
|
bool operator == (const FileCryptoMetaData & rhs) const
|
||||||
{
|
{
|
||||||
if (!(encryption_algorithm == rhs.encryption_algorithm))
|
if (!(encryption_algorithm == rhs.encryption_algorithm))
|
||||||
return false;
|
return false;
|
||||||
if (!(encrypted_footer == rhs.encrypted_footer))
|
if (__isset.key_metadata != rhs.__isset.key_metadata)
|
||||||
return false;
|
return false;
|
||||||
if (__isset.footer_key_metadata != rhs.__isset.footer_key_metadata)
|
else if (__isset.key_metadata && !(key_metadata == rhs.key_metadata))
|
||||||
return false;
|
|
||||||
else if (__isset.footer_key_metadata && !(footer_key_metadata == rhs.footer_key_metadata))
|
|
||||||
return false;
|
|
||||||
if (!(footer_offset == rhs.footer_offset))
|
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
1
contrib/flatbuffers
vendored
Submodule
1
contrib/flatbuffers
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit bf9eb67ab9371755c6bcece13cadc7693bcbf264
|
@ -298,7 +298,7 @@ int Server::main(const std::vector<std::string> & /*args*/)
|
|||||||
|
|
||||||
global_context->shutdown();
|
global_context->shutdown();
|
||||||
|
|
||||||
LOG_DEBUG(log, "Shutted down storages.");
|
LOG_DEBUG(log, "Shut down storages.");
|
||||||
|
|
||||||
/** Explicitly destroy Context. It is more convenient than in destructor of Server, because logger is still available.
|
/** Explicitly destroy Context. It is more convenient than in destructor of Server, because logger is still available.
|
||||||
* At this moment, no one could own shared part of Context.
|
* At this moment, no one could own shared part of Context.
|
||||||
|
@ -84,25 +84,17 @@
|
|||||||
<!-- Quota for user. -->
|
<!-- Quota for user. -->
|
||||||
<quota>default</quota>
|
<quota>default</quota>
|
||||||
|
|
||||||
<!-- For testing the table filters -->
|
<!-- Example of row level security policy. -->
|
||||||
<databases>
|
<!-- <databases>
|
||||||
<test>
|
<test>
|
||||||
<!-- Simple expression filter -->
|
|
||||||
<filtered_table1>
|
<filtered_table1>
|
||||||
<filter>a = 1</filter>
|
<filter>a = 1</filter>
|
||||||
</filtered_table1>
|
</filtered_table1>
|
||||||
|
|
||||||
<!-- Complex expression filter -->
|
|
||||||
<filtered_table2>
|
<filtered_table2>
|
||||||
<filter>a + b < 1 or c - d > 5</filter>
|
<filter>a + b < 1 or c - d > 5</filter>
|
||||||
</filtered_table2>
|
</filtered_table2>
|
||||||
|
|
||||||
<!-- Filter with ALIAS column -->
|
|
||||||
<filtered_table3>
|
|
||||||
<filter>c = 1</filter>
|
|
||||||
</filtered_table3>
|
|
||||||
</test>
|
</test>
|
||||||
</databases>
|
</databases> -->
|
||||||
</default>
|
</default>
|
||||||
|
|
||||||
<!-- Example of user with readonly access. -->
|
<!-- Example of user with readonly access. -->
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <Access/MemoryAccessStorage.h>
|
#include <Access/MemoryAccessStorage.h>
|
||||||
#include <Access/UsersConfigAccessStorage.h>
|
#include <Access/UsersConfigAccessStorage.h>
|
||||||
#include <Access/QuotaContextFactory.h>
|
#include <Access/QuotaContextFactory.h>
|
||||||
|
#include <Access/RowPolicyContextFactory.h>
|
||||||
|
|
||||||
|
|
||||||
namespace DB
|
namespace DB
|
||||||
@ -21,7 +22,8 @@ namespace
|
|||||||
|
|
||||||
AccessControlManager::AccessControlManager()
|
AccessControlManager::AccessControlManager()
|
||||||
: MultipleAccessStorage(createStorages()),
|
: MultipleAccessStorage(createStorages()),
|
||||||
quota_context_factory(std::make_unique<QuotaContextFactory>(*this))
|
quota_context_factory(std::make_unique<QuotaContextFactory>(*this)),
|
||||||
|
row_policy_context_factory(std::make_unique<RowPolicyContextFactory>(*this))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,4 +51,11 @@ std::vector<QuotaUsageInfo> AccessControlManager::getQuotaUsageInfo() const
|
|||||||
{
|
{
|
||||||
return quota_context_factory->getUsageInfo();
|
return quota_context_factory->getUsageInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::shared_ptr<RowPolicyContext> AccessControlManager::getRowPolicyContext(const String & user_name) const
|
||||||
|
{
|
||||||
|
return row_policy_context_factory->createContext(user_name);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,8 @@ namespace DB
|
|||||||
class QuotaContext;
|
class QuotaContext;
|
||||||
class QuotaContextFactory;
|
class QuotaContextFactory;
|
||||||
struct QuotaUsageInfo;
|
struct QuotaUsageInfo;
|
||||||
|
class RowPolicyContext;
|
||||||
|
class RowPolicyContextFactory;
|
||||||
|
|
||||||
|
|
||||||
/// Manages access control entities.
|
/// Manages access control entities.
|
||||||
@ -38,8 +40,11 @@ public:
|
|||||||
|
|
||||||
std::vector<QuotaUsageInfo> getQuotaUsageInfo() const;
|
std::vector<QuotaUsageInfo> getQuotaUsageInfo() const;
|
||||||
|
|
||||||
|
std::shared_ptr<RowPolicyContext> getRowPolicyContext(const String & user_name) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<QuotaContextFactory> quota_context_factory;
|
std::unique_ptr<QuotaContextFactory> quota_context_factory;
|
||||||
|
std::unique_ptr<RowPolicyContextFactory> row_policy_context_factory;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include <Access/IAccessEntity.h>
|
#include <Access/IAccessEntity.h>
|
||||||
#include <Access/Quota.h>
|
#include <Access/Quota.h>
|
||||||
|
#include <Access/RowPolicy.h>
|
||||||
#include <common/demangle.h>
|
#include <common/demangle.h>
|
||||||
|
|
||||||
|
|
||||||
@ -9,6 +10,8 @@ String IAccessEntity::getTypeName(std::type_index type)
|
|||||||
{
|
{
|
||||||
if (type == typeid(Quota))
|
if (type == typeid(Quota))
|
||||||
return "Quota";
|
return "Quota";
|
||||||
|
if (type == typeid(RowPolicy))
|
||||||
|
return "Row policy";
|
||||||
return demangle(type.name());
|
return demangle(type.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
111
dbms/src/Access/RowPolicy.cpp
Normal file
111
dbms/src/Access/RowPolicy.cpp
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
#include <Access/RowPolicy.h>
|
||||||
|
#include <Interpreters/Context.h>
|
||||||
|
#include <Common/quoteString.h>
|
||||||
|
#include <boost/range/algorithm/equal.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace DB
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
void generateFullNameImpl(const String & database_, const String & table_name_, const String & policy_name_, String & full_name_)
|
||||||
|
{
|
||||||
|
full_name_.clear();
|
||||||
|
full_name_.reserve(database_.length() + table_name_.length() + policy_name_.length() + 6);
|
||||||
|
full_name_ += backQuoteIfNeed(policy_name_);
|
||||||
|
full_name_ += " ON ";
|
||||||
|
if (!database_.empty())
|
||||||
|
{
|
||||||
|
full_name_ += backQuoteIfNeed(database_);
|
||||||
|
full_name_ += '.';
|
||||||
|
}
|
||||||
|
full_name_ += backQuoteIfNeed(table_name_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
String RowPolicy::FullNameParts::getFullName() const
|
||||||
|
{
|
||||||
|
String full_name;
|
||||||
|
generateFullNameImpl(database, table_name, policy_name, full_name);
|
||||||
|
return full_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
String RowPolicy::FullNameParts::getFullName(const Context & context) const
|
||||||
|
{
|
||||||
|
String full_name;
|
||||||
|
generateFullNameImpl(database.empty() ? context.getCurrentDatabase() : database, table_name, policy_name, full_name);
|
||||||
|
return full_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RowPolicy::setDatabase(const String & database_)
|
||||||
|
{
|
||||||
|
database = database_;
|
||||||
|
generateFullNameImpl(database, table_name, policy_name, full_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RowPolicy::setTableName(const String & table_name_)
|
||||||
|
{
|
||||||
|
table_name = table_name_;
|
||||||
|
generateFullNameImpl(database, table_name, policy_name, full_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RowPolicy::setName(const String & policy_name_)
|
||||||
|
{
|
||||||
|
policy_name = policy_name_;
|
||||||
|
generateFullNameImpl(database, table_name, policy_name, full_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RowPolicy::setFullName(const String & database_, const String & table_name_, const String & policy_name_)
|
||||||
|
{
|
||||||
|
database = database_;
|
||||||
|
table_name = table_name_;
|
||||||
|
policy_name = policy_name_;
|
||||||
|
generateFullNameImpl(database, table_name, policy_name, full_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool RowPolicy::equal(const IAccessEntity & other) const
|
||||||
|
{
|
||||||
|
if (!IAccessEntity::equal(other))
|
||||||
|
return false;
|
||||||
|
const auto & other_policy = typeid_cast<const RowPolicy &>(other);
|
||||||
|
return (database == other_policy.database) && (table_name == other_policy.table_name) && (policy_name == other_policy.policy_name)
|
||||||
|
&& boost::range::equal(conditions, other_policy.conditions) && restrictive == other_policy.restrictive
|
||||||
|
&& (roles == other_policy.roles) && (all_roles == other_policy.all_roles) && (except_roles == other_policy.except_roles);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char * RowPolicy::conditionIndexToString(ConditionIndex index)
|
||||||
|
{
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case SELECT_FILTER: return "SELECT_FILTER";
|
||||||
|
case INSERT_CHECK: return "INSERT_CHECK";
|
||||||
|
case UPDATE_FILTER: return "UPDATE_FILTER";
|
||||||
|
case UPDATE_CHECK: return "UPDATE_CHECK";
|
||||||
|
case DELETE_FILTER: return "DELETE_FILTER";
|
||||||
|
}
|
||||||
|
__builtin_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char * RowPolicy::conditionIndexToColumnName(ConditionIndex index)
|
||||||
|
{
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case SELECT_FILTER: return "select_filter";
|
||||||
|
case INSERT_CHECK: return "insert_check";
|
||||||
|
case UPDATE_FILTER: return "update_filter";
|
||||||
|
case UPDATE_CHECK: return "update_check";
|
||||||
|
case DELETE_FILTER: return "delete_filter";
|
||||||
|
}
|
||||||
|
__builtin_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
81
dbms/src/Access/RowPolicy.h
Normal file
81
dbms/src/Access/RowPolicy.h
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Access/IAccessEntity.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace DB
|
||||||
|
{
|
||||||
|
class Context;
|
||||||
|
|
||||||
|
|
||||||
|
/** Represents a row level security policy for a table.
|
||||||
|
*/
|
||||||
|
struct RowPolicy : public IAccessEntity
|
||||||
|
{
|
||||||
|
void setDatabase(const String & database_);
|
||||||
|
void setTableName(const String & table_name_);
|
||||||
|
void setName(const String & policy_name_) override;
|
||||||
|
void setFullName(const String & database_, const String & table_name_, const String & policy_name_);
|
||||||
|
|
||||||
|
String getDatabase() const { return database; }
|
||||||
|
String getTableName() const { return table_name; }
|
||||||
|
String getName() const override { return policy_name; }
|
||||||
|
|
||||||
|
struct FullNameParts
|
||||||
|
{
|
||||||
|
String database;
|
||||||
|
String table_name;
|
||||||
|
String policy_name;
|
||||||
|
String getFullName() const;
|
||||||
|
String getFullName(const Context & context) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Filter is a SQL conditional expression used to figure out which rows should be visible
|
||||||
|
/// for user or available for modification. If the expression returns NULL or false for some rows
|
||||||
|
/// those rows are silently suppressed.
|
||||||
|
/// Check is a SQL condition expression used to check whether a row can be written into
|
||||||
|
/// the table. If the expression returns NULL or false an exception is thrown.
|
||||||
|
/// If a conditional expression here is empty it means no filtering is applied.
|
||||||
|
enum ConditionIndex
|
||||||
|
{
|
||||||
|
SELECT_FILTER,
|
||||||
|
INSERT_CHECK,
|
||||||
|
UPDATE_FILTER,
|
||||||
|
UPDATE_CHECK,
|
||||||
|
DELETE_FILTER,
|
||||||
|
};
|
||||||
|
static constexpr size_t MAX_CONDITION_INDEX = 5;
|
||||||
|
static const char * conditionIndexToString(ConditionIndex index);
|
||||||
|
static const char * conditionIndexToColumnName(ConditionIndex index);
|
||||||
|
|
||||||
|
String conditions[MAX_CONDITION_INDEX];
|
||||||
|
|
||||||
|
/// Sets that the policy is permissive.
|
||||||
|
/// A row is only accessible if at least one of the permissive policies passes,
|
||||||
|
/// in addition to all the restrictive policies.
|
||||||
|
void setPermissive(bool permissive_ = true) { setRestrictive(!permissive_); }
|
||||||
|
bool isPermissive() const { return !isRestrictive(); }
|
||||||
|
|
||||||
|
/// Sets that the policy is restrictive.
|
||||||
|
/// A row is only accessible if at least one of the permissive policies passes,
|
||||||
|
/// in addition to all the restrictive policies.
|
||||||
|
void setRestrictive(bool restrictive_ = true) { restrictive = restrictive_; }
|
||||||
|
bool isRestrictive() const { return restrictive; }
|
||||||
|
|
||||||
|
bool equal(const IAccessEntity & other) const override;
|
||||||
|
std::shared_ptr<IAccessEntity> clone() const override { return cloneImpl<RowPolicy>(); }
|
||||||
|
|
||||||
|
/// Which roles or users should use this quota.
|
||||||
|
Strings roles;
|
||||||
|
bool all_roles = false;
|
||||||
|
Strings except_roles;
|
||||||
|
|
||||||
|
private:
|
||||||
|
String database;
|
||||||
|
String table_name;
|
||||||
|
String policy_name;
|
||||||
|
bool restrictive = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
using RowPolicyPtr = std::shared_ptr<const RowPolicy>;
|
||||||
|
}
|
59
dbms/src/Access/RowPolicyContext.cpp
Normal file
59
dbms/src/Access/RowPolicyContext.cpp
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#include <Access/RowPolicyContext.h>
|
||||||
|
#include <boost/range/adaptor/map.hpp>
|
||||||
|
#include <boost/range/algorithm/copy.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace DB
|
||||||
|
{
|
||||||
|
size_t RowPolicyContext::Hash::operator()(const DatabaseAndTableNameRef & database_and_table_name) const
|
||||||
|
{
|
||||||
|
return std::hash<StringRef>{}(database_and_table_name.first) - std::hash<StringRef>{}(database_and_table_name.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RowPolicyContext::RowPolicyContext()
|
||||||
|
: atomic_map_of_mixed_conditions(std::make_shared<MapOfMixedConditions>())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RowPolicyContext::~RowPolicyContext() = default;
|
||||||
|
|
||||||
|
|
||||||
|
RowPolicyContext::RowPolicyContext(const String & user_name_)
|
||||||
|
: user_name(user_name_)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
ASTPtr RowPolicyContext::getCondition(const String & database, const String & table_name, ConditionIndex index) const
|
||||||
|
{
|
||||||
|
/// We don't lock `mutex` here.
|
||||||
|
auto map_of_mixed_conditions = std::atomic_load(&atomic_map_of_mixed_conditions);
|
||||||
|
auto it = map_of_mixed_conditions->find({database, table_name});
|
||||||
|
if (it == map_of_mixed_conditions->end())
|
||||||
|
return {};
|
||||||
|
return it->second.mixed_conditions[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<UUID> RowPolicyContext::getCurrentPolicyIDs() const
|
||||||
|
{
|
||||||
|
/// We don't lock `mutex` here.
|
||||||
|
auto map_of_mixed_conditions = std::atomic_load(&atomic_map_of_mixed_conditions);
|
||||||
|
std::vector<UUID> policy_ids;
|
||||||
|
for (const auto & mixed_conditions : *map_of_mixed_conditions | boost::adaptors::map_values)
|
||||||
|
boost::range::copy(mixed_conditions.policy_ids, std::back_inserter(policy_ids));
|
||||||
|
return policy_ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<UUID> RowPolicyContext::getCurrentPolicyIDs(const String & database, const String & table_name) const
|
||||||
|
{
|
||||||
|
/// We don't lock `mutex` here.
|
||||||
|
auto map_of_mixed_conditions = std::atomic_load(&atomic_map_of_mixed_conditions);
|
||||||
|
auto it = map_of_mixed_conditions->find({database, table_name});
|
||||||
|
if (it == map_of_mixed_conditions->end())
|
||||||
|
return {};
|
||||||
|
return it->second.policy_ids;
|
||||||
|
}
|
||||||
|
}
|
66
dbms/src/Access/RowPolicyContext.h
Normal file
66
dbms/src/Access/RowPolicyContext.h
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Access/RowPolicy.h>
|
||||||
|
#include <Core/Types.h>
|
||||||
|
#include <Core/UUID.h>
|
||||||
|
#include <common/StringRef.h>
|
||||||
|
#include <memory>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
|
||||||
|
namespace DB
|
||||||
|
{
|
||||||
|
class IAST;
|
||||||
|
using ASTPtr = std::shared_ptr<IAST>;
|
||||||
|
|
||||||
|
|
||||||
|
/// Provides fast access to row policies' conditions for a specific user and tables.
|
||||||
|
class RowPolicyContext
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Default constructor makes a row policy usage context which restricts nothing.
|
||||||
|
RowPolicyContext();
|
||||||
|
|
||||||
|
~RowPolicyContext();
|
||||||
|
|
||||||
|
using ConditionIndex = RowPolicy::ConditionIndex;
|
||||||
|
|
||||||
|
/// Returns prepared filter for a specific table and operations.
|
||||||
|
/// The function can return nullptr, that means there is no filters applied.
|
||||||
|
/// The returned filter can be a combination of the filters defined by multiple row policies.
|
||||||
|
ASTPtr getCondition(const String & database, const String & table_name, ConditionIndex index) const;
|
||||||
|
|
||||||
|
/// Returns IDs of all the policies used by the current user.
|
||||||
|
std::vector<UUID> getCurrentPolicyIDs() const;
|
||||||
|
|
||||||
|
/// Returns IDs of the policies used by a concrete table.
|
||||||
|
std::vector<UUID> getCurrentPolicyIDs(const String & database, const String & table_name) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class RowPolicyContextFactory;
|
||||||
|
friend struct ext::shared_ptr_helper<RowPolicyContext>;
|
||||||
|
RowPolicyContext(const String & user_name_); /// RowPolicyContext should be created by RowPolicyContextFactory.
|
||||||
|
|
||||||
|
using DatabaseAndTableName = std::pair<String, String>;
|
||||||
|
using DatabaseAndTableNameRef = std::pair<StringRef, StringRef>;
|
||||||
|
struct Hash
|
||||||
|
{
|
||||||
|
size_t operator()(const DatabaseAndTableNameRef & database_and_table_name) const;
|
||||||
|
};
|
||||||
|
static constexpr size_t MAX_CONDITION_INDEX = RowPolicy::MAX_CONDITION_INDEX;
|
||||||
|
using ParsedConditions = std::array<ASTPtr, MAX_CONDITION_INDEX>;
|
||||||
|
struct MixedConditions
|
||||||
|
{
|
||||||
|
std::unique_ptr<DatabaseAndTableName> database_and_table_name_keeper;
|
||||||
|
ParsedConditions mixed_conditions;
|
||||||
|
std::vector<UUID> policy_ids;
|
||||||
|
};
|
||||||
|
using MapOfMixedConditions = std::unordered_map<DatabaseAndTableNameRef, MixedConditions, Hash>;
|
||||||
|
|
||||||
|
const String user_name;
|
||||||
|
std::shared_ptr<const MapOfMixedConditions> atomic_map_of_mixed_conditions; /// Changed atomically, not protected by `mutex`.
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
using RowPolicyContextPtr = std::shared_ptr<RowPolicyContext>;
|
||||||
|
}
|
314
dbms/src/Access/RowPolicyContextFactory.cpp
Normal file
314
dbms/src/Access/RowPolicyContextFactory.cpp
Normal file
@ -0,0 +1,314 @@
|
|||||||
|
#include <Access/RowPolicyContextFactory.h>
|
||||||
|
#include <Access/RowPolicyContext.h>
|
||||||
|
#include <Access/AccessControlManager.h>
|
||||||
|
#include <Parsers/ASTLiteral.h>
|
||||||
|
#include <Parsers/ASTFunction.h>
|
||||||
|
#include <Parsers/ExpressionListParsers.h>
|
||||||
|
#include <Parsers/parseQuery.h>
|
||||||
|
#include <Common/Exception.h>
|
||||||
|
#include <Common/quoteString.h>
|
||||||
|
#include <ext/range.h>
|
||||||
|
#include <boost/range/algorithm/copy.hpp>
|
||||||
|
#include <boost/range/algorithm_ext/erase.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace DB
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
bool tryGetLiteralBool(const IAST & ast, bool & value)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (const ASTLiteral * literal = ast.as<ASTLiteral>())
|
||||||
|
{
|
||||||
|
value = !literal->value.isNull() && applyVisitor(FieldVisitorConvertToNumber<bool>(), literal->value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ASTPtr applyFunctionAND(ASTs arguments)
|
||||||
|
{
|
||||||
|
bool const_arguments = true;
|
||||||
|
boost::range::remove_erase_if(arguments, [&](const ASTPtr & argument) -> bool
|
||||||
|
{
|
||||||
|
bool b;
|
||||||
|
if (!tryGetLiteralBool(*argument, b))
|
||||||
|
return false;
|
||||||
|
const_arguments &= b;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!const_arguments)
|
||||||
|
return std::make_shared<ASTLiteral>(Field{UInt8(0)});
|
||||||
|
if (arguments.empty())
|
||||||
|
return std::make_shared<ASTLiteral>(Field{UInt8(1)});
|
||||||
|
if (arguments.size() == 1)
|
||||||
|
return arguments[0];
|
||||||
|
|
||||||
|
auto function = std::make_shared<ASTFunction>();
|
||||||
|
auto exp_list = std::make_shared<ASTExpressionList>();
|
||||||
|
function->name = "and";
|
||||||
|
function->arguments = exp_list;
|
||||||
|
function->children.push_back(exp_list);
|
||||||
|
exp_list->children = std::move(arguments);
|
||||||
|
return function;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ASTPtr applyFunctionOR(ASTs arguments)
|
||||||
|
{
|
||||||
|
bool const_arguments = false;
|
||||||
|
boost::range::remove_erase_if(arguments, [&](const ASTPtr & argument) -> bool
|
||||||
|
{
|
||||||
|
bool b;
|
||||||
|
if (!tryGetLiteralBool(*argument, b))
|
||||||
|
return false;
|
||||||
|
const_arguments |= b;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (const_arguments)
|
||||||
|
return std::make_shared<ASTLiteral>(Field{UInt8(1)});
|
||||||
|
if (arguments.empty())
|
||||||
|
return std::make_shared<ASTLiteral>(Field{UInt8(0)});
|
||||||
|
if (arguments.size() == 1)
|
||||||
|
return arguments[0];
|
||||||
|
|
||||||
|
auto function = std::make_shared<ASTFunction>();
|
||||||
|
auto exp_list = std::make_shared<ASTExpressionList>();
|
||||||
|
function->name = "or";
|
||||||
|
function->arguments = exp_list;
|
||||||
|
function->children.push_back(exp_list);
|
||||||
|
exp_list->children = std::move(arguments);
|
||||||
|
return function;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
using ConditionIndex = RowPolicy::ConditionIndex;
|
||||||
|
static constexpr size_t MAX_CONDITION_INDEX = RowPolicy::MAX_CONDITION_INDEX;
|
||||||
|
|
||||||
|
|
||||||
|
/// Accumulates conditions from multiple row policies and joins them using the AND logical operation.
|
||||||
|
class ConditionsMixer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void add(const ASTPtr & condition, bool is_restrictive)
|
||||||
|
{
|
||||||
|
if (!condition)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (is_restrictive)
|
||||||
|
restrictions.push_back(condition);
|
||||||
|
else
|
||||||
|
permissions.push_back(condition);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASTPtr getResult() &&
|
||||||
|
{
|
||||||
|
/// Process permissive conditions.
|
||||||
|
if (!permissions.empty())
|
||||||
|
restrictions.push_back(applyFunctionOR(std::move(permissions)));
|
||||||
|
|
||||||
|
/// Process restrictive conditions.
|
||||||
|
if (!restrictions.empty())
|
||||||
|
return applyFunctionAND(std::move(restrictions));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ASTs permissions;
|
||||||
|
ASTs restrictions;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RowPolicyContextFactory::PolicyInfo::setPolicy(const RowPolicyPtr & policy_)
|
||||||
|
{
|
||||||
|
policy = policy_;
|
||||||
|
|
||||||
|
boost::range::copy(policy->roles, std::inserter(roles, roles.end()));
|
||||||
|
all_roles = policy->all_roles;
|
||||||
|
boost::range::copy(policy->except_roles, std::inserter(except_roles, except_roles.end()));
|
||||||
|
|
||||||
|
for (auto index : ext::range_with_static_cast<ConditionIndex>(0, MAX_CONDITION_INDEX))
|
||||||
|
{
|
||||||
|
const String & condition = policy->conditions[index];
|
||||||
|
auto previous_range = std::pair(std::begin(policy->conditions), std::begin(policy->conditions) + index);
|
||||||
|
auto previous_it = std::find(previous_range.first, previous_range.second, condition);
|
||||||
|
if (previous_it != previous_range.second)
|
||||||
|
{
|
||||||
|
/// The condition is already parsed before.
|
||||||
|
parsed_conditions[index] = parsed_conditions[previous_it - previous_range.first];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/// Try to parse the condition.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ParserExpression parser;
|
||||||
|
parsed_conditions[index] = parseQuery(parser, condition, 0);
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
tryLogCurrentException(
|
||||||
|
&Poco::Logger::get("RowPolicy"),
|
||||||
|
String("Could not parse the condition ") + RowPolicy::conditionIndexToString(index) + " of row policy "
|
||||||
|
+ backQuote(policy->getFullName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool RowPolicyContextFactory::PolicyInfo::canUseWithContext(const RowPolicyContext & context) const
|
||||||
|
{
|
||||||
|
if (roles.count(context.user_name))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (all_roles && !except_roles.count(context.user_name))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RowPolicyContextFactory::RowPolicyContextFactory(const AccessControlManager & access_control_manager_)
|
||||||
|
: access_control_manager(access_control_manager_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RowPolicyContextFactory::~RowPolicyContextFactory() = default;
|
||||||
|
|
||||||
|
|
||||||
|
RowPolicyContextPtr RowPolicyContextFactory::createContext(const String & user_name)
|
||||||
|
{
|
||||||
|
std::lock_guard lock{mutex};
|
||||||
|
ensureAllRowPoliciesRead();
|
||||||
|
auto context = ext::shared_ptr_helper<RowPolicyContext>::create(user_name);
|
||||||
|
contexts.push_back(context);
|
||||||
|
mixConditionsForContext(*context);
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RowPolicyContextFactory::ensureAllRowPoliciesRead()
|
||||||
|
{
|
||||||
|
/// `mutex` is already locked.
|
||||||
|
if (all_policies_read)
|
||||||
|
return;
|
||||||
|
all_policies_read = true;
|
||||||
|
|
||||||
|
subscription = access_control_manager.subscribeForChanges<RowPolicy>(
|
||||||
|
[&](const UUID & id, const AccessEntityPtr & entity)
|
||||||
|
{
|
||||||
|
if (entity)
|
||||||
|
rowPolicyAddedOrChanged(id, typeid_cast<RowPolicyPtr>(entity));
|
||||||
|
else
|
||||||
|
rowPolicyRemoved(id);
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const UUID & id : access_control_manager.findAll<RowPolicy>())
|
||||||
|
{
|
||||||
|
auto quota = access_control_manager.tryRead<RowPolicy>(id);
|
||||||
|
if (quota)
|
||||||
|
all_policies.emplace(id, PolicyInfo(quota));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RowPolicyContextFactory::rowPolicyAddedOrChanged(const UUID & policy_id, const RowPolicyPtr & new_policy)
|
||||||
|
{
|
||||||
|
std::lock_guard lock{mutex};
|
||||||
|
auto it = all_policies.find(policy_id);
|
||||||
|
if (it == all_policies.end())
|
||||||
|
{
|
||||||
|
it = all_policies.emplace(policy_id, PolicyInfo(new_policy)).first;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (it->second.policy == new_policy)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto & info = it->second;
|
||||||
|
info.setPolicy(new_policy);
|
||||||
|
mixConditionsForAllContexts();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RowPolicyContextFactory::rowPolicyRemoved(const UUID & policy_id)
|
||||||
|
{
|
||||||
|
std::lock_guard lock{mutex};
|
||||||
|
all_policies.erase(policy_id);
|
||||||
|
mixConditionsForAllContexts();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RowPolicyContextFactory::mixConditionsForAllContexts()
|
||||||
|
{
|
||||||
|
/// `mutex` is already locked.
|
||||||
|
boost::range::remove_erase_if(
|
||||||
|
contexts,
|
||||||
|
[&](const std::weak_ptr<RowPolicyContext> & weak)
|
||||||
|
{
|
||||||
|
auto context = weak.lock();
|
||||||
|
if (!context)
|
||||||
|
return true; // remove from the `contexts` list.
|
||||||
|
mixConditionsForContext(*context);
|
||||||
|
return false; // keep in the `contexts` list.
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RowPolicyContextFactory::mixConditionsForContext(RowPolicyContext & context)
|
||||||
|
{
|
||||||
|
/// `mutex` is already locked.
|
||||||
|
struct Mixers
|
||||||
|
{
|
||||||
|
ConditionsMixer mixers[MAX_CONDITION_INDEX];
|
||||||
|
std::vector<UUID> policy_ids;
|
||||||
|
};
|
||||||
|
using MapOfMixedConditions = RowPolicyContext::MapOfMixedConditions;
|
||||||
|
using DatabaseAndTableName = RowPolicyContext::DatabaseAndTableName;
|
||||||
|
using DatabaseAndTableNameRef = RowPolicyContext::DatabaseAndTableNameRef;
|
||||||
|
using Hash = RowPolicyContext::Hash;
|
||||||
|
|
||||||
|
std::unordered_map<DatabaseAndTableName, Mixers, Hash> map_of_mixers;
|
||||||
|
|
||||||
|
for (const auto & [policy_id, info] : all_policies)
|
||||||
|
{
|
||||||
|
if (info.canUseWithContext(context))
|
||||||
|
{
|
||||||
|
const auto & policy = *info.policy;
|
||||||
|
auto & mixers = map_of_mixers[std::pair{policy.getDatabase(), policy.getTableName()}];
|
||||||
|
mixers.policy_ids.push_back(policy_id);
|
||||||
|
for (auto index : ext::range(0, MAX_CONDITION_INDEX))
|
||||||
|
mixers.mixers[index].add(info.parsed_conditions[index], policy.isRestrictive());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto map_of_mixed_conditions = std::make_shared<MapOfMixedConditions>();
|
||||||
|
for (auto & [database_and_table_name, mixers] : map_of_mixers)
|
||||||
|
{
|
||||||
|
auto database_and_table_name_keeper = std::make_unique<DatabaseAndTableName>();
|
||||||
|
database_and_table_name_keeper->first = database_and_table_name.first;
|
||||||
|
database_and_table_name_keeper->second = database_and_table_name.second;
|
||||||
|
auto & mixed_conditions = (*map_of_mixed_conditions)[DatabaseAndTableNameRef{database_and_table_name_keeper->first,
|
||||||
|
database_and_table_name_keeper->second}];
|
||||||
|
mixed_conditions.database_and_table_name_keeper = std::move(database_and_table_name_keeper);
|
||||||
|
mixed_conditions.policy_ids = std::move(mixers.policy_ids);
|
||||||
|
for (auto index : ext::range(0, MAX_CONDITION_INDEX))
|
||||||
|
mixed_conditions.mixed_conditions[index] = std::move(mixers.mixers[index]).getResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::atomic_store(&context.atomic_map_of_mixed_conditions, std::shared_ptr<const MapOfMixedConditions>{map_of_mixed_conditions});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
54
dbms/src/Access/RowPolicyContextFactory.h
Normal file
54
dbms/src/Access/RowPolicyContextFactory.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Access/RowPolicyContext.h>
|
||||||
|
#include <Access/IAccessStorage.h>
|
||||||
|
#include <mutex>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
|
|
||||||
|
namespace DB
|
||||||
|
{
|
||||||
|
class AccessControlManager;
|
||||||
|
|
||||||
|
|
||||||
|
/// Stores read and parsed row policies.
|
||||||
|
class RowPolicyContextFactory
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RowPolicyContextFactory(const AccessControlManager & access_control_manager_);
|
||||||
|
~RowPolicyContextFactory();
|
||||||
|
|
||||||
|
RowPolicyContextPtr createContext(const String & user_name);
|
||||||
|
|
||||||
|
private:
|
||||||
|
using ParsedConditions = RowPolicyContext::ParsedConditions;
|
||||||
|
|
||||||
|
struct PolicyInfo
|
||||||
|
{
|
||||||
|
PolicyInfo(const RowPolicyPtr & policy_) { setPolicy(policy_); }
|
||||||
|
void setPolicy(const RowPolicyPtr & policy_);
|
||||||
|
bool canUseWithContext(const RowPolicyContext & context) const;
|
||||||
|
|
||||||
|
RowPolicyPtr policy;
|
||||||
|
std::unordered_set<String> roles;
|
||||||
|
bool all_roles = false;
|
||||||
|
std::unordered_set<String> except_roles;
|
||||||
|
ParsedConditions parsed_conditions;
|
||||||
|
};
|
||||||
|
|
||||||
|
void ensureAllRowPoliciesRead();
|
||||||
|
void rowPolicyAddedOrChanged(const UUID & policy_id, const RowPolicyPtr & new_policy);
|
||||||
|
void rowPolicyRemoved(const UUID & policy_id);
|
||||||
|
void mixConditionsForAllContexts();
|
||||||
|
void mixConditionsForContext(RowPolicyContext & context);
|
||||||
|
|
||||||
|
const AccessControlManager & access_control_manager;
|
||||||
|
std::unordered_map<UUID, PolicyInfo> all_policies;
|
||||||
|
bool all_policies_read = false;
|
||||||
|
IAccessStorage::SubscriptionPtr subscription;
|
||||||
|
std::vector<std::weak_ptr<RowPolicyContext>> contexts;
|
||||||
|
std::mutex mutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
#include <Access/UsersConfigAccessStorage.h>
|
#include <Access/UsersConfigAccessStorage.h>
|
||||||
#include <Access/Quota.h>
|
#include <Access/Quota.h>
|
||||||
|
#include <Access/RowPolicy.h>
|
||||||
#include <Common/StringUtils/StringUtils.h>
|
#include <Common/StringUtils/StringUtils.h>
|
||||||
#include <Common/quoteString.h>
|
#include <Common/quoteString.h>
|
||||||
#include <Poco/Util/AbstractConfiguration.h>
|
#include <Poco/Util/AbstractConfiguration.h>
|
||||||
@ -15,6 +16,8 @@ namespace
|
|||||||
{
|
{
|
||||||
if (type == typeid(Quota))
|
if (type == typeid(Quota))
|
||||||
return 'Q';
|
return 'Q';
|
||||||
|
if (type == typeid(RowPolicy))
|
||||||
|
return 'P';
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,6 +115,57 @@ namespace
|
|||||||
}
|
}
|
||||||
return quotas;
|
return quotas;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<AccessEntityPtr> parseRowPolicies(const Poco::Util::AbstractConfiguration & config, Poco::Logger * log)
|
||||||
|
{
|
||||||
|
std::vector<AccessEntityPtr> policies;
|
||||||
|
Poco::Util::AbstractConfiguration::Keys user_names;
|
||||||
|
config.keys("users", user_names);
|
||||||
|
|
||||||
|
for (const String & user_name : user_names)
|
||||||
|
{
|
||||||
|
const String databases_config = "users." + user_name + ".databases";
|
||||||
|
if (config.has(databases_config))
|
||||||
|
{
|
||||||
|
Poco::Util::AbstractConfiguration::Keys databases;
|
||||||
|
config.keys(databases_config, databases);
|
||||||
|
|
||||||
|
/// Read tables within databases
|
||||||
|
for (const String & database : databases)
|
||||||
|
{
|
||||||
|
const String database_config = databases_config + "." + database;
|
||||||
|
Poco::Util::AbstractConfiguration::Keys table_names;
|
||||||
|
config.keys(database_config, table_names);
|
||||||
|
|
||||||
|
/// Read table properties
|
||||||
|
for (const String & table_name : table_names)
|
||||||
|
{
|
||||||
|
const auto filter_config = database_config + "." + table_name + ".filter";
|
||||||
|
if (config.has(filter_config))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
auto policy = std::make_shared<RowPolicy>();
|
||||||
|
policy->setFullName(database, table_name, user_name);
|
||||||
|
policy->conditions[RowPolicy::SELECT_FILTER] = config.getString(filter_config);
|
||||||
|
policy->roles.push_back(user_name);
|
||||||
|
policies.push_back(policy);
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
tryLogCurrentException(
|
||||||
|
log,
|
||||||
|
"Could not parse row policy " + backQuote(user_name) + " on table " + backQuoteIfNeed(database) + "."
|
||||||
|
+ backQuoteIfNeed(table_name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return policies;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -128,6 +182,8 @@ void UsersConfigAccessStorage::loadFromConfig(const Poco::Util::AbstractConfigur
|
|||||||
std::vector<std::pair<UUID, AccessEntityPtr>> all_entities;
|
std::vector<std::pair<UUID, AccessEntityPtr>> all_entities;
|
||||||
for (const auto & entity : parseQuotas(config, getLogger()))
|
for (const auto & entity : parseQuotas(config, getLogger()))
|
||||||
all_entities.emplace_back(generateID(*entity), entity);
|
all_entities.emplace_back(generateID(*entity), entity);
|
||||||
|
for (const auto & entity : parseRowPolicies(config, getLogger()))
|
||||||
|
all_entities.emplace_back(generateID(*entity), entity);
|
||||||
memory_storage.setAll(all_entities);
|
memory_storage.setAll(all_entities);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,11 +24,16 @@ struct AggregateFunctionArgMinMaxData
|
|||||||
|
|
||||||
ResultData result; // the argument at which the minimum/maximum value is reached.
|
ResultData result; // the argument at which the minimum/maximum value is reached.
|
||||||
ValueData value; // value for which the minimum/maximum is calculated.
|
ValueData value; // value for which the minimum/maximum is calculated.
|
||||||
|
|
||||||
|
static bool allocatesMemoryInArena()
|
||||||
|
{
|
||||||
|
return ResultData::allocatesMemoryInArena() || ValueData::allocatesMemoryInArena();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Returns the first arg value found for the minimum/maximum value. Example: argMax(arg, value).
|
/// Returns the first arg value found for the minimum/maximum value. Example: argMax(arg, value).
|
||||||
template <typename Data, bool AllocatesMemoryInArena>
|
template <typename Data>
|
||||||
class AggregateFunctionArgMinMax final : public IAggregateFunctionDataHelper<Data, AggregateFunctionArgMinMax<Data, AllocatesMemoryInArena>>
|
class AggregateFunctionArgMinMax final : public IAggregateFunctionDataHelper<Data, AggregateFunctionArgMinMax<Data>>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
const DataTypePtr & type_res;
|
const DataTypePtr & type_res;
|
||||||
@ -36,7 +41,7 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
AggregateFunctionArgMinMax(const DataTypePtr & type_res_, const DataTypePtr & type_val_)
|
AggregateFunctionArgMinMax(const DataTypePtr & type_res_, const DataTypePtr & type_val_)
|
||||||
: IAggregateFunctionDataHelper<Data, AggregateFunctionArgMinMax<Data, AllocatesMemoryInArena>>({type_res_, type_val_}, {}),
|
: IAggregateFunctionDataHelper<Data, AggregateFunctionArgMinMax<Data>>({type_res_, type_val_}, {}),
|
||||||
type_res(this->argument_types[0]), type_val(this->argument_types[1])
|
type_res(this->argument_types[0]), type_val(this->argument_types[1])
|
||||||
{
|
{
|
||||||
if (!type_val->isComparable())
|
if (!type_val->isComparable())
|
||||||
@ -77,7 +82,7 @@ public:
|
|||||||
|
|
||||||
bool allocatesMemoryInArena() const override
|
bool allocatesMemoryInArena() const override
|
||||||
{
|
{
|
||||||
return AllocatesMemoryInArena;
|
return Data::allocatesMemoryInArena();
|
||||||
}
|
}
|
||||||
|
|
||||||
void insertResultInto(ConstAggregateDataPtr place, IColumn & to) const override
|
void insertResultInto(ConstAggregateDataPtr place, IColumn & to) const override
|
||||||
|
@ -166,6 +166,11 @@ public:
|
|||||||
{
|
{
|
||||||
return has() && assert_cast<const ColVecType &>(column).getData()[row_num] == value;
|
return has() && assert_cast<const ColVecType &>(column).getData()[row_num] == value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool allocatesMemoryInArena()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -384,6 +389,11 @@ public:
|
|||||||
{
|
{
|
||||||
return has() && assert_cast<const ColumnString &>(column).getDataAtWithTerminatingZero(row_num) == getStringRef();
|
return has() && assert_cast<const ColumnString &>(column).getDataAtWithTerminatingZero(row_num) == getStringRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool allocatesMemoryInArena()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(
|
static_assert(
|
||||||
@ -555,6 +565,11 @@ public:
|
|||||||
{
|
{
|
||||||
return has() && to.value == value;
|
return has() && to.value == value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool allocatesMemoryInArena()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -675,15 +690,15 @@ struct AggregateFunctionAnyHeavyData : Data
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <typename Data, bool use_arena>
|
template <typename Data>
|
||||||
class AggregateFunctionsSingleValue final : public IAggregateFunctionDataHelper<Data, AggregateFunctionsSingleValue<Data, use_arena>>
|
class AggregateFunctionsSingleValue final : public IAggregateFunctionDataHelper<Data, AggregateFunctionsSingleValue<Data>>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
DataTypePtr & type;
|
DataTypePtr & type;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AggregateFunctionsSingleValue(const DataTypePtr & type_)
|
AggregateFunctionsSingleValue(const DataTypePtr & type_)
|
||||||
: IAggregateFunctionDataHelper<Data, AggregateFunctionsSingleValue<Data, use_arena>>({type_}, {})
|
: IAggregateFunctionDataHelper<Data, AggregateFunctionsSingleValue<Data>>({type_}, {})
|
||||||
, type(this->argument_types[0])
|
, type(this->argument_types[0])
|
||||||
{
|
{
|
||||||
if (StringRef(Data::name()) == StringRef("min")
|
if (StringRef(Data::name()) == StringRef("min")
|
||||||
@ -724,7 +739,7 @@ public:
|
|||||||
|
|
||||||
bool allocatesMemoryInArena() const override
|
bool allocatesMemoryInArena() const override
|
||||||
{
|
{
|
||||||
return use_arena;
|
return Data::allocatesMemoryInArena();
|
||||||
}
|
}
|
||||||
|
|
||||||
void insertResultInto(ConstAggregateDataPtr place, IColumn & to) const override
|
void insertResultInto(ConstAggregateDataPtr place, IColumn & to) const override
|
||||||
|
@ -13,8 +13,8 @@
|
|||||||
namespace DB
|
namespace DB
|
||||||
{
|
{
|
||||||
|
|
||||||
/// min, max, any, anyLast
|
/// min, max, any, anyLast, anyHeavy, etc...
|
||||||
template <template <typename, bool> class AggregateFunctionTemplate, template <typename> class Data>
|
template <template <typename> class AggregateFunctionTemplate, template <typename> class Data>
|
||||||
static IAggregateFunction * createAggregateFunctionSingleValue(const String & name, const DataTypes & argument_types, const Array & parameters)
|
static IAggregateFunction * createAggregateFunctionSingleValue(const String & name, const DataTypes & argument_types, const Array & parameters)
|
||||||
{
|
{
|
||||||
assertNoParameters(name, parameters);
|
assertNoParameters(name, parameters);
|
||||||
@ -24,26 +24,26 @@ static IAggregateFunction * createAggregateFunctionSingleValue(const String & na
|
|||||||
|
|
||||||
WhichDataType which(argument_type);
|
WhichDataType which(argument_type);
|
||||||
#define DISPATCH(TYPE) \
|
#define DISPATCH(TYPE) \
|
||||||
if (which.idx == TypeIndex::TYPE) return new AggregateFunctionTemplate<Data<SingleValueDataFixed<TYPE>>, false>(argument_type);
|
if (which.idx == TypeIndex::TYPE) return new AggregateFunctionTemplate<Data<SingleValueDataFixed<TYPE>>>(argument_type);
|
||||||
FOR_NUMERIC_TYPES(DISPATCH)
|
FOR_NUMERIC_TYPES(DISPATCH)
|
||||||
#undef DISPATCH
|
#undef DISPATCH
|
||||||
|
|
||||||
if (which.idx == TypeIndex::Date)
|
if (which.idx == TypeIndex::Date)
|
||||||
return new AggregateFunctionTemplate<Data<SingleValueDataFixed<DataTypeDate::FieldType>>, false>(argument_type);
|
return new AggregateFunctionTemplate<Data<SingleValueDataFixed<DataTypeDate::FieldType>>>(argument_type);
|
||||||
if (which.idx == TypeIndex::DateTime)
|
if (which.idx == TypeIndex::DateTime)
|
||||||
return new AggregateFunctionTemplate<Data<SingleValueDataFixed<DataTypeDateTime::FieldType>>, false>(argument_type);
|
return new AggregateFunctionTemplate<Data<SingleValueDataFixed<DataTypeDateTime::FieldType>>>(argument_type);
|
||||||
if (which.idx == TypeIndex::DateTime64)
|
if (which.idx == TypeIndex::DateTime64)
|
||||||
return new AggregateFunctionTemplate<Data<SingleValueDataFixed<DateTime64>>, false>(argument_type);
|
return new AggregateFunctionTemplate<Data<SingleValueDataFixed<DateTime64>>>(argument_type);
|
||||||
if (which.idx == TypeIndex::Decimal32)
|
if (which.idx == TypeIndex::Decimal32)
|
||||||
return new AggregateFunctionTemplate<Data<SingleValueDataFixed<Decimal32>>, false>(argument_type);
|
return new AggregateFunctionTemplate<Data<SingleValueDataFixed<Decimal32>>>(argument_type);
|
||||||
if (which.idx == TypeIndex::Decimal64)
|
if (which.idx == TypeIndex::Decimal64)
|
||||||
return new AggregateFunctionTemplate<Data<SingleValueDataFixed<Decimal64>>, false>(argument_type);
|
return new AggregateFunctionTemplate<Data<SingleValueDataFixed<Decimal64>>>(argument_type);
|
||||||
if (which.idx == TypeIndex::Decimal128)
|
if (which.idx == TypeIndex::Decimal128)
|
||||||
return new AggregateFunctionTemplate<Data<SingleValueDataFixed<Decimal128>>, false>(argument_type);
|
return new AggregateFunctionTemplate<Data<SingleValueDataFixed<Decimal128>>>(argument_type);
|
||||||
if (which.idx == TypeIndex::String)
|
if (which.idx == TypeIndex::String)
|
||||||
return new AggregateFunctionTemplate<Data<SingleValueDataString>, true>(argument_type);
|
return new AggregateFunctionTemplate<Data<SingleValueDataString>>(argument_type);
|
||||||
|
|
||||||
return new AggregateFunctionTemplate<Data<SingleValueDataGeneric>, false>(argument_type);
|
return new AggregateFunctionTemplate<Data<SingleValueDataGeneric>>(argument_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -52,28 +52,29 @@ template <template <typename> class MinMaxData, typename ResData>
|
|||||||
static IAggregateFunction * createAggregateFunctionArgMinMaxSecond(const DataTypePtr & res_type, const DataTypePtr & val_type)
|
static IAggregateFunction * createAggregateFunctionArgMinMaxSecond(const DataTypePtr & res_type, const DataTypePtr & val_type)
|
||||||
{
|
{
|
||||||
WhichDataType which(val_type);
|
WhichDataType which(val_type);
|
||||||
|
|
||||||
#define DISPATCH(TYPE) \
|
#define DISPATCH(TYPE) \
|
||||||
if (which.idx == TypeIndex::TYPE) \
|
if (which.idx == TypeIndex::TYPE) \
|
||||||
return new AggregateFunctionArgMinMax<AggregateFunctionArgMinMaxData<ResData, MinMaxData<SingleValueDataFixed<TYPE>>>, false>(res_type, val_type);
|
return new AggregateFunctionArgMinMax<AggregateFunctionArgMinMaxData<ResData, MinMaxData<SingleValueDataFixed<TYPE>>>>(res_type, val_type); \
|
||||||
FOR_NUMERIC_TYPES(DISPATCH)
|
FOR_NUMERIC_TYPES(DISPATCH)
|
||||||
#undef DISPATCH
|
#undef DISPATCH
|
||||||
|
|
||||||
if (which.idx == TypeIndex::Date)
|
if (which.idx == TypeIndex::Date)
|
||||||
return new AggregateFunctionArgMinMax<AggregateFunctionArgMinMaxData<ResData, MinMaxData<SingleValueDataFixed<DataTypeDate::FieldType>>>, false>(res_type, val_type);
|
return new AggregateFunctionArgMinMax<AggregateFunctionArgMinMaxData<ResData, MinMaxData<SingleValueDataFixed<DataTypeDate::FieldType>>>>(res_type, val_type);
|
||||||
if (which.idx == TypeIndex::DateTime)
|
if (which.idx == TypeIndex::DateTime)
|
||||||
return new AggregateFunctionArgMinMax<AggregateFunctionArgMinMaxData<ResData, MinMaxData<SingleValueDataFixed<DataTypeDateTime::FieldType>>>, false>(res_type, val_type);
|
return new AggregateFunctionArgMinMax<AggregateFunctionArgMinMaxData<ResData, MinMaxData<SingleValueDataFixed<DataTypeDateTime::FieldType>>>>(res_type, val_type);
|
||||||
if (which.idx == TypeIndex::DateTime64)
|
if (which.idx == TypeIndex::DateTime64)
|
||||||
return new AggregateFunctionArgMinMax<AggregateFunctionArgMinMaxData<ResData, MinMaxData<SingleValueDataFixed<DateTime64>>>, false>(res_type, val_type);
|
return new AggregateFunctionArgMinMax<AggregateFunctionArgMinMaxData<ResData, MinMaxData<SingleValueDataFixed<DateTime64>>>>(res_type, val_type);
|
||||||
if (which.idx == TypeIndex::Decimal32)
|
if (which.idx == TypeIndex::Decimal32)
|
||||||
return new AggregateFunctionArgMinMax<AggregateFunctionArgMinMaxData<ResData, MinMaxData<SingleValueDataFixed<Decimal32>>>, false>(res_type, val_type);
|
return new AggregateFunctionArgMinMax<AggregateFunctionArgMinMaxData<ResData, MinMaxData<SingleValueDataFixed<Decimal32>>>>(res_type, val_type);
|
||||||
if (which.idx == TypeIndex::Decimal64)
|
if (which.idx == TypeIndex::Decimal64)
|
||||||
return new AggregateFunctionArgMinMax<AggregateFunctionArgMinMaxData<ResData, MinMaxData<SingleValueDataFixed<Decimal64>>>, false>(res_type, val_type);
|
return new AggregateFunctionArgMinMax<AggregateFunctionArgMinMaxData<ResData, MinMaxData<SingleValueDataFixed<Decimal64>>>>(res_type, val_type);
|
||||||
if (which.idx == TypeIndex::Decimal128)
|
if (which.idx == TypeIndex::Decimal128)
|
||||||
return new AggregateFunctionArgMinMax<AggregateFunctionArgMinMaxData<ResData, MinMaxData<SingleValueDataFixed<Decimal128>>>, false>(res_type, val_type);
|
return new AggregateFunctionArgMinMax<AggregateFunctionArgMinMaxData<ResData, MinMaxData<SingleValueDataFixed<Decimal128>>>>(res_type, val_type);
|
||||||
if (which.idx == TypeIndex::String)
|
if (which.idx == TypeIndex::String)
|
||||||
return new AggregateFunctionArgMinMax<AggregateFunctionArgMinMaxData<ResData, MinMaxData<SingleValueDataString>>, true>(res_type, val_type);
|
return new AggregateFunctionArgMinMax<AggregateFunctionArgMinMaxData<ResData, MinMaxData<SingleValueDataString>>>(res_type, val_type);
|
||||||
|
|
||||||
return new AggregateFunctionArgMinMax<AggregateFunctionArgMinMaxData<ResData, MinMaxData<SingleValueDataGeneric>>, false>(res_type, val_type);
|
return new AggregateFunctionArgMinMax<AggregateFunctionArgMinMaxData<ResData, MinMaxData<SingleValueDataGeneric>>>(res_type, val_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <template <typename> class MinMaxData>
|
template <template <typename> class MinMaxData>
|
||||||
|
@ -339,7 +339,7 @@ bool DataTypeAggregateFunction::equals(const IDataType & rhs) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static DataTypePtr create(const ASTPtr & arguments)
|
static DataTypePtr create(const String & /*type_name*/, const ASTPtr & arguments)
|
||||||
{
|
{
|
||||||
String function_name;
|
String function_name;
|
||||||
AggregateFunctionPtr function;
|
AggregateFunctionPtr function;
|
||||||
|
@ -508,7 +508,7 @@ size_t DataTypeArray::getNumberOfDimensions() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static DataTypePtr create(const ASTPtr & arguments)
|
static DataTypePtr create(const String & /*type_name*/, const ASTPtr & arguments)
|
||||||
{
|
{
|
||||||
if (!arguments || arguments->children.size() != 1)
|
if (!arguments || arguments->children.size() != 1)
|
||||||
throw Exception("Array data type family must have exactly one argument - type of elements", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
throw Exception("Array data type family must have exactly one argument - type of elements", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
||||||
|
@ -102,16 +102,16 @@ public:
|
|||||||
|
|
||||||
void registerDataTypeDomainIPv4AndIPv6(DataTypeFactory & factory)
|
void registerDataTypeDomainIPv4AndIPv6(DataTypeFactory & factory)
|
||||||
{
|
{
|
||||||
factory.registerSimpleDataTypeCustom("IPv4", []
|
factory.registerSimpleDataTypeCustom("IPv4", [&](const String & /*type_name*/)
|
||||||
{
|
{
|
||||||
return std::make_pair(DataTypeFactory::instance().get("UInt32"),
|
return std::make_pair(DataTypeFactory::instance().get("UInt32"),
|
||||||
std::make_unique<DataTypeCustomDesc>(std::make_unique<DataTypeCustomFixedName>("IPv4"), std::make_unique<DataTypeCustomIPv4Serialization>()));
|
std::make_unique<DataTypeCustomDesc>(std::make_unique<DataTypeCustomFixedName>("IPv4"), std::make_unique<DataTypeCustomIPv4Serialization>()));
|
||||||
});
|
});
|
||||||
|
|
||||||
factory.registerSimpleDataTypeCustom("IPv6", []
|
factory.registerSimpleDataTypeCustom("IPv6", [&](const String & /*type_name*/)
|
||||||
{
|
{
|
||||||
return std::make_pair(DataTypeFactory::instance().get("FixedString(16)"),
|
return std::make_pair(DataTypeFactory::instance().get("FixedString(16)"),
|
||||||
std::make_unique<DataTypeCustomDesc>(std::make_unique<DataTypeCustomFixedName>("IPv6"), std::make_unique<DataTypeCustomIPv6Serialization>()));
|
std::make_unique<DataTypeCustomDesc>(std::make_unique<DataTypeCustomFixedName>("IPv6"), std::make_unique<DataTypeCustomIPv6Serialization>()));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ String DataTypeCustomSimpleAggregateFunction::getName() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static std::pair<DataTypePtr, DataTypeCustomDescPtr> create(const ASTPtr & arguments)
|
static std::pair<DataTypePtr, DataTypeCustomDescPtr> create(const String & /*type_name*/, const ASTPtr & arguments)
|
||||||
{
|
{
|
||||||
String function_name;
|
String function_name;
|
||||||
AggregateFunctionPtr function;
|
AggregateFunctionPtr function;
|
||||||
|
@ -113,7 +113,12 @@ bool DataTypeDate::equals(const IDataType & rhs) const
|
|||||||
|
|
||||||
void registerDataTypeDate(DataTypeFactory & factory)
|
void registerDataTypeDate(DataTypeFactory & factory)
|
||||||
{
|
{
|
||||||
factory.registerSimpleDataType("Date", [] { return DataTypePtr(std::make_shared<DataTypeDate>()); }, DataTypeFactory::CaseInsensitive);
|
const auto & creator = [&](const String & /*type_name*/)
|
||||||
|
{
|
||||||
|
return DataTypePtr(std::make_shared<DataTypeDate>());
|
||||||
|
};
|
||||||
|
|
||||||
|
factory.registerSimpleDataType("Date", creator, DataTypeFactory::CaseInsensitive);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -43,8 +43,8 @@ TimezoneMixin::TimezoneMixin(const String & time_zone_name)
|
|||||||
utc_time_zone(DateLUT::instance("UTC"))
|
utc_time_zone(DateLUT::instance("UTC"))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
DataTypeDateTime::DataTypeDateTime(const String & time_zone_name)
|
DataTypeDateTime::DataTypeDateTime(const String & time_zone_name, const String & type_name_)
|
||||||
: TimezoneMixin(time_zone_name)
|
: TimezoneMixin(time_zone_name), type_name(type_name_)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,10 +55,10 @@ DataTypeDateTime::DataTypeDateTime(const TimezoneMixin & time_zone_)
|
|||||||
String DataTypeDateTime::doGetName() const
|
String DataTypeDateTime::doGetName() const
|
||||||
{
|
{
|
||||||
if (!has_explicit_time_zone)
|
if (!has_explicit_time_zone)
|
||||||
return "DateTime";
|
return type_name;
|
||||||
|
|
||||||
WriteBufferFromOwnString out;
|
WriteBufferFromOwnString out;
|
||||||
out << "DateTime(" << quote << time_zone.getTimeZone() << ")";
|
out << type_name << "(" << quote << time_zone.getTimeZone() << ")";
|
||||||
return out.str();
|
return out.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,10 +194,10 @@ namespace ErrorCodes
|
|||||||
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
|
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DataTypePtr create(const ASTPtr & arguments)
|
static DataTypePtr create(const String & type_name, const ASTPtr & arguments)
|
||||||
{
|
{
|
||||||
if (!arguments)
|
if (!arguments)
|
||||||
return std::make_shared<DataTypeDateTime>();
|
return std::make_shared<DataTypeDateTime>("", type_name);
|
||||||
|
|
||||||
if (arguments->children.size() != 1)
|
if (arguments->children.size() != 1)
|
||||||
throw Exception("DateTime data type can optionally have only one argument - time zone name", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
throw Exception("DateTime data type can optionally have only one argument - time zone name", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
||||||
@ -206,7 +206,7 @@ static DataTypePtr create(const ASTPtr & arguments)
|
|||||||
if (!arg || arg->value.getType() != Field::Types::String)
|
if (!arg || arg->value.getType() != Field::Types::String)
|
||||||
throw Exception("Parameter for DateTime data type must be string literal", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
throw Exception("Parameter for DateTime data type must be string literal", ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
||||||
|
|
||||||
return std::make_shared<DataTypeDateTime>(arg->value.get<String>());
|
return std::make_shared<DataTypeDateTime>(arg->value.get<String>(), type_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void registerDataTypeDateTime(DataTypeFactory & factory)
|
void registerDataTypeDateTime(DataTypeFactory & factory)
|
||||||
|
@ -49,7 +49,7 @@ protected:
|
|||||||
class DataTypeDateTime final : public DataTypeNumberBase<UInt32>, public TimezoneMixin
|
class DataTypeDateTime final : public DataTypeNumberBase<UInt32>, public TimezoneMixin
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit DataTypeDateTime(const String & time_zone_name = "");
|
explicit DataTypeDateTime(const String & time_zone_name = "", const String & type_name_ = "DateTime");
|
||||||
explicit DataTypeDateTime(const TimezoneMixin & time_zone);
|
explicit DataTypeDateTime(const TimezoneMixin & time_zone);
|
||||||
|
|
||||||
static constexpr auto family_name = "DateTime";
|
static constexpr auto family_name = "DateTime";
|
||||||
@ -75,6 +75,8 @@ public:
|
|||||||
bool canBeInsideNullable() const override { return true; }
|
bool canBeInsideNullable() const override { return true; }
|
||||||
|
|
||||||
bool equals(const IDataType & rhs) const override;
|
bool equals(const IDataType & rhs) const override;
|
||||||
|
private:
|
||||||
|
const String type_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -233,7 +233,7 @@ getArgument(const ASTPtr & arguments, size_t argument_index, const char * argume
|
|||||||
return argument->value.get<NearestResultType>();
|
return argument->value.get<NearestResultType>();
|
||||||
}
|
}
|
||||||
|
|
||||||
static DataTypePtr create64(const ASTPtr & arguments)
|
static DataTypePtr create64(const String & /*type_name*/, const ASTPtr & arguments)
|
||||||
{
|
{
|
||||||
if (!arguments || arguments->size() == 0)
|
if (!arguments || arguments->size() == 0)
|
||||||
return std::make_shared<DataTypeDateTime64>(DataTypeDateTime64::default_scale);
|
return std::make_shared<DataTypeDateTime64>(DataTypeDateTime64::default_scale);
|
||||||
|
@ -195,7 +195,7 @@ const DecimalType<U> decimalResultType(const DataTypeNumber<T> &, const DecimalT
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <template <typename> typename DecimalType>
|
template <template <typename> typename DecimalType>
|
||||||
DataTypePtr createDecimal(UInt64 precision_value, UInt64 scale_value)
|
DataTypePtr createDecimal(UInt64 precision_value, UInt64 scale_value, const String & type_name = "Decimal", bool only_scale = false)
|
||||||
{
|
{
|
||||||
if (precision_value < DecimalUtils::minPrecision() || precision_value > DecimalUtils::maxPrecision<Decimal128>())
|
if (precision_value < DecimalUtils::minPrecision() || precision_value > DecimalUtils::maxPrecision<Decimal128>())
|
||||||
throw Exception("Wrong precision", ErrorCodes::ARGUMENT_OUT_OF_BOUND);
|
throw Exception("Wrong precision", ErrorCodes::ARGUMENT_OUT_OF_BOUND);
|
||||||
@ -204,10 +204,10 @@ DataTypePtr createDecimal(UInt64 precision_value, UInt64 scale_value)
|
|||||||
throw Exception("Negative scales and scales larger than precision are not supported", ErrorCodes::ARGUMENT_OUT_OF_BOUND);
|
throw Exception("Negative scales and scales larger than precision are not supported", ErrorCodes::ARGUMENT_OUT_OF_BOUND);
|
||||||
|
|
||||||
if (precision_value <= DecimalUtils::maxPrecision<Decimal32>())
|
if (precision_value <= DecimalUtils::maxPrecision<Decimal32>())
|
||||||
return std::make_shared<DecimalType<Decimal32>>(precision_value, scale_value);
|
return std::make_shared<DecimalType<Decimal32>>(precision_value, scale_value, type_name, only_scale);
|
||||||
else if (precision_value <= DecimalUtils::maxPrecision<Decimal64>())
|
else if (precision_value <= DecimalUtils::maxPrecision<Decimal64>())
|
||||||
return std::make_shared<DecimalType<Decimal64>>(precision_value, scale_value);
|
return std::make_shared<DecimalType<Decimal64>>(precision_value, scale_value, type_name, only_scale);
|
||||||
return std::make_shared<DecimalType<Decimal128>>(precision_value, scale_value);
|
return std::make_shared<DecimalType<Decimal128>>(precision_value, scale_value, type_name, only_scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -364,7 +364,7 @@ static void checkASTStructure(const ASTPtr & child)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename DataTypeEnum>
|
template <typename DataTypeEnum>
|
||||||
static DataTypePtr createExact(const ASTPtr & arguments)
|
static DataTypePtr createExact(const String & /*type_name*/, const ASTPtr & arguments)
|
||||||
{
|
{
|
||||||
if (!arguments || arguments->children.empty())
|
if (!arguments || arguments->children.empty())
|
||||||
throw Exception("Enum data type cannot be empty", ErrorCodes::EMPTY_DATA_PASSED);
|
throw Exception("Enum data type cannot be empty", ErrorCodes::EMPTY_DATA_PASSED);
|
||||||
@ -403,7 +403,7 @@ static DataTypePtr createExact(const ASTPtr & arguments)
|
|||||||
return std::make_shared<DataTypeEnum>(values);
|
return std::make_shared<DataTypeEnum>(values);
|
||||||
}
|
}
|
||||||
|
|
||||||
static DataTypePtr create(const ASTPtr & arguments)
|
static DataTypePtr create(const String & type_name, const ASTPtr & arguments)
|
||||||
{
|
{
|
||||||
if (!arguments || arguments->children.empty())
|
if (!arguments || arguments->children.empty())
|
||||||
throw Exception("Enum data type cannot be empty", ErrorCodes::EMPTY_DATA_PASSED);
|
throw Exception("Enum data type cannot be empty", ErrorCodes::EMPTY_DATA_PASSED);
|
||||||
@ -424,10 +424,10 @@ static DataTypePtr create(const ASTPtr & arguments)
|
|||||||
Int64 value = value_literal->value.get<Int64>();
|
Int64 value = value_literal->value.get<Int64>();
|
||||||
|
|
||||||
if (value > std::numeric_limits<Int8>::max() || value < std::numeric_limits<Int8>::min())
|
if (value > std::numeric_limits<Int8>::max() || value < std::numeric_limits<Int8>::min())
|
||||||
return createExact<DataTypeEnum16>(arguments);
|
return createExact<DataTypeEnum16>(type_name, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
return createExact<DataTypeEnum8>(arguments);
|
return createExact<DataTypeEnum8>(type_name, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
void registerDataTypeEnum(DataTypeFactory & factory)
|
void registerDataTypeEnum(DataTypeFactory & factory)
|
||||||
|
@ -74,7 +74,7 @@ DataTypePtr DataTypeFactory::get(const String & family_name_param, const ASTPtr
|
|||||||
return get("LowCardinality", low_cardinality_params);
|
return get("LowCardinality", low_cardinality_params);
|
||||||
}
|
}
|
||||||
|
|
||||||
return findCreatorByName(family_name)(parameters);
|
return findCreatorByName(family_name)(family_name_param, parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -107,30 +107,30 @@ void DataTypeFactory::registerSimpleDataType(const String & name, SimpleCreator
|
|||||||
throw Exception("DataTypeFactory: the data type " + name + " has been provided "
|
throw Exception("DataTypeFactory: the data type " + name + " has been provided "
|
||||||
" a null constructor", ErrorCodes::LOGICAL_ERROR);
|
" a null constructor", ErrorCodes::LOGICAL_ERROR);
|
||||||
|
|
||||||
registerDataType(name, [name, creator](const ASTPtr & ast)
|
registerDataType(name, [name, creator](const String & type_name, const ASTPtr & ast)
|
||||||
{
|
{
|
||||||
if (ast)
|
if (ast)
|
||||||
throw Exception("Data type " + name + " cannot have arguments", ErrorCodes::DATA_TYPE_CANNOT_HAVE_ARGUMENTS);
|
throw Exception("Data type " + name + " cannot have arguments", ErrorCodes::DATA_TYPE_CANNOT_HAVE_ARGUMENTS);
|
||||||
return creator();
|
return creator(type_name);
|
||||||
}, case_sensitiveness);
|
}, case_sensitiveness);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataTypeFactory::registerDataTypeCustom(const String & family_name, CreatorWithCustom creator, CaseSensitiveness case_sensitiveness)
|
void DataTypeFactory::registerDataTypeCustom(const String & family_name, CreatorWithCustom creator, CaseSensitiveness case_sensitiveness)
|
||||||
{
|
{
|
||||||
registerDataType(family_name, [creator](const ASTPtr & ast)
|
registerDataType(family_name, [creator](const String & type_name, const ASTPtr & ast)
|
||||||
{
|
{
|
||||||
auto res = creator(ast);
|
auto res = creator(type_name, ast);
|
||||||
res.first->setCustomization(std::move(res.second));
|
res.first->setCustomization(std::move(res.second));
|
||||||
|
|
||||||
return res.first;
|
return res.first;
|
||||||
}, case_sensitiveness);
|
}, case_sensitiveness);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataTypeFactory::registerSimpleDataTypeCustom(const String &name, SimpleCreatorWithCustom creator, CaseSensitiveness case_sensitiveness)
|
void DataTypeFactory::registerSimpleDataTypeCustom(const String & name, SimpleCreatorWithCustom creator, CaseSensitiveness case_sensitiveness)
|
||||||
{
|
{
|
||||||
registerDataTypeCustom(name, [creator](const ASTPtr & /*ast*/)
|
registerDataTypeCustom(name, [creator](const String & type_name, const ASTPtr & /*ast*/)
|
||||||
{
|
{
|
||||||
return creator();
|
return creator(type_name);
|
||||||
}, case_sensitiveness);
|
}, case_sensitiveness);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,16 +16,15 @@ namespace DB
|
|||||||
class IDataType;
|
class IDataType;
|
||||||
using DataTypePtr = std::shared_ptr<const IDataType>;
|
using DataTypePtr = std::shared_ptr<const IDataType>;
|
||||||
|
|
||||||
|
|
||||||
/** Creates a data type by name of data type family and parameters.
|
/** Creates a data type by name of data type family and parameters.
|
||||||
*/
|
*/
|
||||||
class DataTypeFactory final : private boost::noncopyable, public IFactoryWithAliases<std::function<DataTypePtr(const ASTPtr & parameters)>>
|
class DataTypeFactory final : private boost::noncopyable, public IFactoryWithAliases<std::function<DataTypePtr(const String & type_name, const ASTPtr & parameters)>>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
using SimpleCreator = std::function<DataTypePtr()>;
|
using SimpleCreator = std::function<DataTypePtr(const String & type_name)>;
|
||||||
using DataTypesDictionary = std::unordered_map<String, Creator>;
|
using DataTypesDictionary = std::unordered_map<String, Creator>;
|
||||||
using CreatorWithCustom = std::function<std::pair<DataTypePtr,DataTypeCustomDescPtr>(const ASTPtr & parameters)>;
|
using CreatorWithCustom = std::function<std::pair<DataTypePtr, DataTypeCustomDescPtr>(const String & type_name, const ASTPtr & parameters)>;
|
||||||
using SimpleCreatorWithCustom = std::function<std::pair<DataTypePtr,DataTypeCustomDescPtr>()>;
|
using SimpleCreatorWithCustom = std::function<std::pair<DataTypePtr, DataTypeCustomDescPtr>(const String & type_name)>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static DataTypeFactory & instance();
|
static DataTypeFactory & instance();
|
||||||
|
@ -34,7 +34,7 @@ namespace ErrorCodes
|
|||||||
|
|
||||||
std::string DataTypeFixedString::doGetName() const
|
std::string DataTypeFixedString::doGetName() const
|
||||||
{
|
{
|
||||||
return "FixedString(" + toString(n) + ")";
|
return type_name + "(" + toString(n) + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -279,7 +279,7 @@ bool DataTypeFixedString::equals(const IDataType & rhs) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static DataTypePtr create(const ASTPtr & arguments)
|
static DataTypePtr create(const String & type_name, const ASTPtr & arguments)
|
||||||
{
|
{
|
||||||
if (!arguments || arguments->children.size() != 1)
|
if (!arguments || arguments->children.size() != 1)
|
||||||
throw Exception("FixedString data type family must have exactly one argument - size in bytes", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
throw Exception("FixedString data type family must have exactly one argument - size in bytes", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
||||||
@ -288,7 +288,7 @@ static DataTypePtr create(const ASTPtr & arguments)
|
|||||||
if (!argument || argument->value.getType() != Field::Types::UInt64 || argument->value.get<UInt64>() == 0)
|
if (!argument || argument->value.getType() != Field::Types::UInt64 || argument->value.get<UInt64>() == 0)
|
||||||
throw Exception("FixedString data type family must have a number (positive integer) as its argument", ErrorCodes::UNEXPECTED_AST_STRUCTURE);
|
throw Exception("FixedString data type family must have a number (positive integer) as its argument", ErrorCodes::UNEXPECTED_AST_STRUCTURE);
|
||||||
|
|
||||||
return std::make_shared<DataTypeFixedString>(argument->value.get<UInt64>());
|
return std::make_shared<DataTypeFixedString>(argument->value.get<UInt64>(), type_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ private:
|
|||||||
public:
|
public:
|
||||||
static constexpr bool is_parametric = true;
|
static constexpr bool is_parametric = true;
|
||||||
|
|
||||||
DataTypeFixedString(size_t n_) : n(n_)
|
DataTypeFixedString(size_t n_, const String & type_name_ = "FixedString") : n(n_), type_name(type_name_)
|
||||||
{
|
{
|
||||||
if (n == 0)
|
if (n == 0)
|
||||||
throw Exception("FixedString size must be positive", ErrorCodes::ARGUMENT_OUT_OF_BOUND);
|
throw Exception("FixedString size must be positive", ErrorCodes::ARGUMENT_OUT_OF_BOUND);
|
||||||
@ -85,6 +85,9 @@ public:
|
|||||||
bool isCategorial() const override { return true; }
|
bool isCategorial() const override { return true; }
|
||||||
bool canBeInsideNullable() const override { return true; }
|
bool canBeInsideNullable() const override { return true; }
|
||||||
bool canBeInsideLowCardinality() const override { return true; }
|
bool canBeInsideLowCardinality() const override { return true; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const String type_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -10,17 +10,22 @@ bool DataTypeInterval::equals(const IDataType & rhs) const
|
|||||||
return typeid(rhs) == typeid(*this) && kind == static_cast<const DataTypeInterval &>(rhs).kind;
|
return typeid(rhs) == typeid(*this) && kind == static_cast<const DataTypeInterval &>(rhs).kind;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <IntervalKind::Kind kind>
|
||||||
|
static DataTypePtr create(const String & /*type_name*/)
|
||||||
|
{
|
||||||
|
return DataTypePtr(std::make_shared<DataTypeInterval>(kind));
|
||||||
|
}
|
||||||
|
|
||||||
void registerDataTypeInterval(DataTypeFactory & factory)
|
void registerDataTypeInterval(DataTypeFactory & factory)
|
||||||
{
|
{
|
||||||
factory.registerSimpleDataType("IntervalSecond", [] { return DataTypePtr(std::make_shared<DataTypeInterval>(IntervalKind::Second)); });
|
factory.registerSimpleDataType("IntervalSecond", create<IntervalKind::Second>);
|
||||||
factory.registerSimpleDataType("IntervalMinute", [] { return DataTypePtr(std::make_shared<DataTypeInterval>(IntervalKind::Minute)); });
|
factory.registerSimpleDataType("IntervalMinute", create<IntervalKind::Minute>);
|
||||||
factory.registerSimpleDataType("IntervalHour", [] { return DataTypePtr(std::make_shared<DataTypeInterval>(IntervalKind::Hour)); });
|
factory.registerSimpleDataType("IntervalHour", create<IntervalKind::Hour>);
|
||||||
factory.registerSimpleDataType("IntervalDay", [] { return DataTypePtr(std::make_shared<DataTypeInterval>(IntervalKind::Day)); });
|
factory.registerSimpleDataType("IntervalDay", create<IntervalKind::Day>);
|
||||||
factory.registerSimpleDataType("IntervalWeek", [] { return DataTypePtr(std::make_shared<DataTypeInterval>(IntervalKind::Week)); });
|
factory.registerSimpleDataType("IntervalWeek", create<IntervalKind::Week>);
|
||||||
factory.registerSimpleDataType("IntervalMonth", [] { return DataTypePtr(std::make_shared<DataTypeInterval>(IntervalKind::Month)); });
|
factory.registerSimpleDataType("IntervalMonth", create<IntervalKind::Month>);
|
||||||
factory.registerSimpleDataType("IntervalQuarter", [] { return DataTypePtr(std::make_shared<DataTypeInterval>(IntervalKind::Quarter)); });
|
factory.registerSimpleDataType("IntervalQuarter", create<IntervalKind::Quarter>);
|
||||||
factory.registerSimpleDataType("IntervalYear", [] { return DataTypePtr(std::make_shared<DataTypeInterval>(IntervalKind::Year)); });
|
factory.registerSimpleDataType("IntervalYear", create<IntervalKind::Year>);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -949,7 +949,7 @@ bool DataTypeLowCardinality::equals(const IDataType & rhs) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static DataTypePtr create(const ASTPtr & arguments)
|
static DataTypePtr create(const String & /*type_name*/, const ASTPtr & arguments)
|
||||||
{
|
{
|
||||||
if (!arguments || arguments->children.size() != 1)
|
if (!arguments || arguments->children.size() != 1)
|
||||||
throw Exception("LowCardinality data type family must have single argument - type of elements",
|
throw Exception("LowCardinality data type family must have single argument - type of elements",
|
||||||
|
@ -38,7 +38,9 @@ bool DataTypeNothing::equals(const IDataType & rhs) const
|
|||||||
|
|
||||||
void registerDataTypeNothing(DataTypeFactory & factory)
|
void registerDataTypeNothing(DataTypeFactory & factory)
|
||||||
{
|
{
|
||||||
factory.registerSimpleDataType("Nothing", [] { return DataTypePtr(std::make_shared<DataTypeNothing>()); });
|
const auto & creator = [&](const String & /*type_name*/) { return DataTypePtr(std::make_shared<DataTypeNothing>()); };
|
||||||
|
|
||||||
|
factory.registerSimpleDataType("Nothing", creator);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -505,7 +505,7 @@ bool DataTypeNullable::equals(const IDataType & rhs) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static DataTypePtr create(const ASTPtr & arguments)
|
static DataTypePtr create(const String & /*type_name*/, const ASTPtr & arguments)
|
||||||
{
|
{
|
||||||
if (!arguments || arguments->children.size() != 1)
|
if (!arguments || arguments->children.size() != 1)
|
||||||
throw Exception("Nullable data type family must have exactly one argument - nested type", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
throw Exception("Nullable data type family must have exactly one argument - nested type", ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
||||||
|
@ -369,7 +369,7 @@ bool DataTypeString::equals(const IDataType & rhs) const
|
|||||||
|
|
||||||
void registerDataTypeString(DataTypeFactory & factory)
|
void registerDataTypeString(DataTypeFactory & factory)
|
||||||
{
|
{
|
||||||
auto creator = static_cast<DataTypePtr(*)()>([] { return DataTypePtr(std::make_shared<DataTypeString>()); });
|
const auto & creator = [&] (const String & type_name) { return std::make_shared<DataTypeString>(type_name); };
|
||||||
|
|
||||||
factory.registerSimpleDataType("String", creator);
|
factory.registerSimpleDataType("String", creator);
|
||||||
|
|
||||||
|
@ -14,6 +14,10 @@ public:
|
|||||||
using FieldType = String;
|
using FieldType = String;
|
||||||
static constexpr bool is_parametric = false;
|
static constexpr bool is_parametric = false;
|
||||||
|
|
||||||
|
DataTypeString(const String & type_name_ = "String") : type_name(type_name_) {}
|
||||||
|
|
||||||
|
String doGetName() const override { return type_name; }
|
||||||
|
|
||||||
const char * getFamilyName() const override
|
const char * getFamilyName() const override
|
||||||
{
|
{
|
||||||
return "String";
|
return "String";
|
||||||
@ -63,6 +67,9 @@ public:
|
|||||||
bool isCategorial() const override { return true; }
|
bool isCategorial() const override { return true; }
|
||||||
bool canBeInsideNullable() const override { return true; }
|
bool canBeInsideNullable() const override { return true; }
|
||||||
bool canBeInsideLowCardinality() const override { return true; }
|
bool canBeInsideLowCardinality() const override { return true; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const String type_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -529,7 +529,7 @@ size_t DataTypeTuple::getSizeOfValueInMemory() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static DataTypePtr create(const ASTPtr & arguments)
|
static DataTypePtr create(const String & /*type_name*/, const ASTPtr & arguments)
|
||||||
{
|
{
|
||||||
if (!arguments || arguments->children.empty())
|
if (!arguments || arguments->children.empty())
|
||||||
throw Exception("Tuple cannot be empty", ErrorCodes::EMPTY_DATA_PASSED);
|
throw Exception("Tuple cannot be empty", ErrorCodes::EMPTY_DATA_PASSED);
|
||||||
@ -568,7 +568,7 @@ void registerDataTypeTuple(DataTypeFactory & factory)
|
|||||||
void registerDataTypeNested(DataTypeFactory & factory)
|
void registerDataTypeNested(DataTypeFactory & factory)
|
||||||
{
|
{
|
||||||
/// Nested(...) data type is just a sugar for Array(Tuple(...))
|
/// Nested(...) data type is just a sugar for Array(Tuple(...))
|
||||||
factory.registerDataType("Nested", [&factory](const ASTPtr & arguments)
|
factory.registerDataType("Nested", [&factory](const String & /*type_name*/, const ASTPtr & arguments)
|
||||||
{
|
{
|
||||||
return std::make_shared<DataTypeArray>(factory.get("Tuple", arguments));
|
return std::make_shared<DataTypeArray>(factory.get("Tuple", arguments));
|
||||||
});
|
});
|
||||||
|
@ -106,7 +106,9 @@ bool DataTypeUUID::equals(const IDataType & rhs) const
|
|||||||
|
|
||||||
void registerDataTypeUUID(DataTypeFactory & factory)
|
void registerDataTypeUUID(DataTypeFactory & factory)
|
||||||
{
|
{
|
||||||
factory.registerSimpleDataType("UUID", [] { return DataTypePtr(std::make_shared<DataTypeUUID>()); });
|
const auto & creator = [&] (const String & /*type_name*/) { return std::make_shared<DataTypeUUID>(); };
|
||||||
|
|
||||||
|
factory.registerSimpleDataType("UUID", creator);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
#include <Parsers/IAST.h>
|
#include <Parsers/IAST.h>
|
||||||
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include "DataTypesDecimal.h"
|
||||||
|
|
||||||
|
|
||||||
namespace DB
|
namespace DB
|
||||||
{
|
{
|
||||||
@ -31,7 +33,12 @@ template <typename T>
|
|||||||
std::string DataTypeDecimal<T>::doGetName() const
|
std::string DataTypeDecimal<T>::doGetName() const
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "Decimal(" << this->precision << ", " << this->scale << ")";
|
ss << type_name << "(";
|
||||||
|
|
||||||
|
if (!only_scale)
|
||||||
|
ss << this->precision << ", ";
|
||||||
|
|
||||||
|
ss << this->scale << ")";
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,8 +142,14 @@ void DataTypeDecimal<T>::deserializeProtobuf(IColumn & column, ProtobufReader &
|
|||||||
container.back() = decimal;
|
container.back() = decimal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
DataTypeDecimal<T>::DataTypeDecimal(UInt32 precision_, UInt32 scale_, const String & type_name_, bool only_scale_)
|
||||||
|
: Base(precision_, scale_), type_name(type_name_), only_scale(only_scale_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
static DataTypePtr create(const ASTPtr & arguments)
|
|
||||||
|
static DataTypePtr create(const String & type_name, const ASTPtr & arguments)
|
||||||
{
|
{
|
||||||
if (!arguments || arguments->children.size() != 2)
|
if (!arguments || arguments->children.size() != 2)
|
||||||
throw Exception("Decimal data type family must have exactly two arguments: precision and scale",
|
throw Exception("Decimal data type family must have exactly two arguments: precision and scale",
|
||||||
@ -152,11 +165,11 @@ static DataTypePtr create(const ASTPtr & arguments)
|
|||||||
UInt64 precision_value = precision->value.get<UInt64>();
|
UInt64 precision_value = precision->value.get<UInt64>();
|
||||||
UInt64 scale_value = scale->value.get<UInt64>();
|
UInt64 scale_value = scale->value.get<UInt64>();
|
||||||
|
|
||||||
return createDecimal<DataTypeDecimal>(precision_value, scale_value);
|
return createDecimal<DataTypeDecimal>(precision_value, scale_value, type_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static DataTypePtr createExact(const ASTPtr & arguments)
|
static DataTypePtr createExact(const String & type_name, const ASTPtr & arguments)
|
||||||
{
|
{
|
||||||
if (!arguments || arguments->children.size() != 1)
|
if (!arguments || arguments->children.size() != 1)
|
||||||
throw Exception("Decimal data type family must have exactly two arguments: precision and scale",
|
throw Exception("Decimal data type family must have exactly two arguments: precision and scale",
|
||||||
@ -170,7 +183,7 @@ static DataTypePtr createExact(const ASTPtr & arguments)
|
|||||||
UInt64 precision = DecimalUtils::maxPrecision<T>();
|
UInt64 precision = DecimalUtils::maxPrecision<T>();
|
||||||
UInt64 scale = scale_arg->value.get<UInt64>();
|
UInt64 scale = scale_arg->value.get<UInt64>();
|
||||||
|
|
||||||
return createDecimal<DataTypeDecimal>(precision, scale);
|
return createDecimal<DataTypeDecimal>(precision, scale, type_name, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void registerDataTypeDecimal(DataTypeFactory & factory)
|
void registerDataTypeDecimal(DataTypeFactory & factory)
|
||||||
|
@ -35,6 +35,8 @@ public:
|
|||||||
using typename Base::ColumnType;
|
using typename Base::ColumnType;
|
||||||
using Base::Base;
|
using Base::Base;
|
||||||
|
|
||||||
|
DataTypeDecimal(UInt32 precision_, UInt32 scale_, const String & type_name_ = "Decimal", bool only_scale_ = false);
|
||||||
|
|
||||||
static constexpr auto family_name = "Decimal";
|
static constexpr auto family_name = "Decimal";
|
||||||
|
|
||||||
const char * getFamilyName() const override { return family_name; }
|
const char * getFamilyName() const override { return family_name; }
|
||||||
@ -57,6 +59,12 @@ public:
|
|||||||
|
|
||||||
static void readText(T & x, ReadBuffer & istr, UInt32 precision_, UInt32 scale_, bool csv = false);
|
static void readText(T & x, ReadBuffer & istr, UInt32 precision_, UInt32 scale_, bool csv = false);
|
||||||
static bool tryReadText(T & x, ReadBuffer & istr, UInt32 precision_, UInt32 scale_);
|
static bool tryReadText(T & x, ReadBuffer & istr, UInt32 precision_, UInt32 scale_);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// The name of data type how the user specified it. A single data type may be referenced by various synonims.
|
||||||
|
const String type_name;
|
||||||
|
/// If the user specified it only with scale parameter but without precision.
|
||||||
|
bool only_scale = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -5,20 +5,26 @@
|
|||||||
namespace DB
|
namespace DB
|
||||||
{
|
{
|
||||||
|
|
||||||
|
template <typename NumberType>
|
||||||
|
static DataTypePtr create(const String & type_name)
|
||||||
|
{
|
||||||
|
return DataTypePtr(std::make_shared<NumberType>(type_name));
|
||||||
|
}
|
||||||
|
|
||||||
void registerDataTypeNumbers(DataTypeFactory & factory)
|
void registerDataTypeNumbers(DataTypeFactory & factory)
|
||||||
{
|
{
|
||||||
factory.registerSimpleDataType("UInt8", [] { return DataTypePtr(std::make_shared<DataTypeUInt8>()); });
|
factory.registerSimpleDataType("UInt8", create<DataTypeUInt8>);
|
||||||
factory.registerSimpleDataType("UInt16", [] { return DataTypePtr(std::make_shared<DataTypeUInt16>()); });
|
factory.registerSimpleDataType("UInt16", create<DataTypeUInt16>);
|
||||||
factory.registerSimpleDataType("UInt32", [] { return DataTypePtr(std::make_shared<DataTypeUInt32>()); });
|
factory.registerSimpleDataType("UInt32", create<DataTypeUInt32>);
|
||||||
factory.registerSimpleDataType("UInt64", [] { return DataTypePtr(std::make_shared<DataTypeUInt64>()); });
|
factory.registerSimpleDataType("UInt64", create<DataTypeUInt64>);
|
||||||
|
|
||||||
factory.registerSimpleDataType("Int8", [] { return DataTypePtr(std::make_shared<DataTypeInt8>()); });
|
factory.registerSimpleDataType("Int8", create<DataTypeInt8>);
|
||||||
factory.registerSimpleDataType("Int16", [] { return DataTypePtr(std::make_shared<DataTypeInt16>()); });
|
factory.registerSimpleDataType("Int16", create<DataTypeInt16>);
|
||||||
factory.registerSimpleDataType("Int32", [] { return DataTypePtr(std::make_shared<DataTypeInt32>()); });
|
factory.registerSimpleDataType("Int32", create<DataTypeInt32>);
|
||||||
factory.registerSimpleDataType("Int64", [] { return DataTypePtr(std::make_shared<DataTypeInt64>()); });
|
factory.registerSimpleDataType("Int64", create<DataTypeInt64>);
|
||||||
|
|
||||||
factory.registerSimpleDataType("Float32", [] { return DataTypePtr(std::make_shared<DataTypeFloat32>()); });
|
factory.registerSimpleDataType("Float32", create<DataTypeFloat32>);
|
||||||
factory.registerSimpleDataType("Float64", [] { return DataTypePtr(std::make_shared<DataTypeFloat64>()); });
|
factory.registerSimpleDataType("Float64", create<DataTypeFloat64>);
|
||||||
|
|
||||||
/// These synonyms are added for compatibility.
|
/// These synonyms are added for compatibility.
|
||||||
|
|
||||||
|
@ -25,6 +25,13 @@ class DataTypeNumber final : public DataTypeNumberBase<T>
|
|||||||
using PromotedType = DataTypeNumber<NearestFieldType<T>>;
|
using PromotedType = DataTypeNumber<NearestFieldType<T>>;
|
||||||
return std::make_shared<PromotedType>();
|
return std::make_shared<PromotedType>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
DataTypeNumber(const String & type_name_ = TypeName<T>::get()) : type_name(type_name_) {}
|
||||||
|
|
||||||
|
String doGetName() const override { return type_name; }
|
||||||
|
private:
|
||||||
|
const String type_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
using DataTypeUInt8 = DataTypeNumber<UInt8>;
|
using DataTypeUInt8 = DataTypeNumber<UInt8>;
|
||||||
|
@ -534,6 +534,7 @@ struct WhichDataType
|
|||||||
|
|
||||||
inline bool isDate(const DataTypePtr & data_type) { return WhichDataType(data_type).isDate(); }
|
inline bool isDate(const DataTypePtr & data_type) { return WhichDataType(data_type).isDate(); }
|
||||||
inline bool isDateOrDateTime(const DataTypePtr & data_type) { return WhichDataType(data_type).isDateOrDateTime(); }
|
inline bool isDateOrDateTime(const DataTypePtr & data_type) { return WhichDataType(data_type).isDateOrDateTime(); }
|
||||||
|
inline bool isDateTime(const DataTypePtr & data_type) { return WhichDataType(data_type).isDateTime(); }
|
||||||
inline bool isDateTime64(const DataTypePtr & data_type) { return WhichDataType(data_type).isDateTime64(); }
|
inline bool isDateTime64(const DataTypePtr & data_type) { return WhichDataType(data_type).isDateTime64(); }
|
||||||
inline bool isEnum(const DataTypePtr & data_type) { return WhichDataType(data_type).isEnum(); }
|
inline bool isEnum(const DataTypePtr & data_type) { return WhichDataType(data_type).isEnum(); }
|
||||||
inline bool isDecimal(const DataTypePtr & data_type) { return WhichDataType(data_type).isDecimal(); }
|
inline bool isDecimal(const DataTypePtr & data_type) { return WhichDataType(data_type).isDecimal(); }
|
||||||
|
@ -19,6 +19,7 @@ namespace ErrorCodes
|
|||||||
extern const int ILLEGAL_COLUMN;
|
extern const int ILLEGAL_COLUMN;
|
||||||
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
|
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
|
||||||
extern const int SIZES_OF_ARRAYS_DOESNT_MATCH;
|
extern const int SIZES_OF_ARRAYS_DOESNT_MATCH;
|
||||||
|
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ColumnConst * checkAndGetColumnConstStringOrFixedString(const IColumn * column)
|
const ColumnConst * checkAndGetColumnConstStringOrFixedString(const IColumn * column)
|
||||||
@ -124,9 +125,9 @@ namespace
|
|||||||
void validateArgumentsImpl(const IFunction & func,
|
void validateArgumentsImpl(const IFunction & func,
|
||||||
const ColumnsWithTypeAndName & arguments,
|
const ColumnsWithTypeAndName & arguments,
|
||||||
size_t argument_offset,
|
size_t argument_offset,
|
||||||
const FunctionArgumentTypeValidators & validators)
|
const FunctionArgumentDescriptors & descriptors)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < validators.size(); ++i)
|
for (size_t i = 0; i < descriptors.size(); ++i)
|
||||||
{
|
{
|
||||||
const auto argument_index = i + argument_offset;
|
const auto argument_index = i + argument_offset;
|
||||||
if (argument_index >= arguments.size())
|
if (argument_index >= arguments.size())
|
||||||
@ -135,24 +136,36 @@ void validateArgumentsImpl(const IFunction & func,
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto & arg = arguments[i + argument_offset];
|
const auto & arg = arguments[i + argument_offset];
|
||||||
const auto validator = validators[i];
|
const auto descriptor = descriptors[i];
|
||||||
if (!validator.validator_func(*arg.type))
|
if (int errorCode = descriptor.isValid(arg.type, arg.column); errorCode != 0)
|
||||||
throw Exception("Illegal type " + arg.type->getName() +
|
throw Exception("Illegal type of argument #" + std::to_string(i)
|
||||||
" of " + std::to_string(i) +
|
+ (descriptor.argument_name ? " '" + std::string(descriptor.argument_name) + "'" : String{})
|
||||||
" argument of function " + func.getName() +
|
+ " of function " + func.getName()
|
||||||
" expected " + validator.expected_type_description,
|
+ (descriptor.expected_type_description ? String(", expected ") + descriptor.expected_type_description : String{})
|
||||||
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT);
|
+ (arg.type ? ", got " + arg.type->getName() : String{}),
|
||||||
|
errorCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int FunctionArgumentDescriptor::isValid(const DataTypePtr & data_type, const ColumnPtr & column) const
|
||||||
|
{
|
||||||
|
if (type_validator_func && (data_type == nullptr || type_validator_func(*data_type) == false))
|
||||||
|
return ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT;
|
||||||
|
|
||||||
|
if (column_validator_func && (column == nullptr || column_validator_func(*column) == false))
|
||||||
|
return ErrorCodes::ILLEGAL_COLUMN;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void validateFunctionArgumentTypes(const IFunction & func,
|
void validateFunctionArgumentTypes(const IFunction & func,
|
||||||
const ColumnsWithTypeAndName & arguments,
|
const ColumnsWithTypeAndName & arguments,
|
||||||
const FunctionArgumentTypeValidators & mandatory_args,
|
const FunctionArgumentDescriptors & mandatory_args,
|
||||||
const FunctionArgumentTypeValidators & optional_args)
|
const FunctionArgumentDescriptors & optional_args)
|
||||||
{
|
{
|
||||||
if (arguments.size() < mandatory_args.size())
|
if (arguments.size() < mandatory_args.size() || arguments.size() > mandatory_args.size() + optional_args.size())
|
||||||
{
|
{
|
||||||
auto joinArgumentTypes = [](const auto & args, const String sep = ", ") -> String
|
auto joinArgumentTypes = [](const auto & args, const String sep = ", ") -> String
|
||||||
{
|
{
|
||||||
@ -160,8 +173,13 @@ void validateFunctionArgumentTypes(const IFunction & func,
|
|||||||
for (const auto & a : args)
|
for (const auto & a : args)
|
||||||
{
|
{
|
||||||
using A = std::decay_t<decltype(a)>;
|
using A = std::decay_t<decltype(a)>;
|
||||||
if constexpr (std::is_same_v<A, FunctionArgumentTypeValidator>)
|
if constexpr (std::is_same_v<A, FunctionArgumentDescriptor>)
|
||||||
result += a.expected_type_description;
|
{
|
||||||
|
if (a.argument_name)
|
||||||
|
result += "'" + std::string(a.argument_name) + "' : ";
|
||||||
|
if (a.expected_type_description)
|
||||||
|
result += a.expected_type_description;
|
||||||
|
}
|
||||||
else if constexpr (std::is_same_v<A, ColumnWithTypeAndName>)
|
else if constexpr (std::is_same_v<A, ColumnWithTypeAndName>)
|
||||||
result += a.type->getName();
|
result += a.type->getName();
|
||||||
|
|
||||||
@ -174,10 +192,14 @@ void validateFunctionArgumentTypes(const IFunction & func,
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
throw Exception("Incorrect number of arguments of function " + func.getName()
|
throw Exception("Incorrect number of arguments for function " + func.getName()
|
||||||
+ " provided " + std::to_string(arguments.size()) + " (" + joinArgumentTypes(arguments) + ")"
|
+ " provided " + std::to_string(arguments.size())
|
||||||
+ " expected " + std::to_string(mandatory_args.size()) + (optional_args.size() ? " or " + std::to_string(mandatory_args.size() + optional_args.size()) : "")
|
+ (arguments.size() ? " (" + joinArgumentTypes(arguments) + ")" : String{})
|
||||||
+ " (" + joinArgumentTypes(mandatory_args) + (optional_args.size() ? ", [" + joinArgumentTypes(mandatory_args) + "]" : "") + ")",
|
+ ", expected " + std::to_string(mandatory_args.size())
|
||||||
|
+ (optional_args.size() ? " to " + std::to_string(mandatory_args.size() + optional_args.size()) : "")
|
||||||
|
+ " (" + joinArgumentTypes(mandatory_args)
|
||||||
|
+ (optional_args.size() ? ", [" + joinArgumentTypes(optional_args) + "]" : "")
|
||||||
|
+ ")",
|
||||||
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,21 +90,46 @@ void validateArgumentType(const IFunction & func, const DataTypes & arguments,
|
|||||||
size_t argument_index, bool (* validator_func)(const IDataType &),
|
size_t argument_index, bool (* validator_func)(const IDataType &),
|
||||||
const char * expected_type_description);
|
const char * expected_type_description);
|
||||||
|
|
||||||
// Simple validator that is used in conjunction with validateFunctionArgumentTypes() to check if function arguments are as expected.
|
/** Simple validator that is used in conjunction with validateFunctionArgumentTypes() to check if function arguments are as expected
|
||||||
struct FunctionArgumentTypeValidator
|
*
|
||||||
|
* Also it is used to generate function description when arguments do not match expected ones.
|
||||||
|
* Any field can be null:
|
||||||
|
* `argument_name` - if not null, reported via type check errors.
|
||||||
|
* `expected_type_description` - if not null, reported via type check errors.
|
||||||
|
* `type_validator_func` - if not null, used to validate data type of function argument.
|
||||||
|
* `column_validator_func` - if not null, used to validate column of function argument.
|
||||||
|
*/
|
||||||
|
struct FunctionArgumentDescriptor
|
||||||
{
|
{
|
||||||
bool (* validator_func)(const IDataType &);
|
const char * argument_name;
|
||||||
|
|
||||||
|
bool (* type_validator_func)(const IDataType &);
|
||||||
|
bool (* column_validator_func)(const IColumn &);
|
||||||
|
|
||||||
const char * expected_type_description;
|
const char * expected_type_description;
|
||||||
|
|
||||||
|
/** Validate argument type and column.
|
||||||
|
*
|
||||||
|
* Returns non-zero error code if:
|
||||||
|
* Validator != nullptr && (Value == nullptr || Validator(*Value) == false)
|
||||||
|
* For:
|
||||||
|
* Validator is either `type_validator_func` or `column_validator_func`
|
||||||
|
* Value is either `data_type` or `column` respectively.
|
||||||
|
* ILLEGAL_TYPE_OF_ARGUMENT if type validation fails
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int isValid(const DataTypePtr & data_type, const ColumnPtr & column) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
using FunctionArgumentTypeValidators = std::vector<FunctionArgumentTypeValidator>;
|
using FunctionArgumentDescriptors = std::vector<FunctionArgumentDescriptor>;
|
||||||
|
|
||||||
/** Validate that function arguments match specification.
|
/** Validate that function arguments match specification.
|
||||||
*
|
*
|
||||||
* Designed to simplify argument validation
|
* Designed to simplify argument validation for functions with variable arguments
|
||||||
* for functions with variable arguments (e.g. depending on result type or other trait).
|
* (e.g. depending on result type or other trait).
|
||||||
* first, checks that mandatory args present and have valid type.
|
* First, checks that number of arguments is as expected (including optional arguments).
|
||||||
* second, checks optional arguents types, skipping ones that are missing.
|
* Second, checks that mandatory args present and have valid type.
|
||||||
|
* Third, checks optional arguents types, skipping ones that are missing.
|
||||||
*
|
*
|
||||||
* Please note that if you have several optional arguments, like f([a, b, c]),
|
* Please note that if you have several optional arguments, like f([a, b, c]),
|
||||||
* only these calls are considered valid:
|
* only these calls are considered valid:
|
||||||
@ -113,11 +138,13 @@ using FunctionArgumentTypeValidators = std::vector<FunctionArgumentTypeValidator
|
|||||||
* f(a, b, c)
|
* f(a, b, c)
|
||||||
*
|
*
|
||||||
* But NOT these: f(a, c), f(b, c)
|
* But NOT these: f(a, c), f(b, c)
|
||||||
* In other words you can't skip
|
* In other words you can't omit middle optional arguments (just like in regular C++).
|
||||||
*
|
*
|
||||||
* If any mandatory arg is missing, throw an exception, with explicit description of expected arguments.
|
* If any mandatory arg is missing, throw an exception, with explicit description of expected arguments.
|
||||||
*/
|
*/
|
||||||
void validateFunctionArgumentTypes(const IFunction & func, const ColumnsWithTypeAndName & arguments, const FunctionArgumentTypeValidators & mandatory_args, const FunctionArgumentTypeValidators & optional_args = {});
|
void validateFunctionArgumentTypes(const IFunction & func, const ColumnsWithTypeAndName & arguments,
|
||||||
|
const FunctionArgumentDescriptors & mandatory_args,
|
||||||
|
const FunctionArgumentDescriptors & optional_args = {});
|
||||||
|
|
||||||
/// Checks if a list of array columns have equal offsets. Return a pair of nested columns and offsets if true, otherwise throw.
|
/// Checks if a list of array columns have equal offsets. Return a pair of nested columns and offsets if true, otherwise throw.
|
||||||
std::pair<std::vector<const IColumn *>, const ColumnArray::Offset *>
|
std::pair<std::vector<const IColumn *>, const ColumnArray::Offset *>
|
||||||
|
@ -918,16 +918,25 @@ public:
|
|||||||
|
|
||||||
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
|
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
|
||||||
{
|
{
|
||||||
FunctionArgumentTypeValidators mandatory_args = {{[](const auto &) {return true;}, "ANY TYPE"}};
|
FunctionArgumentDescriptors mandatory_args = {{"Value", nullptr, nullptr, nullptr}};
|
||||||
FunctionArgumentTypeValidators optional_args;
|
FunctionArgumentDescriptors optional_args;
|
||||||
|
|
||||||
if constexpr (to_decimal || to_datetime64)
|
if constexpr (to_decimal || to_datetime64)
|
||||||
{
|
{
|
||||||
mandatory_args.push_back(FunctionArgumentTypeValidator{&isNativeInteger, "Integer"}); // scale
|
mandatory_args.push_back({"scale", &isNativeInteger, &isColumnConst, "const Integer"});
|
||||||
}
|
}
|
||||||
else
|
// toString(DateTime or DateTime64, [timezone: String])
|
||||||
|
if ((std::is_same_v<Name, NameToString> && arguments.size() > 0 && (isDateTime64(arguments[0].type) || isDateTime(arguments[0].type)))
|
||||||
|
// toUnixTimestamp(value[, timezone : String])
|
||||||
|
|| std::is_same_v<Name, NameToUnixTimestamp>
|
||||||
|
// toDate(value[, timezone : String])
|
||||||
|
|| std::is_same_v<ToDataType, DataTypeDate> // TODO: shall we allow timestamp argument for toDate? DateTime knows nothing about timezones and this arument is ignored below.
|
||||||
|
// toDateTime(value[, timezone: String])
|
||||||
|
|| std::is_same_v<ToDataType, DataTypeDateTime>
|
||||||
|
// toDateTime64(value, scale : Integer[, timezone: String])
|
||||||
|
|| std::is_same_v<ToDataType, DataTypeDateTime64>)
|
||||||
{
|
{
|
||||||
optional_args.push_back(FunctionArgumentTypeValidator{&isString, "String"}); // timezone
|
optional_args.push_back({"timezone", &isString, &isColumnConst, "const String"});
|
||||||
}
|
}
|
||||||
|
|
||||||
validateFunctionArgumentTypes(*this, arguments, mandatory_args, optional_args);
|
validateFunctionArgumentTypes(*this, arguments, mandatory_args, optional_args);
|
||||||
@ -938,8 +947,8 @@ public:
|
|||||||
}
|
}
|
||||||
else if constexpr (to_decimal)
|
else if constexpr (to_decimal)
|
||||||
{
|
{
|
||||||
if (!arguments[1].column)
|
// if (!arguments[1].column)
|
||||||
throw Exception("Second argument for function " + getName() + " must be constant", ErrorCodes::ILLEGAL_COLUMN);
|
// throw Exception("Second argument for function " + getName() + " must be constant", ErrorCodes::ILLEGAL_COLUMN);
|
||||||
|
|
||||||
UInt64 scale = extractToDecimalScale(arguments[1]);
|
UInt64 scale = extractToDecimalScale(arguments[1]);
|
||||||
|
|
||||||
|
225
dbms/src/Functions/currentRowPolicies.cpp
Normal file
225
dbms/src/Functions/currentRowPolicies.cpp
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
#include <Functions/IFunction.h>
|
||||||
|
#include <Functions/FunctionFactory.h>
|
||||||
|
#include <DataTypes/DataTypeArray.h>
|
||||||
|
#include <DataTypes/DataTypeString.h>
|
||||||
|
#include <DataTypes/DataTypeTuple.h>
|
||||||
|
#include <DataTypes/DataTypeUUID.h>
|
||||||
|
#include <Columns/ColumnArray.h>
|
||||||
|
#include <Columns/ColumnConst.h>
|
||||||
|
#include <Columns/ColumnString.h>
|
||||||
|
#include <Columns/ColumnTuple.h>
|
||||||
|
#include <Interpreters/Context.h>
|
||||||
|
#include <Access/RowPolicyContext.h>
|
||||||
|
#include <Access/AccessControlManager.h>
|
||||||
|
#include <ext/range.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace DB
|
||||||
|
{
|
||||||
|
namespace ErrorCodes
|
||||||
|
{
|
||||||
|
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
|
||||||
|
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// The currentRowPolicies() function can be called with 0..2 arguments:
|
||||||
|
/// currentRowPolicies() returns array of tuples (database, table_name, row_policy_name) for all the row policies applied for the current user;
|
||||||
|
/// currentRowPolicies(table_name) is equivalent to currentRowPolicies(currentDatabase(), table_name);
|
||||||
|
/// currentRowPolicies(database, table_name) returns array of names of the row policies applied to a specific table and for the current user.
|
||||||
|
class FunctionCurrentRowPolicies : public IFunction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr auto name = "currentRowPolicies";
|
||||||
|
|
||||||
|
static FunctionPtr create(const Context & context_) { return std::make_shared<FunctionCurrentRowPolicies>(context_); }
|
||||||
|
explicit FunctionCurrentRowPolicies(const Context & context_) : context(context_) {}
|
||||||
|
|
||||||
|
String getName() const override { return name; }
|
||||||
|
size_t getNumberOfArguments() const override { return 0; }
|
||||||
|
bool isVariadic() const override { return true; }
|
||||||
|
|
||||||
|
void checkNumberOfArgumentsIfVariadic(size_t number_of_arguments) const override
|
||||||
|
{
|
||||||
|
if (number_of_arguments > 2)
|
||||||
|
throw Exception("Number of arguments for function " + String(name) + " doesn't match: passed "
|
||||||
|
+ toString(number_of_arguments) + ", should be 0..2",
|
||||||
|
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
||||||
|
}
|
||||||
|
|
||||||
|
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
|
||||||
|
{
|
||||||
|
if (arguments.empty())
|
||||||
|
return std::make_shared<DataTypeArray>(std::make_shared<DataTypeTuple>(
|
||||||
|
DataTypes{std::make_shared<DataTypeString>(), std::make_shared<DataTypeString>(), std::make_shared<DataTypeString>()}));
|
||||||
|
else
|
||||||
|
return std::make_shared<DataTypeArray>(std::make_shared<DataTypeString>());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isDeterministic() const override { return false; }
|
||||||
|
|
||||||
|
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result_pos, size_t input_rows_count) override
|
||||||
|
{
|
||||||
|
if (arguments.empty())
|
||||||
|
{
|
||||||
|
auto database_column = ColumnString::create();
|
||||||
|
auto table_name_column = ColumnString::create();
|
||||||
|
auto policy_name_column = ColumnString::create();
|
||||||
|
for (const auto & policy_id : context.getRowPolicy()->getCurrentPolicyIDs())
|
||||||
|
{
|
||||||
|
const auto policy = context.getAccessControlManager().tryRead<RowPolicy>(policy_id);
|
||||||
|
if (policy)
|
||||||
|
{
|
||||||
|
const String database = policy->getDatabase();
|
||||||
|
const String table_name = policy->getTableName();
|
||||||
|
const String policy_name = policy->getName();
|
||||||
|
database_column->insertData(database.data(), database.length());
|
||||||
|
table_name_column->insertData(table_name.data(), table_name.length());
|
||||||
|
policy_name_column->insertData(policy_name.data(), policy_name.length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto offset_column = ColumnArray::ColumnOffsets::create();
|
||||||
|
offset_column->insertValue(policy_name_column->size());
|
||||||
|
block.getByPosition(result_pos).column = ColumnConst::create(
|
||||||
|
ColumnArray::create(
|
||||||
|
ColumnTuple::create(Columns{std::move(database_column), std::move(table_name_column), std::move(policy_name_column)}),
|
||||||
|
std::move(offset_column)),
|
||||||
|
input_rows_count);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const IColumn * database_column = nullptr;
|
||||||
|
if (arguments.size() == 2)
|
||||||
|
{
|
||||||
|
const auto & database_column_with_type = block.getByPosition(arguments[0]);
|
||||||
|
if (!isStringOrFixedString(database_column_with_type.type))
|
||||||
|
throw Exception{"The first argument of function " + String(name)
|
||||||
|
+ " should be a string containing database name, illegal type: "
|
||||||
|
+ database_column_with_type.type->getName(),
|
||||||
|
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
|
||||||
|
database_column = database_column_with_type.column.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto & table_name_column_with_type = block.getByPosition(arguments[arguments.size() - 1]);
|
||||||
|
if (!isStringOrFixedString(table_name_column_with_type.type))
|
||||||
|
throw Exception{"The" + String(database_column ? " last" : "") + " argument of function " + String(name)
|
||||||
|
+ " should be a string containing table name, illegal type: " + table_name_column_with_type.type->getName(),
|
||||||
|
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
|
||||||
|
const IColumn * table_name_column = table_name_column_with_type.column.get();
|
||||||
|
|
||||||
|
auto policy_name_column = ColumnString::create();
|
||||||
|
auto offset_column = ColumnArray::ColumnOffsets::create();
|
||||||
|
for (const auto i : ext::range(0, input_rows_count))
|
||||||
|
{
|
||||||
|
String database = database_column ? database_column->getDataAt(i).toString() : context.getCurrentDatabase();
|
||||||
|
String table_name = table_name_column->getDataAt(i).toString();
|
||||||
|
for (const auto & policy_id : context.getRowPolicy()->getCurrentPolicyIDs(database, table_name))
|
||||||
|
{
|
||||||
|
const auto policy = context.getAccessControlManager().tryRead<RowPolicy>(policy_id);
|
||||||
|
if (policy)
|
||||||
|
{
|
||||||
|
const String policy_name = policy->getName();
|
||||||
|
policy_name_column->insertData(policy_name.data(), policy_name.length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
offset_column->insertValue(policy_name_column->size());
|
||||||
|
}
|
||||||
|
|
||||||
|
block.getByPosition(result_pos).column = ColumnArray::create(std::move(policy_name_column), std::move(offset_column));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const Context & context;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// The currentRowPolicyIDs() function can be called with 0..2 arguments:
|
||||||
|
/// currentRowPolicyIDs() returns array of IDs of all the row policies applied for the current user;
|
||||||
|
/// currentRowPolicyIDs(table_name) is equivalent to currentRowPolicyIDs(currentDatabase(), table_name);
|
||||||
|
/// currentRowPolicyIDs(database, table_name) returns array of IDs of the row policies applied to a specific table and for the current user.
|
||||||
|
class FunctionCurrentRowPolicyIDs : public IFunction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr auto name = "currentRowPolicyIDs";
|
||||||
|
|
||||||
|
static FunctionPtr create(const Context & context_) { return std::make_shared<FunctionCurrentRowPolicyIDs>(context_); }
|
||||||
|
explicit FunctionCurrentRowPolicyIDs(const Context & context_) : context(context_) {}
|
||||||
|
|
||||||
|
String getName() const override { return name; }
|
||||||
|
size_t getNumberOfArguments() const override { return 0; }
|
||||||
|
bool isVariadic() const override { return true; }
|
||||||
|
|
||||||
|
void checkNumberOfArgumentsIfVariadic(size_t number_of_arguments) const override
|
||||||
|
{
|
||||||
|
if (number_of_arguments > 2)
|
||||||
|
throw Exception("Number of arguments for function " + String(name) + " doesn't match: passed "
|
||||||
|
+ toString(number_of_arguments) + ", should be 0..2",
|
||||||
|
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
||||||
|
}
|
||||||
|
|
||||||
|
DataTypePtr getReturnTypeImpl(const DataTypes & /* arguments */) const override
|
||||||
|
{
|
||||||
|
return std::make_shared<DataTypeArray>(std::make_shared<DataTypeUUID>());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isDeterministic() const override { return false; }
|
||||||
|
|
||||||
|
void executeImpl(Block & block, const ColumnNumbers & arguments, size_t result_pos, size_t input_rows_count) override
|
||||||
|
{
|
||||||
|
if (arguments.empty())
|
||||||
|
{
|
||||||
|
auto policy_id_column = ColumnVector<UInt128>::create();
|
||||||
|
for (const auto & policy_id : context.getRowPolicy()->getCurrentPolicyIDs())
|
||||||
|
policy_id_column->insertValue(policy_id);
|
||||||
|
auto offset_column = ColumnArray::ColumnOffsets::create();
|
||||||
|
offset_column->insertValue(policy_id_column->size());
|
||||||
|
block.getByPosition(result_pos).column
|
||||||
|
= ColumnConst::create(ColumnArray::create(std::move(policy_id_column), std::move(offset_column)), input_rows_count);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const IColumn * database_column = nullptr;
|
||||||
|
if (arguments.size() == 2)
|
||||||
|
{
|
||||||
|
const auto & database_column_with_type = block.getByPosition(arguments[0]);
|
||||||
|
if (!isStringOrFixedString(database_column_with_type.type))
|
||||||
|
throw Exception{"The first argument of function " + String(name)
|
||||||
|
+ " should be a string containing database name, illegal type: "
|
||||||
|
+ database_column_with_type.type->getName(),
|
||||||
|
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
|
||||||
|
database_column = database_column_with_type.column.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto & table_name_column_with_type = block.getByPosition(arguments[arguments.size() - 1]);
|
||||||
|
if (!isStringOrFixedString(table_name_column_with_type.type))
|
||||||
|
throw Exception{"The" + String(database_column ? " last" : "") + " argument of function " + String(name)
|
||||||
|
+ " should be a string containing table name, illegal type: " + table_name_column_with_type.type->getName(),
|
||||||
|
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT};
|
||||||
|
const IColumn * table_name_column = table_name_column_with_type.column.get();
|
||||||
|
|
||||||
|
auto policy_id_column = ColumnVector<UInt128>::create();
|
||||||
|
auto offset_column = ColumnArray::ColumnOffsets::create();
|
||||||
|
for (const auto i : ext::range(0, input_rows_count))
|
||||||
|
{
|
||||||
|
String database = database_column ? database_column->getDataAt(i).toString() : context.getCurrentDatabase();
|
||||||
|
String table_name = table_name_column->getDataAt(i).toString();
|
||||||
|
for (const auto & policy_id : context.getRowPolicy()->getCurrentPolicyIDs(database, table_name))
|
||||||
|
policy_id_column->insertValue(policy_id);
|
||||||
|
offset_column->insertValue(policy_id_column->size());
|
||||||
|
}
|
||||||
|
|
||||||
|
block.getByPosition(result_pos).column = ColumnArray::create(std::move(policy_id_column), std::move(offset_column));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const Context & context;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void registerFunctionCurrentRowPolicies(FunctionFactory & factory)
|
||||||
|
{
|
||||||
|
factory.registerFunction<FunctionCurrentRowPolicies>();
|
||||||
|
factory.registerFunction<FunctionCurrentRowPolicyIDs>();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -9,6 +9,7 @@ class FunctionFactory;
|
|||||||
void registerFunctionCurrentDatabase(FunctionFactory &);
|
void registerFunctionCurrentDatabase(FunctionFactory &);
|
||||||
void registerFunctionCurrentUser(FunctionFactory &);
|
void registerFunctionCurrentUser(FunctionFactory &);
|
||||||
void registerFunctionCurrentQuota(FunctionFactory &);
|
void registerFunctionCurrentQuota(FunctionFactory &);
|
||||||
|
void registerFunctionCurrentRowPolicies(FunctionFactory &);
|
||||||
void registerFunctionHostName(FunctionFactory &);
|
void registerFunctionHostName(FunctionFactory &);
|
||||||
void registerFunctionFQDN(FunctionFactory &);
|
void registerFunctionFQDN(FunctionFactory &);
|
||||||
void registerFunctionVisibleWidth(FunctionFactory &);
|
void registerFunctionVisibleWidth(FunctionFactory &);
|
||||||
|
@ -8,6 +8,7 @@ void registerFunctionsMiscellaneous(FunctionFactory & factory)
|
|||||||
registerFunctionCurrentDatabase(factory);
|
registerFunctionCurrentDatabase(factory);
|
||||||
registerFunctionCurrentUser(factory);
|
registerFunctionCurrentUser(factory);
|
||||||
registerFunctionCurrentQuota(factory);
|
registerFunctionCurrentQuota(factory);
|
||||||
|
registerFunctionCurrentRowPolicies(factory);
|
||||||
registerFunctionHostName(factory);
|
registerFunctionHostName(factory);
|
||||||
registerFunctionFQDN(factory);
|
registerFunctionFQDN(factory);
|
||||||
registerFunctionVisibleWidth(factory);
|
registerFunctionVisibleWidth(factory);
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include <Access/AccessControlManager.h>
|
#include <Access/AccessControlManager.h>
|
||||||
#include <Access/SettingsConstraints.h>
|
#include <Access/SettingsConstraints.h>
|
||||||
#include <Access/QuotaContext.h>
|
#include <Access/QuotaContext.h>
|
||||||
|
#include <Access/RowPolicyContext.h>
|
||||||
#include <Interpreters/ExpressionJIT.h>
|
#include <Interpreters/ExpressionJIT.h>
|
||||||
#include <Interpreters/UsersManager.h>
|
#include <Interpreters/UsersManager.h>
|
||||||
#include <Dictionaries/Embedded/GeoDictionariesLoader.h>
|
#include <Dictionaries/Embedded/GeoDictionariesLoader.h>
|
||||||
@ -333,6 +334,7 @@ Context Context::createGlobal()
|
|||||||
{
|
{
|
||||||
Context res;
|
Context res;
|
||||||
res.quota = std::make_shared<QuotaContext>();
|
res.quota = std::make_shared<QuotaContext>();
|
||||||
|
res.row_policy = std::make_shared<RowPolicyContext>();
|
||||||
res.shared = std::make_shared<ContextShared>();
|
res.shared = std::make_shared<ContextShared>();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -625,6 +627,13 @@ void Context::checkQuotaManagementIsAllowed()
|
|||||||
"User " + client_info.current_user + " doesn't have enough privileges to manage quotas", ErrorCodes::NOT_ENOUGH_PRIVILEGES);
|
"User " + client_info.current_user + " doesn't have enough privileges to manage quotas", ErrorCodes::NOT_ENOUGH_PRIVILEGES);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Context::checkRowPolicyManagementIsAllowed()
|
||||||
|
{
|
||||||
|
if (!is_row_policy_management_allowed)
|
||||||
|
throw Exception(
|
||||||
|
"User " + client_info.current_user + " doesn't have enough privileges to manage row policies", ErrorCodes::NOT_ENOUGH_PRIVILEGES);
|
||||||
|
}
|
||||||
|
|
||||||
void Context::setUsersConfig(const ConfigurationPtr & config)
|
void Context::setUsersConfig(const ConfigurationPtr & config)
|
||||||
{
|
{
|
||||||
auto lock = getLock();
|
auto lock = getLock();
|
||||||
@ -639,34 +648,6 @@ ConfigurationPtr Context::getUsersConfig()
|
|||||||
return shared->users_config;
|
return shared->users_config;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Context::hasUserProperty(const String & database, const String & table, const String & name) const
|
|
||||||
{
|
|
||||||
auto lock = getLock();
|
|
||||||
|
|
||||||
// No user - no properties.
|
|
||||||
if (client_info.current_user.empty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const auto & props = shared->users_manager->getUser(client_info.current_user)->table_props;
|
|
||||||
|
|
||||||
auto db = props.find(database);
|
|
||||||
if (db == props.end())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
auto table_props = db->second.find(table);
|
|
||||||
if (table_props == db->second.end())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return !!table_props->second.count(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
const String & Context::getUserProperty(const String & database, const String & table, const String & name) const
|
|
||||||
{
|
|
||||||
auto lock = getLock();
|
|
||||||
const auto & props = shared->users_manager->getUser(client_info.current_user)->table_props;
|
|
||||||
return props.at(database).at(table).at(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Context::calculateUserSettings()
|
void Context::calculateUserSettings()
|
||||||
{
|
{
|
||||||
auto lock = getLock();
|
auto lock = getLock();
|
||||||
@ -691,6 +672,8 @@ void Context::calculateUserSettings()
|
|||||||
quota = getAccessControlManager().createQuotaContext(
|
quota = getAccessControlManager().createQuotaContext(
|
||||||
client_info.current_user, client_info.current_address.host(), client_info.quota_key);
|
client_info.current_user, client_info.current_address.host(), client_info.quota_key);
|
||||||
is_quota_management_allowed = user->is_quota_management_allowed;
|
is_quota_management_allowed = user->is_quota_management_allowed;
|
||||||
|
row_policy = getAccessControlManager().getRowPolicyContext(client_info.current_user);
|
||||||
|
is_row_policy_management_allowed = user->is_row_policy_management_allowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,6 +45,7 @@ namespace DB
|
|||||||
struct ContextShared;
|
struct ContextShared;
|
||||||
class Context;
|
class Context;
|
||||||
class QuotaContext;
|
class QuotaContext;
|
||||||
|
class RowPolicyContext;
|
||||||
class EmbeddedDictionaries;
|
class EmbeddedDictionaries;
|
||||||
class ExternalDictionariesLoader;
|
class ExternalDictionariesLoader;
|
||||||
class ExternalModelsLoader;
|
class ExternalModelsLoader;
|
||||||
@ -140,6 +141,8 @@ private:
|
|||||||
|
|
||||||
std::shared_ptr<QuotaContext> quota; /// Current quota. By default - empty quota, that have no limits.
|
std::shared_ptr<QuotaContext> quota; /// Current quota. By default - empty quota, that have no limits.
|
||||||
bool is_quota_management_allowed = false; /// Whether the current user is allowed to manage quotas via SQL commands.
|
bool is_quota_management_allowed = false; /// Whether the current user is allowed to manage quotas via SQL commands.
|
||||||
|
std::shared_ptr<RowPolicyContext> row_policy;
|
||||||
|
bool is_row_policy_management_allowed = false; /// Whether the current user is allowed to manage row policies via SQL commands.
|
||||||
String current_database;
|
String current_database;
|
||||||
Settings settings; /// Setting for query execution.
|
Settings settings; /// Setting for query execution.
|
||||||
std::shared_ptr<const SettingsConstraints> settings_constraints;
|
std::shared_ptr<const SettingsConstraints> settings_constraints;
|
||||||
@ -210,6 +213,8 @@ public:
|
|||||||
const AccessControlManager & getAccessControlManager() const;
|
const AccessControlManager & getAccessControlManager() const;
|
||||||
std::shared_ptr<QuotaContext> getQuota() const { return quota; }
|
std::shared_ptr<QuotaContext> getQuota() const { return quota; }
|
||||||
void checkQuotaManagementIsAllowed();
|
void checkQuotaManagementIsAllowed();
|
||||||
|
std::shared_ptr<RowPolicyContext> getRowPolicy() const { return row_policy; }
|
||||||
|
void checkRowPolicyManagementIsAllowed();
|
||||||
|
|
||||||
/** Take the list of users, quotas and configuration profiles from this config.
|
/** Take the list of users, quotas and configuration profiles from this config.
|
||||||
* The list of users is completely replaced.
|
* The list of users is completely replaced.
|
||||||
@ -218,10 +223,6 @@ public:
|
|||||||
void setUsersConfig(const ConfigurationPtr & config);
|
void setUsersConfig(const ConfigurationPtr & config);
|
||||||
ConfigurationPtr getUsersConfig();
|
ConfigurationPtr getUsersConfig();
|
||||||
|
|
||||||
// User property is a key-value pair from the configuration entry: users.<username>.databases.<db_name>.<table_name>.<key_name>
|
|
||||||
bool hasUserProperty(const String & database, const String & table, const String & name) const;
|
|
||||||
const String & getUserProperty(const String & database, const String & table, const String & name) const;
|
|
||||||
|
|
||||||
/// Must be called before getClientInfo.
|
/// Must be called before getClientInfo.
|
||||||
void setUser(const String & name, const String & password, const Poco::Net::SocketAddress & address, const String & quota_key);
|
void setUser(const String & name, const String & password, const Poco::Net::SocketAddress & address, const String & quota_key);
|
||||||
|
|
||||||
|
93
dbms/src/Interpreters/InterpreterCreateRowPolicyQuery.cpp
Normal file
93
dbms/src/Interpreters/InterpreterCreateRowPolicyQuery.cpp
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
#include <Interpreters/InterpreterCreateRowPolicyQuery.h>
|
||||||
|
#include <Parsers/ASTCreateRowPolicyQuery.h>
|
||||||
|
#include <Parsers/ASTRoleList.h>
|
||||||
|
#include <Parsers/formatAST.h>
|
||||||
|
#include <Interpreters/Context.h>
|
||||||
|
#include <Access/AccessControlManager.h>
|
||||||
|
#include <boost/range/algorithm/sort.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
namespace DB
|
||||||
|
{
|
||||||
|
BlockIO InterpreterCreateRowPolicyQuery::execute()
|
||||||
|
{
|
||||||
|
context.checkRowPolicyManagementIsAllowed();
|
||||||
|
const auto & query = query_ptr->as<const ASTCreateRowPolicyQuery &>();
|
||||||
|
auto & access_control = context.getAccessControlManager();
|
||||||
|
|
||||||
|
if (query.alter)
|
||||||
|
{
|
||||||
|
auto update_func = [&](const AccessEntityPtr & entity) -> AccessEntityPtr
|
||||||
|
{
|
||||||
|
auto updated_policy = typeid_cast<std::shared_ptr<RowPolicy>>(entity->clone());
|
||||||
|
updateRowPolicyFromQuery(*updated_policy, query);
|
||||||
|
return updated_policy;
|
||||||
|
};
|
||||||
|
String full_name = query.name_parts.getFullName(context);
|
||||||
|
if (query.if_exists)
|
||||||
|
{
|
||||||
|
if (auto id = access_control.find<RowPolicy>(full_name))
|
||||||
|
access_control.tryUpdate(*id, update_func);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
access_control.update(access_control.getID<RowPolicy>(full_name), update_func);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto new_policy = std::make_shared<RowPolicy>();
|
||||||
|
updateRowPolicyFromQuery(*new_policy, query);
|
||||||
|
|
||||||
|
if (query.if_not_exists)
|
||||||
|
access_control.tryInsert(new_policy);
|
||||||
|
else if (query.or_replace)
|
||||||
|
access_control.insertOrReplace(new_policy);
|
||||||
|
else
|
||||||
|
access_control.insert(new_policy);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void InterpreterCreateRowPolicyQuery::updateRowPolicyFromQuery(RowPolicy & policy, const ASTCreateRowPolicyQuery & query)
|
||||||
|
{
|
||||||
|
if (query.alter)
|
||||||
|
{
|
||||||
|
if (!query.new_policy_name.empty())
|
||||||
|
policy.setName(query.new_policy_name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
policy.setDatabase(query.name_parts.database.empty() ? context.getCurrentDatabase() : query.name_parts.database);
|
||||||
|
policy.setTableName(query.name_parts.table_name);
|
||||||
|
policy.setName(query.name_parts.policy_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query.is_restrictive)
|
||||||
|
policy.setRestrictive(*query.is_restrictive);
|
||||||
|
|
||||||
|
for (const auto & [index, condition] : query.conditions)
|
||||||
|
policy.conditions[index] = condition ? serializeAST(*condition) : String{};
|
||||||
|
|
||||||
|
if (query.roles)
|
||||||
|
{
|
||||||
|
const auto & query_roles = *query.roles;
|
||||||
|
|
||||||
|
/// We keep `roles` sorted.
|
||||||
|
policy.roles = query_roles.roles;
|
||||||
|
if (query_roles.current_user)
|
||||||
|
policy.roles.push_back(context.getClientInfo().current_user);
|
||||||
|
boost::range::sort(policy.roles);
|
||||||
|
policy.roles.erase(std::unique(policy.roles.begin(), policy.roles.end()), policy.roles.end());
|
||||||
|
|
||||||
|
policy.all_roles = query_roles.all_roles;
|
||||||
|
|
||||||
|
/// We keep `except_roles` sorted.
|
||||||
|
policy.except_roles = query_roles.except_roles;
|
||||||
|
if (query_roles.except_current_user)
|
||||||
|
policy.except_roles.push_back(context.getClientInfo().current_user);
|
||||||
|
boost::range::sort(policy.except_roles);
|
||||||
|
policy.except_roles.erase(std::unique(policy.except_roles.begin(), policy.except_roles.end()), policy.except_roles.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
26
dbms/src/Interpreters/InterpreterCreateRowPolicyQuery.h
Normal file
26
dbms/src/Interpreters/InterpreterCreateRowPolicyQuery.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Interpreters/IInterpreter.h>
|
||||||
|
#include <Parsers/IAST_fwd.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace DB
|
||||||
|
{
|
||||||
|
class ASTCreateRowPolicyQuery;
|
||||||
|
struct RowPolicy;
|
||||||
|
|
||||||
|
|
||||||
|
class InterpreterCreateRowPolicyQuery : public IInterpreter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
InterpreterCreateRowPolicyQuery(const ASTPtr & query_ptr_, Context & context_) : query_ptr(query_ptr_), context(context_) {}
|
||||||
|
|
||||||
|
BlockIO execute() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateRowPolicyFromQuery(RowPolicy & policy, const ASTCreateRowPolicyQuery & query);
|
||||||
|
|
||||||
|
ASTPtr query_ptr;
|
||||||
|
Context & context;
|
||||||
|
};
|
||||||
|
}
|
@ -3,6 +3,8 @@
|
|||||||
#include <Interpreters/Context.h>
|
#include <Interpreters/Context.h>
|
||||||
#include <Access/AccessControlManager.h>
|
#include <Access/AccessControlManager.h>
|
||||||
#include <Access/Quota.h>
|
#include <Access/Quota.h>
|
||||||
|
#include <Access/RowPolicy.h>
|
||||||
|
#include <boost/range/algorithm/transform.hpp>
|
||||||
|
|
||||||
|
|
||||||
namespace DB
|
namespace DB
|
||||||
@ -24,6 +26,19 @@ BlockIO InterpreterDropAccessEntityQuery::execute()
|
|||||||
access_control.remove(access_control.getIDs<Quota>(query.names));
|
access_control.remove(access_control.getIDs<Quota>(query.names));
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
case Kind::ROW_POLICY:
|
||||||
|
{
|
||||||
|
context.checkRowPolicyManagementIsAllowed();
|
||||||
|
Strings full_names;
|
||||||
|
boost::range::transform(
|
||||||
|
query.row_policies_names, std::back_inserter(full_names),
|
||||||
|
[this](const RowPolicy::FullNameParts & row_policy_name) { return row_policy_name.getFullName(context); });
|
||||||
|
if (query.if_exists)
|
||||||
|
access_control.tryRemove(access_control.find<RowPolicy>(full_names));
|
||||||
|
else
|
||||||
|
access_control.remove(access_control.getIDs<RowPolicy>(full_names));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
__builtin_unreachable();
|
__builtin_unreachable();
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include <Parsers/ASTCheckQuery.h>
|
#include <Parsers/ASTCheckQuery.h>
|
||||||
#include <Parsers/ASTCreateQuery.h>
|
#include <Parsers/ASTCreateQuery.h>
|
||||||
#include <Parsers/ASTCreateQuotaQuery.h>
|
#include <Parsers/ASTCreateQuotaQuery.h>
|
||||||
|
#include <Parsers/ASTCreateRowPolicyQuery.h>
|
||||||
#include <Parsers/ASTDropAccessEntityQuery.h>
|
#include <Parsers/ASTDropAccessEntityQuery.h>
|
||||||
#include <Parsers/ASTDropQuery.h>
|
#include <Parsers/ASTDropQuery.h>
|
||||||
#include <Parsers/ASTInsertQuery.h>
|
#include <Parsers/ASTInsertQuery.h>
|
||||||
@ -14,6 +15,7 @@
|
|||||||
#include <Parsers/ASTShowCreateAccessEntityQuery.h>
|
#include <Parsers/ASTShowCreateAccessEntityQuery.h>
|
||||||
#include <Parsers/ASTShowProcesslistQuery.h>
|
#include <Parsers/ASTShowProcesslistQuery.h>
|
||||||
#include <Parsers/ASTShowQuotasQuery.h>
|
#include <Parsers/ASTShowQuotasQuery.h>
|
||||||
|
#include <Parsers/ASTShowRowPoliciesQuery.h>
|
||||||
#include <Parsers/ASTShowTablesQuery.h>
|
#include <Parsers/ASTShowTablesQuery.h>
|
||||||
#include <Parsers/ASTUseQuery.h>
|
#include <Parsers/ASTUseQuery.h>
|
||||||
#include <Parsers/ASTExplainQuery.h>
|
#include <Parsers/ASTExplainQuery.h>
|
||||||
@ -24,6 +26,7 @@
|
|||||||
#include <Interpreters/InterpreterCheckQuery.h>
|
#include <Interpreters/InterpreterCheckQuery.h>
|
||||||
#include <Interpreters/InterpreterCreateQuery.h>
|
#include <Interpreters/InterpreterCreateQuery.h>
|
||||||
#include <Interpreters/InterpreterCreateQuotaQuery.h>
|
#include <Interpreters/InterpreterCreateQuotaQuery.h>
|
||||||
|
#include <Interpreters/InterpreterCreateRowPolicyQuery.h>
|
||||||
#include <Interpreters/InterpreterDescribeQuery.h>
|
#include <Interpreters/InterpreterDescribeQuery.h>
|
||||||
#include <Interpreters/InterpreterExplainQuery.h>
|
#include <Interpreters/InterpreterExplainQuery.h>
|
||||||
#include <Interpreters/InterpreterDropAccessEntityQuery.h>
|
#include <Interpreters/InterpreterDropAccessEntityQuery.h>
|
||||||
@ -41,6 +44,7 @@
|
|||||||
#include <Interpreters/InterpreterShowCreateQuery.h>
|
#include <Interpreters/InterpreterShowCreateQuery.h>
|
||||||
#include <Interpreters/InterpreterShowProcesslistQuery.h>
|
#include <Interpreters/InterpreterShowProcesslistQuery.h>
|
||||||
#include <Interpreters/InterpreterShowQuotasQuery.h>
|
#include <Interpreters/InterpreterShowQuotasQuery.h>
|
||||||
|
#include <Interpreters/InterpreterShowRowPoliciesQuery.h>
|
||||||
#include <Interpreters/InterpreterShowTablesQuery.h>
|
#include <Interpreters/InterpreterShowTablesQuery.h>
|
||||||
#include <Interpreters/InterpreterSystemQuery.h>
|
#include <Interpreters/InterpreterSystemQuery.h>
|
||||||
#include <Interpreters/InterpreterUseQuery.h>
|
#include <Interpreters/InterpreterUseQuery.h>
|
||||||
@ -199,6 +203,10 @@ std::unique_ptr<IInterpreter> InterpreterFactory::get(ASTPtr & query, Context &
|
|||||||
{
|
{
|
||||||
return std::make_unique<InterpreterCreateQuotaQuery>(query, context);
|
return std::make_unique<InterpreterCreateQuotaQuery>(query, context);
|
||||||
}
|
}
|
||||||
|
else if (query->as<ASTCreateRowPolicyQuery>())
|
||||||
|
{
|
||||||
|
return std::make_unique<InterpreterCreateRowPolicyQuery>(query, context);
|
||||||
|
}
|
||||||
else if (query->as<ASTDropAccessEntityQuery>())
|
else if (query->as<ASTDropAccessEntityQuery>())
|
||||||
{
|
{
|
||||||
return std::make_unique<InterpreterDropAccessEntityQuery>(query, context);
|
return std::make_unique<InterpreterDropAccessEntityQuery>(query, context);
|
||||||
@ -211,6 +219,10 @@ std::unique_ptr<IInterpreter> InterpreterFactory::get(ASTPtr & query, Context &
|
|||||||
{
|
{
|
||||||
return std::make_unique<InterpreterShowQuotasQuery>(query, context);
|
return std::make_unique<InterpreterShowQuotasQuery>(query, context);
|
||||||
}
|
}
|
||||||
|
else if (query->as<ASTShowRowPoliciesQuery>())
|
||||||
|
{
|
||||||
|
return std::make_unique<InterpreterShowRowPoliciesQuery>(query, context);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
throw Exception("Unknown type of query: " + query->getID(), ErrorCodes::UNKNOWN_TYPE_OF_QUERY);
|
throw Exception("Unknown type of query: " + query->getID(), ErrorCodes::UNKNOWN_TYPE_OF_QUERY);
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,8 @@
|
|||||||
#include <Parsers/ExpressionListParsers.h>
|
#include <Parsers/ExpressionListParsers.h>
|
||||||
#include <Parsers/parseQuery.h>
|
#include <Parsers/parseQuery.h>
|
||||||
|
|
||||||
|
#include <Access/RowPolicyContext.h>
|
||||||
|
|
||||||
#include <Interpreters/InterpreterSelectQuery.h>
|
#include <Interpreters/InterpreterSelectQuery.h>
|
||||||
#include <Interpreters/InterpreterSelectWithUnionQuery.h>
|
#include <Interpreters/InterpreterSelectWithUnionQuery.h>
|
||||||
#include <Interpreters/InterpreterSetQuery.h>
|
#include <Interpreters/InterpreterSetQuery.h>
|
||||||
@ -118,11 +120,10 @@ namespace
|
|||||||
{
|
{
|
||||||
|
|
||||||
/// Assumes `storage` is set and the table filter (row-level security) is not empty.
|
/// Assumes `storage` is set and the table filter (row-level security) is not empty.
|
||||||
String generateFilterActions(ExpressionActionsPtr & actions, const StoragePtr & storage, const Context & context, const Names & prerequisite_columns = {})
|
String generateFilterActions(ExpressionActionsPtr & actions, const Context & context, const StoragePtr & storage, const ASTPtr & row_policy_filter, const Names & prerequisite_columns = {})
|
||||||
{
|
{
|
||||||
const auto & db_name = storage->getDatabaseName();
|
const auto & db_name = storage->getDatabaseName();
|
||||||
const auto & table_name = storage->getTableName();
|
const auto & table_name = storage->getTableName();
|
||||||
const auto & filter_str = context.getUserProperty(db_name, table_name, "filter");
|
|
||||||
|
|
||||||
/// TODO: implement some AST builders for this kind of stuff
|
/// TODO: implement some AST builders for this kind of stuff
|
||||||
ASTPtr query_ast = std::make_shared<ASTSelectQuery>();
|
ASTPtr query_ast = std::make_shared<ASTSelectQuery>();
|
||||||
@ -131,18 +132,15 @@ String generateFilterActions(ExpressionActionsPtr & actions, const StoragePtr &
|
|||||||
select_ast->setExpression(ASTSelectQuery::Expression::SELECT, std::make_shared<ASTExpressionList>());
|
select_ast->setExpression(ASTSelectQuery::Expression::SELECT, std::make_shared<ASTExpressionList>());
|
||||||
auto expr_list = select_ast->select();
|
auto expr_list = select_ast->select();
|
||||||
|
|
||||||
auto parseExpression = [] (const String & expr)
|
|
||||||
{
|
|
||||||
ParserExpression expr_parser;
|
|
||||||
return parseQuery(expr_parser, expr, 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
// The first column is our filter expression.
|
// The first column is our filter expression.
|
||||||
expr_list->children.push_back(parseExpression(filter_str));
|
expr_list->children.push_back(row_policy_filter);
|
||||||
|
|
||||||
/// Keep columns that are required after the filter actions.
|
/// Keep columns that are required after the filter actions.
|
||||||
for (const auto & column_str : prerequisite_columns)
|
for (const auto & column_str : prerequisite_columns)
|
||||||
expr_list->children.push_back(parseExpression(column_str));
|
{
|
||||||
|
ParserExpression expr_parser;
|
||||||
|
expr_list->children.push_back(parseQuery(expr_parser, column_str, 0));
|
||||||
|
}
|
||||||
|
|
||||||
select_ast->setExpression(ASTSelectQuery::Expression::TABLES, std::make_shared<ASTTablesInSelectQuery>());
|
select_ast->setExpression(ASTSelectQuery::Expression::TABLES, std::make_shared<ASTTablesInSelectQuery>());
|
||||||
auto tables = select_ast->tables();
|
auto tables = select_ast->tables();
|
||||||
@ -378,10 +376,11 @@ InterpreterSelectQuery::InterpreterSelectQuery(
|
|||||||
source_header = storage->getSampleBlockForColumns(required_columns);
|
source_header = storage->getSampleBlockForColumns(required_columns);
|
||||||
|
|
||||||
/// Fix source_header for filter actions.
|
/// Fix source_header for filter actions.
|
||||||
if (context->hasUserProperty(storage->getDatabaseName(), storage->getTableName(), "filter"))
|
auto row_policy_filter = context->getRowPolicy()->getCondition(storage->getDatabaseName(), storage->getTableName(), RowPolicy::SELECT_FILTER);
|
||||||
|
if (row_policy_filter)
|
||||||
{
|
{
|
||||||
filter_info = std::make_shared<FilterInfo>();
|
filter_info = std::make_shared<FilterInfo>();
|
||||||
filter_info->column_name = generateFilterActions(filter_info->actions, storage, *context, required_columns);
|
filter_info->column_name = generateFilterActions(filter_info->actions, *context, storage, row_policy_filter, required_columns);
|
||||||
source_header = storage->getSampleBlockForColumns(filter_info->actions->getRequiredColumns());
|
source_header = storage->getSampleBlockForColumns(filter_info->actions->getRequiredColumns());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -502,7 +501,7 @@ Block InterpreterSelectQuery::getSampleBlockImpl()
|
|||||||
|
|
||||||
/// PREWHERE optimization.
|
/// PREWHERE optimization.
|
||||||
/// Turn off, if the table filter (row-level security) is applied.
|
/// Turn off, if the table filter (row-level security) is applied.
|
||||||
if (storage && !context->hasUserProperty(storage->getDatabaseName(), storage->getTableName(), "filter"))
|
if (storage && !context->getRowPolicy()->getCondition(storage->getDatabaseName(), storage->getTableName(), RowPolicy::SELECT_FILTER))
|
||||||
{
|
{
|
||||||
query_analyzer->makeSetsForIndex(query.where());
|
query_analyzer->makeSetsForIndex(query.where());
|
||||||
query_analyzer->makeSetsForIndex(query.prewhere());
|
query_analyzer->makeSetsForIndex(query.prewhere());
|
||||||
@ -1363,11 +1362,12 @@ void InterpreterSelectQuery::executeFetchColumns(
|
|||||||
if (storage)
|
if (storage)
|
||||||
{
|
{
|
||||||
/// Append columns from the table filter to required
|
/// Append columns from the table filter to required
|
||||||
if (context->hasUserProperty(storage->getDatabaseName(), storage->getTableName(), "filter"))
|
auto row_policy_filter = context->getRowPolicy()->getCondition(storage->getDatabaseName(), storage->getTableName(), RowPolicy::SELECT_FILTER);
|
||||||
|
if (row_policy_filter)
|
||||||
{
|
{
|
||||||
auto initial_required_columns = required_columns;
|
auto initial_required_columns = required_columns;
|
||||||
ExpressionActionsPtr actions;
|
ExpressionActionsPtr actions;
|
||||||
generateFilterActions(actions, storage, *context, initial_required_columns);
|
generateFilterActions(actions, *context, storage, row_policy_filter, initial_required_columns);
|
||||||
auto required_columns_from_filter = actions->getRequiredColumns();
|
auto required_columns_from_filter = actions->getRequiredColumns();
|
||||||
|
|
||||||
for (const auto & column : required_columns_from_filter)
|
for (const auto & column : required_columns_from_filter)
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
#include <Interpreters/InterpreterShowCreateAccessEntityQuery.h>
|
#include <Interpreters/InterpreterShowCreateAccessEntityQuery.h>
|
||||||
#include <Interpreters/Context.h>
|
#include <Interpreters/Context.h>
|
||||||
#include <Parsers/ASTCreateQuotaQuery.h>
|
#include <Parsers/ASTCreateQuotaQuery.h>
|
||||||
|
#include <Parsers/ASTCreateRowPolicyQuery.h>
|
||||||
#include <Parsers/ASTShowCreateAccessEntityQuery.h>
|
#include <Parsers/ASTShowCreateAccessEntityQuery.h>
|
||||||
#include <Parsers/ASTRoleList.h>
|
#include <Parsers/ASTRoleList.h>
|
||||||
|
#include <Parsers/ExpressionListParsers.h>
|
||||||
#include <Parsers/formatAST.h>
|
#include <Parsers/formatAST.h>
|
||||||
|
#include <Parsers/parseQuery.h>
|
||||||
#include <Access/AccessControlManager.h>
|
#include <Access/AccessControlManager.h>
|
||||||
#include <Access/QuotaContext.h>
|
#include <Access/QuotaContext.h>
|
||||||
#include <Columns/ColumnString.h>
|
#include <Columns/ColumnString.h>
|
||||||
@ -28,7 +31,7 @@ BlockInputStreamPtr InterpreterShowCreateAccessEntityQuery::executeImpl()
|
|||||||
const auto & show_query = query_ptr->as<ASTShowCreateAccessEntityQuery &>();
|
const auto & show_query = query_ptr->as<ASTShowCreateAccessEntityQuery &>();
|
||||||
|
|
||||||
/// Build a create query.
|
/// Build a create query.
|
||||||
ASTPtr create_query = getCreateQuotaQuery(show_query);
|
ASTPtr create_query = getCreateQuery(show_query);
|
||||||
|
|
||||||
/// Build the result column.
|
/// Build the result column.
|
||||||
std::stringstream create_query_ss;
|
std::stringstream create_query_ss;
|
||||||
@ -49,6 +52,18 @@ BlockInputStreamPtr InterpreterShowCreateAccessEntityQuery::executeImpl()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ASTPtr InterpreterShowCreateAccessEntityQuery::getCreateQuery(const ASTShowCreateAccessEntityQuery & show_query) const
|
||||||
|
{
|
||||||
|
using Kind = ASTShowCreateAccessEntityQuery::Kind;
|
||||||
|
switch (show_query.kind)
|
||||||
|
{
|
||||||
|
case Kind::QUOTA: return getCreateQuotaQuery(show_query);
|
||||||
|
case Kind::ROW_POLICY: return getCreateRowPolicyQuery(show_query);
|
||||||
|
}
|
||||||
|
__builtin_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ASTPtr InterpreterShowCreateAccessEntityQuery::getCreateQuotaQuery(const ASTShowCreateAccessEntityQuery & show_query) const
|
ASTPtr InterpreterShowCreateAccessEntityQuery::getCreateQuotaQuery(const ASTShowCreateAccessEntityQuery & show_query) const
|
||||||
{
|
{
|
||||||
auto & access_control = context.getAccessControlManager();
|
auto & access_control = context.getAccessControlManager();
|
||||||
@ -86,4 +101,38 @@ ASTPtr InterpreterShowCreateAccessEntityQuery::getCreateQuotaQuery(const ASTShow
|
|||||||
|
|
||||||
return create_query;
|
return create_query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ASTPtr InterpreterShowCreateAccessEntityQuery::getCreateRowPolicyQuery(const ASTShowCreateAccessEntityQuery & show_query) const
|
||||||
|
{
|
||||||
|
auto & access_control = context.getAccessControlManager();
|
||||||
|
RowPolicyPtr policy = access_control.read<RowPolicy>(show_query.row_policy_name.getFullName(context));
|
||||||
|
|
||||||
|
auto create_query = std::make_shared<ASTCreateRowPolicyQuery>();
|
||||||
|
create_query->name_parts = RowPolicy::FullNameParts{policy->getDatabase(), policy->getTableName(), policy->getName()};
|
||||||
|
if (policy->isRestrictive())
|
||||||
|
create_query->is_restrictive = policy->isRestrictive();
|
||||||
|
|
||||||
|
for (auto index : ext::range_with_static_cast<RowPolicy::ConditionIndex>(RowPolicy::MAX_CONDITION_INDEX))
|
||||||
|
{
|
||||||
|
const auto & condition = policy->conditions[index];
|
||||||
|
if (!condition.empty())
|
||||||
|
{
|
||||||
|
ParserExpression parser;
|
||||||
|
ASTPtr expr = parseQuery(parser, condition, 0);
|
||||||
|
create_query->conditions.push_back(std::pair{index, expr});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!policy->roles.empty() || policy->all_roles)
|
||||||
|
{
|
||||||
|
auto create_query_roles = std::make_shared<ASTRoleList>();
|
||||||
|
create_query_roles->roles = policy->roles;
|
||||||
|
create_query_roles->all_roles = policy->all_roles;
|
||||||
|
create_query_roles->except_roles = policy->except_roles;
|
||||||
|
create_query->roles = std::move(create_query_roles);
|
||||||
|
}
|
||||||
|
|
||||||
|
return create_query;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,9 @@ private:
|
|||||||
const Context & context;
|
const Context & context;
|
||||||
|
|
||||||
BlockInputStreamPtr executeImpl();
|
BlockInputStreamPtr executeImpl();
|
||||||
|
ASTPtr getCreateQuery(const ASTShowCreateAccessEntityQuery & show_query) const;
|
||||||
ASTPtr getCreateQuotaQuery(const ASTShowCreateAccessEntityQuery & show_query) const;
|
ASTPtr getCreateQuotaQuery(const ASTShowCreateAccessEntityQuery & show_query) const;
|
||||||
|
ASTPtr getCreateRowPolicyQuery(const ASTShowCreateAccessEntityQuery & show_query) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
68
dbms/src/Interpreters/InterpreterShowRowPoliciesQuery.cpp
Normal file
68
dbms/src/Interpreters/InterpreterShowRowPoliciesQuery.cpp
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
#include <Interpreters/InterpreterShowRowPoliciesQuery.h>
|
||||||
|
#include <Parsers/ASTShowRowPoliciesQuery.h>
|
||||||
|
#include <Parsers/formatAST.h>
|
||||||
|
#include <Interpreters/executeQuery.h>
|
||||||
|
#include <Common/quoteString.h>
|
||||||
|
#include <Interpreters/Context.h>
|
||||||
|
#include <ext/range.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace DB
|
||||||
|
{
|
||||||
|
InterpreterShowRowPoliciesQuery::InterpreterShowRowPoliciesQuery(const ASTPtr & query_ptr_, Context & context_)
|
||||||
|
: query_ptr(query_ptr_), context(context_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BlockIO InterpreterShowRowPoliciesQuery::execute()
|
||||||
|
{
|
||||||
|
return executeQuery(getRewrittenQuery(), context, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
String InterpreterShowRowPoliciesQuery::getRewrittenQuery() const
|
||||||
|
{
|
||||||
|
const auto & query = query_ptr->as<ASTShowRowPoliciesQuery &>();
|
||||||
|
|
||||||
|
const String & table_name = query.table_name;
|
||||||
|
String database;
|
||||||
|
if (!table_name.empty())
|
||||||
|
{
|
||||||
|
database = query.database;
|
||||||
|
if (database.empty())
|
||||||
|
database = context.getCurrentDatabase();
|
||||||
|
}
|
||||||
|
|
||||||
|
String filter;
|
||||||
|
if (query.current)
|
||||||
|
{
|
||||||
|
if (table_name.empty())
|
||||||
|
filter = "has(currentRowPolicyIDs(), id)";
|
||||||
|
else
|
||||||
|
filter = "has(currentRowPolicyIDs(" + quoteString(database) + ", " + quoteString(table_name) + "), id)";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!table_name.empty())
|
||||||
|
filter = "database = " + quoteString(database) + " AND table = " + quoteString(table_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
String expr = table_name.empty() ? "full_name" : "name";
|
||||||
|
|
||||||
|
return "SELECT " + expr + " AS " + backQuote(getResultDescription()) + " from system.row_policies"
|
||||||
|
+ (filter.empty() ? "" : " WHERE " + filter) + " ORDER BY " + expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
String InterpreterShowRowPoliciesQuery::getResultDescription() const
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
formatAST(*query_ptr, ss, false, true);
|
||||||
|
String desc = ss.str();
|
||||||
|
String prefix = "SHOW ";
|
||||||
|
if (startsWith(desc, prefix))
|
||||||
|
desc = desc.substr(prefix.length()); /// `desc` always starts with "SHOW ", so we can trim this prefix.
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
}
|
25
dbms/src/Interpreters/InterpreterShowRowPoliciesQuery.h
Normal file
25
dbms/src/Interpreters/InterpreterShowRowPoliciesQuery.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Interpreters/IInterpreter.h>
|
||||||
|
#include <Parsers/IAST_fwd.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace DB
|
||||||
|
{
|
||||||
|
class Context;
|
||||||
|
|
||||||
|
class InterpreterShowRowPoliciesQuery : public IInterpreter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
InterpreterShowRowPoliciesQuery(const ASTPtr & query_ptr_, Context & context_);
|
||||||
|
BlockIO execute() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
String getRewrittenQuery() const;
|
||||||
|
String getResultDescription() const;
|
||||||
|
|
||||||
|
ASTPtr query_ptr;
|
||||||
|
Context & context;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -13,6 +13,7 @@
|
|||||||
#include <Interpreters/InterpreterDropQuery.h>
|
#include <Interpreters/InterpreterDropQuery.h>
|
||||||
#include <Interpreters/InterpreterCreateQuery.h>
|
#include <Interpreters/InterpreterCreateQuery.h>
|
||||||
#include <Interpreters/QueryLog.h>
|
#include <Interpreters/QueryLog.h>
|
||||||
|
#include <Interpreters/DDLWorker.h>
|
||||||
#include <Interpreters/PartLog.h>
|
#include <Interpreters/PartLog.h>
|
||||||
#include <Interpreters/QueryThreadLog.h>
|
#include <Interpreters/QueryThreadLog.h>
|
||||||
#include <Interpreters/TraceLog.h>
|
#include <Interpreters/TraceLog.h>
|
||||||
@ -101,14 +102,14 @@ void startStopAction(Context & context, ASTSystemQuery & query, StorageActionBlo
|
|||||||
auto manager = context.getActionLocksManager();
|
auto manager = context.getActionLocksManager();
|
||||||
manager->cleanExpired();
|
manager->cleanExpired();
|
||||||
|
|
||||||
if (!query.target_table.empty())
|
if (!query.table.empty())
|
||||||
{
|
{
|
||||||
String database = !query.target_database.empty() ? query.target_database : context.getCurrentDatabase();
|
String database = !query.database.empty() ? query.database : context.getCurrentDatabase();
|
||||||
|
|
||||||
if (start)
|
if (start)
|
||||||
manager->remove(database, query.target_table, action_type);
|
manager->remove(database, query.table, action_type);
|
||||||
else
|
else
|
||||||
manager->add(database, query.target_table, action_type);
|
manager->add(database, query.table, action_type);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -131,6 +132,9 @@ BlockIO InterpreterSystemQuery::execute()
|
|||||||
{
|
{
|
||||||
auto & query = query_ptr->as<ASTSystemQuery &>();
|
auto & query = query_ptr->as<ASTSystemQuery &>();
|
||||||
|
|
||||||
|
if (!query.cluster.empty())
|
||||||
|
return executeDDLQueryOnCluster(query_ptr, context, {query.database});
|
||||||
|
|
||||||
using Type = ASTSystemQuery::Type;
|
using Type = ASTSystemQuery::Type;
|
||||||
|
|
||||||
/// Use global context with fresh system profile settings
|
/// Use global context with fresh system profile settings
|
||||||
@ -138,11 +142,11 @@ BlockIO InterpreterSystemQuery::execute()
|
|||||||
system_context.setSetting("profile", context.getSystemProfileName());
|
system_context.setSetting("profile", context.getSystemProfileName());
|
||||||
|
|
||||||
/// Make canonical query for simpler processing
|
/// Make canonical query for simpler processing
|
||||||
if (!query.target_table.empty() && query.target_database.empty())
|
if (!query.table.empty() && query.database.empty())
|
||||||
query.target_database = context.getCurrentDatabase();
|
query.database = context.getCurrentDatabase();
|
||||||
|
|
||||||
if (!query.target_dictionary.empty() && !query.target_database.empty())
|
if (!query.target_dictionary.empty() && !query.database.empty())
|
||||||
query.target_dictionary = query.target_database + "." + query.target_dictionary;
|
query.target_dictionary = query.database + "." + query.target_dictionary;
|
||||||
|
|
||||||
switch (query.type)
|
switch (query.type)
|
||||||
{
|
{
|
||||||
@ -237,8 +241,8 @@ BlockIO InterpreterSystemQuery::execute()
|
|||||||
restartReplicas(system_context);
|
restartReplicas(system_context);
|
||||||
break;
|
break;
|
||||||
case Type::RESTART_REPLICA:
|
case Type::RESTART_REPLICA:
|
||||||
if (!tryRestartReplica(query.target_database, query.target_table, system_context))
|
if (!tryRestartReplica(query.database, query.table, system_context))
|
||||||
throw Exception("There is no " + query.target_database + "." + query.target_table + " replicated table",
|
throw Exception("There is no " + query.database + "." + query.table + " replicated table",
|
||||||
ErrorCodes::BAD_ARGUMENTS);
|
ErrorCodes::BAD_ARGUMENTS);
|
||||||
break;
|
break;
|
||||||
case Type::FLUSH_LOGS:
|
case Type::FLUSH_LOGS:
|
||||||
@ -338,8 +342,8 @@ void InterpreterSystemQuery::restartReplicas(Context & system_context)
|
|||||||
|
|
||||||
void InterpreterSystemQuery::syncReplica(ASTSystemQuery & query)
|
void InterpreterSystemQuery::syncReplica(ASTSystemQuery & query)
|
||||||
{
|
{
|
||||||
String database_name = !query.target_database.empty() ? query.target_database : context.getCurrentDatabase();
|
String database_name = !query.database.empty() ? query.database : context.getCurrentDatabase();
|
||||||
const String & table_name = query.target_table;
|
const String & table_name = query.table;
|
||||||
|
|
||||||
StoragePtr table = context.getTable(database_name, table_name);
|
StoragePtr table = context.getTable(database_name, table_name);
|
||||||
|
|
||||||
@ -361,8 +365,8 @@ void InterpreterSystemQuery::syncReplica(ASTSystemQuery & query)
|
|||||||
|
|
||||||
void InterpreterSystemQuery::flushDistributed(ASTSystemQuery & query)
|
void InterpreterSystemQuery::flushDistributed(ASTSystemQuery & query)
|
||||||
{
|
{
|
||||||
String database_name = !query.target_database.empty() ? query.target_database : context.getCurrentDatabase();
|
String database_name = !query.database.empty() ? query.database : context.getCurrentDatabase();
|
||||||
String & table_name = query.target_table;
|
String & table_name = query.table;
|
||||||
|
|
||||||
if (auto storage_distributed = dynamic_cast<StorageDistributed *>(context.getTable(database_name, table_name).get()))
|
if (auto storage_distributed = dynamic_cast<StorageDistributed *>(context.getTable(database_name, table_name).get()))
|
||||||
storage_distributed->flushClusterNodesAllData();
|
storage_distributed->flushClusterNodesAllData();
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include <IO/ReadHelpers.h>
|
#include <IO/ReadHelpers.h>
|
||||||
#include <Interpreters/Users.h>
|
#include <Interpreters/Users.h>
|
||||||
#include <common/logger_useful.h>
|
#include <common/logger_useful.h>
|
||||||
|
#include <Poco/MD5Engine.h>
|
||||||
|
|
||||||
|
|
||||||
namespace DB
|
namespace DB
|
||||||
@ -102,36 +103,10 @@ User::User(const String & name_, const String & config_elem, const Poco::Util::A
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read properties per "database.table"
|
|
||||||
/// Only tables are expected to have properties, so that all the keys inside "database" are table names.
|
|
||||||
const auto config_databases = config_elem + ".databases";
|
|
||||||
if (config.has(config_databases))
|
|
||||||
{
|
|
||||||
Poco::Util::AbstractConfiguration::Keys database_names;
|
|
||||||
config.keys(config_databases, database_names);
|
|
||||||
|
|
||||||
/// Read tables within databases
|
|
||||||
for (const auto & database : database_names)
|
|
||||||
{
|
|
||||||
const auto config_database = config_databases + "." + database;
|
|
||||||
Poco::Util::AbstractConfiguration::Keys table_names;
|
|
||||||
config.keys(config_database, table_names);
|
|
||||||
|
|
||||||
/// Read table properties
|
|
||||||
for (const auto & table : table_names)
|
|
||||||
{
|
|
||||||
const auto config_filter = config_database + "." + table + ".filter";
|
|
||||||
if (config.has(config_filter))
|
|
||||||
{
|
|
||||||
const auto filter_query = config.getString(config_filter);
|
|
||||||
table_props[database][table]["filter"] = filter_query;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.has(config_elem + ".allow_quota_management"))
|
if (config.has(config_elem + ".allow_quota_management"))
|
||||||
is_quota_management_allowed = config.getBool(config_elem + ".allow_quota_management");
|
is_quota_management_allowed = config.getBool(config_elem + ".allow_quota_management");
|
||||||
|
if (config.has(config_elem + ".allow_row_policy_management"))
|
||||||
|
is_row_policy_management_allowed = config.getBool(config_elem + ".allow_row_policy_management");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Core/Types.h>
|
#include <Core/Types.h>
|
||||||
|
#include <Core/UUID.h>
|
||||||
#include <Access/Authentication.h>
|
#include <Access/Authentication.h>
|
||||||
#include <Access/AllowedClientHosts.h>
|
#include <Access/AllowedClientHosts.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <unordered_map>
|
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
namespace Poco
|
namespace Poco
|
||||||
@ -41,13 +42,8 @@ struct User
|
|||||||
using DictionarySet = std::unordered_set<std::string>;
|
using DictionarySet = std::unordered_set<std::string>;
|
||||||
std::optional<DictionarySet> dictionaries;
|
std::optional<DictionarySet> dictionaries;
|
||||||
|
|
||||||
/// Table properties.
|
|
||||||
using PropertyMap = std::unordered_map<std::string /* name */, std::string /* value */>;
|
|
||||||
using TableMap = std::unordered_map<std::string /* table */, PropertyMap /* properties */>;
|
|
||||||
using DatabaseMap = std::unordered_map<std::string /* database */, TableMap /* tables */>;
|
|
||||||
DatabaseMap table_props;
|
|
||||||
|
|
||||||
bool is_quota_management_allowed = false;
|
bool is_quota_management_allowed = false;
|
||||||
|
bool is_row_policy_management_allowed = false;
|
||||||
|
|
||||||
User(const String & name_, const String & config_elem, const Poco::Util::AbstractConfiguration & config);
|
User(const String & name_, const String & config_elem, const Poco::Util::AbstractConfiguration & config);
|
||||||
};
|
};
|
||||||
|
164
dbms/src/Parsers/ASTCreateRowPolicyQuery.cpp
Normal file
164
dbms/src/Parsers/ASTCreateRowPolicyQuery.cpp
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
#include <Parsers/ASTCreateRowPolicyQuery.h>
|
||||||
|
#include <Parsers/ASTRoleList.h>
|
||||||
|
#include <Parsers/formatAST.h>
|
||||||
|
#include <Common/quoteString.h>
|
||||||
|
#include <boost/range/algorithm/transform.hpp>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
|
||||||
|
namespace DB
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
using ConditionIndex = RowPolicy::ConditionIndex;
|
||||||
|
|
||||||
|
void formatRenameTo(const String & new_policy_name, const IAST::FormatSettings & settings)
|
||||||
|
{
|
||||||
|
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " RENAME TO " << (settings.hilite ? IAST::hilite_none : "")
|
||||||
|
<< backQuote(new_policy_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void formatIsRestrictive(bool is_restrictive, const IAST::FormatSettings & settings)
|
||||||
|
{
|
||||||
|
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " AS " << (is_restrictive ? "RESTRICTIVE" : "PERMISSIVE")
|
||||||
|
<< (settings.hilite ? IAST::hilite_none : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void formatConditionalExpression(const ASTPtr & expr, const IAST::FormatSettings & settings)
|
||||||
|
{
|
||||||
|
if (!expr)
|
||||||
|
{
|
||||||
|
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " NONE" << (settings.hilite ? IAST::hilite_none : "");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
expr->format(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<std::pair<ConditionIndex, String>>
|
||||||
|
conditionalExpressionsToStrings(const std::vector<std::pair<ConditionIndex, ASTPtr>> & exprs, const IAST::FormatSettings & settings)
|
||||||
|
{
|
||||||
|
std::vector<std::pair<ConditionIndex, String>> result;
|
||||||
|
std::stringstream ss;
|
||||||
|
IAST::FormatSettings temp_settings(ss, settings);
|
||||||
|
boost::range::transform(exprs, std::back_inserter(result), [&](const std::pair<ConditionIndex, ASTPtr> & in)
|
||||||
|
{
|
||||||
|
formatConditionalExpression(in.second, temp_settings);
|
||||||
|
auto out = std::pair{in.first, ss.str()};
|
||||||
|
ss.str("");
|
||||||
|
return out;
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void formatConditions(const char * op, const std::optional<String> & filter, const std::optional<String> & check, bool alter, const IAST::FormatSettings & settings)
|
||||||
|
{
|
||||||
|
if (op)
|
||||||
|
{
|
||||||
|
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " FOR" << (settings.hilite ? IAST::hilite_none : "");
|
||||||
|
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << ' ' << op << (settings.hilite ? IAST::hilite_none : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filter)
|
||||||
|
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " USING " << (settings.hilite ? IAST::hilite_none : "") << *filter;
|
||||||
|
|
||||||
|
if (check && (alter || (check != filter)))
|
||||||
|
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " WITH CHECK " << (settings.hilite ? IAST::hilite_none : "") << *check;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void formatMultipleConditions(const std::vector<std::pair<ConditionIndex, ASTPtr>> & conditions, bool alter, const IAST::FormatSettings & settings)
|
||||||
|
{
|
||||||
|
std::optional<String> scond[RowPolicy::MAX_CONDITION_INDEX];
|
||||||
|
for (const auto & [index, scondition] : conditionalExpressionsToStrings(conditions, settings))
|
||||||
|
scond[index] = scondition;
|
||||||
|
|
||||||
|
if ((scond[RowPolicy::SELECT_FILTER] == scond[RowPolicy::UPDATE_FILTER])
|
||||||
|
&& (scond[RowPolicy::UPDATE_FILTER] == scond[RowPolicy::DELETE_FILTER])
|
||||||
|
&& (scond[RowPolicy::INSERT_CHECK] == scond[RowPolicy::UPDATE_CHECK])
|
||||||
|
&& (scond[RowPolicy::SELECT_FILTER] || scond[RowPolicy::INSERT_CHECK]))
|
||||||
|
{
|
||||||
|
formatConditions(nullptr, scond[RowPolicy::SELECT_FILTER], scond[RowPolicy::INSERT_CHECK], alter, settings);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool need_comma = false;
|
||||||
|
if (scond[RowPolicy::SELECT_FILTER])
|
||||||
|
{
|
||||||
|
if (std::exchange(need_comma, true))
|
||||||
|
settings.ostr << ',';
|
||||||
|
formatConditions("SELECT", scond[RowPolicy::SELECT_FILTER], {}, alter, settings);
|
||||||
|
}
|
||||||
|
if (scond[RowPolicy::INSERT_CHECK])
|
||||||
|
{
|
||||||
|
if (std::exchange(need_comma, true))
|
||||||
|
settings.ostr << ',';
|
||||||
|
formatConditions("INSERT", {}, scond[RowPolicy::INSERT_CHECK], alter, settings);
|
||||||
|
}
|
||||||
|
if (scond[RowPolicy::UPDATE_FILTER] || scond[RowPolicy::UPDATE_CHECK])
|
||||||
|
{
|
||||||
|
if (std::exchange(need_comma, true))
|
||||||
|
settings.ostr << ',';
|
||||||
|
formatConditions("UPDATE", scond[RowPolicy::UPDATE_FILTER], scond[RowPolicy::UPDATE_CHECK], alter, settings);
|
||||||
|
}
|
||||||
|
if (scond[RowPolicy::DELETE_FILTER])
|
||||||
|
{
|
||||||
|
if (std::exchange(need_comma, true))
|
||||||
|
settings.ostr << ',';
|
||||||
|
formatConditions("DELETE", scond[RowPolicy::DELETE_FILTER], {}, alter, settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void formatRoles(const ASTRoleList & roles, const IAST::FormatSettings & settings)
|
||||||
|
{
|
||||||
|
settings.ostr << (settings.hilite ? IAST::hilite_keyword : "") << " TO " << (settings.hilite ? IAST::hilite_none : "");
|
||||||
|
roles.format(settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
String ASTCreateRowPolicyQuery::getID(char) const
|
||||||
|
{
|
||||||
|
return "CREATE POLICY or ALTER POLICY query";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ASTPtr ASTCreateRowPolicyQuery::clone() const
|
||||||
|
{
|
||||||
|
return std::make_shared<ASTCreateRowPolicyQuery>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ASTCreateRowPolicyQuery::formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const
|
||||||
|
{
|
||||||
|
settings.ostr << (settings.hilite ? hilite_keyword : "") << (alter ? "ALTER POLICY" : "CREATE POLICY")
|
||||||
|
<< (settings.hilite ? hilite_none : "");
|
||||||
|
|
||||||
|
if (if_exists)
|
||||||
|
settings.ostr << (settings.hilite ? hilite_keyword : "") << " IF EXISTS" << (settings.hilite ? hilite_none : "");
|
||||||
|
else if (if_not_exists)
|
||||||
|
settings.ostr << (settings.hilite ? hilite_keyword : "") << " IF NOT EXISTS" << (settings.hilite ? hilite_none : "");
|
||||||
|
else if (or_replace)
|
||||||
|
settings.ostr << (settings.hilite ? hilite_keyword : "") << " OR REPLACE" << (settings.hilite ? hilite_none : "");
|
||||||
|
|
||||||
|
const String & database = name_parts.database;
|
||||||
|
const String & table_name = name_parts.table_name;
|
||||||
|
const String & policy_name = name_parts.policy_name;
|
||||||
|
settings.ostr << " " << backQuoteIfNeed(policy_name) << (settings.hilite ? hilite_keyword : "") << " ON "
|
||||||
|
<< (settings.hilite ? hilite_none : "") << (database.empty() ? String{} : backQuoteIfNeed(database) + ".") << table_name;
|
||||||
|
|
||||||
|
if (!new_policy_name.empty())
|
||||||
|
formatRenameTo(new_policy_name, settings);
|
||||||
|
|
||||||
|
if (is_restrictive)
|
||||||
|
formatIsRestrictive(*is_restrictive, settings);
|
||||||
|
|
||||||
|
formatMultipleConditions(conditions, alter, settings);
|
||||||
|
|
||||||
|
if (roles)
|
||||||
|
formatRoles(*roles, settings);
|
||||||
|
}
|
||||||
|
}
|
50
dbms/src/Parsers/ASTCreateRowPolicyQuery.h
Normal file
50
dbms/src/Parsers/ASTCreateRowPolicyQuery.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Parsers/IAST.h>
|
||||||
|
#include <Access/RowPolicy.h>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
|
namespace DB
|
||||||
|
{
|
||||||
|
class ASTRoleList;
|
||||||
|
|
||||||
|
/** CREATE [ROW] POLICY [IF NOT EXISTS | OR REPLACE] name ON [database.]table
|
||||||
|
* [AS {PERMISSIVE | RESTRICTIVE}]
|
||||||
|
* [FOR {SELECT | INSERT | UPDATE | DELETE | ALL}]
|
||||||
|
* [USING condition]
|
||||||
|
* [WITH CHECK condition] [,...]
|
||||||
|
* [TO {role [,...] | ALL | ALL EXCEPT role [,...]}]
|
||||||
|
*
|
||||||
|
* ALTER [ROW] POLICY [IF EXISTS] name ON [database.]table
|
||||||
|
* [RENAME TO new_name]
|
||||||
|
* [AS {PERMISSIVE | RESTRICTIVE}]
|
||||||
|
* [FOR {SELECT | INSERT | UPDATE | DELETE | ALL}]
|
||||||
|
* [USING {condition | NONE}]
|
||||||
|
* [WITH CHECK {condition | NONE}] [,...]
|
||||||
|
* [TO {role [,...] | ALL | ALL EXCEPT role [,...]}]
|
||||||
|
*/
|
||||||
|
class ASTCreateRowPolicyQuery : public IAST
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool alter = false;
|
||||||
|
|
||||||
|
bool if_exists = false;
|
||||||
|
bool if_not_exists = false;
|
||||||
|
bool or_replace = false;
|
||||||
|
|
||||||
|
RowPolicy::FullNameParts name_parts;
|
||||||
|
String new_policy_name;
|
||||||
|
|
||||||
|
std::optional<bool> is_restrictive;
|
||||||
|
using ConditionIndex = RowPolicy::ConditionIndex;
|
||||||
|
std::vector<std::pair<ConditionIndex, ASTPtr>> conditions;
|
||||||
|
|
||||||
|
std::shared_ptr<ASTRoleList> roles;
|
||||||
|
|
||||||
|
String getID(char) const override;
|
||||||
|
ASTPtr clone() const override;
|
||||||
|
void formatImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override;
|
||||||
|
};
|
||||||
|
}
|
@ -13,6 +13,7 @@ namespace
|
|||||||
switch (kind)
|
switch (kind)
|
||||||
{
|
{
|
||||||
case Kind::QUOTA: return "QUOTA";
|
case Kind::QUOTA: return "QUOTA";
|
||||||
|
case Kind::ROW_POLICY: return "POLICY";
|
||||||
}
|
}
|
||||||
__builtin_unreachable();
|
__builtin_unreachable();
|
||||||
}
|
}
|
||||||
@ -44,13 +45,32 @@ void ASTDropAccessEntityQuery::formatImpl(const FormatSettings & settings, Forma
|
|||||||
<< (if_exists ? " IF EXISTS" : "")
|
<< (if_exists ? " IF EXISTS" : "")
|
||||||
<< (settings.hilite ? hilite_none : "");
|
<< (settings.hilite ? hilite_none : "");
|
||||||
|
|
||||||
bool need_comma = false;
|
if (kind == Kind::ROW_POLICY)
|
||||||
for (const auto & name : names)
|
|
||||||
{
|
{
|
||||||
if (need_comma)
|
bool need_comma = false;
|
||||||
settings.ostr << ',';
|
for (const auto & row_policy_name : row_policies_names)
|
||||||
need_comma = true;
|
{
|
||||||
settings.ostr << ' ' << backQuoteIfNeed(name);
|
if (need_comma)
|
||||||
|
settings.ostr << ',';
|
||||||
|
need_comma = true;
|
||||||
|
const String & database = row_policy_name.database;
|
||||||
|
const String & table_name = row_policy_name.table_name;
|
||||||
|
const String & policy_name = row_policy_name.policy_name;
|
||||||
|
settings.ostr << ' ' << backQuoteIfNeed(policy_name) << (settings.hilite ? hilite_keyword : "") << " ON "
|
||||||
|
<< (settings.hilite ? hilite_none : "") << (database.empty() ? String{} : backQuoteIfNeed(database) + ".")
|
||||||
|
<< backQuoteIfNeed(table_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool need_comma = false;
|
||||||
|
for (const auto & name : names)
|
||||||
|
{
|
||||||
|
if (need_comma)
|
||||||
|
settings.ostr << ',';
|
||||||
|
need_comma = true;
|
||||||
|
settings.ostr << ' ' << backQuoteIfNeed(name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Parsers/IAST.h>
|
#include <Parsers/IAST.h>
|
||||||
|
#include <Access/RowPolicy.h>
|
||||||
|
|
||||||
|
|
||||||
namespace DB
|
namespace DB
|
||||||
{
|
{
|
||||||
|
|
||||||
/** DROP QUOTA [IF EXISTS] name [,...]
|
/** DROP QUOTA [IF EXISTS] name [,...]
|
||||||
|
* DROP [ROW] POLICY [IF EXISTS] name [,...] ON [database.]table [,...]
|
||||||
*/
|
*/
|
||||||
class ASTDropAccessEntityQuery : public IAST
|
class ASTDropAccessEntityQuery : public IAST
|
||||||
{
|
{
|
||||||
@ -14,11 +16,13 @@ public:
|
|||||||
enum class Kind
|
enum class Kind
|
||||||
{
|
{
|
||||||
QUOTA,
|
QUOTA,
|
||||||
|
ROW_POLICY,
|
||||||
};
|
};
|
||||||
const Kind kind;
|
const Kind kind;
|
||||||
const char * const keyword;
|
const char * const keyword;
|
||||||
bool if_exists = false;
|
bool if_exists = false;
|
||||||
Strings names;
|
Strings names;
|
||||||
|
std::vector<RowPolicy::FullNameParts> row_policies_names;
|
||||||
|
|
||||||
ASTDropAccessEntityQuery(Kind kind_);
|
ASTDropAccessEntityQuery(Kind kind_);
|
||||||
String getID(char) const override;
|
String getID(char) const override;
|
||||||
|
@ -13,6 +13,7 @@ namespace
|
|||||||
switch (kind)
|
switch (kind)
|
||||||
{
|
{
|
||||||
case Kind::QUOTA: return "QUOTA";
|
case Kind::QUOTA: return "QUOTA";
|
||||||
|
case Kind::ROW_POLICY: return "POLICY";
|
||||||
}
|
}
|
||||||
__builtin_unreachable();
|
__builtin_unreachable();
|
||||||
}
|
}
|
||||||
@ -43,7 +44,16 @@ void ASTShowCreateAccessEntityQuery::formatQueryImpl(const FormatSettings & sett
|
|||||||
<< "SHOW CREATE " << keyword
|
<< "SHOW CREATE " << keyword
|
||||||
<< (settings.hilite ? hilite_none : "");
|
<< (settings.hilite ? hilite_none : "");
|
||||||
|
|
||||||
if (current_quota)
|
if (kind == Kind::ROW_POLICY)
|
||||||
|
{
|
||||||
|
const String & database = row_policy_name.database;
|
||||||
|
const String & table_name = row_policy_name.table_name;
|
||||||
|
const String & policy_name = row_policy_name.policy_name;
|
||||||
|
settings.ostr << ' ' << backQuoteIfNeed(policy_name) << (settings.hilite ? hilite_keyword : "") << " ON "
|
||||||
|
<< (settings.hilite ? hilite_none : "") << (database.empty() ? String{} : backQuoteIfNeed(database) + ".")
|
||||||
|
<< backQuoteIfNeed(table_name);
|
||||||
|
}
|
||||||
|
else if ((kind == Kind::QUOTA) && current_quota)
|
||||||
settings.ostr << (settings.hilite ? hilite_keyword : "") << " CURRENT" << (settings.hilite ? hilite_none : "");
|
settings.ostr << (settings.hilite ? hilite_keyword : "") << " CURRENT" << (settings.hilite ? hilite_none : "");
|
||||||
else
|
else
|
||||||
settings.ostr << " " << backQuoteIfNeed(name);
|
settings.ostr << " " << backQuoteIfNeed(name);
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Parsers/ASTQueryWithOutput.h>
|
#include <Parsers/ASTQueryWithOutput.h>
|
||||||
|
#include <Access/RowPolicy.h>
|
||||||
|
|
||||||
|
|
||||||
namespace DB
|
namespace DB
|
||||||
{
|
{
|
||||||
/** SHOW CREATE QUOTA [name | CURRENT]
|
/** SHOW CREATE QUOTA [name | CURRENT]
|
||||||
|
* SHOW CREATE [ROW] POLICY name ON [database.]table
|
||||||
*/
|
*/
|
||||||
class ASTShowCreateAccessEntityQuery : public ASTQueryWithOutput
|
class ASTShowCreateAccessEntityQuery : public ASTQueryWithOutput
|
||||||
{
|
{
|
||||||
@ -13,11 +15,13 @@ public:
|
|||||||
enum class Kind
|
enum class Kind
|
||||||
{
|
{
|
||||||
QUOTA,
|
QUOTA,
|
||||||
|
ROW_POLICY,
|
||||||
};
|
};
|
||||||
const Kind kind;
|
const Kind kind;
|
||||||
const char * const keyword;
|
const char * const keyword;
|
||||||
String name;
|
String name;
|
||||||
bool current_quota = false;
|
bool current_quota = false;
|
||||||
|
RowPolicy::FullNameParts row_policy_name;
|
||||||
|
|
||||||
ASTShowCreateAccessEntityQuery(Kind kind_);
|
ASTShowCreateAccessEntityQuery(Kind kind_);
|
||||||
String getID(char) const override;
|
String getID(char) const override;
|
||||||
|
22
dbms/src/Parsers/ASTShowRowPoliciesQuery.cpp
Normal file
22
dbms/src/Parsers/ASTShowRowPoliciesQuery.cpp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#include <Parsers/ASTShowRowPoliciesQuery.h>
|
||||||
|
#include <Common/quoteString.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace DB
|
||||||
|
{
|
||||||
|
void ASTShowRowPoliciesQuery::formatQueryImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const
|
||||||
|
{
|
||||||
|
settings.ostr << (settings.hilite ? hilite_keyword : "") << "SHOW POLICIES" << (settings.hilite ? hilite_none : "");
|
||||||
|
|
||||||
|
if (current)
|
||||||
|
settings.ostr << (settings.hilite ? hilite_keyword : "") << " CURRENT" << (settings.hilite ? hilite_none : "");
|
||||||
|
|
||||||
|
if (!table_name.empty())
|
||||||
|
{
|
||||||
|
settings.ostr << (settings.hilite ? hilite_keyword : "") << " ON " << (settings.hilite ? hilite_none : "");
|
||||||
|
if (!database.empty())
|
||||||
|
settings.ostr << backQuoteIfNeed(database) << ".";
|
||||||
|
settings.ostr << backQuoteIfNeed(table_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
dbms/src/Parsers/ASTShowRowPoliciesQuery.h
Normal file
23
dbms/src/Parsers/ASTShowRowPoliciesQuery.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Parsers/ASTQueryWithOutput.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace DB
|
||||||
|
{
|
||||||
|
/// SHOW [ROW] POLICIES [CURRENT] [ON [database.]table]
|
||||||
|
class ASTShowRowPoliciesQuery : public ASTQueryWithOutput
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool current = false;
|
||||||
|
String database;
|
||||||
|
String table_name;
|
||||||
|
|
||||||
|
String getID(char) const override { return "SHOW POLICIES query"; }
|
||||||
|
ASTPtr clone() const override { return std::make_shared<ASTShowRowPoliciesQuery>(*this); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void formatQueryImpl(const FormatSettings & settings, FormatState &, FormatStateStacked) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -96,27 +96,30 @@ void ASTSystemQuery::formatImpl(const FormatSettings & settings, FormatState &,
|
|||||||
auto print_database_table = [&]
|
auto print_database_table = [&]
|
||||||
{
|
{
|
||||||
settings.ostr << " ";
|
settings.ostr << " ";
|
||||||
if (!target_database.empty())
|
if (!database.empty())
|
||||||
{
|
{
|
||||||
settings.ostr << (settings.hilite ? hilite_identifier : "") << backQuoteIfNeed(target_database)
|
settings.ostr << (settings.hilite ? hilite_identifier : "") << backQuoteIfNeed(database)
|
||||||
<< (settings.hilite ? hilite_none : "") << ".";
|
<< (settings.hilite ? hilite_none : "") << ".";
|
||||||
}
|
}
|
||||||
settings.ostr << (settings.hilite ? hilite_identifier : "") << backQuoteIfNeed(target_table)
|
settings.ostr << (settings.hilite ? hilite_identifier : "") << backQuoteIfNeed(table)
|
||||||
<< (settings.hilite ? hilite_none : "");
|
<< (settings.hilite ? hilite_none : "");
|
||||||
};
|
};
|
||||||
|
|
||||||
auto print_database_dictionary = [&]
|
auto print_database_dictionary = [&]
|
||||||
{
|
{
|
||||||
settings.ostr << " ";
|
settings.ostr << " ";
|
||||||
if (!target_database.empty())
|
if (!database.empty())
|
||||||
{
|
{
|
||||||
settings.ostr << (settings.hilite ? hilite_identifier : "") << backQuoteIfNeed(target_database)
|
settings.ostr << (settings.hilite ? hilite_identifier : "") << backQuoteIfNeed(database)
|
||||||
<< (settings.hilite ? hilite_none : "") << ".";
|
<< (settings.hilite ? hilite_none : "") << ".";
|
||||||
}
|
}
|
||||||
settings.ostr << (settings.hilite ? hilite_identifier : "") << backQuoteIfNeed(target_dictionary)
|
settings.ostr << (settings.hilite ? hilite_identifier : "") << backQuoteIfNeed(target_dictionary)
|
||||||
<< (settings.hilite ? hilite_none : "");
|
<< (settings.hilite ? hilite_none : "");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!cluster.empty())
|
||||||
|
formatOnCluster(settings);
|
||||||
|
|
||||||
if ( type == Type::STOP_MERGES
|
if ( type == Type::STOP_MERGES
|
||||||
|| type == Type::START_MERGES
|
|| type == Type::START_MERGES
|
||||||
|| type == Type::STOP_TTL_MERGES
|
|| type == Type::STOP_TTL_MERGES
|
||||||
@ -132,7 +135,7 @@ void ASTSystemQuery::formatImpl(const FormatSettings & settings, FormatState &,
|
|||||||
|| type == Type::STOP_DISTRIBUTED_SENDS
|
|| type == Type::STOP_DISTRIBUTED_SENDS
|
||||||
|| type == Type::START_DISTRIBUTED_SENDS)
|
|| type == Type::START_DISTRIBUTED_SENDS)
|
||||||
{
|
{
|
||||||
if (!target_table.empty())
|
if (!table.empty())
|
||||||
print_database_table();
|
print_database_table();
|
||||||
}
|
}
|
||||||
else if (type == Type::RESTART_REPLICA || type == Type::SYNC_REPLICA || type == Type::FLUSH_DISTRIBUTED)
|
else if (type == Type::RESTART_REPLICA || type == Type::SYNC_REPLICA || type == Type::FLUSH_DISTRIBUTED)
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "config_core.h"
|
#include "config_core.h"
|
||||||
|
#include <Parsers/ASTQueryWithOnCluster.h>
|
||||||
#include <Parsers/IAST.h>
|
#include <Parsers/IAST.h>
|
||||||
|
|
||||||
|
|
||||||
namespace DB
|
namespace DB
|
||||||
{
|
{
|
||||||
|
|
||||||
class ASTSystemQuery : public IAST
|
class ASTSystemQuery : public IAST, public ASTQueryWithOnCluster
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -55,13 +56,18 @@ public:
|
|||||||
Type type = Type::UNKNOWN;
|
Type type = Type::UNKNOWN;
|
||||||
|
|
||||||
String target_dictionary;
|
String target_dictionary;
|
||||||
String target_database;
|
String database;
|
||||||
String target_table;
|
String table;
|
||||||
|
|
||||||
String getID(char) const override { return "SYSTEM query"; }
|
String getID(char) const override { return "SYSTEM query"; }
|
||||||
|
|
||||||
ASTPtr clone() const override { return std::make_shared<ASTSystemQuery>(*this); }
|
ASTPtr clone() const override { return std::make_shared<ASTSystemQuery>(*this); }
|
||||||
|
|
||||||
|
ASTPtr getRewrittenASTWithoutOnCluster(const std::string & new_database) const override
|
||||||
|
{
|
||||||
|
return removeOnCluster<ASTSystemQuery>(clone(), new_database);
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override;
|
void formatImpl(const FormatSettings & settings, FormatState & state, FormatStateStacked frame) const override;
|
||||||
|
261
dbms/src/Parsers/ParserCreateRowPolicyQuery.cpp
Normal file
261
dbms/src/Parsers/ParserCreateRowPolicyQuery.cpp
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
#include <Parsers/ParserCreateRowPolicyQuery.h>
|
||||||
|
#include <Parsers/ASTCreateRowPolicyQuery.h>
|
||||||
|
#include <Access/RowPolicy.h>
|
||||||
|
#include <Parsers/ParserRoleList.h>
|
||||||
|
#include <Parsers/ASTRoleList.h>
|
||||||
|
#include <Parsers/parseIdentifierOrStringLiteral.h>
|
||||||
|
#include <Parsers/parseDatabaseAndTableName.h>
|
||||||
|
#include <Parsers/ExpressionListParsers.h>
|
||||||
|
#include <Parsers/ASTLiteral.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace DB
|
||||||
|
{
|
||||||
|
namespace ErrorCodes
|
||||||
|
{
|
||||||
|
extern const int SYNTAX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
using ConditionIndex = RowPolicy::ConditionIndex;
|
||||||
|
|
||||||
|
bool parseRenameTo(IParserBase::Pos & pos, Expected & expected, String & new_policy_name, bool alter)
|
||||||
|
{
|
||||||
|
return IParserBase::wrapParseImpl(pos, [&]
|
||||||
|
{
|
||||||
|
if (!new_policy_name.empty() || !alter)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!ParserKeyword{"RENAME TO"}.ignore(pos, expected))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return parseIdentifierOrStringLiteral(pos, expected, new_policy_name);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parseIsRestrictive(IParserBase::Pos & pos, Expected & expected, std::optional<bool> & is_restrictive)
|
||||||
|
{
|
||||||
|
return IParserBase::wrapParseImpl(pos, [&]
|
||||||
|
{
|
||||||
|
if (is_restrictive)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!ParserKeyword{"AS"}.ignore(pos, expected))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (ParserKeyword{"RESTRICTIVE"}.ignore(pos, expected))
|
||||||
|
is_restrictive = true;
|
||||||
|
else if (ParserKeyword{"PERMISSIVE"}.ignore(pos, expected))
|
||||||
|
is_restrictive = false;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parseConditionalExpression(IParserBase::Pos & pos, Expected & expected, std::optional<ASTPtr> & expr)
|
||||||
|
{
|
||||||
|
if (ParserKeyword("NONE").ignore(pos, expected))
|
||||||
|
{
|
||||||
|
expr = nullptr;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
ParserExpression parser;
|
||||||
|
ASTPtr x;
|
||||||
|
if (parser.parse(pos, x, expected))
|
||||||
|
{
|
||||||
|
expr = x;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
expr.reset();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parseConditions(IParserBase::Pos & pos, Expected & expected, std::vector<std::pair<ConditionIndex, ASTPtr>> & conditions, bool alter)
|
||||||
|
{
|
||||||
|
return IParserBase::wrapParseImpl(pos, [&]
|
||||||
|
{
|
||||||
|
static constexpr char select_op[] = "SELECT";
|
||||||
|
static constexpr char insert_op[] = "INSERT";
|
||||||
|
static constexpr char update_op[] = "UPDATE";
|
||||||
|
static constexpr char delete_op[] = "DELETE";
|
||||||
|
std::vector<const char *> ops;
|
||||||
|
|
||||||
|
bool keyword_for = false;
|
||||||
|
if (ParserKeyword{"FOR"}.ignore(pos, expected))
|
||||||
|
{
|
||||||
|
keyword_for = true;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (ParserKeyword{"SELECT"}.ignore(pos, expected))
|
||||||
|
ops.push_back(select_op);
|
||||||
|
else if (ParserKeyword{"INSERT"}.ignore(pos, expected))
|
||||||
|
ops.push_back(insert_op);
|
||||||
|
else if (ParserKeyword{"UPDATE"}.ignore(pos, expected))
|
||||||
|
ops.push_back(update_op);
|
||||||
|
else if (ParserKeyword{"DELETE"}.ignore(pos, expected))
|
||||||
|
ops.push_back(delete_op);
|
||||||
|
else if (ParserKeyword{"ALL"}.ignore(pos, expected))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
while (ParserToken{TokenType::Comma}.ignore(pos, expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ops.empty())
|
||||||
|
{
|
||||||
|
ops.push_back(select_op);
|
||||||
|
ops.push_back(insert_op);
|
||||||
|
ops.push_back(update_op);
|
||||||
|
ops.push_back(delete_op);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<ASTPtr> filter;
|
||||||
|
std::optional<ASTPtr> check;
|
||||||
|
bool keyword_using = false, keyword_with_check = false;
|
||||||
|
if (ParserKeyword{"USING"}.ignore(pos, expected))
|
||||||
|
{
|
||||||
|
keyword_using = true;
|
||||||
|
if (!parseConditionalExpression(pos, expected, filter))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ParserKeyword{"WITH CHECK"}.ignore(pos, expected))
|
||||||
|
{
|
||||||
|
keyword_with_check = true;
|
||||||
|
if (!parseConditionalExpression(pos, expected, check))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!keyword_for && !keyword_using && !keyword_with_check)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (filter && !check && !alter)
|
||||||
|
check = filter;
|
||||||
|
|
||||||
|
auto set_condition = [&](ConditionIndex index, const ASTPtr & condition)
|
||||||
|
{
|
||||||
|
auto it = std::find_if(conditions.begin(), conditions.end(), [index](const std::pair<ConditionIndex, ASTPtr> & element)
|
||||||
|
{
|
||||||
|
return element.first == index;
|
||||||
|
});
|
||||||
|
if (it == conditions.end())
|
||||||
|
it = conditions.insert(conditions.end(), std::pair<ConditionIndex, ASTPtr>{index, nullptr});
|
||||||
|
it->second = condition;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const auto & op : ops)
|
||||||
|
{
|
||||||
|
if ((op == select_op) && filter)
|
||||||
|
set_condition(RowPolicy::SELECT_FILTER, *filter);
|
||||||
|
else if ((op == insert_op) && check)
|
||||||
|
set_condition(RowPolicy::INSERT_CHECK, *check);
|
||||||
|
else if (op == update_op)
|
||||||
|
{
|
||||||
|
if (filter)
|
||||||
|
set_condition(RowPolicy::UPDATE_FILTER, *filter);
|
||||||
|
if (check)
|
||||||
|
set_condition(RowPolicy::UPDATE_CHECK, *check);
|
||||||
|
}
|
||||||
|
else if ((op == delete_op) && filter)
|
||||||
|
set_condition(RowPolicy::DELETE_FILTER, *filter);
|
||||||
|
else
|
||||||
|
__builtin_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parseMultipleConditions(IParserBase::Pos & pos, Expected & expected, std::vector<std::pair<ConditionIndex, ASTPtr>> & conditions, bool alter)
|
||||||
|
{
|
||||||
|
return IParserBase::wrapParseImpl(pos, [&]
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (!parseConditions(pos, expected, conditions, alter))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
while (ParserToken{TokenType::Comma}.ignore(pos, expected));
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parseRoles(IParserBase::Pos & pos, Expected & expected, std::shared_ptr<ASTRoleList> & roles)
|
||||||
|
{
|
||||||
|
return IParserBase::wrapParseImpl(pos, [&]
|
||||||
|
{
|
||||||
|
ASTPtr node;
|
||||||
|
if (roles || !ParserKeyword{"TO"}.ignore(pos, expected) || !ParserRoleList{}.parse(pos, node, expected))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
roles = std::static_pointer_cast<ASTRoleList>(node);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool ParserCreateRowPolicyQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
||||||
|
{
|
||||||
|
bool alter;
|
||||||
|
if (ParserKeyword{"CREATE POLICY"}.ignore(pos, expected) || ParserKeyword{"CREATE ROW POLICY"}.ignore(pos, expected))
|
||||||
|
alter = false;
|
||||||
|
else if (ParserKeyword{"ALTER POLICY"}.ignore(pos, expected) || ParserKeyword{"ALTER ROW POLICY"}.ignore(pos, expected))
|
||||||
|
alter = true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool if_exists = false;
|
||||||
|
bool if_not_exists = false;
|
||||||
|
bool or_replace = false;
|
||||||
|
if (alter)
|
||||||
|
{
|
||||||
|
if (ParserKeyword{"IF EXISTS"}.ignore(pos, expected))
|
||||||
|
if_exists = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ParserKeyword{"IF NOT EXISTS"}.ignore(pos, expected))
|
||||||
|
if_not_exists = true;
|
||||||
|
else if (ParserKeyword{"OR REPLACE"}.ignore(pos, expected))
|
||||||
|
or_replace = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
RowPolicy::FullNameParts name_parts;
|
||||||
|
String & database = name_parts.database;
|
||||||
|
String & table_name = name_parts.table_name;
|
||||||
|
String & policy_name = name_parts.policy_name;
|
||||||
|
if (!parseIdentifierOrStringLiteral(pos, expected, policy_name) || !ParserKeyword{"ON"}.ignore(pos, expected)
|
||||||
|
|| !parseDatabaseAndTableName(pos, expected, database, table_name))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
String new_policy_name;
|
||||||
|
std::optional<bool> is_restrictive;
|
||||||
|
std::vector<std::pair<ConditionIndex, ASTPtr>> conditions;
|
||||||
|
std::shared_ptr<ASTRoleList> roles;
|
||||||
|
|
||||||
|
while (parseRenameTo(pos, expected, new_policy_name, alter) || parseIsRestrictive(pos, expected, is_restrictive)
|
||||||
|
|| parseMultipleConditions(pos, expected, conditions, alter) || parseRoles(pos, expected, roles))
|
||||||
|
;
|
||||||
|
|
||||||
|
auto query = std::make_shared<ASTCreateRowPolicyQuery>();
|
||||||
|
node = query;
|
||||||
|
|
||||||
|
query->alter = alter;
|
||||||
|
query->if_exists = if_exists;
|
||||||
|
query->if_not_exists = if_not_exists;
|
||||||
|
query->or_replace = or_replace;
|
||||||
|
query->name_parts = std::move(name_parts);
|
||||||
|
query->new_policy_name = std::move(new_policy_name);
|
||||||
|
query->is_restrictive = is_restrictive;
|
||||||
|
query->conditions = std::move(conditions);
|
||||||
|
query->roles = std::move(roles);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
30
dbms/src/Parsers/ParserCreateRowPolicyQuery.h
Normal file
30
dbms/src/Parsers/ParserCreateRowPolicyQuery.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Parsers/IParserBase.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace DB
|
||||||
|
{
|
||||||
|
/** Parses queries like
|
||||||
|
* CREATE [ROW] POLICY [IF NOT EXISTS | OR REPLACE] name ON [database.]table
|
||||||
|
* [AS {PERMISSIVE | RESTRICTIVE}]
|
||||||
|
* [FOR {SELECT | INSERT | UPDATE | DELETE | ALL}]
|
||||||
|
* [USING condition]
|
||||||
|
* [WITH CHECK condition] [,...]
|
||||||
|
* [TO {role [,...] | ALL | ALL EXCEPT role [,...]}]
|
||||||
|
*
|
||||||
|
* ALTER [ROW] POLICY [IF EXISTS] name ON [database.]table
|
||||||
|
* [RENAME TO new_name]
|
||||||
|
* [AS {PERMISSIVE | RESTRICTIVE}]
|
||||||
|
* [FOR {SELECT | INSERT | UPDATE | DELETE | ALL}]
|
||||||
|
* [USING {condition | NONE}]
|
||||||
|
* [WITH CHECK {condition | NONE}] [,...]
|
||||||
|
* [TO {role [,...] | ALL | ALL EXCEPT role [,...]}]
|
||||||
|
*/
|
||||||
|
class ParserCreateRowPolicyQuery : public IParserBase
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
const char * getName() const override { return "CREATE ROW POLICY or ALTER ROW POLICY query"; }
|
||||||
|
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
|
||||||
|
};
|
||||||
|
}
|
@ -2,11 +2,30 @@
|
|||||||
#include <Parsers/ASTDropAccessEntityQuery.h>
|
#include <Parsers/ASTDropAccessEntityQuery.h>
|
||||||
#include <Parsers/CommonParsers.h>
|
#include <Parsers/CommonParsers.h>
|
||||||
#include <Parsers/parseIdentifierOrStringLiteral.h>
|
#include <Parsers/parseIdentifierOrStringLiteral.h>
|
||||||
|
#include <Parsers/parseDatabaseAndTableName.h>
|
||||||
#include <Access/Quota.h>
|
#include <Access/Quota.h>
|
||||||
|
|
||||||
|
|
||||||
namespace DB
|
namespace DB
|
||||||
{
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
bool parseNames(IParserBase::Pos & pos, Expected & expected, Strings & names)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
String name;
|
||||||
|
if (!parseIdentifierOrStringLiteral(pos, expected, name))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
names.push_back(std::move(name));
|
||||||
|
}
|
||||||
|
while (ParserToken{TokenType::Comma}.ignore(pos, expected));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool ParserDropAccessEntityQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
bool ParserDropAccessEntityQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
||||||
{
|
{
|
||||||
if (!ParserKeyword{"DROP"}.ignore(pos, expected))
|
if (!ParserKeyword{"DROP"}.ignore(pos, expected))
|
||||||
@ -16,6 +35,8 @@ bool ParserDropAccessEntityQuery::parseImpl(Pos & pos, ASTPtr & node, Expected &
|
|||||||
Kind kind;
|
Kind kind;
|
||||||
if (ParserKeyword{"QUOTA"}.ignore(pos, expected))
|
if (ParserKeyword{"QUOTA"}.ignore(pos, expected))
|
||||||
kind = Kind::QUOTA;
|
kind = Kind::QUOTA;
|
||||||
|
else if (ParserKeyword{"POLICY"}.ignore(pos, expected) || ParserKeyword{"ROW POLICY"}.ignore(pos, expected))
|
||||||
|
kind = Kind::ROW_POLICY;
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -24,21 +45,35 @@ bool ParserDropAccessEntityQuery::parseImpl(Pos & pos, ASTPtr & node, Expected &
|
|||||||
if_exists = true;
|
if_exists = true;
|
||||||
|
|
||||||
Strings names;
|
Strings names;
|
||||||
do
|
std::vector<RowPolicy::FullNameParts> row_policies_names;
|
||||||
{
|
|
||||||
String name;
|
|
||||||
if (!parseIdentifierOrStringLiteral(pos, expected, name))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
names.push_back(std::move(name));
|
if (kind == Kind::ROW_POLICY)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Strings policy_names;
|
||||||
|
if (!parseNames(pos, expected, policy_names))
|
||||||
|
return false;
|
||||||
|
String database, table_name;
|
||||||
|
if (!ParserKeyword{"ON"}.ignore(pos, expected) || !parseDatabaseAndTableName(pos, expected, database, table_name))
|
||||||
|
return false;
|
||||||
|
for (const String & policy_name : policy_names)
|
||||||
|
row_policies_names.push_back({database, table_name, policy_name});
|
||||||
|
}
|
||||||
|
while (ParserToken{TokenType::Comma}.ignore(pos, expected));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!parseNames(pos, expected, names))
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
while (ParserToken{TokenType::Comma}.ignore(pos, expected));
|
|
||||||
|
|
||||||
auto query = std::make_shared<ASTDropAccessEntityQuery>(kind);
|
auto query = std::make_shared<ASTDropAccessEntityQuery>(kind);
|
||||||
node = query;
|
node = query;
|
||||||
|
|
||||||
query->if_exists = if_exists;
|
query->if_exists = if_exists;
|
||||||
query->names = std::move(names);
|
query->names = std::move(names);
|
||||||
|
query->row_policies_names = std::move(row_policies_names);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include <Parsers/ParserAlterQuery.h>
|
#include <Parsers/ParserAlterQuery.h>
|
||||||
#include <Parsers/ParserSystemQuery.h>
|
#include <Parsers/ParserSystemQuery.h>
|
||||||
#include <Parsers/ParserCreateQuotaQuery.h>
|
#include <Parsers/ParserCreateQuotaQuery.h>
|
||||||
|
#include <Parsers/ParserCreateRowPolicyQuery.h>
|
||||||
#include <Parsers/ParserDropAccessEntityQuery.h>
|
#include <Parsers/ParserDropAccessEntityQuery.h>
|
||||||
|
|
||||||
|
|
||||||
@ -25,6 +26,7 @@ bool ParserQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
|||||||
ParserSetQuery set_p;
|
ParserSetQuery set_p;
|
||||||
ParserSystemQuery system_p;
|
ParserSystemQuery system_p;
|
||||||
ParserCreateQuotaQuery create_quota_p;
|
ParserCreateQuotaQuery create_quota_p;
|
||||||
|
ParserCreateRowPolicyQuery create_row_policy_p;
|
||||||
ParserDropAccessEntityQuery drop_access_entity_p;
|
ParserDropAccessEntityQuery drop_access_entity_p;
|
||||||
|
|
||||||
bool res = query_with_output_p.parse(pos, node, expected)
|
bool res = query_with_output_p.parse(pos, node, expected)
|
||||||
@ -33,6 +35,7 @@ bool ParserQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
|||||||
|| set_p.parse(pos, node, expected)
|
|| set_p.parse(pos, node, expected)
|
||||||
|| system_p.parse(pos, node, expected)
|
|| system_p.parse(pos, node, expected)
|
||||||
|| create_quota_p.parse(pos, node, expected)
|
|| create_quota_p.parse(pos, node, expected)
|
||||||
|
|| create_row_policy_p.parse(pos, node, expected)
|
||||||
|| drop_access_entity_p.parse(pos, node, expected);
|
|| drop_access_entity_p.parse(pos, node, expected);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include <Parsers/ASTExplainQuery.h>
|
#include <Parsers/ASTExplainQuery.h>
|
||||||
#include <Parsers/ParserShowCreateAccessEntityQuery.h>
|
#include <Parsers/ParserShowCreateAccessEntityQuery.h>
|
||||||
#include <Parsers/ParserShowQuotasQuery.h>
|
#include <Parsers/ParserShowQuotasQuery.h>
|
||||||
|
#include <Parsers/ParserShowRowPoliciesQuery.h>
|
||||||
|
|
||||||
|
|
||||||
namespace DB
|
namespace DB
|
||||||
@ -38,6 +39,7 @@ bool ParserQueryWithOutput::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
|
|||||||
ParserWatchQuery watch_p;
|
ParserWatchQuery watch_p;
|
||||||
ParserShowCreateAccessEntityQuery show_create_access_entity_p;
|
ParserShowCreateAccessEntityQuery show_create_access_entity_p;
|
||||||
ParserShowQuotasQuery show_quotas_p;
|
ParserShowQuotasQuery show_quotas_p;
|
||||||
|
ParserShowRowPoliciesQuery show_row_policies_p;
|
||||||
|
|
||||||
ASTPtr query;
|
ASTPtr query;
|
||||||
|
|
||||||
@ -66,7 +68,8 @@ bool ParserQueryWithOutput::parseImpl(Pos & pos, ASTPtr & node, Expected & expec
|
|||||||
|| kill_query_p.parse(pos, query, expected)
|
|| kill_query_p.parse(pos, query, expected)
|
||||||
|| optimize_p.parse(pos, query, expected)
|
|| optimize_p.parse(pos, query, expected)
|
||||||
|| watch_p.parse(pos, query, expected)
|
|| watch_p.parse(pos, query, expected)
|
||||||
|| show_quotas_p.parse(pos, query, expected);
|
|| show_quotas_p.parse(pos, query, expected)
|
||||||
|
|| show_row_policies_p.parse(pos, query, expected);
|
||||||
|
|
||||||
if (!parsed)
|
if (!parsed)
|
||||||
return false;
|
return false;
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
#include <Parsers/ASTShowCreateAccessEntityQuery.h>
|
#include <Parsers/ASTShowCreateAccessEntityQuery.h>
|
||||||
#include <Parsers/CommonParsers.h>
|
#include <Parsers/CommonParsers.h>
|
||||||
#include <Parsers/parseIdentifierOrStringLiteral.h>
|
#include <Parsers/parseIdentifierOrStringLiteral.h>
|
||||||
|
#include <Parsers/parseDatabaseAndTableName.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
|
||||||
namespace DB
|
namespace DB
|
||||||
@ -15,25 +17,41 @@ bool ParserShowCreateAccessEntityQuery::parseImpl(Pos & pos, ASTPtr & node, Expe
|
|||||||
Kind kind;
|
Kind kind;
|
||||||
if (ParserKeyword{"QUOTA"}.ignore(pos, expected))
|
if (ParserKeyword{"QUOTA"}.ignore(pos, expected))
|
||||||
kind = Kind::QUOTA;
|
kind = Kind::QUOTA;
|
||||||
|
else if (ParserKeyword{"POLICY"}.ignore(pos, expected) || ParserKeyword{"ROW POLICY"}.ignore(pos, expected))
|
||||||
|
kind = Kind::ROW_POLICY;
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
String name;
|
String name;
|
||||||
bool current_quota = false;
|
bool current_quota = false;
|
||||||
|
RowPolicy::FullNameParts row_policy_name;
|
||||||
|
|
||||||
if ((kind == Kind::QUOTA) && ParserKeyword{"CURRENT"}.ignore(pos, expected))
|
if (kind == Kind::ROW_POLICY)
|
||||||
{
|
{
|
||||||
/// SHOW CREATE QUOTA CURRENT
|
String & database = row_policy_name.database;
|
||||||
current_quota = true;
|
String & table_name = row_policy_name.table_name;
|
||||||
}
|
String & policy_name = row_policy_name.policy_name;
|
||||||
else if (parseIdentifierOrStringLiteral(pos, expected, name))
|
if (!parseIdentifierOrStringLiteral(pos, expected, policy_name) || !ParserKeyword{"ON"}.ignore(pos, expected)
|
||||||
{
|
|| !parseDatabaseAndTableName(pos, expected, database, table_name))
|
||||||
/// SHOW CREATE QUOTA name
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/// SHOW CREATE QUOTA
|
assert(kind == Kind::QUOTA);
|
||||||
current_quota = true;
|
if (ParserKeyword{"CURRENT"}.ignore(pos, expected))
|
||||||
|
{
|
||||||
|
/// SHOW CREATE QUOTA CURRENT
|
||||||
|
current_quota = true;
|
||||||
|
}
|
||||||
|
else if (parseIdentifierOrStringLiteral(pos, expected, name))
|
||||||
|
{
|
||||||
|
/// SHOW CREATE QUOTA name
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/// SHOW CREATE QUOTA
|
||||||
|
current_quota = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto query = std::make_shared<ASTShowCreateAccessEntityQuery>(kind);
|
auto query = std::make_shared<ASTShowCreateAccessEntityQuery>(kind);
|
||||||
@ -41,6 +59,7 @@ bool ParserShowCreateAccessEntityQuery::parseImpl(Pos & pos, ASTPtr & node, Expe
|
|||||||
|
|
||||||
query->name = std::move(name);
|
query->name = std::move(name);
|
||||||
query->current_quota = current_quota;
|
query->current_quota = current_quota;
|
||||||
|
query->row_policy_name = std::move(row_policy_name);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
40
dbms/src/Parsers/ParserShowRowPoliciesQuery.cpp
Normal file
40
dbms/src/Parsers/ParserShowRowPoliciesQuery.cpp
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#include <Parsers/ParserShowRowPoliciesQuery.h>
|
||||||
|
#include <Parsers/ASTShowRowPoliciesQuery.h>
|
||||||
|
#include <Parsers/CommonParsers.h>
|
||||||
|
#include <Parsers/parseDatabaseAndTableName.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace DB
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
bool parseONDatabaseAndTableName(IParserBase::Pos & pos, Expected & expected, String & database, String & table_name)
|
||||||
|
{
|
||||||
|
return IParserBase::wrapParseImpl(pos, [&]
|
||||||
|
{
|
||||||
|
database.clear();
|
||||||
|
table_name.clear();
|
||||||
|
return ParserKeyword{"ON"}.ignore(pos, expected) && parseDatabaseAndTableName(pos, expected, database, table_name);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool ParserShowRowPoliciesQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
||||||
|
{
|
||||||
|
if (!ParserKeyword{"SHOW POLICIES"}.ignore(pos, expected) && !ParserKeyword{"SHOW ROW POLICIES"}.ignore(pos, expected))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool current = ParserKeyword{"CURRENT"}.ignore(pos, expected);
|
||||||
|
|
||||||
|
String database, table_name;
|
||||||
|
parseONDatabaseAndTableName(pos, expected, database, table_name);
|
||||||
|
|
||||||
|
auto query = std::make_shared<ASTShowRowPoliciesQuery>();
|
||||||
|
query->current = current;
|
||||||
|
query->database = std::move(database);
|
||||||
|
query->table_name = std::move(table_name);
|
||||||
|
node = query;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
17
dbms/src/Parsers/ParserShowRowPoliciesQuery.h
Normal file
17
dbms/src/Parsers/ParserShowRowPoliciesQuery.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Parsers/IParserBase.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace DB
|
||||||
|
{
|
||||||
|
/** Parses queries like
|
||||||
|
* SHOW [ROW] POLICIES [CURRENT] [ON [database.]table]
|
||||||
|
*/
|
||||||
|
class ParserShowRowPoliciesQuery : public IParserBase
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
const char * getName() const override { return "SHOW POLICIES query"; }
|
||||||
|
bool parseImpl(Pos & pos, ASTPtr & node, Expected & expected) override;
|
||||||
|
};
|
||||||
|
}
|
@ -43,10 +43,17 @@ bool ParserSystemQuery::parseImpl(IParser::Pos & pos, ASTPtr & node, Expected &
|
|||||||
{
|
{
|
||||||
case Type::RELOAD_DICTIONARY:
|
case Type::RELOAD_DICTIONARY:
|
||||||
{
|
{
|
||||||
|
String cluster_str;
|
||||||
|
if (ParserKeyword{"ON"}.ignore(pos, expected))
|
||||||
|
{
|
||||||
|
if (!ASTQueryWithOnCluster::parse(pos, cluster_str, expected))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
res->cluster = cluster_str;
|
||||||
ASTPtr ast;
|
ASTPtr ast;
|
||||||
if (ParserStringLiteral{}.parse(pos, ast, expected))
|
if (ParserStringLiteral{}.parse(pos, ast, expected))
|
||||||
res->target_dictionary = ast->as<ASTLiteral &>().value.safeGet<String>();
|
res->target_dictionary = ast->as<ASTLiteral &>().value.safeGet<String>();
|
||||||
else if (!parseDatabaseAndTableName(pos, expected, res->target_database, res->target_dictionary))
|
else if (!parseDatabaseAndTableName(pos, expected, res->database, res->target_dictionary))
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -54,7 +61,7 @@ bool ParserSystemQuery::parseImpl(IParser::Pos & pos, ASTPtr & node, Expected &
|
|||||||
case Type::RESTART_REPLICA:
|
case Type::RESTART_REPLICA:
|
||||||
case Type::SYNC_REPLICA:
|
case Type::SYNC_REPLICA:
|
||||||
case Type::FLUSH_DISTRIBUTED:
|
case Type::FLUSH_DISTRIBUTED:
|
||||||
if (!parseDatabaseAndTableName(pos, expected, res->target_database, res->target_table))
|
if (!parseDatabaseAndTableName(pos, expected, res->database, res->table))
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -72,7 +79,7 @@ bool ParserSystemQuery::parseImpl(IParser::Pos & pos, ASTPtr & node, Expected &
|
|||||||
case Type::START_REPLICATION_QUEUES:
|
case Type::START_REPLICATION_QUEUES:
|
||||||
case Type::STOP_DISTRIBUTED_SENDS:
|
case Type::STOP_DISTRIBUTED_SENDS:
|
||||||
case Type::START_DISTRIBUTED_SENDS:
|
case Type::START_DISTRIBUTED_SENDS:
|
||||||
parseDatabaseAndTableName(pos, expected, res->target_database, res->target_table);
|
parseDatabaseAndTableName(pos, expected, res->database, res->table);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -27,7 +27,7 @@ public:
|
|||||||
|
|
||||||
/** In some usecase (hello Kafka) we need to read a lot of tiny streams in exactly the same format.
|
/** In some usecase (hello Kafka) we need to read a lot of tiny streams in exactly the same format.
|
||||||
* The recreating of parser for each small stream takes too long, so we introduce a method
|
* The recreating of parser for each small stream takes too long, so we introduce a method
|
||||||
* resetParser() which allow to reset the state of parser to continure reading of
|
* resetParser() which allow to reset the state of parser to continue reading of
|
||||||
* source stream w/o recreating that.
|
* source stream w/o recreating that.
|
||||||
* That should be called after current buffer was fully read.
|
* That should be called after current buffer was fully read.
|
||||||
*/
|
*/
|
||||||
|
@ -61,14 +61,14 @@ namespace DB
|
|||||||
|
|
||||||
/// Inserts numeric data right into internal column data to reduce an overhead
|
/// Inserts numeric data right into internal column data to reduce an overhead
|
||||||
template <typename NumericType, typename VectorType = ColumnVector<NumericType>>
|
template <typename NumericType, typename VectorType = ColumnVector<NumericType>>
|
||||||
static void fillColumnWithNumericData(std::shared_ptr<arrow::Column> & arrow_column, MutableColumnPtr & internal_column)
|
static void fillColumnWithNumericData(std::shared_ptr<arrow::ChunkedArray> & arrow_column, MutableColumnPtr & internal_column)
|
||||||
{
|
{
|
||||||
auto & column_data = static_cast<VectorType &>(*internal_column).getData();
|
auto & column_data = static_cast<VectorType &>(*internal_column).getData();
|
||||||
column_data.reserve(arrow_column->length());
|
column_data.reserve(arrow_column->length());
|
||||||
|
|
||||||
for (size_t chunk_i = 0, num_chunks = static_cast<size_t>(arrow_column->data()->num_chunks()); chunk_i < num_chunks; ++chunk_i)
|
for (size_t chunk_i = 0, num_chunks = static_cast<size_t>(arrow_column->num_chunks()); chunk_i < num_chunks; ++chunk_i)
|
||||||
{
|
{
|
||||||
std::shared_ptr<arrow::Array> chunk = arrow_column->data()->chunk(chunk_i);
|
std::shared_ptr<arrow::Array> chunk = arrow_column->chunk(chunk_i);
|
||||||
/// buffers[0] is a null bitmap and buffers[1] are actual values
|
/// buffers[0] is a null bitmap and buffers[1] are actual values
|
||||||
std::shared_ptr<arrow::Buffer> buffer = chunk->data()->buffers[1];
|
std::shared_ptr<arrow::Buffer> buffer = chunk->data()->buffers[1];
|
||||||
|
|
||||||
@ -80,15 +80,15 @@ namespace DB
|
|||||||
/// Inserts chars and offsets right into internal column data to reduce an overhead.
|
/// Inserts chars and offsets right into internal column data to reduce an overhead.
|
||||||
/// Internal offsets are shifted by one to the right in comparison with Arrow ones. So the last offset should map to the end of all chars.
|
/// Internal offsets are shifted by one to the right in comparison with Arrow ones. So the last offset should map to the end of all chars.
|
||||||
/// Also internal strings are null terminated.
|
/// Also internal strings are null terminated.
|
||||||
static void fillColumnWithStringData(std::shared_ptr<arrow::Column> & arrow_column, MutableColumnPtr & internal_column)
|
static void fillColumnWithStringData(std::shared_ptr<arrow::ChunkedArray> & arrow_column, MutableColumnPtr & internal_column)
|
||||||
{
|
{
|
||||||
PaddedPODArray<UInt8> & column_chars_t = assert_cast<ColumnString &>(*internal_column).getChars();
|
PaddedPODArray<UInt8> & column_chars_t = assert_cast<ColumnString &>(*internal_column).getChars();
|
||||||
PaddedPODArray<UInt64> & column_offsets = assert_cast<ColumnString &>(*internal_column).getOffsets();
|
PaddedPODArray<UInt64> & column_offsets = assert_cast<ColumnString &>(*internal_column).getOffsets();
|
||||||
|
|
||||||
size_t chars_t_size = 0;
|
size_t chars_t_size = 0;
|
||||||
for (size_t chunk_i = 0, num_chunks = static_cast<size_t>(arrow_column->data()->num_chunks()); chunk_i < num_chunks; ++chunk_i)
|
for (size_t chunk_i = 0, num_chunks = static_cast<size_t>(arrow_column->num_chunks()); chunk_i < num_chunks; ++chunk_i)
|
||||||
{
|
{
|
||||||
arrow::BinaryArray & chunk = static_cast<arrow::BinaryArray &>(*(arrow_column->data()->chunk(chunk_i)));
|
arrow::BinaryArray & chunk = static_cast<arrow::BinaryArray &>(*(arrow_column->chunk(chunk_i)));
|
||||||
const size_t chunk_length = chunk.length();
|
const size_t chunk_length = chunk.length();
|
||||||
|
|
||||||
chars_t_size += chunk.value_offset(chunk_length - 1) + chunk.value_length(chunk_length - 1);
|
chars_t_size += chunk.value_offset(chunk_length - 1) + chunk.value_length(chunk_length - 1);
|
||||||
@ -98,9 +98,9 @@ namespace DB
|
|||||||
column_chars_t.reserve(chars_t_size);
|
column_chars_t.reserve(chars_t_size);
|
||||||
column_offsets.reserve(arrow_column->length());
|
column_offsets.reserve(arrow_column->length());
|
||||||
|
|
||||||
for (size_t chunk_i = 0, num_chunks = static_cast<size_t>(arrow_column->data()->num_chunks()); chunk_i < num_chunks; ++chunk_i)
|
for (size_t chunk_i = 0, num_chunks = static_cast<size_t>(arrow_column->num_chunks()); chunk_i < num_chunks; ++chunk_i)
|
||||||
{
|
{
|
||||||
arrow::BinaryArray & chunk = static_cast<arrow::BinaryArray &>(*(arrow_column->data()->chunk(chunk_i)));
|
arrow::BinaryArray & chunk = static_cast<arrow::BinaryArray &>(*(arrow_column->chunk(chunk_i)));
|
||||||
std::shared_ptr<arrow::Buffer> buffer = chunk.value_data();
|
std::shared_ptr<arrow::Buffer> buffer = chunk.value_data();
|
||||||
const size_t chunk_length = chunk.length();
|
const size_t chunk_length = chunk.length();
|
||||||
|
|
||||||
@ -118,14 +118,14 @@ namespace DB
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fillColumnWithBooleanData(std::shared_ptr<arrow::Column> & arrow_column, MutableColumnPtr & internal_column)
|
static void fillColumnWithBooleanData(std::shared_ptr<arrow::ChunkedArray> & arrow_column, MutableColumnPtr & internal_column)
|
||||||
{
|
{
|
||||||
auto & column_data = assert_cast<ColumnVector<UInt8> &>(*internal_column).getData();
|
auto & column_data = assert_cast<ColumnVector<UInt8> &>(*internal_column).getData();
|
||||||
column_data.reserve(arrow_column->length());
|
column_data.reserve(arrow_column->length());
|
||||||
|
|
||||||
for (size_t chunk_i = 0, num_chunks = static_cast<size_t>(arrow_column->data()->num_chunks()); chunk_i < num_chunks; ++chunk_i)
|
for (size_t chunk_i = 0, num_chunks = static_cast<size_t>(arrow_column->num_chunks()); chunk_i < num_chunks; ++chunk_i)
|
||||||
{
|
{
|
||||||
arrow::BooleanArray & chunk = static_cast<arrow::BooleanArray &>(*(arrow_column->data()->chunk(chunk_i)));
|
arrow::BooleanArray & chunk = static_cast<arrow::BooleanArray &>(*(arrow_column->chunk(chunk_i)));
|
||||||
/// buffers[0] is a null bitmap and buffers[1] are actual values
|
/// buffers[0] is a null bitmap and buffers[1] are actual values
|
||||||
std::shared_ptr<arrow::Buffer> buffer = chunk.data()->buffers[1];
|
std::shared_ptr<arrow::Buffer> buffer = chunk.data()->buffers[1];
|
||||||
|
|
||||||
@ -135,14 +135,14 @@ namespace DB
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Arrow stores Parquet::DATE in Int32, while ClickHouse stores Date in UInt16. Therefore, it should be checked before saving
|
/// Arrow stores Parquet::DATE in Int32, while ClickHouse stores Date in UInt16. Therefore, it should be checked before saving
|
||||||
static void fillColumnWithDate32Data(std::shared_ptr<arrow::Column> & arrow_column, MutableColumnPtr & internal_column)
|
static void fillColumnWithDate32Data(std::shared_ptr<arrow::ChunkedArray> & arrow_column, MutableColumnPtr & internal_column)
|
||||||
{
|
{
|
||||||
PaddedPODArray<UInt16> & column_data = assert_cast<ColumnVector<UInt16> &>(*internal_column).getData();
|
PaddedPODArray<UInt16> & column_data = assert_cast<ColumnVector<UInt16> &>(*internal_column).getData();
|
||||||
column_data.reserve(arrow_column->length());
|
column_data.reserve(arrow_column->length());
|
||||||
|
|
||||||
for (size_t chunk_i = 0, num_chunks = static_cast<size_t>(arrow_column->data()->num_chunks()); chunk_i < num_chunks; ++chunk_i)
|
for (size_t chunk_i = 0, num_chunks = static_cast<size_t>(arrow_column->num_chunks()); chunk_i < num_chunks; ++chunk_i)
|
||||||
{
|
{
|
||||||
arrow::Date32Array & chunk = static_cast<arrow::Date32Array &>(*(arrow_column->data()->chunk(chunk_i)));
|
arrow::Date32Array & chunk = static_cast<arrow::Date32Array &>(*(arrow_column->chunk(chunk_i)));
|
||||||
|
|
||||||
for (size_t value_i = 0, length = static_cast<size_t>(chunk.length()); value_i < length; ++value_i)
|
for (size_t value_i = 0, length = static_cast<size_t>(chunk.length()); value_i < length; ++value_i)
|
||||||
{
|
{
|
||||||
@ -150,7 +150,7 @@ namespace DB
|
|||||||
if (days_num > DATE_LUT_MAX_DAY_NUM)
|
if (days_num > DATE_LUT_MAX_DAY_NUM)
|
||||||
{
|
{
|
||||||
// TODO: will it rollback correctly?
|
// TODO: will it rollback correctly?
|
||||||
throw Exception{"Input value " + std::to_string(days_num) + " of a column \"" + arrow_column->name()
|
throw Exception{"Input value " + std::to_string(days_num) + " of a column \"" + internal_column->getName()
|
||||||
+ "\" is greater than "
|
+ "\" is greater than "
|
||||||
"max allowed Date value, which is "
|
"max allowed Date value, which is "
|
||||||
+ std::to_string(DATE_LUT_MAX_DAY_NUM),
|
+ std::to_string(DATE_LUT_MAX_DAY_NUM),
|
||||||
@ -163,14 +163,14 @@ namespace DB
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Arrow stores Parquet::DATETIME in Int64, while ClickHouse stores DateTime in UInt32. Therefore, it should be checked before saving
|
/// Arrow stores Parquet::DATETIME in Int64, while ClickHouse stores DateTime in UInt32. Therefore, it should be checked before saving
|
||||||
static void fillColumnWithDate64Data(std::shared_ptr<arrow::Column> & arrow_column, MutableColumnPtr & internal_column)
|
static void fillColumnWithDate64Data(std::shared_ptr<arrow::ChunkedArray> & arrow_column, MutableColumnPtr & internal_column)
|
||||||
{
|
{
|
||||||
auto & column_data = assert_cast<ColumnVector<UInt32> &>(*internal_column).getData();
|
auto & column_data = assert_cast<ColumnVector<UInt32> &>(*internal_column).getData();
|
||||||
column_data.reserve(arrow_column->length());
|
column_data.reserve(arrow_column->length());
|
||||||
|
|
||||||
for (size_t chunk_i = 0, num_chunks = static_cast<size_t>(arrow_column->data()->num_chunks()); chunk_i < num_chunks; ++chunk_i)
|
for (size_t chunk_i = 0, num_chunks = static_cast<size_t>(arrow_column->num_chunks()); chunk_i < num_chunks; ++chunk_i)
|
||||||
{
|
{
|
||||||
auto & chunk = static_cast<arrow::Date64Array &>(*(arrow_column->data()->chunk(chunk_i)));
|
auto & chunk = static_cast<arrow::Date64Array &>(*(arrow_column->chunk(chunk_i)));
|
||||||
for (size_t value_i = 0, length = static_cast<size_t>(chunk.length()); value_i < length; ++value_i)
|
for (size_t value_i = 0, length = static_cast<size_t>(chunk.length()); value_i < length; ++value_i)
|
||||||
{
|
{
|
||||||
auto timestamp = static_cast<UInt32>(chunk.Value(value_i) / 1000); // Always? in ms
|
auto timestamp = static_cast<UInt32>(chunk.Value(value_i) / 1000); // Always? in ms
|
||||||
@ -179,14 +179,14 @@ namespace DB
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fillColumnWithTimestampData(std::shared_ptr<arrow::Column> & arrow_column, MutableColumnPtr & internal_column)
|
static void fillColumnWithTimestampData(std::shared_ptr<arrow::ChunkedArray> & arrow_column, MutableColumnPtr & internal_column)
|
||||||
{
|
{
|
||||||
auto & column_data = assert_cast<ColumnVector<UInt32> &>(*internal_column).getData();
|
auto & column_data = assert_cast<ColumnVector<UInt32> &>(*internal_column).getData();
|
||||||
column_data.reserve(arrow_column->length());
|
column_data.reserve(arrow_column->length());
|
||||||
|
|
||||||
for (size_t chunk_i = 0, num_chunks = static_cast<size_t>(arrow_column->data()->num_chunks()); chunk_i < num_chunks; ++chunk_i)
|
for (size_t chunk_i = 0, num_chunks = static_cast<size_t>(arrow_column->num_chunks()); chunk_i < num_chunks; ++chunk_i)
|
||||||
{
|
{
|
||||||
auto & chunk = static_cast<arrow::TimestampArray &>(*(arrow_column->data()->chunk(chunk_i)));
|
auto & chunk = static_cast<arrow::TimestampArray &>(*(arrow_column->chunk(chunk_i)));
|
||||||
const auto & type = static_cast<const ::arrow::TimestampType &>(*chunk.type());
|
const auto & type = static_cast<const ::arrow::TimestampType &>(*chunk.type());
|
||||||
|
|
||||||
UInt32 divide = 1;
|
UInt32 divide = 1;
|
||||||
@ -215,15 +215,15 @@ namespace DB
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fillColumnWithDecimalData(std::shared_ptr<arrow::Column> & arrow_column, MutableColumnPtr & internal_column)
|
static void fillColumnWithDecimalData(std::shared_ptr<arrow::ChunkedArray> & arrow_column, MutableColumnPtr & internal_column)
|
||||||
{
|
{
|
||||||
auto & column = assert_cast<ColumnDecimal<Decimal128> &>(*internal_column);
|
auto & column = assert_cast<ColumnDecimal<Decimal128> &>(*internal_column);
|
||||||
auto & column_data = column.getData();
|
auto & column_data = column.getData();
|
||||||
column_data.reserve(arrow_column->length());
|
column_data.reserve(arrow_column->length());
|
||||||
|
|
||||||
for (size_t chunk_i = 0, num_chunks = static_cast<size_t>(arrow_column->data()->num_chunks()); chunk_i < num_chunks; ++chunk_i)
|
for (size_t chunk_i = 0, num_chunks = static_cast<size_t>(arrow_column->num_chunks()); chunk_i < num_chunks; ++chunk_i)
|
||||||
{
|
{
|
||||||
auto & chunk = static_cast<arrow::DecimalArray &>(*(arrow_column->data()->chunk(chunk_i)));
|
auto & chunk = static_cast<arrow::DecimalArray &>(*(arrow_column->chunk(chunk_i)));
|
||||||
for (size_t value_i = 0, length = static_cast<size_t>(chunk.length()); value_i < length; ++value_i)
|
for (size_t value_i = 0, length = static_cast<size_t>(chunk.length()); value_i < length; ++value_i)
|
||||||
{
|
{
|
||||||
column_data.emplace_back(chunk.IsNull(value_i) ? Decimal128(0) : *reinterpret_cast<const Decimal128 *>(chunk.Value(value_i))); // TODO: copy column
|
column_data.emplace_back(chunk.IsNull(value_i) ? Decimal128(0) : *reinterpret_cast<const Decimal128 *>(chunk.Value(value_i))); // TODO: copy column
|
||||||
@ -232,14 +232,14 @@ namespace DB
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a null bytemap from arrow's null bitmap
|
/// Creates a null bytemap from arrow's null bitmap
|
||||||
static void fillByteMapFromArrowColumn(std::shared_ptr<arrow::Column> & arrow_column, MutableColumnPtr & bytemap)
|
static void fillByteMapFromArrowColumn(std::shared_ptr<arrow::ChunkedArray> & arrow_column, MutableColumnPtr & bytemap)
|
||||||
{
|
{
|
||||||
PaddedPODArray<UInt8> & bytemap_data = assert_cast<ColumnVector<UInt8> &>(*bytemap).getData();
|
PaddedPODArray<UInt8> & bytemap_data = assert_cast<ColumnVector<UInt8> &>(*bytemap).getData();
|
||||||
bytemap_data.reserve(arrow_column->length());
|
bytemap_data.reserve(arrow_column->length());
|
||||||
|
|
||||||
for (size_t chunk_i = 0; chunk_i != static_cast<size_t>(arrow_column->data()->num_chunks()); ++chunk_i)
|
for (size_t chunk_i = 0; chunk_i != static_cast<size_t>(arrow_column->num_chunks()); ++chunk_i)
|
||||||
{
|
{
|
||||||
std::shared_ptr<arrow::Array> chunk = arrow_column->data()->chunk(chunk_i);
|
std::shared_ptr<arrow::Array> chunk = arrow_column->chunk(chunk_i);
|
||||||
|
|
||||||
for (size_t value_i = 0; value_i != static_cast<size_t>(chunk->length()); ++value_i)
|
for (size_t value_i = 0; value_i != static_cast<size_t>(chunk->length()); ++value_i)
|
||||||
bytemap_data.emplace_back(chunk->IsNull(value_i));
|
bytemap_data.emplace_back(chunk->IsNull(value_i));
|
||||||
@ -255,7 +255,7 @@ namespace DB
|
|||||||
|
|
||||||
columns_list.reserve(header.rows());
|
columns_list.reserve(header.rows());
|
||||||
|
|
||||||
using NameToColumnPtr = std::unordered_map<std::string, std::shared_ptr<arrow::Column>>;
|
using NameToColumnPtr = std::unordered_map<std::string, std::shared_ptr<arrow::ChunkedArray>>;
|
||||||
if (!read_status.ok())
|
if (!read_status.ok())
|
||||||
throw Exception{"Error while reading " + format_name + " data: " + read_status.ToString(),
|
throw Exception{"Error while reading " + format_name + " data: " + read_status.ToString(),
|
||||||
ErrorCodes::CANNOT_READ_ALL_DATA};
|
ErrorCodes::CANNOT_READ_ALL_DATA};
|
||||||
@ -270,10 +270,10 @@ namespace DB
|
|||||||
++row_group_current;
|
++row_group_current;
|
||||||
|
|
||||||
NameToColumnPtr name_to_column_ptr;
|
NameToColumnPtr name_to_column_ptr;
|
||||||
for (size_t i = 0, num_columns = static_cast<size_t>(table->num_columns()); i < num_columns; ++i)
|
for (const auto& column_name : table->ColumnNames())
|
||||||
{
|
{
|
||||||
std::shared_ptr<arrow::Column> arrow_column = table->column(i);
|
std::shared_ptr<arrow::ChunkedArray> arrow_column = table->GetColumnByName(column_name);
|
||||||
name_to_column_ptr[arrow_column->name()] = arrow_column;
|
name_to_column_ptr[column_name] = arrow_column;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t column_i = 0, columns = header.columns(); column_i < columns; ++column_i)
|
for (size_t column_i = 0, columns = header.columns(); column_i < columns; ++column_i)
|
||||||
@ -285,7 +285,7 @@ namespace DB
|
|||||||
throw Exception{"Column \"" + header_column.name + "\" is not presented in input data",
|
throw Exception{"Column \"" + header_column.name + "\" is not presented in input data",
|
||||||
ErrorCodes::THERE_IS_NO_COLUMN};
|
ErrorCodes::THERE_IS_NO_COLUMN};
|
||||||
|
|
||||||
std::shared_ptr<arrow::Column> arrow_column = name_to_column_ptr[header_column.name];
|
std::shared_ptr<arrow::ChunkedArray> arrow_column = name_to_column_ptr[header_column.name];
|
||||||
arrow::Type::type arrow_type = arrow_column->type()->id();
|
arrow::Type::type arrow_type = arrow_column->type()->id();
|
||||||
|
|
||||||
// TODO: check if a column is const?
|
// TODO: check if a column is const?
|
||||||
@ -313,7 +313,7 @@ namespace DB
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw Exception{"The type \"" + arrow_column->type()->name() + "\" of an input column \"" + arrow_column->name()
|
throw Exception{"The type \"" + arrow_column->type()->name() + "\" of an input column \"" + header_column.name
|
||||||
+ "\" is not supported for conversion from a " + format_name + " data format",
|
+ "\" is not supported for conversion from a " + format_name + " data format",
|
||||||
ErrorCodes::CANNOT_CONVERT_TYPE};
|
ErrorCodes::CANNOT_CONVERT_TYPE};
|
||||||
}
|
}
|
||||||
@ -374,7 +374,7 @@ namespace DB
|
|||||||
throw Exception
|
throw Exception
|
||||||
{
|
{
|
||||||
"Unsupported " + format_name + " type \"" + arrow_column->type()->name() + "\" of an input column \""
|
"Unsupported " + format_name + " type \"" + arrow_column->type()->name() + "\" of an input column \""
|
||||||
+ arrow_column->name() + "\"",
|
+ header_column.name + "\"",
|
||||||
ErrorCodes::UNKNOWN_TYPE
|
ErrorCodes::UNKNOWN_TYPE
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -45,9 +45,11 @@ namespace DB
|
|||||||
|
|
||||||
buffer = std::make_unique<arrow::Buffer>(file_data);
|
buffer = std::make_unique<arrow::Buffer>(file_data);
|
||||||
// TODO: maybe use parquet::RandomAccessSource?
|
// TODO: maybe use parquet::RandomAccessSource?
|
||||||
auto reader = parquet::ParquetFileReader::Open(std::make_shared<::arrow::io::BufferReader>(*buffer));
|
auto status = parquet::arrow::FileReader::Make(
|
||||||
file_reader = std::make_unique<parquet::arrow::FileReader>(::arrow::default_memory_pool(),
|
::arrow::default_memory_pool(),
|
||||||
std::move(reader));
|
parquet::ParquetFileReader::Open(std::make_shared<::arrow::io::BufferReader>(*buffer)),
|
||||||
|
&file_reader);
|
||||||
|
|
||||||
row_group_total = file_reader->num_row_groups();
|
row_group_total = file_reader->num_row_groups();
|
||||||
row_group_current = 0;
|
row_group_current = 0;
|
||||||
}
|
}
|
||||||
|
@ -21,9 +21,10 @@
|
|||||||
#include <arrow/api.h>
|
#include <arrow/api.h>
|
||||||
#include <arrow/io/api.h>
|
#include <arrow/io/api.h>
|
||||||
#include <arrow/util/decimal.h>
|
#include <arrow/util/decimal.h>
|
||||||
|
#include <arrow/util/memory.h>
|
||||||
#include <parquet/arrow/writer.h>
|
#include <parquet/arrow/writer.h>
|
||||||
#include <parquet/exception.h>
|
#include <parquet/exception.h>
|
||||||
#include <parquet/util/memory.h>
|
#include <parquet/deprecated_io.h>
|
||||||
|
|
||||||
|
|
||||||
namespace DB
|
namespace DB
|
||||||
@ -238,22 +239,39 @@ static const PaddedPODArray<UInt8> * extractNullBytemapPtr(ColumnPtr column)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class OstreamOutputStream : public parquet::OutputStream
|
class OstreamOutputStream : public arrow::io::OutputStream
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit OstreamOutputStream(WriteBuffer & ostr_) : ostr(ostr_) {}
|
explicit OstreamOutputStream(WriteBuffer & ostr_) : ostr(ostr_) { is_open = true; }
|
||||||
virtual ~OstreamOutputStream() {}
|
~OstreamOutputStream() override {}
|
||||||
virtual void Close() {}
|
|
||||||
virtual int64_t Tell() { return total_length; }
|
// FileInterface
|
||||||
virtual void Write(const uint8_t * data, int64_t length)
|
::arrow::Status Close() override
|
||||||
|
{
|
||||||
|
is_open = false;
|
||||||
|
return ::arrow::Status::OK();
|
||||||
|
}
|
||||||
|
|
||||||
|
::arrow::Status Tell(int64_t* position) const override
|
||||||
|
{
|
||||||
|
*position = total_length;
|
||||||
|
return ::arrow::Status::OK();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool closed() const override { return !is_open; }
|
||||||
|
|
||||||
|
// Writable
|
||||||
|
::arrow::Status Write(const void* data, int64_t length) override
|
||||||
{
|
{
|
||||||
ostr.write(reinterpret_cast<const char *>(data), length);
|
ostr.write(reinterpret_cast<const char *>(data), length);
|
||||||
total_length += length;
|
total_length += length;
|
||||||
|
return ::arrow::Status::OK();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
WriteBuffer & ostr;
|
WriteBuffer & ostr;
|
||||||
int64_t total_length = 0;
|
int64_t total_length = 0;
|
||||||
|
bool is_open = false;
|
||||||
|
|
||||||
PARQUET_DISALLOW_COPY_AND_ASSIGN(OstreamOutputStream);
|
PARQUET_DISALLOW_COPY_AND_ASSIGN(OstreamOutputStream);
|
||||||
};
|
};
|
||||||
@ -396,7 +414,6 @@ void ParquetBlockOutputFormat::consume(Chunk chunk)
|
|||||||
arrow::default_memory_pool(),
|
arrow::default_memory_pool(),
|
||||||
sink,
|
sink,
|
||||||
props, /*parquet::default_writer_properties(),*/
|
props, /*parquet::default_writer_properties(),*/
|
||||||
parquet::arrow::default_arrow_writer_properties(),
|
|
||||||
&file_writer);
|
&file_writer);
|
||||||
if (!status.ok())
|
if (!status.ok())
|
||||||
throw Exception{"Error while opening a table: " + status.ToString(), ErrorCodes::UNKNOWN_EXCEPTION};
|
throw Exception{"Error while opening a table: " + status.ToString(), ErrorCodes::UNKNOWN_EXCEPTION};
|
||||||
|
@ -51,11 +51,12 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
#include <optional>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
#include <typeindex>
|
#include <typeindex>
|
||||||
#include <optional>
|
#include <unordered_set>
|
||||||
|
|
||||||
|
|
||||||
namespace ProfileEvents
|
namespace ProfileEvents
|
||||||
@ -637,11 +638,22 @@ void MergeTreeData::setTTLExpressions(const ColumnsDescription::ColumnTTLs & new
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto new_ttl_entry = create_ttl_entry(ttl_element.children[0]);
|
auto new_ttl_entry = create_ttl_entry(ttl_element.children[0]);
|
||||||
|
|
||||||
|
new_ttl_entry.entry_ast = ttl_element_ptr;
|
||||||
|
new_ttl_entry.destination_type = ttl_element.destination_type;
|
||||||
|
new_ttl_entry.destination_name = ttl_element.destination_name;
|
||||||
|
if (!new_ttl_entry.getDestination(getStoragePolicy()))
|
||||||
|
{
|
||||||
|
String message;
|
||||||
|
if (new_ttl_entry.destination_type == PartDestinationType::DISK)
|
||||||
|
message = "No such disk " + backQuote(new_ttl_entry.destination_name) + " for given storage policy.";
|
||||||
|
else
|
||||||
|
message = "No such volume " + backQuote(new_ttl_entry.destination_name) + " for given storage policy.";
|
||||||
|
throw Exception(message, ErrorCodes::BAD_TTL_EXPRESSION);
|
||||||
|
}
|
||||||
|
|
||||||
if (!only_check)
|
if (!only_check)
|
||||||
{
|
{
|
||||||
new_ttl_entry.entry_ast = ttl_element_ptr;
|
|
||||||
new_ttl_entry.destination_type = ttl_element.destination_type;
|
|
||||||
new_ttl_entry.destination_name = ttl_element.destination_name;
|
|
||||||
move_ttl_entries.emplace_back(std::move(new_ttl_entry));
|
move_ttl_entries.emplace_back(std::move(new_ttl_entry));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -791,6 +803,27 @@ void MergeTreeData::loadDataParts(bool skip_sanity_checks)
|
|||||||
|
|
||||||
auto disks = storage_policy->getDisks();
|
auto disks = storage_policy->getDisks();
|
||||||
|
|
||||||
|
if (getStoragePolicy()->getName() != "default")
|
||||||
|
{
|
||||||
|
/// Check extra parts at different disks, in order to not allow to miss data parts at undefined disks.
|
||||||
|
std::unordered_set<String> defined_disk_names;
|
||||||
|
for (const auto & disk_ptr : disks)
|
||||||
|
defined_disk_names.insert(disk_ptr->getName());
|
||||||
|
|
||||||
|
for (auto & [disk_name, disk_ptr] : global_context.getDiskSelector().getDisksMap())
|
||||||
|
{
|
||||||
|
if (defined_disk_names.count(disk_name) == 0 && Poco::File(getFullPathOnDisk(disk_ptr)).exists())
|
||||||
|
{
|
||||||
|
for (Poco::DirectoryIterator it(getFullPathOnDisk(disk_ptr)); it != end; ++it)
|
||||||
|
{
|
||||||
|
MergeTreePartInfo part_info;
|
||||||
|
if (MergeTreePartInfo::tryParsePartName(it.name(), &part_info, format_version))
|
||||||
|
throw Exception("Part " + backQuote(it.name()) + " was found on disk " + backQuote(disk_name) + " which is not defined in the storage policy", ErrorCodes::UNKNOWN_DISK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Reversed order to load part from low priority disks firstly.
|
/// Reversed order to load part from low priority disks firstly.
|
||||||
/// Used for keep part on low priority disk if duplication found
|
/// Used for keep part on low priority disk if duplication found
|
||||||
for (auto disk_it = disks.rbegin(); disk_it != disks.rend(); ++disk_it)
|
for (auto disk_it = disks.rbegin(); disk_it != disks.rend(); ++disk_it)
|
||||||
|
@ -70,7 +70,7 @@ void StorageJoin::truncate(const ASTPtr &, const Context &, TableStructureWriteL
|
|||||||
|
|
||||||
HashJoinPtr StorageJoin::getJoin(std::shared_ptr<AnalyzedJoin> analyzed_join) const
|
HashJoinPtr StorageJoin::getJoin(std::shared_ptr<AnalyzedJoin> analyzed_join) const
|
||||||
{
|
{
|
||||||
if (!(kind == analyzed_join->kind() && strictness == analyzed_join->strictness()))
|
if (kind != analyzed_join->kind() || strictness != analyzed_join->strictness())
|
||||||
throw Exception("Table " + table_name + " has incompatible type of JOIN.", ErrorCodes::INCOMPATIBLE_TYPE_OF_JOIN);
|
throw Exception("Table " + table_name + " has incompatible type of JOIN.", ErrorCodes::INCOMPATIBLE_TYPE_OF_JOIN);
|
||||||
|
|
||||||
/// TODO: check key columns
|
/// TODO: check key columns
|
||||||
@ -96,58 +96,14 @@ void registerStorageJoin(StorageFactory & factory)
|
|||||||
|
|
||||||
ASTs & engine_args = args.engine_args;
|
ASTs & engine_args = args.engine_args;
|
||||||
|
|
||||||
if (engine_args.size() < 3)
|
|
||||||
throw Exception(
|
|
||||||
"Storage Join requires at least 3 parameters: Join(ANY|ALL, LEFT|INNER, keys...).",
|
|
||||||
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
|
||||||
|
|
||||||
auto opt_strictness_id = tryGetIdentifierName(engine_args[0]);
|
|
||||||
if (!opt_strictness_id)
|
|
||||||
throw Exception("First parameter of storage Join must be ANY or ALL (without quotes).", ErrorCodes::BAD_ARGUMENTS);
|
|
||||||
|
|
||||||
const String strictness_str = Poco::toLower(*opt_strictness_id);
|
|
||||||
ASTTableJoin::Strictness strictness;
|
|
||||||
if (strictness_str == "any")
|
|
||||||
strictness = ASTTableJoin::Strictness::RightAny;
|
|
||||||
else if (strictness_str == "all")
|
|
||||||
strictness = ASTTableJoin::Strictness::All;
|
|
||||||
else
|
|
||||||
throw Exception("First parameter of storage Join must be ANY or ALL (without quotes).", ErrorCodes::BAD_ARGUMENTS);
|
|
||||||
|
|
||||||
auto opt_kind_id = tryGetIdentifierName(engine_args[1]);
|
|
||||||
if (!opt_kind_id)
|
|
||||||
throw Exception("Second parameter of storage Join must be LEFT or INNER (without quotes).", ErrorCodes::BAD_ARGUMENTS);
|
|
||||||
|
|
||||||
const String kind_str = Poco::toLower(*opt_kind_id);
|
|
||||||
ASTTableJoin::Kind kind;
|
|
||||||
if (kind_str == "left")
|
|
||||||
kind = ASTTableJoin::Kind::Left;
|
|
||||||
else if (kind_str == "inner")
|
|
||||||
kind = ASTTableJoin::Kind::Inner;
|
|
||||||
else if (kind_str == "right")
|
|
||||||
kind = ASTTableJoin::Kind::Right;
|
|
||||||
else if (kind_str == "full")
|
|
||||||
kind = ASTTableJoin::Kind::Full;
|
|
||||||
else
|
|
||||||
throw Exception("Second parameter of storage Join must be LEFT or INNER or RIGHT or FULL (without quotes).", ErrorCodes::BAD_ARGUMENTS);
|
|
||||||
|
|
||||||
Names key_names;
|
|
||||||
key_names.reserve(engine_args.size() - 2);
|
|
||||||
for (size_t i = 2, size = engine_args.size(); i < size; ++i)
|
|
||||||
{
|
|
||||||
auto opt_key = tryGetIdentifierName(engine_args[i]);
|
|
||||||
if (!opt_key)
|
|
||||||
throw Exception("Parameter №" + toString(i + 1) + " of storage Join don't look like column name.", ErrorCodes::BAD_ARGUMENTS);
|
|
||||||
|
|
||||||
key_names.push_back(*opt_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto & settings = args.context.getSettingsRef();
|
auto & settings = args.context.getSettingsRef();
|
||||||
|
|
||||||
auto join_use_nulls = settings.join_use_nulls;
|
auto join_use_nulls = settings.join_use_nulls;
|
||||||
auto max_rows_in_join = settings.max_rows_in_join;
|
auto max_rows_in_join = settings.max_rows_in_join;
|
||||||
auto max_bytes_in_join = settings.max_bytes_in_join;
|
auto max_bytes_in_join = settings.max_bytes_in_join;
|
||||||
auto join_overflow_mode = settings.join_overflow_mode;
|
auto join_overflow_mode = settings.join_overflow_mode;
|
||||||
auto join_any_take_last_row = settings.join_any_take_last_row;
|
auto join_any_take_last_row = settings.join_any_take_last_row;
|
||||||
|
auto old_any_join = settings.any_join_distinct_right_table_keys;
|
||||||
|
|
||||||
if (args.storage_def && args.storage_def->settings)
|
if (args.storage_def && args.storage_def->settings)
|
||||||
{
|
{
|
||||||
@ -163,6 +119,8 @@ void registerStorageJoin(StorageFactory & factory)
|
|||||||
join_overflow_mode.set(setting.value);
|
join_overflow_mode.set(setting.value);
|
||||||
else if (setting.name == "join_any_take_last_row")
|
else if (setting.name == "join_any_take_last_row")
|
||||||
join_any_take_last_row.set(setting.value);
|
join_any_take_last_row.set(setting.value);
|
||||||
|
else if (setting.name == "any_join_distinct_right_table_keys")
|
||||||
|
old_any_join.set(setting.value);
|
||||||
else
|
else
|
||||||
throw Exception(
|
throw Exception(
|
||||||
"Unknown setting " + setting.name + " for storage " + args.engine_name,
|
"Unknown setting " + setting.name + " for storage " + args.engine_name,
|
||||||
@ -170,6 +128,68 @@ void registerStorageJoin(StorageFactory & factory)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (engine_args.size() < 3)
|
||||||
|
throw Exception(
|
||||||
|
"Storage Join requires at least 3 parameters: Join(ANY|ALL|SEMI|ANTI, LEFT|INNER|RIGHT, keys...).",
|
||||||
|
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH);
|
||||||
|
|
||||||
|
ASTTableJoin::Strictness strictness = ASTTableJoin::Strictness::Unspecified;
|
||||||
|
ASTTableJoin::Kind kind = ASTTableJoin::Kind::Comma;
|
||||||
|
|
||||||
|
if (auto opt_strictness_id = tryGetIdentifierName(engine_args[0]))
|
||||||
|
{
|
||||||
|
const String strictness_str = Poco::toLower(*opt_strictness_id);
|
||||||
|
|
||||||
|
if (strictness_str == "any" || strictness_str == "\'any\'")
|
||||||
|
{
|
||||||
|
if (old_any_join)
|
||||||
|
strictness = ASTTableJoin::Strictness::RightAny;
|
||||||
|
else
|
||||||
|
strictness = ASTTableJoin::Strictness::Any;
|
||||||
|
}
|
||||||
|
else if (strictness_str == "all" || strictness_str == "\'all\'")
|
||||||
|
strictness = ASTTableJoin::Strictness::All;
|
||||||
|
else if (strictness_str == "semi" || strictness_str == "\'semi\'")
|
||||||
|
strictness = ASTTableJoin::Strictness::Semi;
|
||||||
|
else if (strictness_str == "anti" || strictness_str == "\'anti\'")
|
||||||
|
strictness = ASTTableJoin::Strictness::Anti;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strictness == ASTTableJoin::Strictness::Unspecified)
|
||||||
|
throw Exception("First parameter of storage Join must be ANY or ALL or SEMI or ANTI.", ErrorCodes::BAD_ARGUMENTS);
|
||||||
|
|
||||||
|
if (auto opt_kind_id = tryGetIdentifierName(engine_args[1]))
|
||||||
|
{
|
||||||
|
const String kind_str = Poco::toLower(*opt_kind_id);
|
||||||
|
|
||||||
|
if (kind_str == "left" || kind_str == "\'left\'")
|
||||||
|
kind = ASTTableJoin::Kind::Left;
|
||||||
|
else if (kind_str == "inner" || kind_str == "\'inner\'")
|
||||||
|
kind = ASTTableJoin::Kind::Inner;
|
||||||
|
else if (kind_str == "right" || kind_str == "\'right\'")
|
||||||
|
kind = ASTTableJoin::Kind::Right;
|
||||||
|
else if (kind_str == "full" || kind_str == "\'full\'")
|
||||||
|
{
|
||||||
|
if (strictness == ASTTableJoin::Strictness::Any)
|
||||||
|
strictness = ASTTableJoin::Strictness::RightAny;
|
||||||
|
kind = ASTTableJoin::Kind::Full;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kind == ASTTableJoin::Kind::Comma)
|
||||||
|
throw Exception("Second parameter of storage Join must be LEFT or INNER or RIGHT or FULL.", ErrorCodes::BAD_ARGUMENTS);
|
||||||
|
|
||||||
|
Names key_names;
|
||||||
|
key_names.reserve(engine_args.size() - 2);
|
||||||
|
for (size_t i = 2, size = engine_args.size(); i < size; ++i)
|
||||||
|
{
|
||||||
|
auto opt_key = tryGetIdentifierName(engine_args[i]);
|
||||||
|
if (!opt_key)
|
||||||
|
throw Exception("Parameter №" + toString(i + 1) + " of storage Join don't look like column name.", ErrorCodes::BAD_ARGUMENTS);
|
||||||
|
|
||||||
|
key_names.push_back(*opt_key);
|
||||||
|
}
|
||||||
|
|
||||||
return StorageJoin::create(
|
return StorageJoin::create(
|
||||||
args.relative_data_path,
|
args.relative_data_path,
|
||||||
args.database_name,
|
args.database_name,
|
||||||
@ -246,8 +266,8 @@ protected:
|
|||||||
|
|
||||||
Block block;
|
Block block;
|
||||||
if (!joinDispatch(parent.kind, parent.strictness, parent.data->maps,
|
if (!joinDispatch(parent.kind, parent.strictness, parent.data->maps,
|
||||||
[&](auto, auto strictness, auto & map) { block = createBlock<strictness>(map); }))
|
[&](auto kind, auto strictness, auto & map) { block = createBlock<kind, strictness>(map); }))
|
||||||
throw Exception("Logical error: unknown JOIN strictness (must be ANY or ALL)", ErrorCodes::LOGICAL_ERROR);
|
throw Exception("Logical error: unknown JOIN strictness", ErrorCodes::LOGICAL_ERROR);
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,7 +285,7 @@ private:
|
|||||||
std::unique_ptr<void, std::function<void(void *)>> position; /// type erasure
|
std::unique_ptr<void, std::function<void(void *)>> position; /// type erasure
|
||||||
|
|
||||||
|
|
||||||
template <ASTTableJoin::Strictness STRICTNESS, typename Maps>
|
template <ASTTableJoin::Kind KIND, ASTTableJoin::Strictness STRICTNESS, typename Maps>
|
||||||
Block createBlock(const Maps & maps)
|
Block createBlock(const Maps & maps)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < sample_block.columns(); ++i)
|
for (size_t i = 0; i < sample_block.columns(); ++i)
|
||||||
@ -292,7 +312,7 @@ private:
|
|||||||
{
|
{
|
||||||
#define M(TYPE) \
|
#define M(TYPE) \
|
||||||
case Join::Type::TYPE: \
|
case Join::Type::TYPE: \
|
||||||
rows_added = fillColumns<STRICTNESS>(*maps.TYPE); \
|
rows_added = fillColumns<KIND, STRICTNESS>(*maps.TYPE); \
|
||||||
break;
|
break;
|
||||||
APPLY_FOR_JOIN_VARIANTS_LIMITED(M)
|
APPLY_FOR_JOIN_VARIANTS_LIMITED(M)
|
||||||
#undef M
|
#undef M
|
||||||
@ -323,8 +343,7 @@ private:
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <ASTTableJoin::Kind KIND, ASTTableJoin::Strictness STRICTNESS, typename Map>
|
||||||
template <ASTTableJoin::Strictness STRICTNESS, typename Map>
|
|
||||||
size_t fillColumns(const Map & map)
|
size_t fillColumns(const Map & map)
|
||||||
{
|
{
|
||||||
size_t rows_added = 0;
|
size_t rows_added = 0;
|
||||||
@ -341,34 +360,35 @@ private:
|
|||||||
{
|
{
|
||||||
if constexpr (STRICTNESS == ASTTableJoin::Strictness::RightAny)
|
if constexpr (STRICTNESS == ASTTableJoin::Strictness::RightAny)
|
||||||
{
|
{
|
||||||
for (size_t j = 0; j < columns.size(); ++j)
|
fillOne<Map>(columns, column_indices, it, key_pos, rows_added);
|
||||||
if (j == key_pos)
|
}
|
||||||
columns[j]->insertData(rawData(it->getKey()), rawSize(it->getKey()));
|
else if constexpr (STRICTNESS == ASTTableJoin::Strictness::All)
|
||||||
else
|
{
|
||||||
columns[j]->insertFrom(*it->getMapped().block->getByPosition(column_indices[j]).column.get(), it->getMapped().row_num);
|
fillAll<Map>(columns, column_indices, it, key_pos, rows_added);
|
||||||
++rows_added;
|
|
||||||
}
|
}
|
||||||
else if constexpr (STRICTNESS == ASTTableJoin::Strictness::Any)
|
else if constexpr (STRICTNESS == ASTTableJoin::Strictness::Any)
|
||||||
{
|
{
|
||||||
throw Exception("New ANY join storage is not implemented yet (set any_join_distinct_right_table_keys=1 to use old one)",
|
if constexpr (KIND == ASTTableJoin::Kind::Left || KIND == ASTTableJoin::Kind::Inner)
|
||||||
ErrorCodes::NOT_IMPLEMENTED);
|
fillOne<Map>(columns, column_indices, it, key_pos, rows_added);
|
||||||
|
else if constexpr (KIND == ASTTableJoin::Kind::Right)
|
||||||
|
fillAll<Map>(columns, column_indices, it, key_pos, rows_added);
|
||||||
}
|
}
|
||||||
else if constexpr (STRICTNESS == ASTTableJoin::Strictness::Asof ||
|
else if constexpr (STRICTNESS == ASTTableJoin::Strictness::Semi)
|
||||||
STRICTNESS == ASTTableJoin::Strictness::Semi ||
|
|
||||||
STRICTNESS == ASTTableJoin::Strictness::Anti)
|
|
||||||
{
|
{
|
||||||
throw Exception("ASOF|SEMI|ANTI join storage is not implemented yet", ErrorCodes::NOT_IMPLEMENTED);
|
if constexpr (KIND == ASTTableJoin::Kind::Left)
|
||||||
|
fillOne<Map>(columns, column_indices, it, key_pos, rows_added);
|
||||||
|
else if constexpr (KIND == ASTTableJoin::Kind::Right)
|
||||||
|
fillAll<Map>(columns, column_indices, it, key_pos, rows_added);
|
||||||
|
}
|
||||||
|
else if constexpr (STRICTNESS == ASTTableJoin::Strictness::Anti)
|
||||||
|
{
|
||||||
|
if constexpr (KIND == ASTTableJoin::Kind::Left)
|
||||||
|
fillOne<Map>(columns, column_indices, it, key_pos, rows_added);
|
||||||
|
else if constexpr (KIND == ASTTableJoin::Kind::Right)
|
||||||
|
fillAll<Map>(columns, column_indices, it, key_pos, rows_added);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
for (auto ref_it = it->getMapped().begin(); ref_it.ok(); ++ref_it)
|
throw Exception("This JOIN is not implemented yet", ErrorCodes::NOT_IMPLEMENTED);
|
||||||
{
|
|
||||||
for (size_t j = 0; j < columns.size(); ++j)
|
|
||||||
if (j == key_pos)
|
|
||||||
columns[j]->insertData(rawData(it->getKey()), rawSize(it->getKey()));
|
|
||||||
else
|
|
||||||
columns[j]->insertFrom(*ref_it->block->getByPosition(column_indices[j]).column.get(), ref_it->row_num);
|
|
||||||
++rows_added;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rows_added >= max_block_size)
|
if (rows_added >= max_block_size)
|
||||||
{
|
{
|
||||||
@ -379,6 +399,33 @@ private:
|
|||||||
|
|
||||||
return rows_added;
|
return rows_added;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Map>
|
||||||
|
static void fillOne(MutableColumns & columns, const ColumnNumbers & column_indices, typename Map::const_iterator & it,
|
||||||
|
const std::optional<size_t> & key_pos, size_t & rows_added)
|
||||||
|
{
|
||||||
|
for (size_t j = 0; j < columns.size(); ++j)
|
||||||
|
if (j == key_pos)
|
||||||
|
columns[j]->insertData(rawData(it->getKey()), rawSize(it->getKey()));
|
||||||
|
else
|
||||||
|
columns[j]->insertFrom(*it->getMapped().block->getByPosition(column_indices[j]).column.get(), it->getMapped().row_num);
|
||||||
|
++rows_added;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Map>
|
||||||
|
static void fillAll(MutableColumns & columns, const ColumnNumbers & column_indices, typename Map::const_iterator & it,
|
||||||
|
const std::optional<size_t> & key_pos, size_t & rows_added)
|
||||||
|
{
|
||||||
|
for (auto ref_it = it->getMapped().begin(); ref_it.ok(); ++ref_it)
|
||||||
|
{
|
||||||
|
for (size_t j = 0; j < columns.size(); ++j)
|
||||||
|
if (j == key_pos)
|
||||||
|
columns[j]->insertData(rawData(it->getKey()), rawSize(it->getKey()));
|
||||||
|
else
|
||||||
|
columns[j]->insertFrom(*ref_it->block->getByPosition(column_indices[j]).column.get(), ref_it->row_num);
|
||||||
|
++rows_added;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -196,7 +196,7 @@ BlockInputStreams IStorageURLBase::read(const Names & column_names,
|
|||||||
context,
|
context,
|
||||||
max_block_size,
|
max_block_size,
|
||||||
ConnectionTimeouts::getHTTPTimeouts(context),
|
ConnectionTimeouts::getHTTPTimeouts(context),
|
||||||
IStorage::chooseCompressionMethod(request_uri.toString(), compression_method));
|
IStorage::chooseCompressionMethod(request_uri.getPath(), compression_method));
|
||||||
|
|
||||||
auto column_defaults = getColumns().getDefaults();
|
auto column_defaults = getColumns().getDefaults();
|
||||||
if (column_defaults.empty())
|
if (column_defaults.empty())
|
||||||
|
59
dbms/src/Storages/System/StorageSystemRowPolicies.cpp
Normal file
59
dbms/src/Storages/System/StorageSystemRowPolicies.cpp
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#include <Storages/System/StorageSystemRowPolicies.h>
|
||||||
|
#include <DataTypes/DataTypeString.h>
|
||||||
|
#include <DataTypes/DataTypesNumber.h>
|
||||||
|
#include <DataTypes/DataTypeUUID.h>
|
||||||
|
#include <DataTypes/DataTypeDateTime.h>
|
||||||
|
#include <DataTypes/DataTypeNullable.h>
|
||||||
|
#include <Interpreters/Context.h>
|
||||||
|
#include <Access/AccessControlManager.h>
|
||||||
|
#include <Access/RowPolicy.h>
|
||||||
|
#include <ext/range.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace DB
|
||||||
|
{
|
||||||
|
NamesAndTypesList StorageSystemRowPolicies::getNamesAndTypes()
|
||||||
|
{
|
||||||
|
NamesAndTypesList names_and_types{
|
||||||
|
{"database", std::make_shared<DataTypeString>()},
|
||||||
|
{"table", std::make_shared<DataTypeString>()},
|
||||||
|
{"name", std::make_shared<DataTypeString>()},
|
||||||
|
{"full_name", std::make_shared<DataTypeString>()},
|
||||||
|
{"id", std::make_shared<DataTypeUUID>()},
|
||||||
|
{"source", std::make_shared<DataTypeString>()},
|
||||||
|
{"restrictive", std::make_shared<DataTypeUInt8>()},
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto index : ext::range_with_static_cast<RowPolicy::ConditionIndex>(RowPolicy::MAX_CONDITION_INDEX))
|
||||||
|
names_and_types.push_back({RowPolicy::conditionIndexToColumnName(index), std::make_shared<DataTypeString>()});
|
||||||
|
|
||||||
|
return names_and_types;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void StorageSystemRowPolicies::fillData(MutableColumns & res_columns, const Context & context, const SelectQueryInfo &) const
|
||||||
|
{
|
||||||
|
const auto & access_control = context.getAccessControlManager();
|
||||||
|
std::vector<UUID> ids = access_control.findAll<RowPolicy>();
|
||||||
|
|
||||||
|
for (const auto & id : ids)
|
||||||
|
{
|
||||||
|
auto policy = access_control.tryRead<RowPolicy>(id);
|
||||||
|
if (!policy)
|
||||||
|
continue;
|
||||||
|
const auto * storage = access_control.findStorage(id);
|
||||||
|
|
||||||
|
size_t i = 0;
|
||||||
|
res_columns[i++]->insert(policy->getDatabase());
|
||||||
|
res_columns[i++]->insert(policy->getTableName());
|
||||||
|
res_columns[i++]->insert(policy->getName());
|
||||||
|
res_columns[i++]->insert(policy->getFullName());
|
||||||
|
res_columns[i++]->insert(id);
|
||||||
|
res_columns[i++]->insert(storage ? storage->getStorageName() : "");
|
||||||
|
res_columns[i++]->insert(policy->isRestrictive());
|
||||||
|
|
||||||
|
for (auto index : ext::range(RowPolicy::MAX_CONDITION_INDEX))
|
||||||
|
res_columns[i++]->insert(policy->conditions[index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user