polardbxengine/sql/sequence_common.h

480 lines
12 KiB
C++

/* 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 SEQUENCE_COMMON_INCLUDED
#define SEQUENCE_COMMON_INCLUDED
#if 0
#include "binary_log_types.h" // MYSQL_TYPE_LONGLONG
#endif
#include "map_helpers.h" // collation_unordered_map
#include "sql/psi_memory_key.h" // PSI_memory_key
#include "sql/sql_plugin_ref.h" // plugin_ref
struct handlerton;
class THD;
struct TABLE;
class Alter_info;
struct HA_CREATE_INFO;
class Create_func;
extern PSI_memory_key key_memory_sequence_last_value;
#define SEQUENCE_DEFAULT_BATCH_SIZE (1)
#define SEQUENCE_MAX_BATCH_SIZE (100 * 10000)
/**
Sequence table field value structure.
*/
struct st_sequence_value {
ulonglong currval;
ulonglong nextval;
ulonglong minvalue;
ulonglong maxvalue;
ulonglong start;
ulonglong increment;
ulonglong cache;
ulonglong cycle;
ulonglong round;
};
/**
Sequence create information.
*/
class Sequence_info {
public:
/* All the sequence fields.*/
enum Fields {
FIELD_NUM_CURRVAL = 0,
FIELD_NUM_NEXTVAL,
FIELD_NUM_MINVALUE,
FIELD_NUM_MAXVALUE,
FIELD_NUM_START,
FIELD_NUM_INCREMENT,
FIELD_NUM_CACHE,
FIELD_NUM_CYCLE,
FIELD_NUM_ROUND,
/* This must be last! */
FIELD_NUM_END
};
static constexpr const ulonglong F_CURRVAL = 1L << 0;
static constexpr const ulonglong F_NEXTVAL = 1L << 1;
static constexpr const ulonglong F_MINVALUE = 1L << 2;
static constexpr const ulonglong F_MAXVALUE = 1L << 3;
static constexpr const ulonglong F_START = 1L << 4;
static constexpr const ulonglong F_INCREMENT = 1L << 5;
static constexpr const ulonglong F_CACHE = 1L << 6;
static constexpr const ulonglong F_CYCLE = 1L << 7;
static constexpr const ulonglong F_ROUND = 1L << 8;
static constexpr const ulonglong F_END = 1L << 9;
static_assert(F_END == (1L << FIELD_NUM_END), "");
/** Default value for digital sequence cache size */
static constexpr const ulonglong DEF_CACHE_DIGITAL = 10000;
/** Default value for timestamp sequence cache size (seconds) */
static constexpr const ulonglong DEF_CACHE_TIMESTAMP = 10;
/** Min value for timestamp sequence cache size (seconds) */
static constexpr const ulonglong MIN_CACHE_TIMESTAMP = 1;
/** Max value for timestamp sequence cache size (seconds) */
static constexpr const ulonglong MAX_CACHE_TIMESTAMP = 300;
/** Sequence type: digital or timestamp */
enum Types { DIGITAL = 0, TIMESTAMP };
/**
Construtor and Destrutor
*/
Sequence_info();
virtual ~Sequence_info() {}
/* Disable the copy and assign function */
Sequence_info(const Sequence_info &) = delete;
Sequence_info(const Sequence_info &&) = delete;
Sequence_info &operator=(const Sequence_info &) = delete;
/**
Sequence field setting function
@param[in] field_num Sequence field number
@param[in] value Sequence field value
@retval void
*/
void init_value(const Fields field_num, const ulonglong value);
void init_type(Types value);
void fix_timestamp();
/**
Sequence field getting function
@param[in] field_num Sequence field number
@retval ulonglong Sequence field value
*/
ulonglong get_value(const Fields field_num) const;
/*
Check whether inited values are valid through
syntax: 'CREATE SEQUENCE ...'
@retval true Invalid
@retval false valid
*/
bool check_valid();
const char *db;
const char *table_name;
handlerton *base_db_type; /** Sequence table engine */
private:
/**
Assign initial default values of sequence fields
@retval void
*/
void init_default();
ulonglong values[Fields::FIELD_NUM_END];
ulonglong flags;
enum Types type;
};
typedef Sequence_info::Fields Sequence_field;
typedef Sequence_info::Types Sequence_type;
/**
Sequence table fields definition.
*/
struct st_sequence_field_info {
const char *field_name;
const char *field_length;
const Sequence_field field_num;
const enum enum_field_types field_type;
const LEX_CSTRING comment;
};
/**
The sequence value structure should be consistent with Sequence field
definition
*/
static_assert(sizeof(ulonglong) * Sequence_field::FIELD_NUM_END ==
sizeof(struct st_sequence_value),
"");
/**
Sequence attributes within TABLE_SHARE object, label the table as sequence
table.
*/
class Sequence_property {
public:
Sequence_property() : m_sequence(false), base_db_type(NULL), m_plugin(NULL) {}
~Sequence_property();
/* Disable these copy and assign functions */
Sequence_property(const Sequence_property &) = delete;
Sequence_property(const Sequence_property &&) = delete;
Sequence_property &operator=(const Sequence_property &) = delete;
/**
Configure the sequence flags and base db_type when open_table_share.
@param[in] plugin Storage engine plugin
*/
void configure(plugin_ref plugin);
bool is_sequence() { return m_sequence; }
handlerton *db_type() { return base_db_type; }
private:
bool m_sequence;
handlerton *base_db_type;
plugin_ref m_plugin;
};
/*
* Support some operation for sequence
* 1. nextval_show(sequence)
*/
struct Sequence_operation {
public:
enum Operation_type {
OPERATION_NONE,
OPERATION_SHOW_CACHE
};
Sequence_operation(): m_type(OPERATION_NONE) {}
Sequence_operation(const Sequence_operation &operation) {
m_type = operation.m_type;
}
Sequence_operation &operator=(const Sequence_operation &operation) {
m_type = operation.m_type;
return *this;
}
void set_type(Operation_type type) {
m_type = type;
}
void reset() {
m_type = OPERATION_NONE;
}
bool is_show_cache() {
return m_type == OPERATION_SHOW_CACHE;
}
private:
Operation_type m_type;
};
/** Support nextval_skip(sequence, value) */
struct Sequence_skip {
public:
Sequence_skip(bool skip, ulonglong value)
: m_skip(skip), m_skipped_to(value) {}
Sequence_skip() : m_skip(false), m_skipped_to(0) {}
Sequence_skip(const Sequence_skip &skip) {
m_skip = skip.m_skip;
m_skipped_to = skip.m_skipped_to;
}
Sequence_skip &operator=(const Sequence_skip &skip) {
m_skip = skip.m_skip;
m_skipped_to = skip.m_skipped_to;
return *this;
}
void reset() {
m_skip = false;
m_skipped_to = 0;
}
void init(ulonglong value) {
m_skip = true;
m_skipped_to = value;
}
bool is_skip() { return m_skip; }
ulonglong skipped_to() { return m_skipped_to; }
private:
bool m_skip;
ulonglong m_skipped_to;
};
/**
Sequence scan mode in TABLE object.
*/
class Sequence_scan {
public:
/**
Scan mode example like:
ORIGINAL_SCAN 'SELECT * FROM s'
ITERATION_SCAN 'SELECT NEXTVAL(s), CURRVAL(s)'
Orignal scan only query the base table data.
Iteration scan will apply the sequence logic.
*/
enum Scan_mode { ORIGINAL_SCAN = 0, ITERATION_SCAN };
enum Iter_mode {
IT_NON, /* Query the sequence base table */
IT_NEXTVAL, /* Query nextval */
IT_NON_NEXTVAL, /* Query non nextval, maybe currval or others */
};
Sequence_scan()
: m_mode(ORIGINAL_SCAN), m_batch(1), m_skip(), m_operation() {}
void reset() {
m_mode = ORIGINAL_SCAN;
m_batch = 1;
m_skip.reset();
m_operation.reset();
}
void set(Scan_mode mode) { m_mode = mode; }
Scan_mode get() { return m_mode; }
void set_batch(ulonglong batch) { m_batch = batch; }
ulonglong get_batch() { return m_batch; }
Sequence_skip get_skip() { return m_skip; }
void set_skip(Sequence_skip skip) { m_skip = skip; }
void set_skip(ulonglong value) { m_skip.init(value); }
Sequence_operation get_operation() { return m_operation; }
void set_operation_show_cache() {
m_operation.set_type(Sequence_operation::OPERATION_SHOW_CACHE);
}
/* Overlap the assignment operator */
Sequence_scan &operator=(const Sequence_scan &rhs) {
if (this != &rhs) {
this->m_mode = rhs.m_mode;
this->m_batch = rhs.m_batch;
this->m_skip = rhs.m_skip;
this->m_operation = rhs.m_operation;
}
return *this;
}
private:
Scan_mode m_mode;
/**
Used to get a batch of sequence value, currently only used for
timestamp sequence
*/
ulonglong m_batch;
Sequence_skip m_skip;
Sequence_operation m_operation;
};
typedef Sequence_scan::Scan_mode Sequence_scan_mode;
typedef Sequence_scan::Iter_mode Sequence_iter_mode;
typedef Sequence_operation::Operation_type Sequence_operation_type;
/**
Sequence currval that was saved in THD object.
*/
class Sequence_last_value {
public:
Sequence_last_value(){};
virtual ~Sequence_last_value(){};
void set_version(ulonglong version) { m_version = version; }
ulonglong get_version() { return m_version; }
ulonglong m_values[Sequence_field::FIELD_NUM_END];
private:
ulonglong m_version;
};
typedef collation_unordered_map<std::string, Sequence_last_value *>
Sequence_last_value_hash;
extern const LEX_CSTRING SEQUENCE_ENGINE_NAME;
extern const LEX_CSTRING SEQUENCE_BASE_ENGINE_NAME;
/**
Resolve the sequence engine and sequence base engine, it needs to
unlock_plugin explicitly if thd is null;
*/
extern plugin_ref ha_resolve_sequence(const THD *thd);
extern plugin_ref ha_resolve_sequence_base(const THD *thd);
extern st_sequence_field_info seq_fields[];
extern bool check_sequence_values_valid(Sequence_type type,
const ulonglong *items);
extern Sequence_type convert_sequence_type_by_increment(ulonglong value);
extern bool check_sequence_fields_valid(Alter_info *alter_info);
extern Sequence_iter_mode sequence_iteration_type(TABLE *table);
/**
Clear or destroy the global Sequence_share_hash and
session Sequence_last_value_hash.
*/
template <typename K, typename V>
void clear_hash(collation_unordered_map<K, V> *hash) {
if (hash) {
for (auto it = hash->cbegin(); it != hash->cend(); ++it) {
delete it->second;
}
hash->clear();
}
}
template <typename K, typename V>
void destroy_hash(collation_unordered_map<K, V> *hash) {
if (hash) {
clear_hash<K, V>(hash);
delete hash;
}
}
/**
Whether it is SEQUENCE object creation;
@retval true CREATE SEQUENCE or
CREATE TABLE ...sequence engine
@retval false Not
*/
bool sequence_create_info(HA_CREATE_INFO *create_info);
/**
Return the item builder of 'NEXTVAL' and 'CURRVAL'
@retval Create_func Builder
@retval NULL Not surpported function
*/
extern Create_func *find_sequence_function_builder(const LEX_STRING &f_name);
/**
Check whether the sp with the given name exist.
@retval true Exist
@retval false Not exist
*/
extern bool user_seq_sp_exist(THD *thd, const LEX_STRING &f_name);
/**
Init/De-init the existence of sequence SP.
*/
extern bool user_seq_sp_init();
extern void user_seq_sp_exit();
/**
Trace changes of procedures, update the existence of sequence SP.
@param[in] db database
@param[in] name sp name
@param[in] is_added true - newly added or renamed
false - dropped
*/
extern void on_user_sp_status_changed(const char *db, const char *name,
bool is_added);
/* Is the name sequence function */
extern bool is_seq_func_name(const char *name);
extern bool is_seq_nextval_func_name(const char *name);
extern bool is_seq_currval_func_name(const char *name);
extern bool is_seq_nextval_skip_func_name(const char *name);
extern bool is_seq_nextval_show_func_name(const char *name);
extern ulonglong time_system_ms(void);
#endif