diff --git a/storage/tianchi/sql/extra_defs.h b/storage/tianchi/sql/extra_defs.h new file mode 100644 index 0000000000000000000000000000000000000000..eddc4c418f4ca30871ade65f3e53973b8c131c7f --- /dev/null +++ b/storage/tianchi/sql/extra_defs.h @@ -0,0 +1,28 @@ +typedef float rec_per_key_t; +constexpr const int DATETIME_MAX_DECIMALS = 6; +void set_records_per_key(KEY *key, uint key_part_no, ulong rec_per_key_est); +bool field_has_flag(const Field *fld, int flag_bit); + +/** + Predicate which returns true if at least one of the date members are non-zero. + + @param my_time time point to check. + @retval false if all the date members are zero + @retval true otherwise + */ +static inline bool non_zero_date(const MYSQL_TIME &my_time) { + return my_time.year || my_time.month || my_time.day; +} + +/** + Predicate which returns true if at least one of the time members are non-zero. + + @param my_time time point to check. + @retval false if all the time members are zero + @retval true otherwise +*/ +static inline bool non_zero_time(const MYSQL_TIME &my_time) { + return my_time.hour || my_time.minute || my_time.second || + my_time.second_part; +} + diff --git a/storage/tianchi/sql/field_common_properties.h b/storage/tianchi/sql/field_common_properties.h new file mode 100644 index 0000000000000000000000000000000000000000..5e08d7ae7b18277fa4a49ebdcb87c9fd4aeb04c3 --- /dev/null +++ b/storage/tianchi/sql/field_common_properties.h @@ -0,0 +1,201 @@ +/* Copyright (c) 2020, 2021, Oracle and/or its affiliates. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef FIELD_COMMON_OPERATIONS_INCLUDED +#define FIELD_COMMON_OPERATIONS_INCLUDED + +#include "mysql_com.h" + +/** + @file field_common_properties.h + + @brief This file contains basic method for field types. + + @note This file can be imported from both the server and + tools like mysqlbinlog, hence its simplicity +*/ + +/** + Tests if field type is an integer + + @param type Field type, as returned by field->type() + + @returns true if integer type, false otherwise + */ +inline bool is_integer_type(enum_field_types type) { + switch (type) { + case MYSQL_TYPE_TINY: + case MYSQL_TYPE_SHORT: + case MYSQL_TYPE_INT24: + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_LONGLONG: + return true; + default: + return false; + } +} + +/** + Tests if field type is a numeric type + + @param type Field type, as returned by field->type() + + @returns true if numeric type, false otherwise +*/ +inline bool is_numeric_type(enum_field_types type) { + switch (type) { + case MYSQL_TYPE_TINY: + case MYSQL_TYPE_SHORT: + case MYSQL_TYPE_INT24: + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_LONGLONG: + case MYSQL_TYPE_FLOAT: + case MYSQL_TYPE_DOUBLE: + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: + return true; + default: + return false; + } +} + +/** + Tests if field type is a string type + + @param type Field type, as returned by field->type() + + @returns true if string type, false otherwise +*/ +inline bool is_string_type(enum_field_types type) { + switch (type) { + case MYSQL_TYPE_VARCHAR: + case MYSQL_TYPE_VAR_STRING: + case MYSQL_TYPE_STRING: + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_SET: + //case MYSQL_TYPE_JSON: + return true; + default: + return false; + } +} + +/** + Tests if field type is temporal, i.e. represents + DATE, TIME, DATETIME, TIMESTAMP or YEAR types in SQL. + + @param type Field type, as returned by field->type(). + @retval true If field type is temporal + @retval false If field type is not temporal +*/ +inline bool is_temporal_type(enum_field_types type) { + switch (type) { + case MYSQL_TYPE_TIME: + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_NEWDATE: + case MYSQL_TYPE_YEAR: + return true; + default: + return false; + } +} + +/** + Tests if field type is temporal and has time part, + i.e. represents TIME, DATETIME or TIMESTAMP types in SQL. + + @param type Field type, as returned by field->type(). + @retval true If field type is temporal type with time part. + @retval false If field type is not temporal type with time part. +*/ +inline bool is_temporal_type_with_time(enum_field_types type) { + switch (type) { + case MYSQL_TYPE_TIME: + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_TIMESTAMP: + return true; + default: + return false; + } +} + + +/** + Tests if field type is temporal and has date and time parts, + i.e. represents DATETIME or TIMESTAMP types in SQL. + + @param type Field type, as returned by field->type(). + @retval true If field type is temporal type with date and time parts. + @retval false If field type is not temporal type with date and time parts. +*/ +inline bool is_temporal_type_with_date_and_time(enum_field_types type) { + switch (type) { + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_TIMESTAMP: + return true; + default: + return false; + } +} + +/** + Recognizer for concrete data type (called real_type for some reason), + returning true if it is one of the TIMESTAMP types. +*/ +inline bool is_timestamp_type(enum_field_types type) { + return type == MYSQL_TYPE_TIMESTAMP || type == MYSQL_TYPE_TIMESTAMP2; +} + +/** + Test if the field type contains information on being signed/unsigned. + This includes numeric but also YEAR that still contains sign modifiers + even if ignored. + + @param type Field type, as returned by field->type() + + @returns true if the type contains info on being signed/unsigned +*/ +inline bool has_signedess_information_type(enum_field_types type) { + switch (type) { + case MYSQL_TYPE_TINY: + case MYSQL_TYPE_SHORT: + case MYSQL_TYPE_INT24: + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_LONGLONG: + case MYSQL_TYPE_YEAR: + case MYSQL_TYPE_FLOAT: + case MYSQL_TYPE_DOUBLE: + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: + return true; + default: + return false; + } +} + +#endif /* FIELD_COMMON_OPERATIONS_INCLUDED */ diff --git a/storage/tianchi/sql/malloc_allocator.h b/storage/tianchi/sql/malloc_allocator.h new file mode 100644 index 0000000000000000000000000000000000000000..1ca6401462abab5c6d5cf4272d4f583044a4a426 --- /dev/null +++ b/storage/tianchi/sql/malloc_allocator.h @@ -0,0 +1,146 @@ +/* Copyright (c) 2014, 2021, Oracle and/or its affiliates. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef MALLOC_ALLOCATOR_INCLUDED +#define MALLOC_ALLOCATOR_INCLUDED + +#include +#include +#include +#include // std::forward + +#include "my_sys.h" +//#include "mysql/service_mysql_alloc.h" +//#include "sql/psi_memory_key.h" + +/** + Malloc_allocator is a C++ STL memory allocator based on my_malloc/my_free. + + This allows for P_S instrumentation of memory allocation done by + internally by STL container classes. + + Example usage: + vector> + v((Malloc_allocator(PSI_NOT_INSTRUMENTED))); + + If the type is complicated, you can just write Malloc_allocator<>(psi_key) + as a shorthand for Malloc_allocator(psi_key), as all + Malloc_allocator instances are implicitly convertible to each other + and there is a default template parameter. + + @note allocate() throws std::bad_alloc() similarly to the default + STL memory allocator. This is necessary - STL functions which allocates + memory expects it. Otherwise these functions will try to use the memory, + leading to segfaults if memory allocation was not successful. + + @note This allocator cannot be used for std::basic_string with RHEL 6/7 + because of this bug: + https://bugzilla.redhat.com/show_bug.cgi?id=1546704 + "Define _GLIBCXX_USE_CXX11_ABI gets ignored by gcc in devtoolset-7" +*/ + +template +class Malloc_allocator { + // This cannot be const if we want to be able to swap. + PSI_memory_key m_key; + + public: + typedef T value_type; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + typedef T *pointer; + typedef const T *const_pointer; + + typedef T &reference; + typedef const T &const_reference; + + pointer address(reference r) const { return &r; } + const_pointer address(const_reference r) const { return &r; } + + explicit Malloc_allocator(PSI_memory_key key) : m_key(key) {} + + template + Malloc_allocator(const Malloc_allocator &other MY_ATTRIBUTE((unused))) + : m_key(other.psi_key()) {} + + template + Malloc_allocator &operator=( + const Malloc_allocator &other MY_ATTRIBUTE((unused))) { + assert(m_key == other.psi_key()); // Don't swap key. + } + + pointer allocate(size_type n, + const_pointer hint MY_ATTRIBUTE((unused)) = nullptr) { + if (n == 0) return nullptr; + if (n > max_size()) throw std::bad_alloc(); + + pointer p = static_cast( + my_malloc(m_key, n * sizeof(T), MYF(MY_WME | ME_FATAL))); + if (p == nullptr) throw std::bad_alloc(); + return p; + } + + void deallocate(pointer p, size_type) { my_free(p); } + + template + void construct(U *p, Args &&... args) { + assert(p != nullptr); + try { + ::new ((void *)p) U(std::forward(args)...); + } catch (...) { + assert(false); // Constructor should not throw an exception. + } + } + + void destroy(pointer p) { + assert(p != nullptr); + try { + p->~T(); + } catch (...) { + assert(false); // Destructor should not throw an exception + } + } + + size_type max_size() const { + return std::numeric_limits::max() / sizeof(T); + } + + template + struct rebind { + typedef Malloc_allocator other; + }; + + PSI_memory_key psi_key() const { return m_key; } +}; + +template +bool operator==(const Malloc_allocator &a1, const Malloc_allocator &a2) { + return a1.psi_key() == a2.psi_key(); +} + +template +bool operator!=(const Malloc_allocator &a1, const Malloc_allocator &a2) { + return a1.psi_key() != a2.psi_key(); +} + +#endif // MALLOC_ALLOCATOR_INCLUDED diff --git a/storage/tianchi/sql/map_helpers.h b/storage/tianchi/sql/map_helpers.h new file mode 100644 index 0000000000000000000000000000000000000000..e4ec0f8b6f0e99ed50dc046eca652b87a1fea530 --- /dev/null +++ b/storage/tianchi/sql/map_helpers.h @@ -0,0 +1,335 @@ +/* Copyright (c) 2017, 2021, Oracle and/or its affiliates. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef MAP_HELPERS_INCLUDED +#define MAP_HELPERS_INCLUDED + +#include +#include +#include +#include +#include +#include +#include + +#include "m_ctype.h" +#include +#include "sql/malloc_allocator.h" +#include "sql/mem_root_allocator.h" +#include "template_utils.h" + +/** + Some useful helpers for associative arrays with MySQL-specific semantics. +*/ + +/** + For unordered_map or unordered_map>, does + find() and returns nullptr if the element was not found. + + It is not possible to distinguish between "not found" and "found, but + contained nullptr" in this case. Thus, you should normally prefer checking + against container.end() yourself. +*/ +template +static inline auto find_or_nullptr(const Container &container, const Key &key) + -> typename std::enable_if< + std::is_pointer::value, + typename Container::value_type::second_type>::type { + const auto it = container.find(key); + if (it == container.end()) + return nullptr; + else + return it->second; +} + +template +static inline auto find_or_nullptr(const Container &container, const Key &key) + -> typename std::enable_if< + std::is_pointer< + typename Container::value_type::second_type::pointer>::value, + typename Container::value_type::second_type::pointer>::type { + const auto it = container.find(key); + if (it == container.end()) + return nullptr; + else + return it->second.get(); +} + +/** + For unordered_multimap, erase the first specific element that + matches _both_ the given key and value. +*/ +template +typename Container::iterator erase_specific_element( + Container *container, const typename Container::key_type &key, + const typename Container::value_type::second_type &value) { + auto it_range = container->equal_range(key); + for (auto it = it_range.first; it != it_range.second; ++it) { + if (it->second == value) return container->erase(it); + } + return container->end(); +} + +/** + Same as regular erase_specific_element(), but for the case where the + container holds unique_ptr elements. +*/ +template +static inline auto erase_specific_element( + Container *container, const typename Container::key_type &key, + typename Container::value_type::second_type::pointer value) -> + typename std::enable_if< + std::is_pointer< + typename Container::value_type::second_type::pointer>::value, + typename Container::iterator>::type { + auto it_range = container->equal_range(key); + for (auto it = it_range.first; it != it_range.second; ++it) { + if (it->second.get() == value) return container->erase(it); + } + return container->end(); +} + +/** + std::unique_ptr, but with a custom delete function. + Normally, it is more efficient to have a deleter class instead, + but this allows you to have a unique_ptr to a forward-declared class, + so it keeps include dependencies down somewhat. +*/ +template +using unique_ptr_with_deleter = std::unique_ptr; + +struct My_free_deleter { + void operator()(void *ptr) const { my_free(ptr); } +}; + +/** std::unique_ptr, but with my_free as deleter. */ +template +using unique_ptr_my_free = std::unique_ptr; + +struct Free_deleter { + void operator()(void *ptr) const { free(ptr); } +}; + +/** std::unique_ptr, but with free as deleter. */ +template +using unique_ptr_free = std::unique_ptr; + +/** A Hasher that hashes std::strings according to a MySQL collation. */ +class Collation_hasher { + public: + explicit Collation_hasher(const CHARSET_INFO *cs_arg) + : cs(cs_arg), hash_sort(cs->coll->hash_sort) {} + + size_t operator()(const std::string &s) const { + ulong nr1 = 1, nr2 = 4; + hash_sort(cs, pointer_cast(s.data()), s.size(), &nr1, &nr2); + return nr1; + } + + private: + const CHARSET_INFO *cs; + decltype(cs->coll->hash_sort) hash_sort; +}; + +/** A KeyEqual that compares std::strings according to a MySQL collation. */ +class Collation_key_equal { + public: + explicit Collation_key_equal(const CHARSET_INFO *cs_arg) + : cs(cs_arg), strnncollsp(cs->coll->strnncollsp) {} + + size_t operator()(const std::string &a, const std::string &b) const { + return strnncollsp(cs, pointer_cast(a.data()), a.size(), + pointer_cast(b.data()), b.size()) == 0; + } + + private: + const CHARSET_INFO *cs; + decltype(cs->coll->strnncollsp) strnncollsp; +}; + +/** + std::unordered_map, but with my_malloc, so that you can track the memory + used using PSI memory keys. +*/ +template , + class KeyEqual = std::equal_to> +class malloc_unordered_map + : public std::unordered_map>> { + public: + /* + In theory, we should be allowed to send in the allocator only, but GCC 4.8 + is missing several unordered_map constructors, so let's give in everything. + */ + malloc_unordered_map(PSI_memory_key psi_key) + : std::unordered_map>>( + /*bucket_count=*/10, Hash(), KeyEqual(), + Malloc_allocator<>(psi_key)) {} +}; + +/** + std::unordered_set, but with my_malloc, so that you can track the memory + used using PSI memory keys. +*/ +template , + class KeyEqual = std::equal_to> +class malloc_unordered_set + : public std::unordered_set> { + public: + /* + In theory, we should be allowed to send in the allocator only, but GCC 4.8 + is missing several unordered_set constructors, so let's give in everything. + */ + malloc_unordered_set(PSI_memory_key psi_key) + : std::unordered_set>( + /*bucket_count=*/10, Hash(), KeyEqual(), + Malloc_allocator<>(psi_key)) {} +}; + +/** + std::unordered_multimap, but with my_malloc, so that you can track the memory + used using PSI memory keys. +*/ +template , + class KeyEqual = std::equal_to> +class malloc_unordered_multimap + : public std::unordered_multimap< + Key, Value, Hash, KeyEqual, + Malloc_allocator>> { + public: + /* + In theory, we should be allowed to send in the allocator only, but GCC 4.8 + is missing several unordered_multimap constructors, so let's give in + everything. + */ + malloc_unordered_multimap(PSI_memory_key psi_key) + : std::unordered_multimap>>( + /*bucket_count=*/10, Hash(), KeyEqual(), + Malloc_allocator<>(psi_key)) {} +}; + +/** + std::unordered_map, but with my_malloc and collation-aware comparison. +*/ +template +class collation_unordered_map + : public std::unordered_map>> { + public: + collation_unordered_map(const CHARSET_INFO *cs, PSI_memory_key psi_key) + : std::unordered_map>>( + /*bucket_count=*/10, Collation_hasher(cs), Collation_key_equal(cs), + Malloc_allocator<>(psi_key)) {} +}; + +/** + std::unordered_multimap, but with my_malloc and collation-aware comparison. +*/ +template +class collation_unordered_multimap + : public std::unordered_multimap< + Key, Value, Collation_hasher, Collation_key_equal, + Malloc_allocator>> { + public: + collation_unordered_multimap(CHARSET_INFO *cs, PSI_memory_key psi_key) + : std::unordered_multimap>>( + /*bucket_count=*/10, Collation_hasher(cs), Collation_key_equal(cs), + Malloc_allocator<>(psi_key)) {} +}; + +/** + std::unordered_set, but with my_malloc and collation-aware comparison. +*/ +template +class collation_unordered_set + : public std::unordered_set> { + public: + collation_unordered_set(CHARSET_INFO *cs, PSI_memory_key psi_key) + : std::unordered_set>( + /*bucket_count=*/10, Collation_hasher(cs), Collation_key_equal(cs), + Malloc_allocator<>(psi_key)) {} + collation_unordered_set(std::initializer_list il, CHARSET_INFO *cs, + PSI_memory_key psi_key) + : std::unordered_set>( + il, /*bucket_count=*/10, Collation_hasher(cs), + Collation_key_equal(cs), Malloc_allocator<>(psi_key)) {} +}; + +/** std::unordered_set, but allocated on a MEM_ROOT. */ +template , + class KeyEqual = std::equal_to> +class mem_root_unordered_set + : public std::unordered_set> { + public: + /* + In theory, we should be allowed to send in the allocator only, but GCC 4.8 + is missing several unordered_set constructors, so let's give in everything. + */ + mem_root_unordered_set(MEM_ROOT *mem_root) + : std::unordered_set>( + /*bucket_count=*/10, Hash(), KeyEqual(), + Mem_root_allocator(mem_root)) {} +}; + +/** + std::unordered_map, but allocated on a MEM_ROOT. +*/ +template , + class KeyEqual = std::equal_to> +class mem_root_unordered_map + : public std::unordered_map< + Key, Value, Hash, KeyEqual, + Mem_root_allocator>> { + public: + explicit mem_root_unordered_map(MEM_ROOT *mem_root, Hash hash = Hash()) + : std::unordered_map>>( + /*bucket_count=*/10, hash, KeyEqual(), + Mem_root_allocator>(mem_root)) {} +}; + +/** + std::unordered_map, but collation aware and allocated on a MEM_ROOT. +*/ +template +class mem_root_collation_unordered_map + : public std::unordered_map< + Key, Value, Collation_hasher, Collation_key_equal, + Mem_root_allocator>> { + public: + mem_root_collation_unordered_map(const CHARSET_INFO *cs, MEM_ROOT *mem_root) + : std::unordered_map>>( + /*bucket_count=*/10, Collation_hasher(cs), Collation_key_equal(cs), + Mem_root_allocator>(mem_root)) {} +}; + +#endif // MAP_HELPERS_INCLUDED diff --git a/storage/tianchi/sql/mem_root_allocator.h b/storage/tianchi/sql/mem_root_allocator.h new file mode 100644 index 0000000000000000000000000000000000000000..025da600eb5b79f18f777517c2dad230fca1c90b --- /dev/null +++ b/storage/tianchi/sql/mem_root_allocator.h @@ -0,0 +1,155 @@ +/* Copyright (c) 2014, 2021, Oracle and/or its affiliates. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef MEM_ROOT_ALLOCATOR_INCLUDED +#define MEM_ROOT_ALLOCATOR_INCLUDED + +#include +#include +#include +#include // std::forward + +#include "my_alloc.h" +#include "my_sys.h" + +/** + Mem_root_allocator is a C++ STL memory allocator based on MEM_ROOT. + + No deallocation is done by this allocator. Calling init_sql_alloc() + and free_root() on the supplied MEM_ROOT is the responsibility of + the caller. Do *not* call free_root() until the destructor of any + objects using this allocator has completed. This includes iterators. + + Example of use: + vector > v((Mem_root_allocator(&mem_root))); + + @note allocate() throws std::bad_alloc() similarly to the default + STL memory allocator. This is necessary - STL functions which allocate + memory expect it. Otherwise these functions will try to use the memory, + leading to seg faults if memory allocation was not successful. + + @note This allocator cannot be used for std::basic_string with RHEL 6/7 + because of this bug: + https://bugzilla.redhat.com/show_bug.cgi?id=1546704 + "Define _GLIBCXX_USE_CXX11_ABI gets ignored by gcc in devtoolset-7" + + @note C++98 says that STL implementors can assume that allocator objects + of the same type always compare equal. This will only be the case for + two Mem_root_allocators that use the same MEM_ROOT. Care should be taken + when this is not the case. Especially: + - Using list::splice() on two lists with allocators using two different + MEM_ROOTs causes undefined behavior. Most implementations seem to give + runtime errors in such cases. + - swap() on two collections with allocators using two different MEM_ROOTs + is not well defined. At least some implementations also swap allocators, + but this should not be depended on. +*/ + +template +class Mem_root_allocator { + // This cannot be const if we want to be able to swap. + MEM_ROOT *m_memroot; + + public: + typedef T value_type; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + typedef T *pointer; + typedef const T *const_pointer; + + typedef T &reference; + typedef const T &const_reference; + + pointer address(reference r) const { return &r; } + const_pointer address(const_reference r) const { return &r; } + + explicit Mem_root_allocator(MEM_ROOT *memroot) : m_memroot(memroot) {} + + explicit Mem_root_allocator() : m_memroot(nullptr) {} + + template + Mem_root_allocator(const Mem_root_allocator &other) + : m_memroot(other.memroot()) {} + + template + Mem_root_allocator &operator=( + const Mem_root_allocator &other MY_ATTRIBUTE((unused))) { + assert(m_memroot == other.memroot()); // Don't swap memroot. + } + + pointer allocate(size_type n, + const_pointer hint MY_ATTRIBUTE((unused)) = nullptr) { + if (n == 0) return nullptr; + if (n > max_size()) throw std::bad_alloc(); + + pointer p = static_cast(alloc_root(m_memroot, n * sizeof(T))); + if (p == nullptr) throw std::bad_alloc(); + return p; + } + + void deallocate(pointer, size_type) {} + + template + void construct(U *p, Args &&... args) { + assert(p != nullptr); + try { + ::new ((void *)p) U(std::forward(args)...); + } catch (...) { + assert(false); // Constructor should not throw an exception. + } + } + + void destroy(pointer p) { + assert(p != nullptr); + try { + p->~T(); + } catch (...) { + assert(false); // Destructor should not throw an exception + } + } + + size_type max_size() const { + return std::numeric_limits::max() / sizeof(T); + } + + template + struct rebind { + typedef Mem_root_allocator other; + }; + + MEM_ROOT *memroot() const { return m_memroot; } +}; + +template +bool operator==(const Mem_root_allocator &a1, + const Mem_root_allocator &a2) { + return a1.memroot() == a2.memroot(); +} + +template +bool operator!=(const Mem_root_allocator &a1, + const Mem_root_allocator &a2) { + return a1.memroot() != a2.memroot(); +} + +#endif // MEM_ROOT_ALLOCATOR_INCLUDED diff --git a/storage/tianchi/sql/record_buffer.h b/storage/tianchi/sql/record_buffer.h new file mode 100644 index 0000000000000000000000000000000000000000..99d553bd4a8f32d5013d3181a7ae8bd261d99477 --- /dev/null +++ b/storage/tianchi/sql/record_buffer.h @@ -0,0 +1,157 @@ +#ifndef RECORD_BUFFER_INCLUDED +#define RECORD_BUFFER_INCLUDED + +/* + Copyright (c) 2016, 2021, Oracle and/or its affiliates. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include "my_base.h" // ha_rows + +/** + This class represents a buffer that can be used for multi-row reads. It is + allocated by the executor and given to the storage engine through the + handler, using handler::ha_set_record_buffer(), so that the storage engine + can fill the buffer with multiple rows in a single read call. + + For now, the record buffer is only used internally by the storage engine as + a prefetch cache. The storage engine fills the record buffer when the + executor requests the first record, but it returns a single record only to + the executor. If the executor wants to access the records in the buffer, it + has to call a handler function such as handler::ha_index_next() or + handler::ha_rnd_next(). Then the storage engine will copy the next record + from the record buffer to the memory area specified in the arguments of the + handler function, typically TABLE::record[0]. +*/ +class Record_buffer { + /// The maximum number of records that can be stored in the buffer. + ha_rows m_max_records; + /// The number of bytes available for each record. + size_t m_record_size; + /// The number of records currently stored in the buffer. + ha_rows m_count = 0; + /// The @c uchar buffer that holds the records. + uchar *m_buffer; + /// Tells if end-of-range was found while filling the buffer. + bool m_out_of_range = false; + + public: + /** + Create a new record buffer with the specified size. + + @param records the number of records that can be stored in the buffer + @param record_size the size of each record + @param buffer the @c uchar buffer that will hold the records (its + size should be at least + `Record_buffer::buffer_size(records, record_size)`) + */ + Record_buffer(ha_rows records, size_t record_size, uchar *buffer) + : m_max_records(records), m_record_size(record_size), m_buffer(buffer) {} + + /** + This function calculates how big the @c uchar buffer provided to + Record_buffer's constructor must be, given a number of records and + the record size. + + @param records the maximum number of records in the buffer + @param record_size the size of each record + @return the total number of bytes needed for all the records + */ + static constexpr size_t buffer_size(ha_rows records, size_t record_size) { + return static_cast(records * record_size); + } + + /** + Get the number of records that can be stored in the buffer. + @return the maximum number of records in the buffer + */ + ha_rows max_records() const { return m_max_records; } + + /** + Get the amount of space allocated for each record in the buffer. + @return the record size + */ + size_t record_size() const { return m_record_size; } + + /** + Get the number of records currently stored in the buffer. + @return the number of records stored in the buffer + */ + ha_rows records() const { return m_count; } + + /** + Get the buffer that holds the record on position @a pos. + @param pos the record number (must be smaller than records()) + @return the @c uchar buffer that holds the specified record + */ + uchar *record(ha_rows pos) const { + assert(pos < max_records()); + return m_buffer + m_record_size * pos; + } + + /** + Add a new record at the end of the buffer. + @return the @c uchar buffer of the added record + */ + uchar *add_record() { + assert(m_count < max_records()); + return record(m_count++); + } + + /** + Remove the record that was last added to the buffer. + */ + void remove_last() { + assert(m_count > 0); + --m_count; + } + + /** + Clear the buffer. Remove all the records. The end-of-range flag is + preserved. + */ + void clear() { m_count = 0; } + + /** + Reset the buffer. Remove all records and clear the end-of-range flag. + */ + void reset() { + m_count = 0; + set_out_of_range(false); + } + + /** + Set whether the end of the range was reached while filling the buffer. + @param val true if end of range was reached, false if still within range + */ + void set_out_of_range(bool val) { m_out_of_range = val; } + + /** + Check if the end of the range was reached while filling the buffer. + @retval true if the end range was reached + @retval false if the scan is still within the range + */ + bool is_out_of_range() const { return m_out_of_range; } +}; + +#endif /* RECORD_BUFFER_INCLUDED */ diff --git a/storage/tianchi/sql/stateless_allocator.cc b/storage/tianchi/sql/stateless_allocator.cc new file mode 100644 index 0000000000000000000000000000000000000000..7ac22ec480d5410310c19f7ae0f5950bebb2a1e3 --- /dev/null +++ b/storage/tianchi/sql/stateless_allocator.cc @@ -0,0 +1,27 @@ +/* Copyright (c) 2016, 2021, Oracle and/or its affiliates. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "sql/stateless_allocator.h" + +#include "mysql/service_mysql_alloc.h" // my_free + +void My_free_functor::operator()(void *p, size_t) const { my_free(p); } diff --git a/storage/tianchi/sql/stateless_allocator.h b/storage/tianchi/sql/stateless_allocator.h new file mode 100644 index 0000000000000000000000000000000000000000..8c36ddf4acf5038d7783948390438da327d24868 --- /dev/null +++ b/storage/tianchi/sql/stateless_allocator.h @@ -0,0 +1,171 @@ +/* Copyright (c) 2016, 2021, Oracle and/or its affiliates. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef STATELESS_ALLOCATOR_INCLUDED +#define STATELESS_ALLOCATOR_INCLUDED + +#include +#include +#include +#include +#include // std::forward + +#include "my_compiler.h" + +/** + Functor struct which invokes my_free. Declared here as it is used as the + defalt value for Stateless_allocator's DEALLOC_FUN template parameter. +*/ +struct My_free_functor { + void operator()(void *p, size_t) const; +}; + +/** + Stateless_allocator is a C++ STL memory allocator skeleton based on + Malloc_allocator, which assumes that a global free function can be + used to allocate and deallocate memory, so that no state need to be + kept by the allocator object. + + The allocation and deallocation functions must be provided as + callable types (aka functors) which have no state and can be default + constructed. + + Example usage: + + @verbatim + struct My_psi_key_alloc + { + void* operator(size_t s)() + { + return my_malloc(My_psi_key, s, MYF(MY_WME | ME_FATALERROR)); + } + }; + + template + using My_psi_key_allocator = + Stateless_allocator; + + template < template class Allocator > + using default_string= + std::basic_string, Allocator >; + + + typedef default_string My_psi_key_str; + + My_psi_key_str x("foobar"); + @endverbatim + + Since a Stateless_allocator instance is always + default-constructible, it can also be used to create instances of + std::basic_string, even with compilers that have this libstd++ bug: + http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56437 "basic_string + assumes that allocators are default-constructible". + + @note allocate() throws std::bad_alloc() similarly to the default + STL memory allocator. This is necessary - STL functions which allocate + memory expect it. Otherwise these functions will try to use the memory, + leading to seg faults if memory allocation was not successful. + +*/ + +template +class Stateless_allocator { + public: + typedef T value_type; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + typedef T *pointer; + typedef const T *const_pointer; + + typedef T &reference; + typedef const T &const_reference; + + template + using Stateless_allocator_type = + Stateless_allocator; + + Stateless_allocator() = default; + + pointer address(reference r) const { return &r; } + const_pointer address(const_reference r) const { return &r; } + + template + Stateless_allocator(const Stateless_allocator_type &) {} + + template + Stateless_allocator &operator=(const Stateless_allocator_type &) {} + + pointer allocate(size_type n, + const_pointer hint MY_ATTRIBUTE((unused)) = nullptr) { + if (n == 0) return nullptr; + if (n > max_size()) throw std::bad_alloc(); + + pointer p = static_cast(ALLOC_FUN()(n * sizeof(T))); + if (p == nullptr) throw std::bad_alloc(); + return p; + } + + void deallocate(pointer p, size_type n) { DEALLOC_FUN()(p, n); } + + template + void construct(U *p, Args &&... args) { + assert(p != nullptr); + try { + ::new ((void *)p) U(std::forward(args)...); + } catch (...) { + assert(false); // Constructor should not throw an exception. + } + } + + void destroy(pointer p) { + assert(p != nullptr); + try { + p->~T(); + } catch (...) { + assert(false); // Destructor should not throw an exception + } + } + + size_type max_size() const { + return std::numeric_limits::max() / sizeof(T); + } + + template + struct rebind { + typedef Stateless_allocator other; + }; +}; + +template +bool operator==(const Stateless_allocator &, + const Stateless_allocator &) { + return true; +} + +template +bool operator!=(const Stateless_allocator &, + const Stateless_allocator &) { + return false; +} + +#endif // STATELESS_ALLOCATOR_INCLUDED diff --git a/storage/tianchi/sql/template_utils.h b/storage/tianchi/sql/template_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..844bded67e7db630a12cb3ced5efa29f988887c3 --- /dev/null +++ b/storage/tianchi/sql/template_utils.h @@ -0,0 +1,243 @@ +/* Copyright (c) 2013, 2021, Oracle and/or its affiliates. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is also distributed with certain software (including + but not limited to OpenSSL) that is licensed under separate terms, + as designated in a particular file or component or in included license + documentation. The authors of MySQL hereby grant you an additional + permission to link the program and your derivative works with the + separately licensed software that they have included with MySQL. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ + +#ifndef TEMPLATE_UTILS_INCLUDED +#define TEMPLATE_UTILS_INCLUDED + +#include +#include +#include +#include +#include +#include + +/** + @file include/template_utils.h +*/ + +/** + Clears a container, but deletes all objects that the elements point to first. + @tparam Container_type Container of pointers. + */ +template +void delete_container_pointers(Container_type &container) { + typename Container_type::iterator it1 = container.begin(); + typename Container_type::iterator it2 = container.end(); + for (; it1 != it2; ++it1) { + delete (*it1); + } + container.clear(); +} + +/** + Clears a container, but frees all objects that the elements point to first. + @tparam Container_type Container of pointers. + */ +template +void my_free_container_pointers(Container_type &container) { + typename Container_type::iterator it1 = container.begin(); + typename Container_type::iterator it2 = container.end(); + for (; it1 != it2; ++it1) { + my_free(*it1); + } + container.clear(); +} + +/** + Casts from one pointer type, to another, without using + reinterpret_cast or C-style cast: + foo *f; bar *b= pointer_cast(f); + This avoids having to do: + foo *f; bar *b= static_cast(static_cast(f)); + */ +template +inline T pointer_cast(void *p) { + return static_cast(p); +} + +template +inline const T pointer_cast(const void *p) { + return static_cast(p); +} + +/** + Casts from one pointer type to another in a type hierarchy. + In debug mode, we verify the cast is indeed legal. + + @tparam Target The descendent type, must be a pointer type. + @tparam Source The parent type. + + @param arg The pointer to be down-cast. + + @return A pointer of type Target. +*/ +template +inline Target down_cast(Source *arg) { + static_assert( + !std::is_base_of::type, + Source>::value, + "Do not use down_cast for upcasts; use implicit_cast or nothing"); + assert(nullptr != static_cast(arg)); + return static_cast(arg); +} + +/** + Casts from one reference type to another in a type hierarchy. + In debug mode, we verify the cast is indeed legal. + + @tparam Target The descendent type, must be a reference type. + @tparam Source The parent type. + + @param arg The reference to be down-cast. + + @return A reference of type Target. +*/ +template +inline Target down_cast(Source &arg) { + // We still use the pointer version of dynamic_cast, as the + // reference-accepting version throws exceptions, and we don't want to deal + // with that. + static_assert( + !std::is_base_of::type, + Source>::value, + "Do not use down_cast for upcasts; use implicit_cast or nothing"); + assert(dynamic_cast::type *>(&arg) != + nullptr); + return static_cast(arg); +} + +/** + Sometimes the compiler insists that types be the same and does not do any + implicit conversion. For example: + Derived1 *a; + Derived2 *b; // Derived1 and 2 are children classes of Base + Base *x= cond ? a : b; // Error, need to force a cast. + + Use: + Base *x= cond ? implicit_cast(a) : implicit_cast(b); + static_cast would work too, but would be less safe (allows any + pointer-to-pointer conversion, not only up-casts). +*/ +template +inline To implicit_cast(To x) { + return x; +} + +/** + Utility to allow returning values from functions which can fail + (until we have std::optional). + */ +template +struct ReturnValueOrError { + /** Value returned from function in the normal case. */ + VALUE_TYPE value; + + /** True if an error occured. */ + bool error; +}; + +/** + Number of elements in a constant C array. +template +constexpr size_t array_elements(T (&)[N]) noexcept { + return N; +} + */ + +namespace myu { +/** + Split a range into sub ranges delimited by elements satisfying a predicate. + Examines the elements from first to last, exclusive. Each time an element + which satisfies the splitting predicate is encountered, the action argument's + operator() is invoked with the starting and past-the-end iterators for the + current sub-range, even if this is empty. When iteration is complete, action() + is called on the range between the start of the last subrange and last. + + It must be possible to pass a single element with type const + InputIt::value_type to is_split_element. It must be possible to pass two + InputIt arguments to action. + + @param first Beginning of the range to split. + @param last End of the range to split. + @param pred Callable which will be invoked on each element in + turn to determine if it is a splitting element. + @param action Callable which will be invoked with the beginning + and one-past-the-end iterators for each subrange. + */ +template +inline void Split(InputIt first, InputIt last, Pred &&pred, Action &&action) { + while (first != last) { + InputIt split = std::find_if(first, last, std::forward(pred)); + action(first, split); // Called even for empty subranges, action must + // discard if not wanted + if (split == last) return; + first = split + 1; + } +} + +/** + Search backwards for the first occurence of an element which does not satisfy + the trimming predicate, and return an InputIt to the element after it. + + @param first Beginning of the range to search. + @param last End of the range to search. + @param pred Callable which can be applied to a dereferenced InputIt and which + returns true if the element should be trimmed. + + @returns InputIt referencing the first element of sub range satisfying the + trimming predicate at the end of the range. last if no elements + satisfy the trimming predicate. + */ +template +inline InputIt FindTrimmedEnd(InputIt first, InputIt last, Pred &&pred) { + return std::find_if_not(std::make_reverse_iterator(last), + std::make_reverse_iterator(first), + std::forward(pred)) + .base(); +} + +/** + Searches for a sub range such that no elements before or after fail to + satisfy the trimming predicate. + + @param first Beginning of the range to search. + @param last End of the range to search. + @param pred Callable which can be applied to a dereferenced InputIt and which + returns true if the element should be trimmed. + + @returns Pair of iterators denoting the sub range which does not include the + leading and trailing sub ranges matching the trimming predicate. + {last, last} if all elements match the trimming predicate. + */ +template +inline std::pair FindTrimmedRange(InputIt first, InputIt last, + Pred &&pred) { + InputIt f = std::find_if_not(first, last, std::forward(pred)); + return {f, FindTrimmedEnd(f, last, std::forward(pred))}; +} + +/** Convenience lambdas for common predicates. */ +const auto IsSpace = [](char c) { return isspace(c); }; +const auto IsComma = [](char c) { return c == ','; }; + +} // namespace myu +#endif // TEMPLATE_UTILS_INCLUDED diff --git a/storage/tianchi/tse_cbo.cc b/storage/tianchi/tse_cbo.cc index 4d64a299b360e0066f211a9f0682e82c7f8d8c6e..b571f46748541c49d314e1c0af60c887b6ca56c9 100644 --- a/storage/tianchi/tse_cbo.cc +++ b/storage/tianchi/tse_cbo.cc @@ -14,6 +14,8 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Bon, MA 02110-1301 USA */ + +#include "my_global.h" #include "tse_cbo.h" #include "ha_tse.h" #include "tse_log.h" @@ -21,6 +23,8 @@ #include "tse_srv_mq_module.h" #include "datatype_cnvrtr.h" #include "tse_util.h" +#include "sql/extra_defs.h" + static void convert_enum_key_to_variant(const uchar *enum_key, cache_variant_t *variant, capacity_usage cap_usage_of_enum_key) { @@ -69,7 +73,7 @@ void r_key2variant(tse_key *rKey, KEY_PART_INFO *cur_index_part, cache_variant_t Field *field = cur_index_part->field; uint32_t offset = 0; - if (cur_index_part->field->is_nullable()) { + if (cur_index_part->field->is_null()) { /* The first byte in the field tells if this is an SQL NULL value */ if(*(rKey->key + key_offset) == 1) { *ret_val = *value; @@ -579,8 +583,10 @@ double calc_density_by_cond(tse_cbo_stats_table_t *cbo_stats, KEY_PART_INFO cur_ low_val = &cbo_stats->columns[col_id].low_value; high_val = &cbo_stats->columns[col_id].high_value; - cache_variant_t min_key_val = { 0 }; - cache_variant_t max_key_val = { 0 }; + //cache_variant_t min_key_val = { 0 }; + //cache_variant_t max_key_val = { 0 }; + cache_variant_t min_key_val; + cache_variant_t max_key_val; enum_field_types field_type = cur_index_part.field->real_type(); char v_str_min[CBO_STRING_MAX_LEN] = { 0 }; char v_str_max[CBO_STRING_MAX_LEN] = { 0 }; @@ -634,22 +640,22 @@ double calc_density_one_table(uint16_t idx_id, tse_range_key *key, calc_accumulate_gcol_num(table.s->fields, table.s->field, acc_gcol_num); uint32_t key_offset = 0;//列在索引中的偏移量 uint64_t col_map = max(key->min_key->col_map, key->max_key->col_map); - KEY cur_index = table.key_info[idx_id]; + KEY &cur_index = table.key_info[idx_id]; /* * For all columns in used index, * density = 1.0 / (column[0]->num_distinct * ... * column[n]->num_distinct) */ - for (uint32_t idx_col_num = 0; idx_col_num < cur_index.actual_key_parts; idx_col_num++) { + for (uint32_t idx_col_num = 0; idx_col_num < cur_index.user_defined_key_parts; idx_col_num++) { double col_product = 1.0; if (col_map & ((uint64_t)1 << idx_col_num)) { - KEY_PART_INFO cur_index_part = cur_index.key_part[idx_col_num]; + const KEY_PART_INFO &cur_index_part = cur_index.key_part[idx_col_num]; if (cur_index_part.field->is_virtual_gcol()) { continue; } - my_col_id = cur_index_part.field->field_index(); + my_col_id = cur_index_part.field->field_index; ct_col_id = my_col_id - acc_gcol_num[my_col_id]; - uint32_t offset = cur_index_part.field->is_nullable() ? 1 : 0; + uint32_t offset = cur_index_part.field->is_null() ? 1 : 0; if ((offset == 1) && *(key->min_key->key + key_offset) == 1 && key->max_key->key == nullptr) { // select * from table where col is not null col_product = (double)1 - calc_equal_null_density(cbo_stats, ct_col_id); @@ -679,7 +685,6 @@ double calc_density_one_table(uint16_t idx_id, tse_range_key *key, void tse_index_stats_update(TABLE *table, tianchi_cbo_stats_t *cbo_stats) { rec_per_key_t rec_per_key = 0.0f; - KEY sk; uint32_t *n_diff = cbo_stats->ndv_keys; uint32_t records; uint32_t table_part_num = cbo_stats->part_cnt == 0 ? 1 : cbo_stats->part_cnt; @@ -690,11 +695,11 @@ void tse_index_stats_update(TABLE *table, tianchi_cbo_stats_t *cbo_stats) } for (uint32 i = 0; i < table->s->keys; i++) { - sk = table->key_info[i]; - for (uint32 j = 0; j < sk.actual_key_parts; j++) { + KEY &sk = table->key_info[i]; + for (uint32 j = 0; j < sk.user_defined_key_parts; j++) { bool all_n_diff_is_zero = true; rec_per_key = 0.0f; - uint32 fld_idx = sk.key_part[j].field->field_index(); + uint32 fld_idx = sk.key_part[j].field->field_index; fld_idx = fld_idx - acc_gcol_num[fld_idx]; for (uint32 k = 0; k < table_part_num; k++) { records = cbo_stats->tse_cbo_stats_table[k].estimate_rows; @@ -719,7 +724,8 @@ void tse_index_stats_update(TABLE *table, tianchi_cbo_stats_t *cbo_stats) if (rec_per_key < 1.0) { rec_per_key = 1.0; } - sk.set_records_per_key(j, rec_per_key); + + set_records_per_key(&sk, j, rec_per_key); } } } diff --git a/storage/tianchi/tse_cbo.h b/storage/tianchi/tse_cbo.h index b10d691085895850f0e92042282da538f41571c5..8a7c79325ada099b378740a0c586549cc103cb6d 100644 --- a/storage/tianchi/tse_cbo.h +++ b/storage/tianchi/tse_cbo.h @@ -20,7 +20,6 @@ #include "tse_srv.h" #include "sql/table.h" -#include "sql/dd/types/table.h" #include "srv_mq_msg.h" #define REAL_EPSINON 0.00001 diff --git a/storage/tianchi/tse_ddl_rewriter_plugin.cc b/storage/tianchi/tse_ddl_rewriter_plugin.cc index d823580595016f38aace4aa4280e97b26f60543f..afbd7c8dc90a443e900199d82db2f3885db346c3 100644 --- a/storage/tianchi/tse_ddl_rewriter_plugin.cc +++ b/storage/tianchi/tse_ddl_rewriter_plugin.cc @@ -15,6 +15,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "my_global.h" #include #include #include @@ -22,13 +23,13 @@ #include #include #include -#include +//#include #include #include #include -#include "my_inttypes.h" -#include "my_psi_config.h" -#include "my_thread.h" // my_thread_handle needed by mysql_memory.h +#include +//#include "my_psi_config.h" +//#include "my_thread.h" // my_thread_handle needed by mysql_memory.h #include "sql/sql_class.h" #include "sql/sql_lex.h" #include "sql/sql_error.h" @@ -39,30 +40,27 @@ #include "tse_error.h" #include "ha_tse.h" #include "ha_tse_ddl.h" -#include "sql/sql_initialize.h" // opt_initialize_insecure +//#include "sql/sql_initialize.h" // opt_initialize_insecure #include "sql/sql_list.h" #include "sql/set_var.h" -#include "sql/dd/types/schema.h" -#include "sql/dd/cache/dictionary_client.h" #include "sql/lock.h" -#include "sql/auth/auth_common.h" #include #include -#include "sql/sql_tablespace.h" +//#include "sql/sql_tablespace.h" #include "sql/sql_lex.h" #include "sql/sql_db.h" // check_schema_readonly -#include "sql/sql_backup_lock.h" -#include "mysql/plugin_auth.h" -#include "sql/auth/sql_auth_cache.h" -#include "sql/auth/auth_internal.h" +//#include "sql/sql_backup_lock.h" #include "sql/sql_parse.h" #ifdef FEATURE_X_FOR_MYSQL_32 #include "sql/sys_vars_shared.h" // intern_find_sys_var #endif +#include "sql_plugin.h" +class ACL_USER; using namespace std; +bool check_readonly(THD *thd, bool err_if_readonly); -static SYS_VAR *tse_rewriter_system_variables[] = { +static st_mysql_sys_var *tse_rewriter_system_variables[] = { nullptr }; @@ -83,7 +81,7 @@ int check_default_engine(set_var *setvar, bool &need_forward MY_ATTRIBUTE((unuse return 0; } - if (setvar->value->item_name.ptr() == nullptr) { + if (setvar->value->name.str == nullptr) { if (user_val_str == "") { return 0; } @@ -98,7 +96,7 @@ int check_default_engine(set_var *setvar, bool &need_forward MY_ATTRIBUTE((unuse return -1; } - if (strcasecmp(setvar->value->item_name.ptr(), tse_hton_name) != 0) { + if (strcasecmp(setvar->value->name.str, tse_hton_name) != 0) { my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), "Once the CTC is loaded, it must be set as the default engine. To modify the setting, uninstall the CTC first."); return -1; @@ -117,7 +115,7 @@ int check_session_pool_volume(set_var *setvar, bool &need_forward MY_ATTRIBUTE(( return -1; } - if (setvar->value->item_name.ptr() == nullptr) { + if (setvar->value->name.str == nullptr) { if (user_val_str == "") { return 0; } @@ -138,7 +136,7 @@ int check_session_pool_volume(set_var *setvar, bool &need_forward MY_ATTRIBUTE(( return 0; } - int num_max_conns = atoi(setvar->value->item_name.ptr()); + int num_max_conns = atoi(setvar->value->name.str); if (num_max_conns > (int)max_sessions) { my_printf_error(ER_DISALLOWED_OPERATION, "Current SE can only provide %d connections for one mysql-server", MYF(0), max_sessions); return -1; @@ -170,12 +168,12 @@ int unsupport_tx_isolation_level(set_var *setvar, bool &need_forward MY_ATTRIBUT if (setvar->value->result_type() == STRING_RESULT) { // 对应 SET @@global.transaction_isolation = @global_start_value;的写法 - if (setvar->value->item_name.ptr() == nullptr) { + if (setvar->value->name.str == nullptr) { transform(user_val_str.begin(), user_val_str.end(), user_val_str.begin(), ::tolower); if (user_val_str == "read-committed" || user_val_str == "1") { return 0; } else if (user_val_str == "repeatable-read" || user_val_str == "2") { - push_warning_printf(current_thd, Sql_condition::SL_WARNING, ER_DISALLOWED_OPERATION, + push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN, ER_DISALLOWED_OPERATION, "CTC: The Function of REPEATABLE READ transaction isolation is in progress."); return 0; } @@ -186,10 +184,10 @@ int unsupport_tx_isolation_level(set_var *setvar, bool &need_forward MY_ATTRIBUT } // 对应set transaction_isolation='read-committed' 写法 - if (strcasecmp(setvar->value->item_name.ptr(), "read-committed") == 0) { + if (strcasecmp(setvar->value->name.str, "read-committed") == 0) { return 0; - } else if (strcasecmp(setvar->value->item_name.ptr(), "repeatable-read") == 0) { - push_warning_printf(current_thd, Sql_condition::SL_WARNING, ER_DISALLOWED_OPERATION, + } else if (strcasecmp(setvar->value->name.str, "repeatable-read") == 0) { + push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN, ER_DISALLOWED_OPERATION, "CTC: The Function of REPEATABLE READ transaction isolation is in progress."); return 0; } @@ -199,7 +197,7 @@ int unsupport_tx_isolation_level(set_var *setvar, bool &need_forward MY_ATTRIBUT if (tx_isol == ISO_READ_COMMITTED) { return 0; } else if (tx_isol == ISO_REPEATABLE_READ) { - push_warning_printf(current_thd, Sql_condition::SL_WARNING, ER_DISALLOWED_OPERATION, + push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN, ER_DISALLOWED_OPERATION, "CTC: The Function of REPEATABLE READ transaction isolation is in progress."); return 0; } @@ -213,7 +211,7 @@ int unsupport_tx_isolation_level(set_var *setvar, bool &need_forward MY_ATTRIBUT int tse_check_opt_forward(set_var *setvar MY_ATTRIBUTE((unused)), bool &need_forward, string user_val_str MY_ATTRIBUTE((unused))) { need_forward = false; - push_warning_printf(current_thd, Sql_condition::SL_WARNING, ER_DISALLOWED_OPERATION, + push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN, ER_DISALLOWED_OPERATION, "CTC: This parameter will not be broadcast to other nodes."); return 0; } @@ -233,10 +231,11 @@ static int tse_get_user_var_string(MYSQL_THD thd, Item_func_get_user_var *itemFu String str; user_var_entry *var_entry; - var_entry = find_or_nullptr(thd->user_vars, itemFunc->name.ptr()); + auto usrvarname = itemFunc->get_name(); + var_entry = get_variable(&thd->user_vars, &usrvarname, false); if (var_entry == nullptr) { - tse_log_system("user var:%s have no value. no need to broadcast.", itemFunc->name.ptr()); - my_printf_error(ER_DISALLOWED_OPERATION, "[CTC]:Please make sure %s has value in it.", MYF(0), itemFunc->name.ptr()); + tse_log_system("user var:%s have no value. no need to broadcast.", usrvarname.str); + my_printf_error(ER_DISALLOWED_OPERATION, "[CTC]:Please make sure %s has value in it.", MYF(0), usrvarname.str); mysql_mutex_unlock(&thd->LOCK_thd_data); return -1; } @@ -255,8 +254,9 @@ static int tse_get_user_var_string(MYSQL_THD thd, Item_func_get_user_var *itemFu static int allow_sqlcmd(MYSQL_THD thd, string session_var_name) { String str; - user_var_entry *var_entry = find_or_nullptr(thd->user_vars, session_var_name); - if(var_entry == nullptr || var_entry->ptr() == nullptr) { + LEX_CSTRING name{session_var_name.c_str(), session_var_name.length()}; + auto var_entry = get_variable(&thd->user_vars, &name, false); + if(var_entry == nullptr || var_entry->value == nullptr) { return 0; } bool is_var_null; @@ -271,9 +271,9 @@ static int allow_sqlcmd(MYSQL_THD thd, string session_var_name) { } static int tse_check_dcl(string &, MYSQL_THD thd, bool &need_forward) { - if (check_readonly(thd, false) || - (thd->lex->query_tables != nullptr && - check_schema_readonly(thd, thd->lex->query_tables->table_name))) { + if (check_readonly(thd, false) + /* || (thd->lex->query_tables != nullptr && //mariadb database has no readonly property + check_schema_readonly(thd, thd->lex->query_tables->table_name.str)) */) { need_forward = false; } if (allow_sqlcmd(thd, "ctc_dcl_disabled") != 0) { @@ -284,39 +284,9 @@ static int tse_check_dcl(string &, MYSQL_THD thd, bool &need_forward) { } // reference for 'validate_password_require_current' function -int tse_verify_password4existed_user(MYSQL_THD thd, const LEX_USER *existed_user, bool &res) { - ACL_USER *acl_user = nullptr; - plugin_ref plugin = nullptr; - int is_error = 0; - Acl_cache_lock_guard acl_cache_lock(thd, Acl_cache_lock_mode::WRITE_MODE); - if (!acl_cache_lock.lock()) { - tse_log_error("tse_verify_password failed, lock acl cache failed"); - return -1; - } - acl_user = find_acl_user(existed_user->host.str, existed_user->user.str, true); - if (!acl_user) { - tse_log_error("tse_verify_password failed, find acl user failed"); - return -1; - } - plugin = my_plugin_lock_by_name(nullptr, acl_user->plugin, MYSQL_AUTHENTICATION_PLUGIN); - if (!plugin) { - tse_log_error("tse_verify_password failed, lock plugin %s failed", acl_user->plugin.str ? acl_user->plugin.str : ""); - return -1; - } - st_mysql_auth *auth = (st_mysql_auth *)plugin_decl(plugin)->info; +// moved to sql_acl.cc because ACL_USER is defined there. let's not expose ACL_USER class. +int tse_verify_password4existed_user(MYSQL_THD thd, const LEX_USER *existed_user, bool &res); - if (acl_user->credentials[PRIMARY_CRED].m_auth_string.length == 0 && existed_user->current_auth.length > 0) { - res = false; - } else if ((auth->authentication_flags & AUTH_FLAG_USES_INTERNAL_STORAGE) && auth->compare_password_with_hash && - auth->compare_password_with_hash(acl_user->credentials[PRIMARY_CRED].m_auth_string.str, - (unsigned long)acl_user->credentials[PRIMARY_CRED].m_auth_string.length, existed_user->current_auth.str, - (unsigned long)existed_user->current_auth.length, &is_error) && !is_error) { - res = false; - } - res = true; - plugin_unlock(nullptr, plugin); - return 0; -} void tse_remove_replace_clause4sql(string &sql_str) { // match: replace "xxx" | replace 'xxx' @@ -339,24 +309,27 @@ static int tse_rewrite_alter_user4update_passwd(MYSQL_THD thd, string &sql_str) while ((tmp_user = user_list++)) { /* If it is an empty lex_user update it with current user */ if (!tmp_user->host.str && !tmp_user->user.str) { - assert(sctx->priv_host().str); - tmp_user->host.str = sctx->priv_host().str; - tmp_user->host.length = strlen(sctx->priv_host().str); - assert(sctx->user().str); - tmp_user->user.str = sctx->user().str; - tmp_user->user.length = strlen(sctx->user().str); + assert(sctx->priv_host); + tmp_user->host.str = sctx->priv_host; + tmp_user->host.length = strlen(sctx->priv_host); + assert(sctx->user); + tmp_user->user.str = sctx->user; + tmp_user->user.length = strlen(sctx->user); } user = get_current_user(thd, tmp_user); - bool is_self = !strcmp(sctx->user().length ? sctx->user().str : "", user->user.str) && - !my_strcasecmp(&my_charset_latin1, user->host.str, sctx->priv_host().str); - if (user->uses_replace_clause) { + bool is_self = !strcmp((sctx->user && strlen(sctx->user)) ? sctx->user : "", user->user.str) && + !my_strcasecmp(&my_charset_latin1, user->host.str, sctx->priv_host); + // mariadb has no REPLACE password feature + bool user_uses_replace_clause = false; + + if (user_uses_replace_clause) { if (is_self) { bool is_password_matched = false; if (tse_verify_password4existed_user(thd, user, is_password_matched)) { return -1; } if (!is_password_matched) { - my_error(ER_INCORRECT_CURRENT_PASSWORD, MYF(0)); + my_error(ER_NOT_VALID_PASSWORD, MYF(0)); return -1; } } else { @@ -368,10 +341,10 @@ static int tse_rewrite_alter_user4update_passwd(MYSQL_THD thd, string &sql_str) tse_remove_replace_clause4sql(rw_query_sql); } regex current_user_pattern(" \\s*current_user[(][)] ", regex_constants::icase); - string current_user_name(sctx->user().str); + string current_user_name(sctx->user); current_user_name = tse_deserilize_username_with_single_quotation(current_user_name); string user2host(""); - user2host = " '" + current_user_name + "'@'" + string(sctx->priv_host().str) + "'"; + user2host = " '" + current_user_name + "'@'" + string(sctx->priv_host) + "'"; rw_query_sql = regex_replace(rw_query_sql, current_user_pattern, user2host.c_str()); sql_str = rw_query_sql; return 0; @@ -385,6 +358,7 @@ static int tse_check_alter_user(string &sql_str, MYSQL_THD thd, bool &need_forwa return tse_rewrite_alter_user4update_passwd(thd, sql_str); } +#if 0 static int tse_rewrite_setpasswd(MYSQL_THD thd, string &sql_str) { // match: set password = | set password to | set password for current_user(),but 'to' and '=' dont match for replacing regex add_or_rewrite_for_pattern("^set \\s*password\\s*((?=to|=)|for \\s*current_user[(][)])", regex_constants::icase); @@ -397,15 +371,19 @@ static int tse_rewrite_setpasswd(MYSQL_THD thd, string &sql_str) { set_var_base *var; while ((var = it++)) { set_var_password *set_passwd = static_cast(var); - const LEX_USER *user_for_setpasswd = set_passwd->get_user(); - string username(user_for_setpasswd->user.str); + const LEX_USER *user_for_setpasswd = set_passwd->user; + const char *cname = user_for_setpasswd->user.str; + string username(cname); + username = tse_deserilize_username_with_single_quotation(username); user2host = "SET PASSWORD FOR '" + username + "'@'" + string(user_for_setpasswd->host.str) + "' "; rw_query_sql = regex_replace(rw_query_sql, add_or_rewrite_for_pattern, user2host.c_str()); // 为当前用户设置密码,为不报错不加replace - if (user_for_setpasswd->uses_replace_clause && - !strcmp(thd->m_main_security_ctx.priv_user().str, user_for_setpasswd->user.str)) { + // mariadb has no REPLACE password feature + bool user_uses_replace_clause = false; + if (user_uses_replace_clause && + !strcmp(thd->main_security_ctx.priv_user, cname)) { // check replacing old password is correct or not bool is_password_matched = false; if (tse_verify_password4existed_user(thd, user_for_setpasswd, is_password_matched)) { @@ -414,7 +392,7 @@ static int tse_rewrite_setpasswd(MYSQL_THD thd, string &sql_str) { if (is_password_matched) { tse_remove_replace_clause4sql(rw_query_sql); } else { - my_error(ER_INCORRECT_CURRENT_PASSWORD, MYF(0)); + my_error(ER_NOT_VALID_PASSWORD, MYF(0)); return -1; } } @@ -422,7 +400,9 @@ static int tse_rewrite_setpasswd(MYSQL_THD thd, string &sql_str) { sql_str = rw_query_sql; return 0; } +#endif +#if 0 static int tse_check_set_password(SENSI_INFO string &sql_str, MYSQL_THD thd, bool &need_forward) { if (tse_check_dcl(sql_str, thd, need_forward) != 0) { return -1; @@ -430,6 +410,7 @@ static int tse_check_set_password(SENSI_INFO string &sql_str, MYSQL_THD thd, boo return tse_rewrite_setpasswd(thd, sql_str); } +#endif static int tse_check_flush(string &, MYSQL_THD thd, bool &need_forward) { need_forward = thd->lex->type & (REFRESH_FOR_EXPORT | REFRESH_READ_LOCK | REFRESH_GRANT); @@ -459,12 +440,13 @@ static uint32_t tse_set_var_option(bool is_null_value, bool is_set_default_value if (is_set_default_value) { options |= TSE_SET_VARIABLE_TO_DEFAULT; } + /* if (setvar->type == OPT_PERSIST_ONLY) { options |= TSE_SET_VARIABLE_PERSIST_ONLY; } if (setvar->type == OPT_PERSIST) { options |= TSE_SET_VARIABLE_PERSIST; - } + }*/ return options; } @@ -478,8 +460,8 @@ static int tse_set_var_meta(MYSQL_THD thd, uint32_t options, const char* base_na tse_ddl_broadcast_request broadcast_req {{0}, {0}, {0}, {0}, 0, 0, 0, 0, {0}}; broadcast_req.options |= TSE_NOT_NEED_CANTIAN_EXECUTE; - broadcast_req.options |= (thd->lex->contains_plaintext_password ? TSE_CURRENT_SQL_CONTAIN_PLAINTEXT_PASSWORD : 0); - string sql = string(thd->query().str).substr(0, thd->query().length); + //broadcast_req.options |= (thd->lex->contains_plaintext_password ? TSE_CURRENT_SQL_CONTAIN_PLAINTEXT_PASSWORD : 0); + string sql = string(thd->query()).substr(0, thd->query_length()); // user_name存变量名,user_ip存变量值 FILL_BROADCAST_BASE_REQ(broadcast_req, sql.c_str(), var_name.c_str(), @@ -518,6 +500,7 @@ static int tse_get_variables_value_string(MYSQL_THD thd, string &sql_str, set_va String* new_str; String str; tse_log_system("[TSE_DDL_REWRITE]:get system var value. %s", sql_str.c_str()); +#if 0 #ifdef FEATURE_X_FOR_MYSQL_26 if (itemFuncSys->bind(thd)) { need_forward = false; @@ -525,13 +508,16 @@ static int tse_get_variables_value_string(MYSQL_THD thd, string &sql_str, set_va } #endif itemFuncSys->fixed = true; +#endif new_str = itemFuncSys->val_str(&str); if (!new_str) { is_null_value = true; val_str = "null"; +#if 0 } else if (new_str == itemFuncSys->error_str()) { need_forward = false; return -1; +#endif } else { val_str = new_str->c_ptr(); } @@ -597,12 +583,13 @@ static int tse_check_set_opt(string &sql_str, MYSQL_THD thd, bool &need_forward) }; setvar->m_var_tracker.access_system_variable(thd, f).value_or(true); name_str = setvar->m_var_tracker.get_var_name(); -#elif defined(FEATURE_X_FOR_MYSQL_26) +//#elif defined(FEATURE_X_FOR_MYSQL_26) +#else if (setvar && setvar->var) { - need_forward = !setvar->var->is_readonly() && setvar->is_global_persist(); + need_forward = !setvar->var->is_readonly() && false /*setvar->is_global_persist()*/ ; name_str = setvar->var->name.str; #endif - + if (!contain_subselect) { /* get user value (@xxxxx) as string */ if (!setvar->value) { @@ -626,10 +613,11 @@ static int tse_check_set_opt(string &sql_str, MYSQL_THD thd, bool &need_forward) if(IS_METADATA_NORMALIZATION() && !contain_subselect && need_forward && setvar) { if (setvar->check(thd) == 0) { uint32_t options = tse_set_var_option(is_null_value, is_set_default_value, setvar); -#ifdef FEATURE_X_FOR_MYSQL_26 - ret = tse_set_var_meta(thd, options, setvar->base.str, name_str, val_str); -#elif defined(FEATURE_X_FOR_MYSQL_32) +#ifdef FEATURE_X_FOR_MYSQL_32 ret = tse_set_var_meta(thd, options, setvar->m_var_tracker.get_var_name(), name_str, val_str); +//#elif defined(FEATURE_X_FOR_MYSQL_26) +#else + ret = tse_set_var_meta(thd, options, setvar->base.str, name_str, val_str); #endif } else { thd->clear_error(); @@ -660,17 +648,17 @@ static int tse_check_ddl_engine(string &, MYSQL_THD thd, bool &need_forward) { tse_name.str = tse_hton_name; tse_name.length = strlen(tse_hton_name); handlerton *tse_handlerton = nullptr; - // 获取TSE引擎handlerton指针,如果thd->lex->create_info->db_type和TSE引擎指针不相等,那么必然不是TSE引擎 + // 获取TSE引擎handlerton指针,如果thd->lex->create_info.db_type和TSE引擎指针不相等,那么必然不是TSE引擎 plugin_ref plugin = ha_resolve_by_name(thd, &tse_name, false); if (plugin) { - tse_handlerton = plugin_data(plugin); + tse_handlerton = plugin_data(plugin, handlerton *); } // 检查ddl语句是否显示指定非CTC - if (thd->lex->create_info != nullptr && - thd->lex->create_info->db_type != nullptr && - thd->lex->create_info->db_type != tse_handlerton && - !(thd->lex->create_info->options & HA_LEX_CREATE_TMP_TABLE)) { + if ( + thd->lex->create_info.db_type != nullptr && + thd->lex->create_info.db_type != tse_handlerton && + !(thd->lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)) { my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), "Once the CTC is loaded, it must be used as the default engine. To specify other engine for table, uninstall the CTC first."); return -1; @@ -680,16 +668,15 @@ static int tse_check_ddl_engine(string &, MYSQL_THD thd, bool &need_forward) { // create like table 检查是否是系统库 if (thd->lex->query_tables != nullptr && thd->lex->query_tables->next_global != nullptr && - thd->lex->create_info != nullptr && - thd->lex->create_info->options & HA_LEX_CREATE_TABLE_LIKE && - !(thd->lex->create_info->options & HA_LEX_CREATE_TMP_TABLE) && - !thd->lex->drop_temporary) { - const char *ddl_db = thd->lex->query_tables->next_global->db; + thd->lex->create_info.like() && + !(thd->lex->create_info.tmp_table())) { + const char *ddl_db = thd->lex->query_tables->next_global->db.str; return is_system_db(ddl_db); } } // create tablespace 检查是否为engine=Innodb情况 +#ifdef SUPPORTS_ALTER_TABLESPACE if (thd->lex->sql_command == SQLCOM_ALTER_TABLESPACE) { const Sql_cmd_tablespace *sct = dynamic_cast(thd->lex->m_sql_cmd); if (sct != nullptr && @@ -700,13 +687,12 @@ static int tse_check_ddl_engine(string &, MYSQL_THD thd, bool &need_forward) { return -1; } } - +#endif if (!IS_METADATA_NORMALIZATION()) { // create表 && drop表/库 (检查是否是系统库上ddl) if (thd->lex->query_tables != nullptr && - (thd->lex->create_info != nullptr && !(thd->lex->create_info->options & HA_LEX_CREATE_TMP_TABLE)) && - !thd->lex->drop_temporary) { - const char *ddl_db = thd->lex->query_tables->db; + !thd->lex->create_info.tmp_table()) { + const char *ddl_db = thd->lex->query_tables->db.str; return is_system_db(ddl_db); } } @@ -725,9 +711,9 @@ static int tse_check_unspport_ddl(string &, MYSQL_THD, bool &) { } static int tse_read_only_ddl(string &, MYSQL_THD thd, bool &need_forward) { - if (check_readonly(thd, true) || - (thd->lex->query_tables != nullptr && - check_schema_readonly(thd, thd->lex->query_tables->table_name))) { + if (check_readonly(thd, true) /* || + (thd->lex->query_tables != nullptr &&//mariadb database has no readonly property + check_schema_readonly(thd, thd->lex->query_tables->table_name.str))*/ ) { need_forward = false; } return 0; @@ -745,7 +731,8 @@ static int tse_lock_tables_ddl(string &, MYSQL_THD thd, bool &) { #ifdef FEATURE_X_FOR_MYSQL_32 Table_ref *tables = thd->lex->query_tables; for (Table_ref *table = tables; table != NULL; table = table->next_global) { -#elif defined(FEATURE_X_FOR_MYSQL_26) +#else +//#elif defined(FEATURE_X_FOR_MYSQL_26) TABLE_LIST *tables = thd->lex->query_tables; for (TABLE_LIST *table = tables; table != NULL; table = table->next_global) { #endif @@ -755,7 +742,7 @@ static int tse_lock_tables_ddl(string &, MYSQL_THD thd, bool &) { TSE_RETURN_IF_NOT_ZERO(get_tch_in_handler_data(hton, thd, tch)); int32_t mdl_type = 0; - auto desc_type = table->lock_descriptor().type; + auto desc_type = table->lock_type; if (desc_type >= TL_READ_DEFAULT && desc_type <= TL_READ_NO_INSERT) { mdl_type = (int32_t)MDL_SHARED_READ_ONLY; } else if (desc_type >= TL_WRITE_ALLOW_WRITE && desc_type <= TL_WRITE_ONLY) { @@ -765,8 +752,8 @@ static int tse_lock_tables_ddl(string &, MYSQL_THD thd, bool &) { } tse_lock_table_info lock_info = {{0}, {0}, {0}, {0}, SQLCOM_LOCK_TABLES, mdl_type}; FILL_USER_INFO_WITH_THD(lock_info, thd); - strncpy(lock_info.db_name, table->db, SMALL_RECORD_SIZE - 1); - strncpy(lock_info.table_name, table->table_name, SMALL_RECORD_SIZE - 1); + strncpy(lock_info.db_name, table->db.str, SMALL_RECORD_SIZE - 1); + strncpy(lock_info.table_name, table->table_name.str, SMALL_RECORD_SIZE - 1); int err_code = 0; ret = tse_lock_table(&tch, lock_info.db_name, &lock_info, &err_code); if (ret != 0) { @@ -779,7 +766,8 @@ static int tse_lock_tables_ddl(string &, MYSQL_THD thd, bool &) { if (ret != 0) { #ifdef FEATURE_X_FOR_MYSQL_32 for (Table_ref *table = tables; table != NULL; table = table->next_global) { -#elif defined(FEATURE_X_FOR_MYSQL_26) +#else +//#elif defined(FEATURE_X_FOR_MYSQL_26) for (TABLE_LIST *table = tables; table != NULL; table = table->next_global) { #endif tianchi_handler_t tch; @@ -789,8 +777,8 @@ static int tse_lock_tables_ddl(string &, MYSQL_THD thd, bool &) { TSE_RETURN_IF_NOT_ZERO(get_tch_in_handler_data(hton, thd, tch)); tse_lock_table_info lock_info = {{0}, {0}, {0}, {0}, SQLCOM_LOCK_TABLES, (int32_t)TL_UNLOCK}; FILL_USER_INFO_WITH_THD(lock_info, thd); - strncpy(lock_info.db_name, table->db, SMALL_RECORD_SIZE - 1); - strncpy(lock_info.table_name, table->table_name, SMALL_RECORD_SIZE - 1); + strncpy(lock_info.db_name, table->db.str, SMALL_RECORD_SIZE - 1); + strncpy(lock_info.table_name, table->table_name.str, SMALL_RECORD_SIZE - 1); ret = tse_unlock_table(&tch, ctc_instance_id, &lock_info); if (ret != 0) { tse_log_error("[TSE_DDL_REWRITE]:unlock table failed, table:%s.%s", lock_info.db_name, lock_info.table_name); @@ -834,13 +822,13 @@ static unordered_map {SQLCOM_RENAME_USER, {false, tse_check_dcl}}, {SQLCOM_REVOKE_ALL, {false, tse_check_dcl}}, {SQLCOM_ALTER_USER, {false, tse_check_alter_user}}, - {SQLCOM_ALTER_USER_DEFAULT_ROLE, {false, tse_check_dcl}}, + //{SQLCOM_ALTER_USER_DEFAULT_ROLE, {false, tse_check_dcl}}, {SQLCOM_CREATE_ROLE, {false, tse_check_dcl}}, {SQLCOM_DROP_ROLE, {false, tse_check_dcl}}, - {SQLCOM_SET_ROLE, {false, tse_check_dcl}}, + //{SQLCOM_SET_ROLE, {false, tse_check_dcl}}, {SQLCOM_GRANT_ROLE, {false, tse_check_dcl}}, {SQLCOM_REVOKE_ROLE, {false, tse_check_dcl}}, - {SQLCOM_SET_PASSWORD, {false, tse_check_set_password}}, + //{SQLCOM_SET_PASSWORD, {false, tse_check_set_password}}, // prepare statement {SQLCOM_PREPARE, {false, tse_check_ddl}}, @@ -867,8 +855,8 @@ static unordered_map // Locking, broadcast {SQLCOM_LOCK_TABLES, {true, tse_lock_tables_ddl}}, {SQLCOM_UNLOCK_TABLES, {true, tse_unlock_tables_ddl}}, - {SQLCOM_LOCK_INSTANCE, {false, NULL}}, - {SQLCOM_UNLOCK_INSTANCE, {false, NULL}}, + //{SQLCOM_LOCK_INSTANCE, {false, NULL}}, + //{SQLCOM_UNLOCK_INSTANCE, {false, NULL}}, // analyze broardcast for share cbo {SQLCOM_ANALYZE, {true, NULL}}, @@ -885,7 +873,7 @@ static unordered_map {SQLCOM_OPTIMIZE, {false, tse_check_ddl}}, {SQLCOM_CHECK, {false, tse_check_ddl}}, {SQLCOM_RENAME_TABLE, {false, tse_check_ddl}}, - {SQLCOM_ALTER_TABLESPACE, {false, tse_check_ddl_engine}}, + //{SQLCOM_ALTER_TABLESPACE, {false, tse_check_ddl_engine}}, // drop table operations, do not broadcast in rewriter {SQLCOM_DROP_TABLE, {false, tse_check_ddl_engine}}, @@ -910,20 +898,20 @@ static unordered_map {SQLCOM_ALTER_SERVER, {false, tse_check_unspport_ddl}}, // 不支持alter instance - {SQLCOM_ALTER_INSTANCE, {false, tse_check_unspport_ddl}}, + //{SQLCOM_ALTER_INSTANCE, {false, tse_check_unspport_ddl}}, // 不支持import table - {SQLCOM_IMPORT, {false, tse_check_unspport_ddl}}, + //{SQLCOM_IMPORT, {false, tse_check_unspport_ddl}}, // 不支持创建,删除SRS - {SQLCOM_CREATE_SRS, {false, tse_check_unspport_ddl}}, - {SQLCOM_DROP_SRS, {false, tse_check_unspport_ddl}}, + //{SQLCOM_CREATE_SRS, {false, tse_check_unspport_ddl}}, + //{SQLCOM_DROP_SRS, {false, tse_check_unspport_ddl}}, // 不支持创建,修改,删除,设置资源组 - {SQLCOM_CREATE_RESOURCE_GROUP, {false, tse_check_unspport_ddl}}, - {SQLCOM_ALTER_RESOURCE_GROUP, {false, tse_check_unspport_ddl}}, - {SQLCOM_DROP_RESOURCE_GROUP, {false, tse_check_unspport_ddl}}, - {SQLCOM_SET_RESOURCE_GROUP, {false, tse_check_unspport_ddl}}, + //{SQLCOM_CREATE_RESOURCE_GROUP, {false, tse_check_unspport_ddl}}, + //{SQLCOM_ALTER_RESOURCE_GROUP, {false, tse_check_unspport_ddl}}, + //{SQLCOM_DROP_RESOURCE_GROUP, {false, tse_check_unspport_ddl}}, + //{SQLCOM_SET_RESOURCE_GROUP, {false, tse_check_unspport_ddl}}, // XA operations - unsupported {SQLCOM_XA_START, {false, tse_check_unspport_ddl}}, @@ -952,9 +940,10 @@ bool is_dcl_sql_cmd(enum_sql_command sql_cmd) { if (sql_cmd == SQLCOM_GRANT || sql_cmd == SQLCOM_REVOKE || sql_cmd == SQLCOM_CREATE_USER || sql_cmd == SQLCOM_DROP_USER || sql_cmd == SQLCOM_RENAME_USER || sql_cmd == SQLCOM_REVOKE_ALL || - sql_cmd == SQLCOM_ALTER_USER || sql_cmd == SQLCOM_ALTER_USER_DEFAULT_ROLE || + sql_cmd == SQLCOM_ALTER_USER || //sql_cmd == SQLCOM_ALTER_USER_DEFAULT_ROLE || sql_cmd == SQLCOM_CREATE_ROLE || sql_cmd == SQLCOM_DROP_ROLE || - sql_cmd == SQLCOM_SET_ROLE || sql_cmd ==SQLCOM_GRANT_ROLE || + //sql_cmd == SQLCOM_SET_ROLE || + sql_cmd ==SQLCOM_GRANT_ROLE || sql_cmd == SQLCOM_REVOKE_ROLE) { return true; } @@ -966,7 +955,7 @@ bool is_dcl_sql_cmd(enum_sql_command sql_cmd) { static PSI_memory_key key_memory_tse_ddl_rewriter; static PSI_memory_info all_rewrite_memory[] = { - {&key_memory_tse_ddl_rewriter, "ctc_ddl_rewriter", 0, 0, PSI_DOCUMENT_ME}}; + {&key_memory_tse_ddl_rewriter, "ctc_ddl_rewriter", 0}}; static int plugin_init(MYSQL_PLUGIN) { const char *category = "rewriter"; @@ -995,10 +984,10 @@ static void tse_ddl_rewrite_handle_error(MYSQL_THD thd, int ret, tse_ddl_broadca sql_without_plaintext_password(&broadcast_req).c_str(), broadcast_req.user_name, broadcast_req.err_code, broadcast_req.err_msg); // unlock when lock instance failed - if (sql_cmd == SQLCOM_LOCK_INSTANCE) { + /*if (sql_cmd == SQLCOM_LOCK_INSTANCE) { tse_check_unlock_instance(thd); } - +*/ return; } @@ -1012,9 +1001,9 @@ int ddl_broadcast_and_wait(MYSQL_THD thd, string &query_str, tse_ddl_broadcast_request broadcast_req {{0}, {0}, {0}, {0}, 0, 0, 0, 0, {0}}; - if (thd->db().str != NULL && strlen(thd->db().str) > 0 && + if (thd->db.str != NULL && strlen(thd->db.str) > 0 && broadcast_cmd.need_select_db) { - strncpy(broadcast_req.db_name, thd->db().str, SMALL_RECORD_SIZE - 1); + strncpy(broadcast_req.db_name, thd->db.str, SMALL_RECORD_SIZE - 1); } if (sql_cmd == SQLCOM_SET_OPTION) { @@ -1022,10 +1011,10 @@ int ddl_broadcast_and_wait(MYSQL_THD thd, string &query_str, broadcast_req.options |= TSE_SET_VARIABLE_WITH_SUBSELECT; } broadcast_req.options |= TSE_NOT_NEED_CANTIAN_EXECUTE; - broadcast_req.options |= (thd->lex->contains_plaintext_password ? TSE_CURRENT_SQL_CONTAIN_PLAINTEXT_PASSWORD : 0); - FILL_BROADCAST_BASE_REQ(broadcast_req, query_str.c_str(), thd->m_main_security_ctx.priv_user().str, - thd->m_main_security_ctx.priv_host().str, ctc_instance_id, sql_cmd); - + //broadcast_req.options |= (thd->lex->contains_plaintext_password ? TSE_CURRENT_SQL_CONTAIN_PLAINTEXT_PASSWORD : 0); + FILL_BROADCAST_BASE_REQ(broadcast_req, query_str.c_str(), thd->main_security_ctx.priv_user, + thd->main_security_ctx.priv_host, ctc_instance_id, sql_cmd); + vector ticket_list; if (sql_cmd == SQLCOM_LOCK_TABLES) { int pre_lock_ret = tse_lock_table_pre(thd, ticket_list); @@ -1081,14 +1070,14 @@ bool plugin_ddl_passthru(MYSQL_THD thd, bool check_agent_connection(MYSQL_THD thd) { // Only user from localhost/127.0.0.1 or % can be proxied remotely - if (strcmp(thd->m_main_security_ctx.priv_host().str, my_localhost) != 0 && - strcmp(thd->m_main_security_ctx.priv_host().str, "127.0.0.1") != 0 && - strcmp(thd->m_main_security_ctx.priv_host().str, "%") != 0 && - strcmp(thd->m_main_security_ctx.priv_host().str, "skip-grants host") != 0) { + if (strcmp(thd->main_security_ctx.priv_host, my_localhost) != 0 && + strcmp(thd->main_security_ctx.priv_host, "127.0.0.1") != 0 && + strcmp(thd->main_security_ctx.priv_host, "%") != 0 && + strcmp(thd->main_security_ctx.priv_host, "skip-grants host") != 0) { my_printf_error(ER_DISALLOWED_OPERATION, "%s@%s is not allowed for DDL remote execution!", MYF(0), - thd->m_main_security_ctx.priv_user().str, - thd->m_main_security_ctx.priv_host().str); + thd->main_security_ctx.priv_user, + thd->main_security_ctx.priv_host); return true; } @@ -1114,21 +1103,21 @@ int ctc_record_sql(MYSQL_THD thd, bool need_select_db) { tse_ddl_broadcast_request broadcast_req {{0}, {0}, {0}, {0}, 0, 0, 0, 0, {0}}; - if (thd->db().str != NULL && strlen(thd->db().str) > 0 && need_select_db) { - strncpy(broadcast_req.db_name, thd->db().str, SMALL_RECORD_SIZE - 1); + if (thd->db.str != NULL && strlen(thd->db.str) > 0 && need_select_db) { + strncpy(broadcast_req.db_name, thd->db.str, SMALL_RECORD_SIZE - 1); } broadcast_req.options |= TSE_NOT_NEED_CANTIAN_EXECUTE; - broadcast_req.options |= (thd->lex->contains_plaintext_password ? TSE_CURRENT_SQL_CONTAIN_PLAINTEXT_PASSWORD : 0); - string sql = string(thd->query().str).substr(0, thd->query().length); + //broadcast_req.options |= (thd->lex->contains_plaintext_password ? TSE_CURRENT_SQL_CONTAIN_PLAINTEXT_PASSWORD : 0); + string sql = string(thd->query()).substr(0, thd->query_length()); + + FILL_BROADCAST_BASE_REQ(broadcast_req, sql.c_str(), thd->main_security_ctx.priv_user, + thd->main_security_ctx.priv_host, ctc_instance_id, (uint8_t)thd->lex->sql_command); - FILL_BROADCAST_BASE_REQ(broadcast_req, sql.c_str(), thd->m_main_security_ctx.priv_user().str, - thd->m_main_security_ctx.priv_host().str, ctc_instance_id, (uint8_t)thd->lex->sql_command); - int ret = ctc_record_sql_for_cantian(&tch, &broadcast_req, false); update_sess_ctx_by_tch(tch, hton, thd); - tse_log_system("[TSE_REWRITE_META]:ret:%d, query:%s", ret, sql_without_plaintext_password(&broadcast_req).c_str()); + //tse_log_system("[TSE_REWRITE_META]:ret:%d, query:%s", ret, sql_without_plaintext_password(&broadcast_req).c_str()); this causes a crash... return ret; } @@ -1179,16 +1168,17 @@ bool plugin_ddl_block(MYSQL_THD thd, return false; } -// due to MDL_key::BACKUP_LOCK`s MDL_INTENTION_EXCLUSIVE comflicts with MDL_key::BACKUP_LOCK`s MDL_SHARED (user execute STMT `lock instance for backup`) +#if 0 +// due to MDL_key::BACKUP`s MDL_INTENTION_EXCLUSIVE comflicts with MDL_key::BACKUP`s MDL_SHARED (user execute STMT `lock instance for backup`) static bool tse_is_instance_locked_by_backup(MYSQL_THD thd) { - MDL_request mdl_request; - MDL_key key(MDL_key::BACKUP_LOCK, "", ""); // check this conn whether has backup S lock - if (thd->mdl_context.owns_equal_or_stronger_lock(&key, MDL_SHARED)) { + if (thd->mdl_context.is_lock_owner(MDL_key::BACKUP, "", "", MDL_SHARED)) { return true; } + + MDL_request mdl_request; // check other conn whether has backup S lock - MDL_REQUEST_INIT(&mdl_request, MDL_key::BACKUP_LOCK, "", "", MDL_INTENTION_EXCLUSIVE, MDL_EXPLICIT); + MDL_REQUEST_INIT(&mdl_request, MDL_key::BACKUP, "", "", MDL_INTENTION_EXCLUSIVE, MDL_EXPLICIT); if (thd->mdl_context.acquire_lock(&mdl_request, 0)) { thd->clear_error(); // clear lock failed error return true; @@ -1197,7 +1187,9 @@ static bool tse_is_instance_locked_by_backup(MYSQL_THD thd) { return false; } } +#endif +#if 0 static bool tse_is_have_global_read_lock(MYSQL_THD thd) { // check if current connetion hold global read lock, let it go if (thd->global_read_lock.is_acquired()) { @@ -1211,11 +1203,13 @@ static bool tse_is_have_global_read_lock(MYSQL_THD thd) { return false; } +#endif static inline bool tse_is_broadcast_by_storage_engine(ddl_broadcast_cmd broadcast_cmd) { return broadcast_cmd.pre_func == tse_check_ddl || broadcast_cmd.pre_func == tse_check_ddl_engine; } +#if 0 static bool tse_is_set_session_var(MYSQL_THD thd, string &query_str) { if (thd->lex->sql_command != SQLCOM_SET_OPTION) { return false; @@ -1242,7 +1236,9 @@ static bool tse_is_set_session_var(MYSQL_THD thd, string &query_str) { return false; } +#endif +#if 0 static int tse_check_metadata_switch() { metadata_switchs metadata_switch = (metadata_switchs)tse_get_metadata_switch(); switch (metadata_switch) { @@ -1265,7 +1261,9 @@ static int tse_check_metadata_switch() { return -1; } } +#endif +#ifdef SUPPORTS_PARSE_CLASS_EVENTS static int tse_ddl_rewrite(MYSQL_THD thd, mysql_event_class_t event_class, const void *event) { if (is_meta_version_initialize()) { @@ -1301,14 +1299,16 @@ static int tse_ddl_rewrite(MYSQL_THD thd, mysql_event_class_t event_class, if (check_metadata_switch_result != 1 && !(need_forward && sql_cmd == SQLCOM_SET_OPTION)) { return check_metadata_switch_result; } - +#ifdef SUPPORTS_LOCK_INSTANCE_STMT if (sql_cmd == SQLCOM_LOCK_INSTANCE) { if (tse_check_lock_instance(thd, need_forward)) { return -1; } } else if (sql_cmd == SQLCOM_UNLOCK_INSTANCE) { tse_check_unlock_instance(thd); - } else if (!IS_METADATA_NORMALIZATION() && (need_forward || tse_is_broadcast_by_storage_engine(it->second))) { + } else +#endif + if (!IS_METADATA_NORMALIZATION() && (need_forward || tse_is_broadcast_by_storage_engine(it->second))) { // block ddl when instance has exclusive backup lock (LOCK INSTANCE FOR BACKUP), ref sql_backup_lock.cc if (tse_is_instance_locked_by_backup(thd)) { @@ -1333,16 +1333,46 @@ static int tse_ddl_rewrite(MYSQL_THD thd, mysql_event_class_t event_class, return need_forward && ddl_broadcast_and_wait(thd, query_str, (uint8_t)sql_cmd, broadcast_cmd); // 0: success other: fail } +#else + +static void tse_ddl_rewrite(MYSQL_THD thd, uint event_class, + const void *event) { + +} +#endif + +ACL_USER* find_acl_user(const char *host, const char *user, bool exact); + + +int tse_verify_password4existed_user(MYSQL_THD thd, const LEX_USER *existed_user, bool &res) { + ACL_USER *acl_user = nullptr; + //plugin_ref plugin = nullptr; + //int is_error = 0; + acl_user = find_acl_user(existed_user->host.str, existed_user->user.str, true); + if (!acl_user) { + sql_print_error("tse_verify_password failed, find acl user failed"); + return -1; + } + res = false; + // TODO: do simple password verification + //mariadb has no multiple auth plugins or multiple credentials per user + return 0; +} + /* Audit plugin descriptor. */ static struct st_mysql_audit tse_ddl_rewriter_descriptor = { MYSQL_AUDIT_INTERFACE_VERSION, /* interface version */ nullptr, /* release_thd() */ tse_ddl_rewrite, /* event_notify() */ +#ifdef SUPPORTS_PARSE_CLASS_EVENTS { 0, 0, - (unsigned long)MYSQL_AUDIT_PARSE_POSTPARSE, + (unsigned long)MYSQL_AUDIT_PARSE_POSTPARSE } /* class mask */ +#else + {0} +#endif }; #if !defined __STRICT_ANSI__ && defined __GNUC__ && !defined __clang__ @@ -1383,7 +1413,7 @@ struct st_mysql_plugin g_tse_ddl_rewriter_plugin = { /* the function to invoke when plugin is un installed */ /* int (*)(void*); */ - nullptr, + ///nullptr, /* the function to invoke when plugin is unloaded */ /* int (*)(void*); */ @@ -1405,5 +1435,5 @@ struct st_mysql_plugin g_tse_ddl_rewriter_plugin = { /* Plugin flags */ /* unsigned long */ - STRUCT_FLD(flags, PLUGIN_OPT_ALLOW_EARLY), + STRUCT_FLD(flags, 0), }; diff --git a/storage/tianchi/tse_ddl_util.cc b/storage/tianchi/tse_ddl_util.cc index f256be4ba2f5d317d92160af790c8d29d417f62e..b6dee087611b35806f7a030eeea463cecd3cb81d 100644 --- a/storage/tianchi/tse_ddl_util.cc +++ b/storage/tianchi/tse_ddl_util.cc @@ -10,13 +10,15 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ - +#include "my_global.h" #include "tse_ddl_util.h" #include "tse_log.h" #include "sql/sql_class.h" -#include "sql/create_field.h" +//#include "sql/create_field.h" #include "sql/sql_lex.h" #include "sql/sql_table.h" +#include "sql/template_utils.h" +#include "sql/extra_defs.h" using namespace std; @@ -90,7 +92,7 @@ bool check_data_file_name(const char *data_file_name) { Field *tse_get_field_by_name(TABLE *form, const char *name) { for (uint32_t i = 0; i < form->s->fields; i++) { - if (strcasecmp(form->field[i]->field_name, name) == 0) { + if (strcasecmp(form->field[i]->field_name.str, name) == 0) { return form->field[i]; } } @@ -99,12 +101,12 @@ Field *tse_get_field_by_name(TABLE *form, const char *name) { const Create_field *tse_get_create_field_by_column_name(THD *thd, const char* field_name) { // 处理普通建表 - Alter_info *alter_info = thd->lex->alter_info; + Alter_info *alter_info = &thd->lex->alter_info; const Create_field *field = NULL; if (alter_info != nullptr) { List_iterator_fast field_it(alter_info->create_list); while ((field = field_it++)) { - if(strcmp(field->field_name, field_name) == 0) { + if(strcmp(field->field_name.str, field_name) == 0) { return field; } } @@ -113,16 +115,56 @@ const Create_field *tse_get_create_field_by_column_name(THD *thd, const char* fi // 此时alter_info->create_list为空,需生成Create_field TABLE tmp_table MY_ATTRIBUTE((unused)); // lex execution is not started, item->field cannot be got. - if(!thd->lex->is_exec_started()) { + /*if(!thd->lex->is_exec_started()) { //how could we get here before execution started? return nullptr; - } - mem_root_deque *items = thd->lex->unit->get_unit_column_types(); - for (Item *item : VisibleFields(*items)) { - if(strcmp(item->item_name.ptr(), field_name) == 0) { - Create_field *cr_field = generate_create_field(thd, item, &tmp_table); - if (cr_field == nullptr) { + }*/ +/* + List_iterator inner_col_it(*item_in->unit->get_column_types(false)); + Item *outer_col, *inner_col; + + for (uint i= 0; i < item_in->left_expr->cols(); i++) + { + outer_col= item_in->left_expr->element_index(i); + inner_col= inner_col_it++; + +*/ + List_iterator itr(*(thd->lex->unit.get_column_types(false))); + Item_ident *item; + for (;;) { // all fields are visible for mariadb + item = down_cast(itr++); + if(strcmp(item->field_name.str, field_name) == 0) { + Field *table_field; +// Create_field *cr_field = generate_create_field(thd, item, &tmp_table); +// if (cr_field == nullptr) { +// break; +// } + Field *tmp_field= item->create_field_for_create_select(thd->mem_root, + &tmp_table); + + if (!tmp_field) + break; + + switch (item->type()) + { + /* + We have to take into account both the real table's fields and + pseudo-fields used in trigger's body. These fields are used + to copy defaults values later inside constructor of + the class Create_field. + */ + case Item::FIELD_ITEM: + case Item::TRIGGER_FIELD_ITEM: + table_field= ((Item_field *) item)->field; break; + default: + table_field= NULL; } + + Create_field *cr_field= new (thd->mem_root) + Create_field(thd, tmp_field, table_field); + if (!cr_field) + break; + return cr_field; } } @@ -133,12 +175,12 @@ const Create_field *tse_get_create_field_by_column_name(THD *thd, const char* fi if (thd->lex->sql_command != SQLCOM_CREATE_TABLE) { return nullptr; } - Alter_info local_alter_info(thd->mem_root); - const dd::Table *src_table = nullptr; + + //Alter_info* local_alter_info; Alter_table_ctx local_alter_ctx MY_ATTRIBUTE((unused)); #ifdef FEATURE_X_FOR_MYSQL_32 Table_ref *table_list = thd->lex->query_tables->next_global; -#elif defined(FEATURE_X_FOR_MYSQL_26) +#else TABLE_LIST *table_list = thd->lex->query_tables->next_global; #endif if (table_list != nullptr && table_list->table != nullptr) { @@ -149,56 +191,48 @@ const Create_field *tse_get_create_field_by_column_name(THD *thd, const char* fi // row_type denontes the desired row_type, and a different row_type may be // assigned to real_row_type later. create_info.row_type = table_list->table->s->row_type; +#if 0 create_info.init_create_options_from_share(table_list->table->s, create_info.used_fields); // Prepare Create_field and Key_spec objects for ALTER and upgrade. - prepare_fields_and_keys(thd, src_table, table_list->table, &create_info, &local_alter_info, + prepare_fields_and_keys(thd, table_list->table, &create_info, &local_alter_info, &local_alter_ctx, create_info.used_fields); - List_iterator_fast field_like_it(local_alter_info.create_list); + List_iterator_fast field_like_it(local_alter_info->create_list); while ((field = field_like_it++)) { - if(strcmp(field->field_name, field_name) == 0) { + if(strcmp(field->field_name.str, field_name) == 0) { return field; } } +#endif } - + return nullptr; } -tse_alter_table_drop_type tse_ddl_get_drop_type_from_mysql_type( - Alter_drop::drop_type drop_type) { +tse_alter_table_drop_type tse_ddl_get_drop_type_from_mysql_type(ulonglong drop_type) { + /* + PERIOD? + */ switch (drop_type) { - case Alter_drop::drop_type::KEY: + + case ALTER_DROP_INDEX: return TSE_ALTER_TABLE_DROP_KEY; - case Alter_drop::drop_type::COLUMN: + case ALTER_DROP_COLUMN: return TSE_ALTER_TABLE_DROP_COLUMN; - case Alter_drop::drop_type::FOREIGN_KEY: + case ALTER_DROP_FOREIGN_KEY: return TSE_ALTER_TABLE_DROP_FOREIGN_KEY; - case Alter_drop::drop_type::CHECK_CONSTRAINT: + case ALTER_DROP_CHECK_CONSTRAINT: return TSE_ALTER_TABLE_DROP_CHECK_CONSTRAINT; - case Alter_drop::drop_type::ANY_CONSTRAINT: - return TSE_ALTER_TABLE_DROP_ANY_CONSTRAINT; default: return TSE_ALTER_TABLE_DROP_UNKNOW; } } tse_alter_column_type tse_ddl_get_alter_column_type_from_mysql_type( - Alter_column::Type alter_column_type) { - switch (alter_column_type) {// SET_DEFAULT, DROP_DEFAULT, RENAME_COLUMN - case Alter_column::Type::SET_DEFAULT: - return TSE_ALTER_COLUMN_SET_DEFAULT; - case Alter_column::Type::DROP_DEFAULT: - return TSE_ALTER_COLUMN_DROP_DEFAULT; - case Alter_column::Type::RENAME_COLUMN: - return TSE_ALTER_COLUMN_RENAME_COLUMN; - case Alter_column::Type::SET_COLUMN_VISIBLE: - return TSE_ALTER_COLUMN_SET_COLUMN_VISIBLE; - case Alter_column::Type::SET_COLUMN_INVISIBLE: - return TSE_ALTER_COLUMN_SET_COLUMN_INVISIBLE; - default: - return TSE_ALTER_COLUMN_UNKNOW; - } + Alter_column *alt_col) { + if (alt_col->is_rename()) return TSE_ALTER_COLUMN_RENAME_COLUMN; + if (alt_col->default_value) return TSE_ALTER_COLUMN_SET_DEFAULT; + else return TSE_ALTER_COLUMN_DROP_DEFAULT; } bool get_tse_key_type(const KEY *key_info, int32_t *ret_type) { @@ -206,7 +240,7 @@ bool get_tse_key_type(const KEY *key_info, int32_t *ret_type) { if (key_info->flags & HA_SPATIAL) { *ret_type = TSE_KEYTYPE_SPATIAL; } else if (key_info->flags & HA_NOSAME) { - if (!my_strcasecmp(system_charset_info, key_info->name, primary_key_name)) { + if (!my_strcasecmp(system_charset_info, key_info->name.str, primary_key_name.str)) { *ret_type = TSE_KEYTYPE_PRIMARY; } else { *ret_type = TSE_KEYTYPE_UNIQUE; @@ -233,15 +267,26 @@ bool get_tse_key_type(const KEY *key_info, int32_t *ret_type) { return true; } +struct key_alg_map_entry { + ha_key_alg ha_alg; + tse_ha_key_alg tse_alg; +}; + +static key_alg_map_entry g_key_alg_map[] = { + {HA_KEY_ALG_UNDEF, TSE_HA_KEY_ALG_SE_SPECIFIC}, + {HA_KEY_ALG_BTREE, TSE_HA_KEY_ALG_BTREE}, + {HA_KEY_ALG_RTREE, TSE_HA_KEY_ALG_RTREE}, + {HA_KEY_ALG_HASH, TSE_HA_KEY_ALG_HASH}, + {HA_KEY_ALG_LONG_HASH, TSE_HA_KEY_ALG_HASH}, + {HA_KEY_ALG_FULLTEXT, TSE_HA_KEY_ALG_FULLTEXT} +}; + bool get_tse_key_algorithm(ha_key_alg algorithm, int32_t *ret_algorithm) { *ret_algorithm = (int32_t)TSE_HA_KEY_ALG_BTREE; switch (algorithm) { case HA_KEY_ALG_RTREE: tse_log_error("unsupport index hash_type:HA_KEY_ALG_RTREE"); return true; - case HA_KEY_ALG_SE_SPECIFIC: - TSE_ENGINE_ERROR("unsupport index hash_type:HA_KEY_ALG_SE_SPECIFIC"); - return false; case HA_KEY_ALG_FULLTEXT: TSE_ENGINE_ERROR("unsupport index hash_type:HA_KEY_ALG_FULLTEXT"); return false; @@ -252,18 +297,16 @@ bool get_tse_key_algorithm(ha_key_alg algorithm, int32_t *ret_algorithm) { break; } // mysql字符序和daac的参数对接 - static map - g_tse_key_algorithm_map = { - {HA_KEY_ALG_SE_SPECIFIC, TSE_HA_KEY_ALG_SE_SPECIFIC}, - {HA_KEY_ALG_BTREE, TSE_HA_KEY_ALG_BTREE}, - {HA_KEY_ALG_RTREE, TSE_HA_KEY_ALG_RTREE}, - {HA_KEY_ALG_HASH, TSE_HA_KEY_ALG_HASH}, - {HA_KEY_ALG_FULLTEXT, TSE_HA_KEY_ALG_FULLTEXT}}; - auto it = g_tse_key_algorithm_map.find(algorithm); - if (it != g_tse_key_algorithm_map.end()) { - *ret_algorithm = (int32_t)it->second; - return true; + for (uint i = 0; i < sizeof(g_key_alg_map)/sizeof(key_alg_map_entry); i++) + { + auto *entry = g_key_alg_map + i; + if (algorithm == entry->ha_alg) + { + *ret_algorithm = (int32_t)entry->tse_alg; + return true; + } } + return false; } @@ -302,32 +345,35 @@ bool set_column_datatype(size_t set_num, TcDb__TseDDLColumnDef *column) { return false; } -bool tse_is_with_default_value(Field *field, const dd::Column *col_obj) { +bool tse_is_with_default_value(Field *field) { +#if 0 bool has_default_value = false; - if (col_obj != nullptr) { - const bool has_default = ((!field->is_flag_set(NO_DEFAULT_VALUE_FLAG) && - !(field->auto_flags & Field::NEXT_NUMBER)) && - !col_obj->is_default_value_null()) || - field->m_default_val_expr; - has_default_value = has_default && (col_obj->default_value_utf8().data()) != NULL; - } - const bool has_default_timestamp = field->has_insert_default_datetime_value_expression(); + const bool has_default = ((!field_has_flag(field, NO_DEFAULT_VALUE_FLAG) && + !(field->unireg_check & Field::NEXT_NUMBER)) && + true) || //!col_obj->is_default_value_null()) || TODO + field->default_value ;// m_default_val_expr; + has_default_value = has_default && field->table->s->default_values;//(col_obj->default_value_utf8().data()) != NULL; + + const bool has_default_timestamp = field->has_insert_default_datetime_value_expression(); if (has_default_value || has_default_timestamp) { return true; } +#endif return false; } -tse_ddl_fk_rule tse_ddl_get_foreign_key_rule(fk_option rule) { + +tse_ddl_fk_rule tse_ddl_get_foreign_key_rule(enum enum_fk_option rule) { + switch (rule) { case FK_OPTION_UNDEF: - case FK_OPTION_NO_ACTION: case FK_OPTION_RESTRICT: - case FK_OPTION_DEFAULT: + case FK_OPTION_NO_ACTION: + case FK_OPTION_SET_DEFAULT: return TSE_DDL_FK_RULE_RESTRICT; case FK_OPTION_CASCADE: return TSE_DDL_FK_RULE_CASCADE; - case FK_OPTION_SET_NULL: + case FK_OPTION_SET_NULL: return TSE_DDL_FK_RULE_SET_NULL; default: break; @@ -337,122 +383,50 @@ tse_ddl_fk_rule tse_ddl_get_foreign_key_rule(fk_option rule) { return TSE_DDL_FK_RULE_UNKNOW; } -tse_ddl_fk_rule tse_ddl_get_foreign_key_rule(dd::Foreign_key::enum_rule rule) { - switch (rule) { - case dd::Foreign_key::enum_rule::RULE_NO_ACTION: - case dd::Foreign_key::enum_rule::RULE_RESTRICT: - case dd::Foreign_key::enum_rule::RULE_SET_DEFAULT: - return TSE_DDL_FK_RULE_RESTRICT; - case dd::Foreign_key::enum_rule::RULE_CASCADE: - return TSE_DDL_FK_RULE_CASCADE; - case dd::Foreign_key::enum_rule::RULE_SET_NULL: - return TSE_DDL_FK_RULE_SET_NULL; - default: - break; - } - tse_log_error("unknown foreign key option %d", (int)rule); - assert(0); - return TSE_DDL_FK_RULE_UNKNOW; -} - -const dd::Index *tse_ddl_get_index_by_name(const dd::Table *tab_obj, - const char *index_name) { - for (const dd::Index *index : tab_obj->indexes()) { - if (strcmp(index->name().data(), index_name) == 0) { - return index; +const KEY*tse_ddl_get_index_by_name(TABLE *tbl, const char *index_name) { + for (uint i = 0; i < tbl->s->keys; i++) + { + KEY *key = tbl->s->key_info + i; + if (strcmp(key->name.str, index_name) == 0) { + return key; } } return nullptr; } -const dd::Column *tse_ddl_get_column_by_name(const dd::Table *table_def, - const char *col_name) { - for (auto iter : table_def->columns()) { - if (my_strcasecmp(system_charset_info, iter->name().data(), col_name) == 0) { - return iter; +const Field *tse_ddl_get_column_by_name(const TABLE *tbl, const char *col_name) { + + for (uint i = 0; i < tbl->s->fields; i++) + { + Field *fld = tbl->field[i]; + + if (my_strcasecmp(system_charset_info, fld->field_name.str, col_name) == 0) { + return fld; } } return nullptr; } -bool tse_ddl_get_create_key_type(dd::Index::enum_index_type type, int32_t *ret_type) { - *ret_type = TSE_KEYTYPE_UNKNOW; - switch (type) { - case dd::Index::enum_index_type::IT_PRIMARY: - *ret_type = TSE_KEYTYPE_PRIMARY; - return true; - case dd::Index::enum_index_type::IT_UNIQUE: - *ret_type = TSE_KEYTYPE_UNIQUE; - return true; - case dd::Index::enum_index_type::IT_MULTIPLE: - *ret_type = TSE_KEYTYPE_MULTIPLE; - return true; - case dd::Index::enum_index_type::IT_FULLTEXT: - TSE_ENGINE_ERROR("unsupport index type:IT_FULLTEXT"); - return false; - case dd::Index::enum_index_type::IT_SPATIAL: - TSE_ENGINE_ERROR("unsupport index type:IT_SPATIAL"); - return false; - default: - break; - } - return true; -} - -bool tse_ddl_get_create_key_algorithm(dd::Index::enum_index_algorithm algorithm, - int32_t *ret_algorithm) { - *ret_algorithm = (int32_t)TSE_HA_KEY_ALG_BTREE; - switch (algorithm) { - case dd::Index::enum_index_algorithm::IA_RTREE: - // tse_log_error("unsupport index hash_type:IA_RTREE,use TSE_HA_KEY_ALG_BTREE"); - return true; - case dd::Index::enum_index_algorithm::IA_SE_SPECIFIC: - TSE_ENGINE_ERROR("unsupport index hash_type:IA_SE_SPECIFIC"); - return false; - case dd::Index::enum_index_algorithm::IA_FULLTEXT: - TSE_ENGINE_ERROR("unsupport index hash_type:IA_FULLTEXT"); - return false; - case dd::Index::enum_index_algorithm::IA_HASH: - // tse_log_error("unsupport index hash_type:IA_HASH USE TSE_HA_KEY_ALG_BTREE"); - return true; - default: - break; - } - static map - g_tse_create_key_algorithm_map = { - {dd::Index::enum_index_algorithm::IA_SE_SPECIFIC, TSE_HA_KEY_ALG_SE_SPECIFIC}, - {dd::Index::enum_index_algorithm::IA_BTREE, TSE_HA_KEY_ALG_BTREE}, - {dd::Index::enum_index_algorithm::IA_RTREE, TSE_HA_KEY_ALG_RTREE}, - {dd::Index::enum_index_algorithm::IA_HASH, TSE_HA_KEY_ALG_HASH}, - {dd::Index::enum_index_algorithm::IA_FULLTEXT, TSE_HA_KEY_ALG_FULLTEXT}}; - auto it = g_tse_create_key_algorithm_map.find(algorithm); - if (it != g_tse_create_key_algorithm_map.end()) { - *ret_algorithm = (int32_t)it->second; - return true; - } - my_printf_error(ER_DISALLOWED_OPERATION, - "get index algorithm failed, unsuported index algorithm", MYF(0)); - return false; -} uint16 get_prefix_index_len(const Field *field, const uint16 key_length) { uint16 prefix_len = 0; /* No prefix index on multi-value field */ - if (!field->is_array() && - (field->is_flag_set(BLOB_FLAG)|| + if ( // !field->is_array() && + (field_has_flag(field, BLOB_FLAG)|| (key_length < field->pack_length() && field->type() == MYSQL_TYPE_STRING) || (field->type() == MYSQL_TYPE_VARCHAR && - key_length < field->pack_length() - field->get_length_bytes()))) { + key_length < field->pack_length() - down_cast(const_cast(field))->length_size()))) { prefix_len = key_length; prefix_len /= field->charset()->mbmaxlen; - assert(!field->gcol_info); + assert(!field->vcol_info); } return prefix_len; } +#if 0 int convert_tse_part_type(dd::Table::enum_partition_type mysql_part_type, uint32_t *tse_part_type) { *tse_part_type = TSE_PART_TYPE_INVALID; switch (mysql_part_type) { @@ -480,7 +454,9 @@ int convert_tse_part_type(dd::Table::enum_partition_type mysql_part_type, uint32 } return 0; } +#endif +#if 0 int convert_tse_subpart_type(dd::Table::enum_subpartition_type mysql_subpart_type, uint32_t *tse_part_type) { *tse_part_type = TSE_PART_TYPE_INVALID; switch (mysql_subpart_type) { @@ -503,3 +479,5 @@ int convert_tse_subpart_type(dd::Table::enum_subpartition_type mysql_subpart_typ } return 0; } +#endif + diff --git a/storage/tianchi/tse_ddl_util.h b/storage/tianchi/tse_ddl_util.h index 05655398f4586c9fd536aaf30b85c558177ad8b8..0e15d70316035fa7ddcbc3b84bf848850168b717 100644 --- a/storage/tianchi/tse_ddl_util.h +++ b/storage/tianchi/tse_ddl_util.h @@ -28,21 +28,20 @@ bool check_data_file_name(const char *data_file_name); Field *tse_get_field_by_name(TABLE *form, const char *name); const Create_field *tse_get_create_field_by_column_name(THD *thd, const char* field_name); tse_alter_table_drop_type tse_ddl_get_drop_type_from_mysql_type(Alter_drop::drop_type drop_type); -tse_alter_column_type tse_ddl_get_alter_column_type_from_mysql_type( - Alter_column::Type alter_column_type); +tse_alter_column_type tse_ddl_get_alter_column_type_from_mysql_type(const Alter_column *alt_col); bool get_tse_key_type(const KEY *key_info, int32_t *ret_type); bool get_tse_key_algorithm(ha_key_alg algorithm, int32_t *ret_algorithm); bool tse_ddl_get_data_type_from_mysql_type(Field *field, const enum_field_types &mysql_type, int32_t *ret_type); bool set_column_datatype(size_t set_num, TcDb__TseDDLColumnDef *column); -bool tse_is_with_default_value(Field *field, const dd::Column *col_obj); -tse_ddl_fk_rule tse_ddl_get_foreign_key_rule(fk_option rule); -tse_ddl_fk_rule tse_ddl_get_foreign_key_rule(dd::Foreign_key::enum_rule rule); -const dd::Index *tse_ddl_get_index_by_name(const dd::Table *tab_obj, const char *index_name); -const dd::Column *tse_ddl_get_column_by_name(const dd::Table *table_def, const char *col_name); -bool tse_ddl_get_create_key_type(dd::Index::enum_index_type type, int32_t *ret_type); -bool tse_ddl_get_create_key_algorithm(dd::Index::enum_index_algorithm algorithm, int32_t *ret_algorithm); +bool tse_is_with_default_value(Field *field); +tse_ddl_fk_rule tse_ddl_get_foreign_key_rule(enum enum_fk_option rule); + +const KEY*tse_ddl_get_index_by_name(const char *index_name); +const Create_field* tse_ddl_get_column_by_name(const char *col_name); +bool tse_ddl_get_create_key_type(ha_base_keytype type, int32_t *ret_type); +bool tse_ddl_get_create_key_algorithm(ha_key_alg algorithm, int32_t *ret_algorithm); uint16 get_prefix_index_len(const Field *field, const uint16 key_length); -int convert_tse_part_type(dd::Table::enum_partition_type mysql_part_type, uint32_t *tse_part_type); -int convert_tse_subpart_type(dd::Table::enum_subpartition_type mysql_subpart_type, uint32_t *tse_part_type); -#endif // __TSE_DDL_UTIL_H__ \ No newline at end of file +//int convert_tse_part_type(partition_type mysql_part_type, uint32_t *tse_part_type); +//int convert_tse_subpart_type(partition_type mysql_subpart_type, uint32_t *tse_part_type); +#endif // __TSE_DDL_UTIL_H__ diff --git a/storage/tianchi/tse_error.cc b/storage/tianchi/tse_error.cc index 1fd16e47ca8beb2ffd7558d11ccb04f503838f04..89fb0c166c17367450bc9510c38d9f64f9b7ef82 100644 --- a/storage/tianchi/tse_error.cc +++ b/storage/tianchi/tse_error.cc @@ -14,7 +14,9 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "my_global.h" #include +#include "mysqld_error.h" #include "tse_error.h" #include "my_base.h" #include "tse_log.h" @@ -44,7 +46,7 @@ static std::unordered_map err_code_lookup_map = { /* If prefix is true then a 768-byte prefix is stored locally for BLOB fields. Refer to dict_table_get_format(). We limit max record size to 16k for 64k page size. */ - {ERR_RECORD_SIZE_OVERFLOW, HA_ERR_TOO_BIG_ROW}, + {ERR_RECORD_SIZE_OVERFLOW, HA_ERR_TO_BIG_ROW}, /* Be cautious with returning this error, since mysql could re-enter the storage layer to get duplicated key info, the operation requires a @@ -57,7 +59,7 @@ static std::unordered_map err_code_lookup_map = { {ERR_DEF_CHANGED, HA_ERR_TABLE_DEF_CHANGED}, {ERR_SAVEPOINT_NOT_EXIST, HA_ERR_NO_SAVEPOINT}, {ERR_NO_MORE_LOCKS, HA_ERR_LOCK_TABLE_FULL}, - {ERR_FILE_NOT_EXIST, HA_ERR_WRONG_FILE_NAME}, + //{ERR_FILE_NOT_EXIST, HA_ERR_WRONG_FILE_NAME}, {ERR_SPACE_NOT_EXIST, HA_ERR_TABLESPACE_MISSING}, {ERR_SPACE_ALREADY_EXIST, HA_ERR_TABLESPACE_EXISTS}, {ERR_BTREE_LEVEL_EXCEEDED, HA_ERR_INTERNAL_ERROR}, @@ -65,8 +67,8 @@ static std::unordered_map err_code_lookup_map = { {ERR_DC_INVALIDATED, HA_ERR_NO_SUCH_TABLE}, {ERR_INDEX_INVALID, HA_ERR_WRONG_INDEX}, {ERR_CONNECTION_FAILED, HA_ERR_NO_CONNECTION}, - {ERR_ALLOC_MEMORY, HA_ERR_SE_OUT_OF_MEMORY}, - {ERR_ROW_LOCKED_NOWAIT, HA_ERR_NO_WAIT_LOCK}, + {ERR_ALLOC_MEMORY, HA_ERR_OUT_OF_MEM}, + //{ERR_ROW_LOCKED_NOWAIT, HA_ERR_NO_WAIT_LOCK}, {ERR_OPERATION_CANCELED, HA_ERR_QUERY_INTERRUPTED}, {ERR_SEM_FAULT, HA_ERR_INTERNAL_ERROR}, {ERR_BATCH_DATA_HANDLE_FAILED, HA_ERR_INTERNAL_ERROR}, diff --git a/storage/tianchi/tse_log.h b/storage/tianchi/tse_log.h index 6b96dc689edcceaacb483747d21e43aada0e30ba..0a21ae9f85a2be1ebcac9725b519da48521d6d31 100644 --- a/storage/tianchi/tse_log.h +++ b/storage/tianchi/tse_log.h @@ -20,9 +20,7 @@ #include #include "sql/log.h" #include "sql/mysqld.h" -#include #include "my_dbug.h" -#include "mysqld_error.h" #ifndef __TSE_LOG_H__ #define __TSE_LOG_H__ @@ -31,6 +29,7 @@ #define UNUSED_PARAM(_p) (void(_p)) // supress warning declared but not used #define __FILENAME__ (strrchr("/" __FILE__, '/') + 1) +#if 0 typedef enum en_regex_type_e { REGEX_LINE, @@ -63,60 +62,19 @@ static void replace_all(char *filter_str, const char *regex) { filter_str[s.length()] = '\0'; return; } - -static void do_security_filter(char *filter_str) { - for (uint index = 0; index < sizeof(g_regex_conf) / sizeof(g_regex_conf[0]); index++) { - replace_all(filter_str, g_regex_conf[index].regex); - } -} - -/* - Print message to MySQL Server's error log(s) - - @param loglevel Selects the loglevel used when - printing the message to log. - @param[in] fmt printf-like format string - @param[in] ap Arguments - -*/ - -inline void tse_log_print(enum loglevel loglevel, const char *fmt, ...) MY_ATTRIBUTE((format(printf, 2, 3))); - -void tse_log_print(enum loglevel loglevel, const char *fmt, ...) { - if (log_error_verbosity < loglevel) return; - assert(fmt); - va_list args; - char msg_buf[TSE_LOG_SIZE]; - - va_start(args, fmt); - int res = vsnprintf(msg_buf, sizeof(msg_buf), fmt, args); - va_end(args); - - assert(res); - if (res >= TSE_LOG_SIZE) { - msg_buf[TSE_LOG_SIZE - 2] = '.'; - msg_buf[TSE_LOG_SIZE - 3] = '.'; - msg_buf[TSE_LOG_SIZE - 4] = '.'; - } - - if (!opt_general_log_raw) { //配置文件中的log-raw - do_security_filter(msg_buf); - } - - LogErr(loglevel, ER_IB_MSG_1381, msg_buf); -} +#endif /* System Level log */ -#define tse_log_system(fmt, args...) tse_log_print(SYSTEM_LEVEL, "[%s:%s(%d)]" fmt, __FILENAME__, __FUNCTION__, __LINE__, ##args) +#define tse_log_system(fmt, args...) sql_print_information("[%s:%s(%d)]" fmt, __FILENAME__, __FUNCTION__, __LINE__, ##args) /* Error Level log */ -#define tse_log_error(fmt, args...) tse_log_print(ERROR_LEVEL, "[%s:%s(%d)]" fmt, __FILENAME__, __FUNCTION__, __LINE__, ##args) +#define tse_log_error(fmt, args...) sql_print_error("[%s:%s(%d)]" fmt, __FILENAME__, __FUNCTION__, __LINE__, ##args) /* Warning Level log */ -#define tse_log_warning(fmt, args...) tse_log_print(WARNING_LEVEL, "[%s:%s(%d)]" fmt, __FILENAME__, __FUNCTION__, __LINE__, ##args) +#define tse_log_warning(fmt, args...) sql_print_warning("[%s:%s(%d)]" fmt, __FILENAME__, __FUNCTION__, __LINE__, ##args) /* note Level log */ -#define tse_log_note(fmt, args...) tse_log_print(INFORMATION_LEVEL, "[%s:%s(%d)]" fmt, __FILENAME__, __FUNCTION__, __LINE__, ##args) +#define tse_log_note(fmt, args...) sql_print_information("[%s:%s(%d)]" fmt, __FILENAME__, __FUNCTION__, __LINE__, ##args) #define tse_log_verbose tse_log_note #define tse_log_info tse_log_note #define tse_log_trivia tse_log_note @@ -128,7 +86,7 @@ void tse_log_print(enum loglevel loglevel, const char *fmt, ...) { #define TSE_ENGINE_ERROR(message) \ do { \ tse_log_error(message); \ - my_error(ER_IB_MSG_1381, MYF(0), message); \ + my_error(ER_CTC_ENGINE_ERROR, MYF(0), message); \ } while (0) #define TSE_RETURN_IF_ERROR(_expVal, retVal) \ diff --git a/storage/tianchi/tse_mysql_proxy.cc b/storage/tianchi/tse_mysql_proxy.cc index 4695d5d2a81413b27a0d78ddbe6ec2a28fc3b328..a19bf24d58d37910e8d8de8eaca4e33cb32a2509 100644 --- a/storage/tianchi/tse_mysql_proxy.cc +++ b/storage/tianchi/tse_mysql_proxy.cc @@ -21,8 +21,9 @@ #include #include #include + +#include "my_global.h" #include "my_md5.h" -#include "my_md5_size.h" #include "mysql.h" #include "sql/mysqld.h" // mysql_port, my_localhost #include "tse_log.h" @@ -36,20 +37,15 @@ #include "sql/sql_handler.h" #include "sql/sql_base.h" #include "sql/sql_class.h" -#include "sql/dd/cache/dictionary_client.h" -#include "sql/mysqld_thd_manager.h" -#include "sql/dd/types/procedure.h" -#include "sql/dd/types/function.h" -#include "sql/dd/types/routine.h" +//#include "sql/mysqld_thd_manager.h" #include "sql/mdl.h" -#include "sql/dd/types/event.h" -#include "sql/dd/types/resource_group.h" -#include "sql/dd/types/trigger.h" -#include "sql/auth/auth_common.h" +//#include "sql/auth/auth_common.h" #include "sql/sys_vars_shared.h" // intern_find_sys_var #include "sql/sql_lex.h" // lex_start/lex_end #include "sql/handler.h" // ha_tse_commit +#define MD5_HASH_SIZE 16 /* Hash size in bytes */ + using namespace std; struct ctc_mysql_conn { @@ -323,8 +319,7 @@ static void close_mysql_conn_by_inst_id(uint32_t inst_id, bool by_mysql_inst) { } static inline bool is_backup_lock_op(uint8_t sql_command) { - return sql_command == SQLCOM_LOCK_INSTANCE || - sql_command == SQLCOM_UNLOCK_INSTANCE; + return sql_command == SQLCOM_BACKUP_LOCK;// mariadb uses this for both backup lock&unlock } static inline bool tse_use_proxy(uint8_t sql_command) { @@ -391,7 +386,7 @@ __attribute__((visibility("default"))) int tse_ddl_execute_update(uint32_t thd_i } // 设置随机密码seed - if (broadcast_req->sql_command == SQLCOM_CREATE_USER || broadcast_req->sql_command == SQLCOM_ALTER_USER || broadcast_req->sql_command == SQLCOM_SET_PASSWORD) { + if (broadcast_req->sql_command == SQLCOM_CREATE_USER || broadcast_req->sql_command == SQLCOM_ALTER_USER ){ //|| broadcast_req->sql_command == SQLCOM_SET_PASSWORD) { ret = tse_mysql_query(curr_conn, ("set @random_password_seed = " + std::to_string(thd_id) + ";").c_str()); if (ret != 0) { tse_log_error("tse_init_proxy_client set @random_password_seed failed, error_code:%d", mysql_errno(curr_conn)); @@ -440,7 +435,7 @@ __attribute__((visibility("default"))) int tse_ddl_execute_update(uint32_t thd_i static int tse_ddl_get_lock(MYSQL *curr_conn, const uint64_t &conn_map_key, const char *lock_name, int *err_code) { uchar digest[MD5_HASH_SIZE]; - compute_md5_hash(pointer_cast(digest), lock_name, strlen(lock_name)); + compute_md5_hash(digest, lock_name, strlen(lock_name)); // + 1 for the null terminator char output[(MD5_HASH_SIZE * 2) + 1]; diff --git a/storage/tianchi/tse_proxy_util.cc b/storage/tianchi/tse_proxy_util.cc index 2ab93bf34fda2fcf0c519d3aa5ae150c474aae99..d1f721c8a49b04e11c98a95155eebb04a9fe7d37 100644 --- a/storage/tianchi/tse_proxy_util.cc +++ b/storage/tianchi/tse_proxy_util.cc @@ -14,16 +14,18 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ - +#include "my_global.h" #include "tse_proxy_util.h" #include +#include "mysql/psi/psi.h" +#include "mysql/psi/psi_memory.h" #include "tse_log.h" #include "sql/sql_connect.h" -#include "sql/conn_handler/connection_handler_manager.h" // Connection_handler_manager -#include "compression.h" +//#include "compression.h" #include "ha_tse.h" #include "sql/mysqld.h" #include "ctc_meta_data.h" +#include "errmsg.h" // CR_OUT_OF_MEMORY #define TSE_CONN_MAX_RETRY_TIMES 10 #define TSE_PASSWORD_BUFFER_SIZE (uint32)512 @@ -104,20 +106,22 @@ static int tse_get_agent_info(char *password, uint password_size) { static void tse_inc_conn_count(int &dec_conn_count) { + /* Connection_handler_manager *conn_manager = Connection_handler_manager::get_instance(); conn_manager->check_and_incr_conn_count(true); Connection_handler_manager::reset_max_used_connections(); + */ dec_conn_count--; - tse_log_warning("[TSE_CONN_INC]:connection_count:%u, max_used_connections:%lu, max_connections:%lu, dec_conn_count:%d", - Connection_handler_manager::connection_count, Connection_handler_manager::max_used_connections, max_connections, dec_conn_count); + //tse_log_warning("[TSE_CONN_INC]:connection_count:%u, max_used_connections:%lu, max_connections:%lu, dec_conn_count:%d", + // Connection_handler_manager::connection_count, Connection_handler_manager::max_used_connections, max_connections, dec_conn_count); } static void tse_dec_conn_count(int &dec_conn_count) { - Connection_handler_manager::dec_connection_count(); + //Connection_handler_manager::dec_connection_count(); dec_conn_count++; - tse_log_warning("[TSE_CONN_DEC]:connection_count:%u, max_used_connections:%lu, max_connections:%lu, dec_conn_count:%d", - Connection_handler_manager::connection_count, Connection_handler_manager::max_used_connections, max_connections, dec_conn_count); + //tse_log_warning("[TSE_CONN_DEC]:connection_count:%u, max_used_connections:%lu, max_connections:%lu, dec_conn_count:%d", + // Connection_handler_manager::connection_count, Connection_handler_manager::max_used_connections, max_connections, dec_conn_count); } int tse_mysql_conn(MYSQL *&con, const char *host, const char *user, const char *passwd) { @@ -157,6 +161,8 @@ int tse_mysql_conn(MYSQL *&con, const char *host, const char *user, const char * if (err == ER_CON_COUNT_ERROR) { tse_dec_conn_count(dec_conn_count); } +#if 0 + // mariadb doesn't support wire compression // 3922 errcode, server has open compress conn, client need to open. if (err == ER_WRONG_COMPRESSION_ALGORITHM_CLIENT) { if ((con->server_capabilities & CLIENT_COMPRESS)) { // server open zlib conn @@ -167,6 +173,7 @@ int tse_mysql_conn(MYSQL *&con, const char *host, const char *user, const char * retry_time--; continue; } +#endif tse_log_error("tse_mysql_conn create internal connection failed, retry_time=%d, user=%s, err_code=%d, err_msg=%s.", retry_time, user, err, mysql_error(con)); retry_time--; @@ -199,7 +206,7 @@ int tse_init_agent_client(MYSQL *&curr_conn) { } int tse_mysql_query(MYSQL *mysql, const char *query) { - reset_mqh(nullptr, nullptr, 0); + reset_mqh(nullptr, 0); int ret = mysql_ping(mysql); if (ret != 0) { @@ -236,4 +243,4 @@ int tse_mysql_query(MYSQL *mysql, const char *query) { void tse_close_mysql_conn(MYSQL **curr_conn) { mysql_close(*curr_conn); *curr_conn = NULL; -} \ No newline at end of file +} diff --git a/storage/tianchi/tse_proxy_util.h b/storage/tianchi/tse_proxy_util.h index e8a04d21e3486ae1538afe90f62fc25b247e0ca5..16691dbd8f0414382abb4f04c6812cd1f59b0659 100644 --- a/storage/tianchi/tse_proxy_util.h +++ b/storage/tianchi/tse_proxy_util.h @@ -19,6 +19,7 @@ #define __TSE_PROXY_UTIL_H__ #include +#include #pragma GCC visibility push(default) diff --git a/storage/tianchi/tse_srv_mq_module.cc b/storage/tianchi/tse_srv_mq_module.cc index b04edf80a09a6ffdd72f800cb1d554aa8fd4469a..8715eddf349cd879aa103d26a20b8d55f0f6e39f 100644 --- a/storage/tianchi/tse_srv_mq_module.cc +++ b/storage/tianchi/tse_srv_mq_module.cc @@ -15,6 +15,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "my_global.h" #include "srv_mq_msg.h" #include "tse_srv_mq_module.h" #include @@ -32,7 +33,9 @@ #define MAX_DDL_THD_NUM 1024 #define SHM_MAX_SEG_NUM 8 using namespace std; -#define CTC_IGNORE_ERROR_WHEN_MYSQL_SHUTDOWN(req, tag) \ +#define CTC_IGNORE_ERROR_WHEN_MYSQL_SHUTDOWN(req, tag) + +#if 0 // mariadb has doesn't track server states. do { \ if ((req)->result != 0 && get_server_state() == SERVER_SHUTTING_DOWN) { \ tse_log_error("%s failed,server will shutdown:result:%d", (tag), \ @@ -40,6 +43,7 @@ using namespace std; (req)->result = 0; \ } \ } while (0) +#endif #define CTC_GET_CLIENT_ID(inst_id) ((int) ((inst_id) & 0xFFFF)) @@ -336,7 +340,7 @@ EXTER_ATTACK int tse_mq_deal_func(void *shm_inst, TSE_FUNC_TYPE func_type, { uint64_t start_time = 0; if (ctc_stats::get_instance().get_statistics_enabled()) { - start_time = my_getsystime() / 10; + start_time = my_hrtime().val / 10; } shm_seg_s *seg = (shm_seg_s *)shm_inst; @@ -414,7 +418,7 @@ EXTER_ATTACK int tse_mq_deal_func(void *shm_inst, TSE_FUNC_TYPE func_type, if (ctc_stats::get_instance().get_statistics_enabled()) { - ctc_stats::get_instance().gather_stats(func_type, my_getsystime() / 10 - start_time); + ctc_stats::get_instance().gather_stats(func_type, my_hrtime().val / 10 - start_time); } return result; diff --git a/storage/tianchi/tse_srv_mq_stub.cc b/storage/tianchi/tse_srv_mq_stub.cc index 2ffbbc804a5bf5fe04e8e9fcb67fe639faa08042..94bcc4e45beb13ad78fb12c961a76e406b4392cf 100644 --- a/storage/tianchi/tse_srv_mq_stub.cc +++ b/storage/tianchi/tse_srv_mq_stub.cc @@ -15,6 +15,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "my_global.h" #include "srv_mq_msg.h" #include "tse_srv_mq_module.h" #include "message_queue/dsw_shm.h" @@ -134,6 +135,7 @@ int tse_write_row(tianchi_handler_t *tch, const record_info_t *record_info, req->record = record_info->record; req->serial_column_offset = serial_column_offset; req->flag = flag; + int result = ERR_CONNECTION_FAILED; int ret = CT_SUCCESS; ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_WRITE_ROW, req, tch->msg_buf); @@ -160,6 +162,7 @@ int tse_bulk_write(tianchi_handler_t *tch, const record_info_t *record_info, uin req->record_len = record_info->record_len; req->record_num = rec_num; req->flag = flag; + memcpy(req->record, record_info->record, record_info->record_len * rec_num); if (part_ids != nullptr) { memcpy(req->part_ids, part_ids, rec_num * sizeof(ctc_part_t)); @@ -193,6 +196,7 @@ int tse_update_row(tianchi_handler_t *tch, uint16_t new_record_len, const uint8_ req->col_num = col_num; req->new_record = const_cast(new_record); req->flag = flag; + memcpy(req->upd_cols, upd_cols, sizeof(uint16_t) * col_num); int result = ERR_CONNECTION_FAILED; int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_UPDATE_ROW, req, tch->msg_buf); @@ -215,6 +219,7 @@ int tse_delete_row(tianchi_handler_t *tch, uint16_t record_len, dml_flag_t flag) req->tch = *tch; req->record_len = record_len; req->flag = flag; + int result = ERR_CONNECTION_FAILED; int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_DELETE_ROW, req, tch->msg_buf); *tch = req->tch; @@ -409,6 +414,7 @@ int tse_delete_all_rows(tianchi_handler_t *tch, dml_flag_t flag) { } req->tch = *tch; req->flag = flag; + int result = ERR_CONNECTION_FAILED; int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_DELETE_ALL_ROWS, req, tch->msg_buf); *tch = req->tch; @@ -683,7 +689,7 @@ int tse_free_session_cursors(tianchi_handler_t *tch, uint64_t *cursors, int32_t req->tch = *tch; req->csize = csize; req->cursors = cursors; - + int result = ERR_CONNECTION_FAILED; int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_FREE_CURSORS, req, tch->msg_buf); *tch = req->tch; @@ -1087,7 +1093,7 @@ int tse_lock_table(tianchi_handler_t *tch, const char *db_name, tse_lock_table_i tse_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, len); return ERR_ALLOC_MEMORY; } - + memset(req, 0, len); if (db_name != nullptr) { strncpy(req->db_name, db_name, SMALL_RECORD_SIZE - 1); @@ -1150,6 +1156,7 @@ int tse_unlock_table(tianchi_handler_t *tch, uint32_t mysql_insert_id, tse_lock_ req->tch = *tch; req->mysql_inst_id = mysql_insert_id; req->lock_info = *lock_info; + int result = ERR_CONNECTION_FAILED; int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_UNLOCK_TABLE, req, tch->msg_buf); *tch = req->tch; @@ -1342,6 +1349,7 @@ int tse_execute_mysql_ddl_sql(tianchi_handler_t *tch, tse_ddl_broadcast_request memcpy(&req->broadcast_req, broadcast_req, sizeof(tse_ddl_broadcast_request)); req->tch = *tch; req->allow_fail = allow_fail; + int result = ERR_CONNECTION_FAILED; int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_EXCUTE_MYSQL_DDL_SQL, req, tch->msg_buf); *tch = req->tch; @@ -1363,6 +1371,7 @@ int tse_broadcast_mysql_dd_invalidate(tianchi_handler_t *tch, tse_invalidate_bro } memcpy(&req->broadcast_req, broadcast_req, sizeof(tse_invalidate_broadcast_request)); req->tch = *tch; + int result = ERR_CONNECTION_FAILED; int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_INVALIDATE_OBJECT, req, tch->msg_buf); *tch = req->tch; @@ -1385,6 +1394,7 @@ int tse_broadcast_rewrite_sql(tianchi_handler_t *tch, tse_ddl_broadcast_request memcpy(&req->broadcast_req, broadcast_req, sizeof(tse_ddl_broadcast_request)); req->tch = *tch; req->allow_fail = allow_fail; + int result = ERR_CONNECTION_FAILED; int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_BROADCAST_REWRITE_SQL, req, tch->msg_buf); *tch = req->tch; @@ -1409,6 +1419,7 @@ int tse_get_serial_value(tianchi_handler_t *tch, uint64_t *value, dml_flag_t fla req->flag.auto_inc_step = flag.auto_inc_step; req->flag.auto_inc_offset = flag.auto_inc_offset; req->flag.auto_increase = flag.auto_increase; + int result = ERR_CONNECTION_FAILED; int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_TYPE_GET_SERIAL_VALUE, req, tch->msg_buf); *tch = req->tch; @@ -1517,6 +1528,7 @@ int tse_lock_instance(bool *is_mysqld_starting, tse_lock_table_mode_t lock_type, req->tch = *tch; req->lock_type = lock_type; req->is_mysqld_starting = *is_mysqld_starting; + int result = ERR_CONNECTION_FAILED; int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_LOCK_INSTANCE, req, tch->msg_buf); *tch = req->tch; @@ -1538,6 +1550,7 @@ int tse_unlock_instance(bool *is_mysqld_starting, tianchi_handler_t *tch) { req->tch = *tch; req->is_mysqld_starting = *is_mysqld_starting; + int result = ERR_CONNECTION_FAILED; int ret = tse_mq_deal_func(shm_inst, TSE_FUNC_UNLOCK_INSTANCE, req, tch->msg_buf); *tch = req->tch; diff --git a/storage/tianchi/tse_stats.cc b/storage/tianchi/tse_stats.cc index 9fb1c7a09f1f93466eb0f7c1b726e2e05e92b88a..acbff8d2ed44c7794195ff6da9068b5614c09e76 100644 --- a/storage/tianchi/tse_stats.cc +++ b/storage/tianchi/tse_stats.cc @@ -14,6 +14,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "my_global.h" #include "tse_stats.h" #include "tse_log.h" #include diff --git a/storage/tianchi/tse_util.cc b/storage/tianchi/tse_util.cc index 0bfb3fee12b1eb4c745cd0e77bb76072711e1c88..bd9299da6b4c4d3b14917d0832aefe04625c6859 100644 --- a/storage/tianchi/tse_util.cc +++ b/storage/tianchi/tse_util.cc @@ -14,7 +14,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ - +#include "my_global.h" #include "tse_srv.h" #include "tse_util.h" #include "tse_log.h" @@ -32,10 +32,83 @@ #include "decimal_convert.h" #include "sql_string.h" #include "ha_tse_ddl.h" +#include "sql/extra_defs.h" +#include using namespace std; extern bool ctc_enable_x_lock_instance; +void my_date_to_binary(const MYSQL_TIME *ltime, uchar *ptr); + + +/** + Acquire either exclusive or shared Backup Lock. + + @param[in] thd Current thread context + @param[in] mdl_type Type of metadata lock to acquire for backup + @param[in] mdl_duration Duration of metadata lock + @param[in] lock_wait_timeout How many seconds to wait before timeout. + + @return Operation status. + @retval false Success + @retval true Failure +*/ + +static bool acquire_mdl_for_backup(THD *thd, enum_mdl_type mdl_type, + enum_mdl_duration mdl_duration, + ulong lock_wait_timeout) { + MDL_request mdl_request; + + assert(mdl_type == MDL_SHARED || mdl_type == MDL_INTENTION_EXCLUSIVE); + + MDL_REQUEST_INIT(&mdl_request, MDL_key::BACKUP, "", "", mdl_type, + mdl_duration); + + return thd->mdl_context.acquire_lock(&mdl_request, lock_wait_timeout); +} + +/* + The following rationale is for justification of choice for specific lock + types to support BACKUP LOCK. + + IX and S locks are mutually incompatible. On the other hand both these + lock types are compatible with themselves. IX lock has lower priority + than S locks. So we can use S lock for rare Backup operation which should + not be starved by more frequent DDL operations using IX locks. + + From all listed above follows that S lock should be considered as Exclusive + Backup Lock and IX lock should be considered as Shared Backup Lock. +*/ + +bool acquire_exclusive_backup_lock(THD *thd, ulong lock_wait_timeout, + bool for_trx) { + enum_mdl_duration duration = (for_trx ? MDL_TRANSACTION : MDL_EXPLICIT); + return acquire_mdl_for_backup(thd, MDL_SHARED, duration, lock_wait_timeout); +} + +/** + MDL_release_locks_visitor subclass to release MDL for BACKUP_LOCK. +*/ + +class Release_all_backup_locks : public MDL_release_locks_visitor { + public: + bool release(MDL_ticket *ticket) override { + return ticket->get_key()->mdl_namespace() == MDL_key::BACKUP; + } +}; + + +void release_backup_lock(THD *thd) { + Release_all_backup_locks lock_visitor; + thd->mdl_context.release_locks(&lock_visitor); +} + + +/* + MariaDB has no Item_func_comparison, which in MySQL derives from Item_bool_func2. +*/ +using Item_func_comparison = Item_bool_func2 ; + string cnvrt_name_for_sql(string name) { string res = ""; for (size_t i = 0; i < name.length(); i++) { @@ -55,8 +128,8 @@ void tse_print_cantian_err_msg(const ddl_ctrl_t *ddl_ctrl, ct_errno_t ret) case ERR_DUPLICATE_ENTRY: my_printf_error(ER_DUP_ENTRY, "%s", MYF(0), ddl_ctrl->error_msg); break; - case ERR_COL_TYPE_MISMATCH: - my_printf_error(ER_FK_INCOMPATIBLE_COLUMNS, "%s", MYF(0), ddl_ctrl->error_msg); + case ERR_COL_TYPE_MISMATCH:// there is no corresponding concrete error code in mariadb + my_printf_error(ER_WRONG_FK_DEF, "%s", MYF(0), ddl_ctrl->error_msg); break; default: my_printf_error(ER_DISALLOWED_OPERATION, "%s", MYF(0), ddl_ctrl->error_msg); @@ -70,7 +143,7 @@ static uint32_t tse_convert_identifier_to_sysname(char *to, const char *from, si CHARSET_INFO *cs_to = system_charset_info; return (static_cast( - strconvert(cs_from, from, cs_to, to, to_len, &errors_ignored))); + strconvert(cs_from, from, strlen(from), cs_to, to, to_len, &errors_ignored))); } void tse_split_normalized_name(const char *file_name, char db[], size_t db_buf_len, @@ -135,7 +208,7 @@ string sql_without_plaintext_password(tse_ddl_broadcast_request* broadcast_req) int16_t tse_get_column_by_field(Field **field, const char *col_name) { int16_t col_id; for (col_id = 0; *field != nullptr; field++, col_id++) { - if (my_strcasecmp(system_charset_info, (*field)->field_name, col_name) == 0) { + if (my_strcasecmp(system_charset_info, (*field)->field_name.str, col_name) == 0) { return col_id; } } @@ -210,8 +283,13 @@ int tse_fill_cond_field_data_num(tianchi_handler_t m_tch, Item *items, Field *my uchar *buff = new uchar[binary_size]; Item_decimal *item_decimal = dynamic_cast(item_func_comparison->arguments()[1]); TSE_RET_ERR_IF_NULL(item_decimal); + my_decimal *d = item_decimal->val_decimal(nullptr); - my_decimal2binary(E_DEC_FATAL_ERROR, d, buff, prec, scale); + if (d->to_binary(buff, prec, scale, E_DEC_FATAL_ERROR) != E_DEC_OK) { + tse_log_error("[tse_copy_cond_field_data] Invalid decimal value."); + return CT_ERROR; + } + data = (uchar *)my_malloc(PSI_NOT_INSTRUMENTED, binary_size, MYF(MY_WME)); if (data == nullptr) { tse_log_error("[tse_fill_cond_field_data_num]alloc mem failed, size(%d)", binary_size); @@ -274,13 +352,13 @@ int tse_fill_cond_field_data_date(tianchi_handler_t m_tch, const field_cnvrt_aux longlong ll; switch (mysql_info->mysql_field_type) { case MYSQL_TYPE_TIME: - ll = TIME_to_longlong_time_packed(ltime); + ll = TIME_to_longlong_time_packed(<ime); my_time_packed_to_binary(ll, my_ptr, DATETIME_MAX_DECIMALS); memcpy(cond->field_info.field_value, my_ptr, cond->field_info.field_size); return ret; case MYSQL_TYPE_DATETIME: - ll = TIME_to_longlong_datetime_packed(ltime); + ll = TIME_to_longlong_datetime_packed(<ime); my_datetime_packed_to_binary(ll, my_ptr, DATETIME_MAX_DECIMALS); memcpy(cond->field_info.field_value, my_ptr, cond->field_info.field_size); return ret; @@ -297,13 +375,13 @@ int tse_fill_cond_field_data_date(tianchi_handler_t m_tch, const field_cnvrt_aux int warnings = 0; #ifdef FEATURE_X_FOR_MYSQL_32 struct my_timeval tm = {0, 0}; - datetime_with_no_zero_in_date_to_timeval(<ime, *thd->time_zone(), &tm, &warnings); -#elif defined(FEATURE_X_FOR_MYSQL_26) + datetime_with_no_zero_in_date_to_timeval(<ime, *thd->variables.time_zone, &tm, &warnings); +#else struct timeval tm = {0, 0}; - tse_datetime_with_no_zero_in_date_to_timeval(<ime, *thd->time_zone(), &tm, &warnings); + tse_datetime_with_no_zero_in_date_to_timeval(<ime, *thd->variables.time_zone, &tm, &warnings); #endif assert((warnings == EOK) || (warnings == MYSQL_TIME_WARN_TRUNCATED)); - my_tz_UTC->gmt_sec_to_TIME(<ime, tm); + my_tz_UTC->gmt_sec_to_TIME(<ime, tm.tv_sec); } /* fall through */ } @@ -358,7 +436,7 @@ int tse_fill_cond_field_data_string(tianchi_handler_t m_tch, Item_func *item_fun TSE_RET_ERR_IF_NULL(item_string); String *item_str = item_string->val_str(nullptr); cond->field_info.field_size = item_str->length(); - void *data = item_str->ptr(); + const void *data = item_str->ptr(); cond->field_info.field_value = tse_alloc_buf(&m_tch, cond->field_info.field_size); if (cond->field_info.field_size > 0 && cond->field_info.field_value == nullptr) { tse_log_error("tse_fill_cond_field: alloc field_data error, size(%u).", cond->field_info.field_size); @@ -416,7 +494,7 @@ int tse_fill_cond_field_data(tianchi_handler_t m_tch, Item *items, Field *mysql_ TSE_RET_ERR_IF_NULL(item_date_func); Item_date_literal *item_date_literal = (Item_date_literal *)(item_date_func); TSE_RET_ERR_IF_NULL(item_date_literal); - if (item_date_literal->get_date(<ime, TIME_FUZZY_DATE)) { + if (item_date_literal->get_date(mysql_field->table->in_use, <ime, date_mode_t((ulonglong)date_mode_t::FUZZY_DATES))) { return CT_ERROR; } } @@ -439,7 +517,7 @@ int tse_fill_cond_field_data(tianchi_handler_t m_tch, Item *items, Field *mysql_ int tse_fill_cond_field(tianchi_handler_t m_tch, Item *items, Field **field, tse_conds *cond, bool no_backslash) { Item_func *item_func = dynamic_cast(items); TSE_RET_ERR_IF_NULL(item_func); - const char *field_name = item_func->arguments()[0]->item_name.ptr(); + const char *field_name = item_func->arguments()[0]->name.str; cond->field_info.field_no = tse_get_column_by_field(field, field_name); if (cond->field_info.field_no == INVALID_MAX_COLUMN) { return CT_ERROR; @@ -476,7 +554,7 @@ int tse_push_cond_list(tianchi_handler_t m_tch, Item *items, Field **field, Item_cond *item_cond = dynamic_cast(items); TSE_RET_ERR_IF_NULL(item_cond); List *argument_list = item_cond->argument_list(); - uint16_t size = argument_list->size(); + uint16_t size = argument_list->elements; list_node *node = argument_list->first_node(); for (uint16_t i = 0; i < size; i++) { @@ -720,7 +798,7 @@ static bool tse_is_ddl_processing() { } int tse_check_lock_instance(MYSQL_THD thd, bool &need_forward) { - if (thd->mdl_context.has_locks(MDL_key::BACKUP_LOCK)) { + if (thd->mdl_context.has_locks(MDL_key::BACKUP)) { need_forward = false; return 0; } @@ -762,7 +840,7 @@ int tse_check_lock_instance(MYSQL_THD thd, bool &need_forward) { } int tse_check_unlock_instance(MYSQL_THD thd) { - if (!thd->mdl_context.has_locks(MDL_key::BACKUP_LOCK)) { + if (!thd->mdl_context.has_locks(MDL_key::BACKUP)) { return 0; } @@ -775,9 +853,28 @@ int tse_check_unlock_instance(MYSQL_THD thd) { return 0; } +/** + Check if a TABLE_LIST instance represents a pre-opened temporary table. +*/ + +static bool is_temporary_table(const TABLE_LIST *tl) { + if (tl->is_view() || tl->schema_table) return false; + + if (!tl->table) return false; + + /* + NOTE: 'table->s' might be NULL for specially constructed TABLE + instances. See SHOW TRIGGERS for example. + */ + + if (!tl->table->s) return false; + + return tl->table->s->tmp_table != NO_TMP_TABLE; +} + #ifdef FEATURE_X_FOR_MYSQL_32 static inline bool is_temporary_table_being_opened(const Table_ref *table) -#elif defined(FEATURE_X_FOR_MYSQL_26) +#else static inline bool is_temporary_table_being_opened(const TABLE_LIST *table) #endif { @@ -791,7 +888,7 @@ int tse_lock_table_pre(MYSQL_THD thd, vector& ticket_list) { Table_ref *tables_start = thd->lex->query_tables; Table_ref *tables_end = thd->lex->first_not_own_table(); Table_ref *table; -#elif defined(FEATURE_X_FOR_MYSQL_26) +#else TABLE_LIST *tables_start = thd->lex->query_tables; TABLE_LIST *tables_end = thd->lex->first_not_own_table(); TABLE_LIST *table; @@ -802,9 +899,9 @@ int tse_lock_table_pre(MYSQL_THD thd, vector& ticket_list) { continue; } MDL_request req; - MDL_REQUEST_INIT(&req, MDL_key::TABLE, table->db, table->table_name, + MDL_REQUEST_INIT(&req, MDL_key::TABLE, table->db.str, table->table_name.str, MDL_SHARED_NO_READ_WRITE, MDL_EXPLICIT); - if (thd->mdl_context.acquire_lock(&req, 1)) { + if (thd->mdl_context.acquire_lock(&req, thd->variables.lock_wait_timeout)) { return 1; } ticket_list.push_back(req.ticket); @@ -817,4 +914,4 @@ void tse_lock_table_post(MYSQL_THD thd, vector& ticket_list) { thd->mdl_context.release_lock(*it); } ticket_list.clear(); -} \ No newline at end of file +} diff --git a/storage/tianchi/tse_util.h b/storage/tianchi/tse_util.h index f5abc55a6cbbcdfb7026e2b8b3f6a3dc8230d609..572b8480afe92c809e306c25e94ce494cf17ee4f 100644 --- a/storage/tianchi/tse_util.h +++ b/storage/tianchi/tse_util.h @@ -26,7 +26,7 @@ #include "datatype_cnvrtr.h" #include "sql/item_timefunc.h" #include "sql/my_decimal.h" -#include "sql/sql_backup_lock.h" +//#include "sql/sql_backup_lock.h" using namespace std; @@ -34,7 +34,7 @@ static unordered_set mysql_system_db{"information_schema", "mysql", "per #define CM_IS_EMPTY_STR(str) (((str) == NULL) || ((str)[0] == 0)) -#define TSE_GET_THD_DB_NAME(thd) (thd->db().str == NULL) ? nullptr : const_cast(thd->db().str) +#define TSE_GET_THD_DB_NAME(thd) (thd->db.str == NULL) ? nullptr : const_cast(thd->db.str) #define CBO_STRING_MAX_LEN 16 @@ -80,6 +80,8 @@ string sql_without_plaintext_password(tse_ddl_broadcast_request* broadcast_req); string tse_escape_single_quotation_str(string &src); string cnvrt_name_for_sql(string name); +bool acquire_exclusive_backup_lock(THD *thd, ulong lock_wait_timeout, bool for_trx); +void release_backup_lock(THD *thd); #pragma GCC visibility pop #endif // __TSE_UTIL_H__