/* Copyright (c) 2018, 2021, Alibaba and/or its affiliates. All rights reserved. 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/PolarDB-X Engine 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/PolarDB-X Engine. 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 SQL_SEQUENCE_INCLUDED #define SQL_SEQUENCE_INCLUDED #include "handler.h" #include "lex_string.h" // LEX_STRING #include "my_inttypes.h" #include "sql/mem_root_array.h" // MEM_ROOT #include "sql/parse_tree_nodes.h" #include "sql/sql_cmd_ddl_table.h" // Sql_cmd_create_table #include "sql/sequence_common.h" // Sequence_info /** Sequence engine as the builtin plugin. The base table engine now only support InnoDB plugin. */ /** The struture of SEQUENCE options parser */ template class PT_values_create_sequence_option : public PT_create_table_option { public: explicit PT_values_create_sequence_option(FIELD_TYPE value) : value(value) {} virtual ~PT_values_create_sequence_option() {} bool contextualize(Table_ddl_parse_context *pc) override { if (PT_create_table_option::contextualize(pc)) return true; pc->sequence_info->init_value(field_num, value); return false; } private: FIELD_TYPE value; }; class PT_values_create_sequence_type : public PT_create_table_option { public: explicit PT_values_create_sequence_type(Sequence_type type) : m_type(type) {} virtual ~PT_values_create_sequence_type() {} bool contextualize(Table_ddl_parse_context *pc) override { if (PT_create_table_option::contextualize(pc)) return true; pc->sequence_info->init_type(m_type); return false; } private: Sequence_type m_type; }; class PT_create_sequence_stmt : public PT_create_table_stmt { public: /** @param mem_root MEM_ROOT to use for allocation @param only_if_not_exists True if @SQL{CREATE %TABLE ... @B{IF NOT EXISTS}} @param table_name @SQL{CREATE %TABLE ... @B{@}} @param on_duplicate DUPLICATE, IGNORE or fail with an error on data duplication errors (relevant for @SQL{CREATE TABLE ... SELECT} statements). @param opt_create_sequence_options For @SQL {CREATE SEQUENCE ...} */ explicit PT_create_sequence_stmt( MEM_ROOT *mem_root, bool only_if_not_exists, Table_ident *table_name, On_duplicate on_duplicate, const Mem_root_array *opt_create_sequence_options) : PT_create_table_stmt(mem_root, false, only_if_not_exists, table_name, NULL, NULL, NULL, on_duplicate, NULL), opt_create_sequence_options(opt_create_sequence_options) {} /** CREATE SEQUENCE statement command @param[in] thd Connection context @retval Sql_cmd SQL command */ Sql_cmd *make_cmd(THD *thd) override; /** Prepare sequence base engine @param[in] thd Connection context @param[in] table TABLE_LIST @retval false success @retval true failure */ bool prepare_sequence_engine(const THD *thd, const TABLE_LIST *table); /** Prepare and check sequence table columns @param[in] thd Connection context @retval false success @retval true failure */ bool prepare_sequence_fields(const THD *thd); /** Check the fields whether it is consistent with pre-defined. @param[in] alter_info All the DDL information @retval false success @retval true failure */ bool check_sequence_fields(Alter_info *alter_info) const; private: const Mem_root_array *opt_create_sequence_options; Sequence_info m_sequence_info; }; /** CREATE SEQUENCE statement cmd */ class Sql_cmd_create_sequence : public Sql_cmd_create_table { typedef Sql_cmd_create_table super; public: explicit Sql_cmd_create_sequence(Alter_info *alter_info, TABLE_LIST *query_expression_tables, Sequence_info *sequence_info) : Sql_cmd_create_table(alter_info, query_expression_tables), m_sequence_info(sequence_info) {} /* CREATE SEQUENCE is also SQLCOM_CREATE_TABLE */ enum_sql_command sql_command_code() const override { return SQLCOM_CREATE_TABLE; } bool execute(THD *thd) override; bool prepare(THD *thd) override; private: const Sequence_info *m_sequence_info; }; class Open_sequence_table_ctx { public: /** Temporary TABLE_LIST object that is used to hold opened table. */ class Table_list_state { public: /* Used by CREATE SEQUENCE. */ Table_list_state(THD *thd, TABLE_LIST *table) { m_table = new (thd->mem_root) TABLE_LIST(table->db, table->db_length, table->table_name, table->table_name_length, table->alias, TL_WRITE_CONCURRENT_DEFAULT, MDL_SHARED_WRITE); m_table->open_strategy = TABLE_LIST::OPEN_IF_EXISTS; m_table->open_type = OT_BASE_ONLY; } /* Used by reload sequence share cache */ Table_list_state(THD *thd, TABLE_SHARE *share) { char *db = (char *)thd->memdup(share->db.str, share->db.length + 1); char *table_name = (char *)thd->memdup(share->table_name.str, share->table_name.length + 1); char *alias = (char *)thd->memdup(share->table_name.str, share->table_name.length + 1); m_table = new (thd->mem_root) TABLE_LIST(db, share->db.length, table_name, share->table_name.length, alias, TL_WRITE_CONCURRENT_DEFAULT, MDL_SHARED_WRITE); m_table->open_strategy = TABLE_LIST::OPEN_IF_EXISTS; m_table->open_type = OT_BASE_ONLY; m_table->sequence_scan.set(Sequence_scan::ORIGINAL_SCAN); } /** The cloned TABLE_LIST will be free when statement end. */ ~Table_list_state() {} TABLE_LIST *cloned_table() const { return m_table; } private: THD *thd; TABLE_LIST *m_table; }; Open_sequence_table_ctx(THD *thd, TABLE_LIST *table_list); Open_sequence_table_ctx(THD *thd, TABLE_SHARE *share); virtual ~Open_sequence_table_ctx(); /** Open and lock the sequence table. @retval false success @retval true failure */ bool open_table(); /** Get the TABLE object @retval table TABLE object */ TABLE *get_table() const { if (m_inherit_table && m_inherit_table->table) return m_inherit_table->table; else return m_state.cloned_table()->table; } private: THD *m_thd; TABLE_LIST *m_inherit_table; Table_list_state m_state; }; /** When CREATE SQUENCE, beside of creating table structure, also need to insert initial row into table. */ class Insert_sequence_table_ctx { public: Insert_sequence_table_ctx(THD *thd, TABLE_LIST *table_list, const Sequence_info *seq_info); virtual ~Insert_sequence_table_ctx(); /** Write the sequence initial row. @retval false success @retval true failure */ bool write_record(); private: Open_sequence_table_ctx otx; THD *m_thd; const Sequence_info *m_seq_info; bool m_save_binlog_row_based; }; #endif