303 lines
9.4 KiB
C++
303 lines
9.4 KiB
C++
/* Copyright (c) 2015, 2019, Oracle 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 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 KEY_SPEC_INCLUDED
|
||
#define KEY_SPEC_INCLUDED
|
||
|
||
#include <sys/types.h>
|
||
|
||
#include "lex_string.h"
|
||
#include "m_string.h"
|
||
#include "my_base.h"
|
||
#include "sql/mem_root_array.h"
|
||
#include "sql/sql_list.h"
|
||
|
||
class Create_field;
|
||
class Item;
|
||
class THD;
|
||
struct MEM_ROOT;
|
||
|
||
enum keytype {
|
||
KEYTYPE_PRIMARY,
|
||
KEYTYPE_UNIQUE,
|
||
KEYTYPE_MULTIPLE,
|
||
KEYTYPE_FULLTEXT,
|
||
KEYTYPE_SPATIAL,
|
||
KEYTYPE_FOREIGN
|
||
};
|
||
|
||
enum fk_option {
|
||
FK_OPTION_UNDEF,
|
||
FK_OPTION_RESTRICT,
|
||
FK_OPTION_CASCADE,
|
||
FK_OPTION_SET_NULL,
|
||
FK_OPTION_NO_ACTION,
|
||
FK_OPTION_DEFAULT
|
||
};
|
||
|
||
enum fk_match_opt {
|
||
FK_MATCH_UNDEF,
|
||
FK_MATCH_FULL,
|
||
FK_MATCH_PARTIAL,
|
||
FK_MATCH_SIMPLE
|
||
};
|
||
|
||
enum enum_order { ORDER_NOT_RELEVANT = 1, ORDER_ASC, ORDER_DESC };
|
||
|
||
class KEY_CREATE_INFO {
|
||
public:
|
||
enum ha_key_alg algorithm = HA_KEY_ALG_SE_SPECIFIC;
|
||
/**
|
||
A flag which indicates that index algorithm was explicitly specified
|
||
by user.
|
||
*/
|
||
bool is_algorithm_explicit = false;
|
||
ulong block_size = 0;
|
||
LEX_CSTRING parser_name = {NullS, 0};
|
||
LEX_CSTRING comment = {NullS, 0};
|
||
bool is_visible = true;
|
||
|
||
KEY_CREATE_INFO() = default;
|
||
|
||
explicit KEY_CREATE_INFO(bool is_visible_arg) : is_visible(is_visible_arg) {}
|
||
};
|
||
|
||
extern KEY_CREATE_INFO default_key_create_info;
|
||
|
||
class Key_part_spec {
|
||
public:
|
||
Key_part_spec(Item *expression, enum_order order)
|
||
: m_is_ascending((order == ORDER_DESC) ? false : true),
|
||
m_is_explicit(order != ORDER_NOT_RELEVANT),
|
||
m_field_name(nullptr),
|
||
m_prefix_length(0),
|
||
m_expression(expression),
|
||
m_has_expression(true) {}
|
||
|
||
Key_part_spec(const char *column_name, Item *expression, enum_order order)
|
||
: m_is_ascending((order == ORDER_DESC) ? false : true),
|
||
m_is_explicit(order != ORDER_NOT_RELEVANT),
|
||
m_field_name(column_name),
|
||
m_prefix_length(0),
|
||
m_expression(expression),
|
||
m_has_expression(true) {}
|
||
|
||
Key_part_spec(LEX_CSTRING column_name, uint prefix_length, enum_order order)
|
||
: m_is_ascending((order == ORDER_DESC) ? false : true),
|
||
m_is_explicit(order != ORDER_NOT_RELEVANT),
|
||
m_field_name(column_name.str),
|
||
m_prefix_length(prefix_length),
|
||
m_expression(nullptr),
|
||
m_has_expression(false) {}
|
||
|
||
bool operator==(const Key_part_spec &other) const;
|
||
/**
|
||
Construct a copy of this Key_part_spec. field_name is copied
|
||
by-pointer as it is known to never change. At the same time
|
||
'length' may be reset in mysql_prepare_create_table, and this
|
||
is why we supply it with a copy.
|
||
|
||
@return If out of memory, 0 is returned and an error is set in
|
||
THD.
|
||
*/
|
||
Key_part_spec *clone(MEM_ROOT *mem_root) const {
|
||
return new (mem_root) Key_part_spec(*this);
|
||
}
|
||
|
||
const char *get_field_name() const { return m_field_name; }
|
||
|
||
uint get_prefix_length() const { return m_prefix_length; }
|
||
|
||
Item *get_expression() const {
|
||
DBUG_ASSERT(has_expression());
|
||
return m_expression;
|
||
}
|
||
|
||
/**
|
||
@retval true if this is an ascending index.
|
||
@retval false if this is a descending index.
|
||
*/
|
||
bool is_ascending() const { return m_is_ascending; }
|
||
|
||
/**
|
||
@retval true if the user explicitly specified the index direction when
|
||
creating the index.
|
||
@retval false if the user didn't specify the index direction.
|
||
*/
|
||
bool is_explicit() const { return m_is_explicit; }
|
||
|
||
/**
|
||
Resolve the expression that this key part contains. Should only be called
|
||
if has_expression() returns true.
|
||
|
||
@param thd thread handler.
|
||
|
||
@retval true if an error occurred.
|
||
@retval false on success.
|
||
*/
|
||
bool resolve_expression(THD *thd);
|
||
|
||
/**
|
||
Set the name and the prefix length of the column this key part references.
|
||
The supplied column name string should have a lifetime equal to or longer
|
||
than this Key_part_spec
|
||
|
||
@param name the new column that this key part points to.
|
||
@param prefix_length the prefix length of the index, or 0 if no length is
|
||
specified.
|
||
*/
|
||
void set_name_and_prefix_length(const char *name, uint prefix_length);
|
||
|
||
/**
|
||
@retval true if this index has an expression. In that case, this a
|
||
functional key part.
|
||
@retval false if this index doesn't have an expression. In that case this
|
||
key part references a normal column.
|
||
*/
|
||
bool has_expression() const { return m_has_expression; }
|
||
|
||
private:
|
||
/// true <=> ascending, false <=> descending.
|
||
const bool m_is_ascending;
|
||
|
||
/// true <=> ASC/DESC is explicitly specified, false <=> implicit ASC
|
||
const bool m_is_explicit;
|
||
|
||
/// The name of the column that this key part points to.
|
||
const char *m_field_name;
|
||
|
||
/// The prefix length of this index.
|
||
uint m_prefix_length;
|
||
|
||
/**
|
||
The indexed expression if this is a functional key part. If this key part
|
||
points to a "normal" column, m_expression is nullptr.
|
||
*/
|
||
Item *m_expression;
|
||
|
||
/**
|
||
Whether this key part has an expression or not. If so, this is a functional
|
||
key part.
|
||
*/
|
||
bool m_has_expression;
|
||
};
|
||
|
||
class Key_spec {
|
||
public:
|
||
const keytype type;
|
||
const KEY_CREATE_INFO key_create_info;
|
||
Mem_root_array<Key_part_spec *> columns;
|
||
LEX_CSTRING name;
|
||
const bool generated;
|
||
/**
|
||
A flag to determine if we will check for duplicate indexes.
|
||
This typically means that the key information was specified
|
||
directly by the user (set by the parser) or a column
|
||
associated with it was dropped.
|
||
*/
|
||
const bool check_for_duplicate_indexes;
|
||
|
||
Key_spec(MEM_ROOT *mem_root, keytype type_par, const LEX_CSTRING &name_arg,
|
||
const KEY_CREATE_INFO *key_info_arg, bool generated_arg,
|
||
bool check_for_duplicate_indexes_arg, List<Key_part_spec> &cols)
|
||
: type(type_par),
|
||
key_create_info(*key_info_arg),
|
||
columns(mem_root),
|
||
name(name_arg),
|
||
generated(generated_arg),
|
||
check_for_duplicate_indexes(check_for_duplicate_indexes_arg) {
|
||
columns.reserve(cols.elements);
|
||
List_iterator<Key_part_spec> it(cols);
|
||
Key_part_spec *column;
|
||
while ((column = it++)) columns.push_back(column);
|
||
}
|
||
|
||
virtual ~Key_spec() {}
|
||
};
|
||
|
||
class Foreign_key_spec : public Key_spec {
|
||
public:
|
||
const LEX_CSTRING ref_db;
|
||
const LEX_CSTRING orig_ref_db;
|
||
const LEX_CSTRING ref_table;
|
||
const LEX_CSTRING orig_ref_table;
|
||
Mem_root_array<Key_part_spec *> ref_columns;
|
||
const fk_option delete_opt;
|
||
const fk_option update_opt;
|
||
const fk_match_opt match_opt;
|
||
|
||
Foreign_key_spec(MEM_ROOT *mem_root, const LEX_CSTRING &name_arg,
|
||
List<Key_part_spec> cols, const LEX_CSTRING &ref_db_arg,
|
||
const LEX_CSTRING &orig_ref_db_arg,
|
||
const LEX_CSTRING &ref_table_arg,
|
||
const LEX_CSTRING &orig_ref_table_arg,
|
||
List<Key_part_spec> *ref_cols, fk_option delete_opt_arg,
|
||
fk_option update_opt_arg, fk_match_opt match_opt_arg)
|
||
: Key_spec(mem_root, KEYTYPE_FOREIGN, name_arg, &default_key_create_info,
|
||
false,
|
||
false, // We don't check for duplicate FKs.
|
||
cols),
|
||
ref_db(ref_db_arg),
|
||
orig_ref_db(orig_ref_db_arg),
|
||
ref_table(ref_table_arg),
|
||
orig_ref_table(orig_ref_table_arg),
|
||
ref_columns(mem_root),
|
||
delete_opt(delete_opt_arg),
|
||
update_opt(update_opt_arg),
|
||
match_opt(match_opt_arg) {
|
||
if (ref_cols) {
|
||
ref_columns.reserve(ref_cols->elements);
|
||
List_iterator<Key_part_spec> it(*ref_cols);
|
||
Key_part_spec *ref_column;
|
||
while ((ref_column = it++)) ref_columns.push_back(ref_column);
|
||
}
|
||
}
|
||
|
||
/**
|
||
Check if the foreign key name has valid length and its options
|
||
are compatible with columns on which the FK is created.
|
||
|
||
@param thd Thread handle
|
||
@param table_name Table name (for error reporting)
|
||
@param table_fields List of columns
|
||
|
||
@retval false Key valid
|
||
@retval true Key invalid
|
||
*/
|
||
bool validate(THD *thd, const char *table_name,
|
||
List<Create_field> &table_fields) const;
|
||
};
|
||
|
||
/**
|
||
Test if a foreign key (= generated key) is a prefix of the given key
|
||
(ignoring key name, key type and order of columns)
|
||
|
||
@note This is only used to test if an index for a FOREIGN KEY exists.
|
||
We only compare field names.
|
||
|
||
@retval false Generated key is a prefix of other key
|
||
@retval true Not equal
|
||
*/
|
||
bool foreign_key_prefix(const Key_spec *a, const Key_spec *b);
|
||
|
||
#endif // KEY_SPEC_INCLUDED
|