From e0942286313f78e497a36394111b4546d5a20ed0 Mon Sep 17 00:00:00 2001 From: Kosov Eugene Date: Thu, 20 Oct 2016 23:05:55 +0300 Subject: [PATCH] SQL: hide implicitly added columns from SELECT * --- include/mysql_com.h | 1 + mysql-test/suite/versioning/r/select.result | 16 + mysql-test/suite/versioning/t/select.test | 16 + sql/field.h | 3 + sql/field.h.orig | 4160 +++++++++++++++++++ sql/handler.cc | 4 +- sql/sql_base.cc | 8 + sql/sql_table.cc | 2 + sql/table.cc | 3 + 9 files changed, 4211 insertions(+), 2 deletions(-) create mode 100644 sql/field.h.orig diff --git a/include/mysql_com.h b/include/mysql_com.h index 904a64b08f8..d52bd8eaada 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -193,6 +193,7 @@ enum enum_indicator_type #define WITHOUT_SYSTEM_VERSIONING_FLAG (1 << 29) /* column that doesn't support system versioning when table itself supports it*/ +#define HIDDEN_FLAG (1 << 31) /* hide from SELECT * */ #define REFRESH_GRANT (1ULL << 0) /* Refresh grant tables */ #define REFRESH_LOG (1ULL << 1) /* Start on new log file */ diff --git a/mysql-test/suite/versioning/r/select.result b/mysql-test/suite/versioning/r/select.result index a691019c80c..94dcb243e65 100644 --- a/mysql-test/suite/versioning/r/select.result +++ b/mysql-test/suite/versioning/r/select.result @@ -241,6 +241,21 @@ RJ2_x1 y1 x2 y2 1 3 1 2 NULL NULL 2 1 NULL NULL 3 1 +create table t1( +A int +) with system versioning engine=myisam; +insert into t1 values(1); +select * from t1; +A +1 +create or replace table t1( +A int +) with system versioning engine=innodb; +insert into t1 values(1); +select * from t1; +A +1 +drop table t1; call verify_vtq; No A B C D 1 1 1 1 1 @@ -251,6 +266,7 @@ No A B C D 6 1 1 1 1 7 1 1 1 1 8 1 1 1 1 +9 1 1 1 1 drop procedure test_01; drop procedure test_02; drop procedure verify_vtq; diff --git a/mysql-test/suite/versioning/t/select.test b/mysql-test/suite/versioning/t/select.test index 621374051bb..0aa4f561882 100644 --- a/mysql-test/suite/versioning/t/select.test +++ b/mysql-test/suite/versioning/t/select.test @@ -89,6 +89,22 @@ call test_01('bigint unsigned', 'innodb', 'commit_ts(sys_start)'); call test_02('timestamp(6)', 'myisam', 'sys_start'); call test_02('bigint unsigned', 'innodb', 'commit_ts(sys_start)'); +# Test wildcard expansion on hidden fields. +create table t1( + A int +) with system versioning engine=myisam; +insert into t1 values(1); +select * from t1; + +create or replace table t1( + A int +) with system versioning engine=innodb; +insert into t1 values(1); +select * from t1; + +drop table t1; +# End test wildcard expansion. + call verify_vtq; drop procedure test_01; diff --git a/sql/field.h b/sql/field.h index a52fb656b39..e50595df11a 100644 --- a/sql/field.h +++ b/sql/field.h @@ -4281,6 +4281,8 @@ bool check_expression(Virtual_column_info *vcol, const char *name, #define FIELDFLAG_BITFIELD 512U // mangled with decimals! #define FIELDFLAG_BLOB 1024U // mangled with decimals! #define FIELDFLAG_GEOM 2048U // mangled with decimals! +// Do not show field in SELECT *. Hope GEOM field is never hidden. +#define FIELDFLAG_HIDDEN 2048U #define FIELDFLAG_TREAT_BIT_AS_CHAR 4096U /* use Field_bit_as_char */ #define FIELDFLAG_LONG_DECIMAL 8192U @@ -4312,5 +4314,6 @@ bool check_expression(Virtual_column_info *vcol, const char *name, #define f_bit_as_char(x) ((x) & FIELDFLAG_TREAT_BIT_AS_CHAR) #define f_is_hex_escape(x) ((x) & FIELDFLAG_HEX_ESCAPE) #define f_without_system_versioning(x) ((x) & FIELDFLAG_WITHOUT_SYSTEM_VERSIONING) +#define f_hidden(x) ((x) & FIELDFLAG_HIDDEN) #endif /* FIELD_INCLUDED */ diff --git a/sql/field.h.orig b/sql/field.h.orig new file mode 100644 index 00000000000..03d9ba06ac4 --- /dev/null +++ b/sql/field.h.orig @@ -0,0 +1,4160 @@ +#ifndef FIELD_INCLUDED +#define FIELD_INCLUDED +/* Copyright (c) 2000, 2015, Oracle and/or its affiliates. + Copyright (c) 2008, 2017, MariaDB Corporation. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + 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 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 */ + +/* + Because of the function make_new_field() all field classes that have static + variables must declare the size_of() member function. +*/ + +#ifdef USE_PRAGMA_INTERFACE +#pragma interface /* gcc class implementation */ +#endif + +#include "mysqld.h" /* system_charset_info */ +#include "table.h" /* TABLE */ +#include "sql_string.h" /* String */ +#include "my_decimal.h" /* my_decimal */ +#include "sql_error.h" /* Sql_condition */ +#include "compat56.h" +#include "sql_type.h" /* Type_std_attributes */ + +class Send_field; +class Copy_field; +class Protocol; +class Create_field; +class Relay_log_info; +class Field; +class Column_statistics; +class Column_statistics_collected; +class Item_func; +class Item_bool_func; +class Item_equal; + +enum enum_check_fields +{ + CHECK_FIELD_IGNORE, + CHECK_FIELD_WARN, + CHECK_FIELD_ERROR_FOR_NULL +}; + +/* + Common declarations for Field and Item +*/ +class Value_source +{ +protected: + + // Parameters for warning and note generation + class Warn_filter + { + bool m_want_warning_edom; + bool m_want_note_truncated_spaces; + public: + Warn_filter(bool want_warning_edom, bool want_note_truncated_spaces) : + m_want_warning_edom(want_warning_edom), + m_want_note_truncated_spaces(want_note_truncated_spaces) + { } + Warn_filter(const THD *thd); + bool want_warning_edom() const + { return m_want_warning_edom; } + bool want_note_truncated_spaces() const + { return m_want_note_truncated_spaces; } + }; + class Warn_filter_all: public Warn_filter + { + public: + Warn_filter_all() :Warn_filter(true, true) { } + }; + + class Converter_double_to_longlong + { + protected: + bool m_error; + longlong m_result; + public: + Converter_double_to_longlong(double nr, bool unsigned_flag); + longlong result() const { return m_result; } + bool error() const { return m_error; } + void push_warning(THD *thd, double nr, bool unsigned_flag); + }; + class Converter_double_to_longlong_with_warn: + public Converter_double_to_longlong + { + public: + Converter_double_to_longlong_with_warn(THD *thd, double nr, + bool unsigned_flag) + :Converter_double_to_longlong(nr, unsigned_flag) + { + if (m_error) + push_warning(thd, nr, unsigned_flag); + } + Converter_double_to_longlong_with_warn(double nr, bool unsigned_flag) + :Converter_double_to_longlong(nr, unsigned_flag) + { + if (m_error) + push_warning(current_thd, nr, unsigned_flag); + } + }; + + // String-to-number converters + class Converter_string_to_number + { + protected: + char *m_end_of_num; // Where the low-level conversion routine stopped + int m_error; // The error code returned by the low-level routine + bool m_edom; // If EDOM-alike error happened during conversion + /** + Check string-to-number conversion and produce a warning if + - could not convert any digits (EDOM-alike error) + - found garbage at the end of the string + - found extra spaces at the end (a note) + See also Field_num::check_edom_and_truncation() for a similar function. + + @param thd - the thread that will be used to generate warnings. + Can be NULL (which means current_thd will be used + if a warning is really necessary). + @param type - name of the data type + (e.g. "INTEGER", "DECIMAL", "DOUBLE") + @param cs - character set of the original string + @param str - the original string + @param end - the end of the string + @param allow_notes - tells if trailing space notes should be displayed + or suppressed. + + Unlike Field_num::check_edom_and_truncation(), this function does not + distinguish between EDOM and truncation and reports the same warning for + both cases. Perhaps we should eventually print different warnings, + to make the explicit CAST work closer to the implicit cast in + Field_xxx::store(). + */ + void check_edom_and_truncation(THD *thd, Warn_filter filter, + const char *type, + CHARSET_INFO *cs, + const char *str, + size_t length) const; + public: + int error() const { return m_error; } + }; + + class Converter_strntod: public Converter_string_to_number + { + double m_result; + public: + Converter_strntod(CHARSET_INFO *cs, const char *str, size_t length) + { + m_result= my_strntod(cs, (char *) str, length, &m_end_of_num, &m_error); + // strntod() does not set an error if the input string was empty + m_edom= m_error !=0 || str == m_end_of_num; + } + double result() const { return m_result; } + }; + + class Converter_string_to_longlong: public Converter_string_to_number + { + protected: + longlong m_result; + public: + longlong result() const { return m_result; } + }; + + class Converter_strntoll: public Converter_string_to_longlong + { + public: + Converter_strntoll(CHARSET_INFO *cs, const char *str, size_t length) + { + m_result= my_strntoll(cs, str, length, 10, &m_end_of_num, &m_error); + /* + All non-zero errors means EDOM error. + strntoll() does not set an error if the input string was empty. + Check it here. + Notice the different with the same condition in Converter_strntoll10. + */ + m_edom= m_error != 0 || str == m_end_of_num; + } + }; + + class Converter_strtoll10: public Converter_string_to_longlong + { + public: + Converter_strtoll10(CHARSET_INFO *cs, const char *str, size_t length) + { + m_end_of_num= (char *) str + length; + m_result= (*(cs->cset->strtoll10))(cs, str, &m_end_of_num, &m_error); + /* + Negative error means "good negative number". + Only a positive m_error value means a real error. + strtoll10() sets error to MY_ERRNO_EDOM in case of an empty string, + so we don't have to additionally catch empty strings here. + */ + m_edom= m_error > 0; + } + }; + + class Converter_str2my_decimal: public Converter_string_to_number + { + public: + Converter_str2my_decimal(uint mask, + CHARSET_INFO *cs, const char *str, size_t length, + my_decimal *buf) + { + m_error= str2my_decimal(mask, str, length, cs, + buf, (const char **) &m_end_of_num); + // E_DEC_TRUNCATED means a very minor truncation: '1e-100' -> 0 + m_edom= m_error && m_error != E_DEC_TRUNCATED; + } + }; + + + // String-to-number converters with automatic warning generation + class Converter_strntod_with_warn: public Converter_strntod + { + public: + Converter_strntod_with_warn(THD *thd, Warn_filter filter, + CHARSET_INFO *cs, + const char *str, size_t length) + :Converter_strntod(cs, str, length) + { + check_edom_and_truncation(thd, filter, "DOUBLE", cs, str, length); + } + }; + + class Converter_strntoll_with_warn: public Converter_strntoll + { + public: + Converter_strntoll_with_warn(THD *thd, Warn_filter filter, + CHARSET_INFO *cs, + const char *str, size_t length) + :Converter_strntoll(cs, str, length) + { + check_edom_and_truncation(thd, filter, "INTEGER", cs, str, length); + } + }; + + class Converter_strtoll10_with_warn: public Converter_strtoll10 + { + public: + Converter_strtoll10_with_warn(THD *thd, Warn_filter filter, + CHARSET_INFO *cs, + const char *str, size_t length) + :Converter_strtoll10(cs, str, length) + { + check_edom_and_truncation(thd, filter, "INTEGER", cs, str, length); + } + }; + + class Converter_str2my_decimal_with_warn: public Converter_str2my_decimal + { + public: + Converter_str2my_decimal_with_warn(THD *thd, Warn_filter filter, + uint mask, CHARSET_INFO *cs, + const char *str, size_t length, + my_decimal *buf) + :Converter_str2my_decimal(mask, cs, str, length, buf) + { + check_edom_and_truncation(thd, filter, "DECIMAL", cs, str, length); + } + }; + + + // String-to-number convertion methods for the old code compatibility + longlong longlong_from_string_with_check(CHARSET_INFO *cs, const char *cptr, + const char *end) const + { + /* + TODO: Give error if we wanted a signed integer and we got an unsigned + one + + Notice, longlong_from_string_with_check() honors thd->no_error, because + it's used to handle queries like this: + SELECT COUNT(@@basedir); + and is called when Item_func_get_system_var::update_null_value() + suppresses warnings and then calls val_int(). + The other methods {double|decimal}_from_string_with_check() ignore + thd->no_errors, because they are not used for update_null_value() + and they always allow all kind of warnings. + */ + THD *thd= current_thd; + return Converter_strtoll10_with_warn(thd, Warn_filter(thd), + cs, cptr, end - cptr).result(); + } + + double double_from_string_with_check(CHARSET_INFO *cs, const char *cptr, + const char *end) const + { + return Converter_strntod_with_warn(NULL, Warn_filter_all(), + cs, cptr, end - cptr).result(); + } + my_decimal *decimal_from_string_with_check(my_decimal *decimal_value, + CHARSET_INFO *cs, + const char *cptr, + const char *end) + { + Converter_str2my_decimal_with_warn(NULL, Warn_filter_all(), + E_DEC_FATAL_ERROR & ~E_DEC_BAD_NUM, + cs, cptr, end - cptr, decimal_value); + return decimal_value; + } + + longlong longlong_from_hex_hybrid(const char *str, uint32 length) + { + const char *end= str + length; + const char *ptr= end - MY_MIN(length, sizeof(longlong)); + ulonglong value= 0; + for ( ; ptr != end ; ptr++) + value= (value << 8) + (ulonglong) (uchar) *ptr; + return (longlong) value; + } + + longlong longlong_from_string_with_check(const String *str) const + { + return longlong_from_string_with_check(str->charset(), + str->ptr(), str->end()); + } + double double_from_string_with_check(const String *str) const + { + return double_from_string_with_check(str->charset(), + str->ptr(), str->end()); + } + my_decimal *decimal_from_string_with_check(my_decimal *decimal_value, + const String *str) + { + return decimal_from_string_with_check(decimal_value, str->charset(), + str->ptr(), str->end()); + } + // End of String-to-number conversion methods + +public: + /* + The enumeration Subst_constraint is currently used only in implementations + of the virtual function subst_argument_checker. + */ + enum Subst_constraint + { + ANY_SUBST, /* Any substitution for a field is allowed */ + IDENTITY_SUBST /* Substitution for a field is allowed if any two + different values of the field type are not equal */ + }; + /* + Item context attributes. + Comparison functions pass their attributes to propagate_equal_fields(). + For exmple, for string comparison, the collation of the comparison + operation is important inside propagate_equal_fields(). + */ + class Context + { + /* + Which type of propagation is allowed: + - ANY_SUBST (loose equality, according to the collation), or + - IDENTITY_SUBST (strict binary equality). + */ + Subst_constraint m_subst_constraint; + /* + Comparison type. + Impostant only when ANY_SUBSTS. + */ + Item_result m_compare_type; + /* + Collation of the comparison operation. + Important only when ANY_SUBST. + */ + CHARSET_INFO *m_compare_collation; + public: + Context(Subst_constraint subst, Item_result type, CHARSET_INFO *cs) + :m_subst_constraint(subst), + m_compare_type(type), + m_compare_collation(cs) { } + Subst_constraint subst_constraint() const { return m_subst_constraint; } + Item_result compare_type() const + { + DBUG_ASSERT(m_subst_constraint == ANY_SUBST); + return m_compare_type; + } + CHARSET_INFO *compare_collation() const + { + DBUG_ASSERT(m_subst_constraint == ANY_SUBST); + return m_compare_collation; + } + }; + class Context_identity: public Context + { // Use this to request only exact value, no invariants. + public: + Context_identity() + :Context(IDENTITY_SUBST, STRING_RESULT, &my_charset_bin) { } + }; + class Context_boolean: public Context + { // Use this when an item is [a part of] a boolean expression + public: + Context_boolean() :Context(ANY_SUBST, INT_RESULT, &my_charset_bin) { } + }; +}; + + +#define STORAGE_TYPE_MASK 7 +#define COLUMN_FORMAT_MASK 7 +#define COLUMN_FORMAT_SHIFT 3 + +/* The length of the header part for each virtual column in the .frm file */ +#define FRM_VCOL_OLD_HEADER_SIZE(b) (3 + MY_TEST(b)) +#define FRM_VCOL_NEW_BASE_SIZE 16 +#define FRM_VCOL_NEW_HEADER_SIZE 6 + +class Count_distinct_field; + +struct ha_field_option_struct; + +struct st_cache_field; +int field_conv(Field *to,Field *from); +int truncate_double(double *nr, uint field_length, uint dec, + bool unsigned_flag, double max_value); + +inline uint get_enum_pack_length(int elements) +{ + return elements < 256 ? 1 : 2; +} + +inline uint get_set_pack_length(int elements) +{ + uint len= (elements + 7) / 8; + return len > 4 ? 8 : len; +} + + +/** + Tests if field type is temporal and has date part, + i.e. represents DATE, 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 part. + @retval false If field type is not temporal type with date part. +*/ +inline bool is_temporal_type_with_date(enum_field_types type) +{ + switch (type) + { + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_TIMESTAMP: + return true; + case MYSQL_TYPE_DATETIME2: + case MYSQL_TYPE_TIMESTAMP2: + DBUG_ASSERT(0); // field->real_type() should not get to here. + 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; +} + + +/** + Convert temporal real types as retuned by field->real_type() + to field type as returned by field->type(). + + @param real_type Real type. + @retval Field type. +*/ +inline enum_field_types real_type_to_type(enum_field_types real_type) +{ + switch (real_type) + { + case MYSQL_TYPE_TIME2: + return MYSQL_TYPE_TIME; + case MYSQL_TYPE_DATETIME2: + return MYSQL_TYPE_DATETIME; + case MYSQL_TYPE_TIMESTAMP2: + return MYSQL_TYPE_TIMESTAMP; + case MYSQL_TYPE_NEWDATE: + return MYSQL_TYPE_DATE; + /* Note: NEWDECIMAL is a type, not only a real_type */ + default: return real_type; + } +} + + +static inline enum enum_mysql_timestamp_type +mysql_type_to_time_type(enum enum_field_types mysql_type) +{ + switch(mysql_type) { + case MYSQL_TYPE_TIME2: + case MYSQL_TYPE_TIME: return MYSQL_TIMESTAMP_TIME; + case MYSQL_TYPE_TIMESTAMP2: + case MYSQL_TYPE_TIMESTAMP: + case MYSQL_TYPE_DATETIME2: + case MYSQL_TYPE_DATETIME: return MYSQL_TIMESTAMP_DATETIME; + case MYSQL_TYPE_NEWDATE: + case MYSQL_TYPE_DATE: return MYSQL_TIMESTAMP_DATE; + default: return MYSQL_TIMESTAMP_ERROR; + } +} + + +/** + Tests if field type is temporal, i.e. represents + DATE, TIME, DATETIME or TIMESTAMP 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) +{ + return mysql_type_to_time_type(type) != MYSQL_TIMESTAMP_ERROR; +} + + +/** + 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; + } +} + +enum enum_vcol_info_type +{ + VCOL_GENERATED_VIRTUAL, VCOL_GENERATED_STORED, + VCOL_DEFAULT, VCOL_CHECK_FIELD, VCOL_CHECK_TABLE +}; + +static inline const char *vcol_type_name(enum_vcol_info_type type) +{ + switch (type) + { + case VCOL_GENERATED_VIRTUAL: + case VCOL_GENERATED_STORED: + return "GENERATED ALWAYS AS"; + case VCOL_DEFAULT: + return "DEFAULT"; + case VCOL_CHECK_FIELD: + case VCOL_CHECK_TABLE: + return "CHECK"; + } + return 0; +} + +/* + Flags for Virtual_column_info. If none is set, the expression must be + a constant with no side-effects, so it's calculated at CREATE TABLE time, + stored in table->record[2], and not recalculated for every statement. +*/ +#define VCOL_FIELD_REF 1 +#define VCOL_NON_DETERMINISTIC 2 +#define VCOL_SESSION_FUNC 4 /* uses session data, e.g. USER or DAYNAME */ +#define VCOL_TIME_FUNC 8 +#define VCOL_IMPOSSIBLE 16 + +#define VCOL_NOT_STRICTLY_DETERMINISTIC \ + (VCOL_NON_DETERMINISTIC | VCOL_TIME_FUNC | VCOL_SESSION_FUNC) + +/* + Virtual_column_info is the class to contain additional + characteristics that is specific for a virtual/computed + field such as: + - the defining expression that is evaluated to compute the value + of the field + - whether the field is to be stored in the database + - whether the field is used in a partitioning expression +*/ + +class Virtual_column_info: public Sql_alloc +{ +private: + /* + The following data is only updated by the parser and read + when a Create_field object is created/initialized. + */ + enum_field_types field_type; /* Real field type*/ + /* Flag indicating that the field used in a partitioning expression */ + bool in_partitioning_expr; + +public: + /* Flag indicating that the field is physically stored in the database */ + bool stored_in_db; + bool utf8; /* Already in utf8 */ + Item *expr; + LEX_STRING name; /* Name of constraint */ + uint flags; + + Virtual_column_info() + : field_type((enum enum_field_types)MYSQL_TYPE_VIRTUAL), + in_partitioning_expr(FALSE), stored_in_db(FALSE), + utf8(TRUE), expr(NULL), flags(0) + { + name.str= NULL; + name.length= 0; + }; + ~Virtual_column_info() {} + enum_field_types get_real_type() const + { + return field_type; + } + void set_field_type(enum_field_types fld_type) + { + /* Calling this function can only be done once. */ + field_type= fld_type; + } + bool is_stored() const + { + return stored_in_db; + } + void set_stored_in_db_flag(bool stored) + { + stored_in_db= stored; + } + bool is_in_partitioning_expr() const + { + return in_partitioning_expr; + } + void mark_as_in_partitioning_expr() + { + in_partitioning_expr= TRUE; + } + inline bool is_equal(const Virtual_column_info* vcol) const; + void print(String*); +}; + +class Field: public Value_source +{ + Field(const Item &); /* Prevent use of these */ + void operator=(Field &); +protected: + int save_in_field_str(Field *to) + { + StringBuffer result(charset()); + val_str(&result); + return to->store(result.ptr(), result.length(), charset()); + } + static void do_field_int(Copy_field *copy); + static void do_field_real(Copy_field *copy); + static void do_field_string(Copy_field *copy); + static void do_field_temporal(Copy_field *copy); + static void do_field_decimal(Copy_field *copy); +public: + static void *operator new(size_t size, MEM_ROOT *mem_root) throw () + { return alloc_root(mem_root, size); } + static void *operator new(size_t size) throw () + { return thd_alloc(current_thd, size); } + static void operator delete(void *ptr_arg, size_t size) { TRASH(ptr_arg, size); } + static void operator delete(void *ptr, MEM_ROOT *mem_root) + { DBUG_ASSERT(0); } + + /** + Used by System Versioning. + */ + virtual bool set_max() + { DBUG_ASSERT(0); return false; } + + /** + Used by System Versioning. + */ + virtual bool is_max() + { DBUG_ASSERT(0); return false; } + + uchar *ptr; // Position to field in record + /** + Byte where the @c NULL bit is stored inside a record. If this Field is a + @c NOT @c NULL field, this member is @c NULL. + */ + uchar *null_ptr; + /* + Note that you can use table->in_use as replacement for current_thd member + only inside of val_*() and store() members (e.g. you can't use it in cons) + */ + TABLE *table; // Pointer for table + TABLE *orig_table; // Pointer to original table + const char * const *table_name; + const char *field_name; + /** reference to the list of options or NULL */ + engine_option_value *option_list; + ha_field_option_struct *option_struct; /* structure with parsed options */ + LEX_STRING comment; + /* Field is part of the following keys */ + key_map key_start, part_of_key, part_of_key_not_clustered; + + /* + Bitmap of indexes that have records ordered by col1, ... this_field, ... + + For example, INDEX (col(prefix_n)) is not present in col.part_of_sortkey. + */ + key_map part_of_sortkey; + /* + We use three additional unireg types for TIMESTAMP to overcome limitation + of current binary format of .frm file. We'd like to be able to support + NOW() as default and on update value for such fields but unable to hold + this info anywhere except unireg_check field. This issue will be resolved + in more clean way with transition to new text based .frm format. + See also comment for Field_timestamp::Field_timestamp(). + */ + enum utype { + NONE=0, + NEXT_NUMBER=15, // AUTO_INCREMENT + TIMESTAMP_OLD_FIELD=18, // TIMESTAMP created before 4.1.3 + TIMESTAMP_DN_FIELD=21, // TIMESTAMP DEFAULT NOW() + TIMESTAMP_UN_FIELD=22, // TIMESTAMP ON UPDATE NOW() + TIMESTAMP_DNUN_FIELD=23 // TIMESTAMP DEFAULT NOW() ON UPDATE NOW() + }; + enum geometry_type + { + GEOM_GEOMETRY = 0, GEOM_POINT = 1, GEOM_LINESTRING = 2, GEOM_POLYGON = 3, + GEOM_MULTIPOINT = 4, GEOM_MULTILINESTRING = 5, GEOM_MULTIPOLYGON = 6, + GEOM_GEOMETRYCOLLECTION = 7 + }; + enum imagetype { itRAW, itMBR}; + + utype unireg_check; + uint32 field_length; // Length of field + uint32 flags; + uint16 field_index; // field number in fields array + uchar null_bit; // Bit used to test null bit + /** + If true, this field was created in create_tmp_field_from_item from a NULL + value. This means that the type of the field is just a guess, and the type + may be freely coerced to another type. + + @see create_tmp_field_from_item + @see Item_type_holder::get_real_type + + */ + bool is_created_from_null_item; + + /* TRUE in Field objects created for column min/max values */ + bool is_stat_field; + + /* + Selectivity of the range condition over this field. + When calculating this selectivity a range predicate + is taken into account only if: + - it is extracted from the WHERE clause + - it depends only on the table the field belongs to + */ + double cond_selectivity; + + /* + The next field in the class of equal fields at the top AND level + of the WHERE clause + */ + Field *next_equal_field; + + /* + This structure is used for statistical data on the column + that has been read from the statistical table column_stat + */ + Column_statistics *read_stats; + /* + This structure is used for statistical data on the column that + is collected by the function collect_statistics_for_table + */ + Column_statistics_collected *collected_stats; + + /* + This is additional data provided for any computed(virtual) field, + default function or check constraint. + In particular it includes a pointer to the item by which this field + can be computed from other fields. + */ + Virtual_column_info *vcol_info, *check_constraint, *default_value; + + Field(uchar *ptr_arg,uint32 length_arg,uchar *null_ptr_arg, + uchar null_bit_arg, utype unireg_check_arg, + const char *field_name_arg); + virtual ~Field() {} + + DTCollation dtcollation() const + { + return DTCollation(charset(), derivation(), repertoire()); + } + Type_std_attributes type_std_attributes() const + { + return Type_std_attributes(field_length, decimals(), + MY_TEST(flags & UNSIGNED_FLAG), + dtcollation()); + } + + /** + Convenience definition of a copy function returned by + Field::get_copy_func() + */ + typedef void Copy_func(Copy_field*); + virtual Copy_func *get_copy_func(const Field *from) const= 0; + /* Store functions returns 1 on overflow and -1 on fatal error */ + virtual int store_field(Field *from) { return from->save_in_field(this); } + virtual int save_in_field(Field *to)= 0; + /** + Check if it is possible just copy the value + of the field 'from' to the field 'this', e.g. for + INSERT INTO t1 (field1) SELECT field2 FROM t2; + @param from - The field to copy from + @retval true - it is possible to just copy value of 'from' to 'this' + @retval false - conversion is needed + */ + virtual bool memcpy_field_possible(const Field *from) const= 0; + virtual int store(const char *to, uint length,CHARSET_INFO *cs)=0; + virtual int store_hex_hybrid(const char *str, uint length); + virtual int store(double nr)=0; + virtual int store(longlong nr, bool unsigned_val)=0; + virtual int store_decimal(const my_decimal *d)=0; + virtual int store_time_dec(MYSQL_TIME *ltime, uint dec); + int store_time(MYSQL_TIME *ltime) + { return store_time_dec(ltime, TIME_SECOND_PART_DIGITS); } + int store(const char *to, uint length, CHARSET_INFO *cs, + enum_check_fields check_level); + int store(const LEX_STRING *ls, CHARSET_INFO *cs) + { return store(ls->str, ls->length, cs); } + virtual double val_real(void)=0; + virtual longlong val_int(void)=0; + virtual bool val_bool(void)= 0; + virtual my_decimal *val_decimal(my_decimal *); + inline String *val_str(String *str) { return val_str(str, str); } + /* + val_str(buf1, buf2) gets two buffers and should use them as follows: + if it needs a temp buffer to convert result to string - use buf1 + example Field_tiny::val_str() + if the value exists as a string already - use buf2 + example Field_string::val_str() + consequently, buf2 may be created as 'String buf;' - no memory + will be allocated for it. buf1 will be allocated to hold a + value if it's too small. Using allocated buffer for buf2 may result in + an unnecessary free (and later, may be an alloc). + This trickery is used to decrease a number of malloc calls. + */ + virtual String *val_str(String*,String *)=0; + String *val_int_as_str(String *val_buffer, bool unsigned_flag); + fast_field_copier get_fast_field_copier(const Field *from); + /* + str_needs_quotes() returns TRUE if the value returned by val_str() needs + to be quoted when used in constructing an SQL query. + */ + virtual bool str_needs_quotes() { return FALSE; } + virtual Item_result result_type () const=0; + virtual Item_result cmp_type () const { return result_type(); } + virtual const Type_handler *cast_to_int_type_handler() const + { + return Type_handler::get_handler_by_field_type(type()); + } + static bool type_can_have_key_part(enum_field_types); + static enum_field_types field_type_merge(enum_field_types, enum_field_types); + virtual bool eq(Field *field) + { + return (ptr == field->ptr && null_ptr == field->null_ptr && + null_bit == field->null_bit && field->type() == type()); + } + virtual bool eq_def(const Field *field) const; + + /* + pack_length() returns size (in bytes) used to store field data in memory + (i.e. it returns the maximum size of the field in a row of the table, + which is located in RAM). + */ + virtual uint32 pack_length() const { return (uint32) field_length; } + + /* + pack_length_in_rec() returns size (in bytes) used to store field data on + storage (i.e. it returns the maximal size of the field in a row of the + table, which is located on disk). + */ + virtual uint32 pack_length_in_rec() const { return pack_length(); } + virtual bool compatible_field_size(uint metadata, Relay_log_info *rli, + uint16 mflags, int *order); + virtual uint pack_length_from_metadata(uint field_metadata) + { + DBUG_ENTER("Field::pack_length_from_metadata"); + DBUG_RETURN(field_metadata); + } + virtual uint row_pack_length() const { return 0; } + virtual int save_field_metadata(uchar *first_byte) + { return do_save_field_metadata(first_byte); } + + /* + data_length() return the "real size" of the data in memory. + */ + virtual uint32 data_length() { return pack_length(); } + virtual uint32 sort_length() const { return pack_length(); } + + /* + Get the number bytes occupied by the value in the field. + CHAR values are stripped of trailing spaces. + Flexible values are stripped of their length. + */ + virtual uint32 value_length() + { + uint len; + if (!zero_pack() && + (type() == MYSQL_TYPE_STRING && + (len= pack_length()) >= 4 && len < 256)) + { + uchar *str, *end; + for (str= ptr, end= str+len; end > str && end[-1] == ' '; end--) {} + len=(uint) (end-str); + return len; + } + return data_length(); + } + + /** + Get the maximum size of the data in packed format. + + @return Maximum data length of the field when packed using the + Field::pack() function. + */ + virtual uint32 max_data_length() const { + return pack_length(); + }; + + virtual int reset(void) { bzero(ptr,pack_length()); return 0; } + virtual void reset_fields() {} + const uchar *ptr_in_record(const uchar *record) const + { + my_ptrdiff_t l_offset= (my_ptrdiff_t) (record - table->record[0]); + return ptr + l_offset; + } + virtual void set_default(); + + bool has_update_default_function() const + { + return flags & ON_UPDATE_NOW_FLAG; + } + bool has_default_now_unireg_check() const + { + return unireg_check == TIMESTAMP_DN_FIELD + || unireg_check == TIMESTAMP_DNUN_FIELD; + } + + /* + Mark the field as having a value supplied by the client, thus it should + not be auto-updated. + */ + void set_has_explicit_value() + { + bitmap_set_bit(&table->has_value_set, field_index); + } + bool has_explicit_value() + { + return bitmap_is_set(&table->has_value_set, field_index); + } + virtual bool set_explicit_default(Item *value); + + /** + Evaluates the @c UPDATE default function, if one exists, and stores the + result in the record buffer. If no such function exists for the column, + or the function is not valid for the column's data type, invoking this + function has no effect. + */ + virtual int evaluate_update_default_function() { return 0; } + + virtual bool binary() const { return 1; } + virtual bool zero_pack() const { return 1; } + virtual enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } + virtual uint32 key_length() const { return pack_length(); } + virtual enum_field_types type() const =0; + virtual enum_field_types real_type() const { return type(); } + virtual enum_field_types binlog_type() const + { + /* + Binlog stores field->type() as type code by default. For example, + it puts MYSQL_TYPE_STRING in case of CHAR, VARCHAR, SET and ENUM, + with extra data type details put into metadata. + + Binlog behaviour slightly differs between various MySQL and MariaDB + versions for the temporal data types TIME, DATETIME and TIMESTAMP. + + MySQL prior to 5.6 uses MYSQL_TYPE_TIME, MYSQL_TYPE_DATETIME + and MYSQL_TYPE_TIMESTAMP type codes in binlog and stores no + additional metadata. + + MariaDB-5.3 implements new versions for TIME, DATATIME, TIMESTAMP + with fractional second precision, but uses the old format for the + types TIME(0), DATETIME(0), TIMESTAMP(0), and it still stores + MYSQL_TYPE_TIME, MYSQL_TYPE_DATETIME and MYSQL_TYPE_TIMESTAMP in binlog, + with no additional metadata. + So row-based replication between temporal data types of + different precision is not possible in MariaDB. + + MySQL-5.6 also implements a new version of TIME, DATETIME, TIMESTAMP + which support fractional second precision 0..6, and use the new + format even for the types TIME(0), DATETIME(0), TIMESTAMP(0). + For these new data types, MySQL-5.6 stores new type codes + MYSQL_TYPE_TIME2, MYSQL_TYPE_DATETIME2, MYSQL_TYPE_TIMESTAMP2 in binlog, + with fractional precision 0..6 put into metadata. + This makes it in theory possible to do row-based replication between + columns of different fractional precision (e.g. from TIME(1) on master + to TIME(6) on slave). However, it's not currently fully implemented yet. + MySQL-5.6 can only do row-based replication from the old types + TIME, DATETIME, TIMESTAMP (represented by MYSQL_TYPE_TIME, + MYSQL_TYPE_DATETIME and MYSQL_TYPE_TIMESTAMP type codes in binlog) + to the new corresponding types TIME(0), DATETIME(0), TIMESTAMP(0). + + Note: MariaDB starting from the version 10.0 understands the new + MySQL-5.6 type codes MYSQL_TYPE_TIME2, MYSQL_TYPE_DATETIME2, + MYSQL_TYPE_TIMESTAMP2. When started over MySQL-5.6 tables both on + master and on slave, MariaDB-10.0 can also do row-based replication + from the old types TIME, DATETIME, TIMESTAMP to the new MySQL-5.6 + types TIME(0), DATETIME(0), TIMESTAMP(0). + + Note: perhaps binlog should eventually be modified to store + real_type() instead of type() for all column types. + */ + return type(); + } + inline int cmp(const uchar *str) { return cmp(ptr,str); } + virtual int cmp_max(const uchar *a, const uchar *b, uint max_len) + { return cmp(a, b); } + virtual int cmp(const uchar *,const uchar *)=0; + virtual int cmp_binary(const uchar *a,const uchar *b, uint32 max_length=~0U) + { return memcmp(a,b,pack_length()); } + virtual int cmp_offset(uint row_offset) + { return cmp(ptr,ptr+row_offset); } + virtual int cmp_binary_offset(uint row_offset) + { return cmp_binary(ptr, ptr+row_offset); }; + virtual int key_cmp(const uchar *a,const uchar *b) + { return cmp(a, b); } + virtual int key_cmp(const uchar *str, uint length) + { return cmp(ptr,str); } + /* + Update the value m of the 'min_val' field with the current value v + of this field if force_update is set to TRUE or if v < m. + Return TRUE if the value has been updated. + */ + virtual bool update_min(Field *min_val, bool force_update) + { + bool update_fl= force_update || cmp(ptr, min_val->ptr) < 0; + if (update_fl) + { + min_val->set_notnull(); + memcpy(min_val->ptr, ptr, pack_length()); + } + return update_fl; + } + /* + Update the value m of the 'max_val' field with the current value v + of this field if force_update is set to TRUE or if v > m. + Return TRUE if the value has been updated. + */ + virtual bool update_max(Field *max_val, bool force_update) + { + bool update_fl= force_update || cmp(ptr, max_val->ptr) > 0; + if (update_fl) + { + max_val->set_notnull(); + memcpy(max_val->ptr, ptr, pack_length()); + } + return update_fl; + } + virtual void store_field_value(uchar *val, uint len) + { + memcpy(ptr, val, len); + } + virtual uint decimals() const { return 0; } + /* + Caller beware: sql_type can change str.Ptr, so check + ptr() to see if it changed if you are using your own buffer + in str and restore it with set() if needed + */ + virtual void sql_type(String &str) const =0; + virtual uint size_of() const =0; // For new field + inline bool is_null(my_ptrdiff_t row_offset= 0) const + { + /* + The table may have been marked as containing only NULL values + for all fields if it is a NULL-complemented row of an OUTER JOIN + or if the query is an implicitly grouped query (has aggregate + functions but no GROUP BY clause) with no qualifying rows. If + this is the case (in which TABLE::null_row is true), the field + is considered to be NULL. + + Note that if a table->null_row is set then also all null_bits are + set for the row. + + In the case of the 'result_field' for GROUP BY, table->null_row might + refer to the *next* row in the table (when the algorithm is: read the + next row, see if any of group column values have changed, send the + result - grouped - row to the client if yes). So, table->null_row might + be wrong, but such a result_field is always nullable (that's defined by + original_field->maybe_null()) and we trust its null bit. + */ + return null_ptr ? null_ptr[row_offset] & null_bit : table->null_row; + } + inline bool is_real_null(my_ptrdiff_t row_offset= 0) const + { return null_ptr && (null_ptr[row_offset] & null_bit); } + inline bool is_null_in_record(const uchar *record) const + { + if (maybe_null_in_table()) + return record[(uint) (null_ptr - table->record[0])] & null_bit; + return 0; + } + inline void set_null(my_ptrdiff_t row_offset= 0) + { if (null_ptr) null_ptr[row_offset]|= null_bit; } + inline void set_notnull(my_ptrdiff_t row_offset= 0) + { if (null_ptr) null_ptr[row_offset]&= (uchar) ~null_bit; } + inline bool maybe_null(void) const + { return null_ptr != 0 || table->maybe_null; } + + /* @return true if this field is NULL-able (even if temporarily) */ + inline bool real_maybe_null(void) const { return null_ptr != 0; } + uint null_offset(const uchar *record) const + { return (uint) (null_ptr - record); } + /* + For a NULL-able field (that can actually store a NULL value in a table) + null_ptr points to the "null bitmap" in the table->record[0] header. For + NOT NULL fields it is either 0 or points outside table->record[0] into the + table->triggers->extra_null_bitmap (so that the field can store a NULL + value temporarily, only in memory) + */ + bool maybe_null_in_table() const + { return null_ptr >= table->record[0] && null_ptr <= ptr; } + + uint null_offset() const + { return null_offset(table->record[0]); } + void set_null_ptr(uchar *p_null_ptr, uint p_null_bit) + { + null_ptr= p_null_ptr; + null_bit= p_null_bit; + } + + bool stored_in_db() const { return !vcol_info || vcol_info->stored_in_db; } + + inline THD *get_thd() const + { return likely(table) ? table->in_use : current_thd; } + + enum { + LAST_NULL_BYTE_UNDEF= 0 + }; + + /* + Find the position of the last null byte for the field. + + SYNOPSIS + last_null_byte() + + DESCRIPTION + Return a pointer to the last byte of the null bytes where the + field conceptually is placed. + + RETURN VALUE + The position of the last null byte relative to the beginning of + the record. If the field does not use any bits of the null + bytes, the value 0 (LAST_NULL_BYTE_UNDEF) is returned. + */ + size_t last_null_byte() const { + size_t bytes= do_last_null_byte(); + DBUG_PRINT("debug", ("last_null_byte() ==> %ld", (long) bytes)); + DBUG_ASSERT(bytes <= table->s->null_bytes); + return bytes; + } + + void make_sort_key(uchar *buff, uint length); + virtual void make_field(Send_field *); + virtual void sort_string(uchar *buff,uint length)=0; + virtual bool optimize_range(uint idx, uint part); + virtual void free() {} + virtual Field *make_new_field(MEM_ROOT *root, TABLE *new_table, + bool keep_type); + virtual Field *new_key_field(MEM_ROOT *root, TABLE *new_table, + uchar *new_ptr, uint32 length, + uchar *new_null_ptr, uint new_null_bit); + Field *clone(MEM_ROOT *mem_root, TABLE *new_table); + Field *clone(MEM_ROOT *mem_root, TABLE *new_table, my_ptrdiff_t diff, + bool stat_flag= FALSE); + Field *clone(MEM_ROOT *mem_root, my_ptrdiff_t diff); + inline void move_field(uchar *ptr_arg,uchar *null_ptr_arg,uchar null_bit_arg) + { + ptr=ptr_arg; null_ptr=null_ptr_arg; null_bit=null_bit_arg; + } + inline void move_field(uchar *ptr_arg) { ptr=ptr_arg; } + inline uchar *record_ptr() // record[0] or wherever the field was moved to + { + my_ptrdiff_t offset= table->s->field[field_index]->ptr - table->s->default_values; + return ptr - offset; + } + virtual void move_field_offset(my_ptrdiff_t ptr_diff) + { + ptr=ADD_TO_PTR(ptr,ptr_diff, uchar*); + if (null_ptr) + null_ptr=ADD_TO_PTR(null_ptr,ptr_diff,uchar*); + } + virtual void get_image(uchar *buff, uint length, CHARSET_INFO *cs) + { memcpy(buff,ptr,length); } + virtual void set_image(const uchar *buff,uint length, CHARSET_INFO *cs) + { memcpy(ptr,buff,length); } + + + /* + Copy a field part into an output buffer. + + SYNOPSIS + Field::get_key_image() + buff [out] output buffer + length output buffer size + type itMBR for geometry blobs, otherwise itRAW + + DESCRIPTION + This function makes a copy of field part of size equal to or + less than "length" parameter value. + For fields of string types (CHAR, VARCHAR, TEXT) the rest of buffer + is padded by zero byte. + + NOTES + For variable length character fields (i.e. UTF-8) the "length" + parameter means a number of output buffer bytes as if all field + characters have maximal possible size (mbmaxlen). In the other words, + "length" parameter is a number of characters multiplied by + field_charset->mbmaxlen. + + RETURN + Number of copied bytes (excluding padded zero bytes -- see above). + */ + + virtual uint get_key_image(uchar *buff, uint length, imagetype type_arg) + { + get_image(buff, length, &my_charset_bin); + return length; + } + virtual void set_key_image(const uchar *buff,uint length) + { set_image(buff,length, &my_charset_bin); } + inline longlong val_int_offset(uint row_offset) + { + ptr+=row_offset; + longlong tmp=val_int(); + ptr-=row_offset; + return tmp; + } + inline longlong val_int(const uchar *new_ptr) + { + uchar *old_ptr= ptr; + longlong return_value; + ptr= (uchar*) new_ptr; + return_value= val_int(); + ptr= old_ptr; + return return_value; + } + inline String *val_str(String *str, const uchar *new_ptr) + { + uchar *old_ptr= ptr; + ptr= (uchar*) new_ptr; + val_str(str); + ptr= old_ptr; + return str; + } + virtual bool send_binary(Protocol *protocol); + + virtual uchar *pack(uchar *to, const uchar *from, uint max_length); + /** + @overload Field::pack(uchar*, const uchar*, uint, bool) + */ + uchar *pack(uchar *to, const uchar *from) + { + DBUG_ENTER("Field::pack"); + uchar *result= this->pack(to, from, UINT_MAX); + DBUG_RETURN(result); + } + + virtual const uchar *unpack(uchar* to, const uchar *from, + const uchar *from_end, uint param_data=0); + + virtual uint packed_col_length(const uchar *to, uint length) + { return length;} + virtual uint max_packed_col_length(uint max_length) + { return max_length;} + + uint offset(uchar *record) const + { + return (uint) (ptr - record); + } + void copy_from_tmp(int offset); + uint fill_cache_field(struct st_cache_field *copy); + virtual bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); + bool get_time(MYSQL_TIME *ltime) { return get_date(ltime, TIME_TIME_ONLY); } + virtual CHARSET_INFO *charset(void) const { return &my_charset_bin; } + virtual CHARSET_INFO *charset_for_protocol(void) const + { return binary() ? &my_charset_bin : charset(); } + virtual CHARSET_INFO *sort_charset(void) const { return charset(); } + virtual bool has_charset(void) const { return FALSE; } + virtual enum Derivation derivation(void) const + { return DERIVATION_IMPLICIT; } + virtual uint repertoire(void) const { return MY_REPERTOIRE_UNICODE30; } + virtual void set_derivation(enum Derivation derivation_arg, + uint repertoire_arg) + { } + virtual int set_time() { return 1; } + bool set_warning(Sql_condition::enum_warning_level, unsigned int code, + int cuted_increment) const; +protected: + bool set_warning(unsigned int code, int cuted_increment) const + { + return set_warning(Sql_condition::WARN_LEVEL_WARN, code, cuted_increment); + } + bool set_note(unsigned int code, int cuted_increment) const + { + return set_warning(Sql_condition::WARN_LEVEL_NOTE, code, cuted_increment); + } + void set_datetime_warning(Sql_condition::enum_warning_level, uint code, + const ErrConv *str, timestamp_type ts_type, + int cuted_increment) const; + void set_datetime_warning(uint code, + const ErrConv *str, timestamp_type ts_type, + int cuted_increment) const + { + set_datetime_warning(Sql_condition::WARN_LEVEL_WARN, code, str, ts_type, + cuted_increment); + } + void set_warning_truncated_wrong_value(const char *type, const char *value); + inline bool check_overflow(int op_result) + { + return (op_result == E_DEC_OVERFLOW); + } + int warn_if_overflow(int op_result); + Copy_func *get_identical_copy_func() const; +public: + void set_table_name(String *alias) + { + table_name= &alias->Ptr; + } + void init(TABLE *table_arg) + { + orig_table= table= table_arg; + set_table_name(&table_arg->alias); + } + + /* maximum possible display length */ + virtual uint32 max_display_length()= 0; + + /** + Whether a field being created is compatible with a existing one. + + Used by the ALTER TABLE code to evaluate whether the new definition + of a table is compatible with the old definition so that it can + determine if data needs to be copied over (table data change). + */ + virtual uint is_equal(Create_field *new_field); + /* convert decimal to longlong with overflow check */ + longlong convert_decimal2longlong(const my_decimal *val, bool unsigned_flag, + int *err); + /* The max. number of characters */ + virtual uint32 char_length() const + { + return field_length / charset()->mbmaxlen; + } + + virtual geometry_type get_geometry_type() + { + /* shouldn't get here. */ + DBUG_ASSERT(0); + return GEOM_GEOMETRY; + } + + ha_storage_media field_storage_type() const + { + return (ha_storage_media) + ((flags >> FIELD_FLAGS_STORAGE_MEDIA) & 3); + } + + void set_storage_type(ha_storage_media storage_type_arg) + { + DBUG_ASSERT(field_storage_type() == HA_SM_DEFAULT); + flags |= static_cast(storage_type_arg) << + FIELD_FLAGS_STORAGE_MEDIA; + } + + column_format_type column_format() const + { + return (column_format_type) + ((flags >> FIELD_FLAGS_COLUMN_FORMAT) & 3); + } + + void set_column_format(column_format_type column_format_arg) + { + DBUG_ASSERT(column_format() == COLUMN_FORMAT_TYPE_DEFAULT); + flags |= static_cast(column_format_arg) << + FIELD_FLAGS_COLUMN_FORMAT; + } + + /* + System versioning support. + */ + + bool is_generated() + { + return flags & (GENERATED_ROW_START_FLAG | GENERATED_ROW_END_FLAG); + } + + bool is_generated_row_start() + { + return flags & GENERATED_ROW_START_FLAG; + } + + bool is_generated_row_end() + { + return flags & GENERATED_ROW_END_FLAG; + } + + bool is_versioning_disabled() + { + return flags & WITHOUT_SYSTEM_VERSIONING_FLAG; + } + + /* Mark a field as auto-generated row start column. */ + void set_generated_row_start() + { + //DBUG_ASSERT((flags & GENERATED_ROW_END_FLAG) == 0); + flags |= GENERATED_ROW_START_FLAG; + } + + /* Mark a field as auto-generated row start column. */ + void set_generated_row_end() + { + //DBUG_ASSERT((flags & GENERATED_ROW_START_FLAG) == 0); + flags |= GENERATED_ROW_END_FLAG; + } + + /* Disable a field versioning for a versioned table. */ + void disable_versioning() + { + flags |= WITHOUT_SYSTEM_VERSIONING_FLAG; + } + + /* Inherit a field versioning status from the table. */ + void inherit_versioning() + { + flags &= ~WITHOUT_SYSTEM_VERSIONING_FLAG; + } + + /* + Validate a non-null field value stored in the given record + according to the current thread settings, e.g. sql_mode. + @param thd - the thread + @param record - the record to check in + */ + virtual bool validate_value_in_record(THD *thd, const uchar *record) const + { return false; } + bool validate_value_in_record_with_warn(THD *thd, const uchar *record); + key_map get_possible_keys(); + + /* Hash value */ + virtual void hash(ulong *nr, ulong *nr2); + +/** + Checks whether a string field is part of write_set. + + @return + FALSE - If field is not char/varchar/.... + - If field is char/varchar/.. and is not part of write set. + TRUE - If field is char/varchar/.. and is part of write set. +*/ + virtual bool is_varchar_and_in_write_set() const { return FALSE; } + + /* Check whether the field can be used as a join attribute in hash join */ + virtual bool hash_join_is_possible() { return TRUE; } + virtual bool eq_cmp_as_binary() { return TRUE; } + + /* Position of the field value within the interval of [min, max] */ + virtual double pos_in_interval(Field *min, Field *max) + { + return (double) 0.5; + } + + /* + Check if comparison between the field and an item unambiguously + identifies a distinct field value. + + Example1: SELECT * FROM t1 WHERE int_column=10; + This example returns distinct integer value of 10. + + Example2: SELECT * FROM t1 WHERE varchar_column=DATE'2001-01-01' + This example returns non-distinct values. + Comparison as DATE will return '2001-01-01' and '2001-01-01x', + but these two values are not equal to each other as VARCHARs. + See also the function with the same name in sql_select.cc. + */ + virtual bool test_if_equality_guarantees_uniqueness(const Item *const_item) + const; + virtual bool can_be_substituted_to_equal_item(const Context &ctx, + const Item_equal *item); + virtual Item *get_equal_const_item(THD *thd, const Context &ctx, + Item *const_item) + { + return const_item; + } + virtual bool can_optimize_keypart_ref(const Item_bool_func *cond, + const Item *item) const; + virtual bool can_optimize_hash_join(const Item_bool_func *cond, + const Item *item) const + { + return can_optimize_keypart_ref(cond, item); + } + virtual bool can_optimize_group_min_max(const Item_bool_func *cond, + const Item *const_item) const; + /** + Test if Field can use range optimizer for a standard comparison operation: + <=, <, =, <=>, >, >= + Note, this method does not cover spatial operations. + */ + virtual bool can_optimize_range(const Item_bool_func *cond, + const Item *item, + bool is_eq_func) const; + + bool can_optimize_outer_join_table_elimination(const Item_bool_func *cond, + const Item *item) const + { + // Exactly the same rules with REF access + return can_optimize_keypart_ref(cond, item); + } + + bool save_in_field_default_value(bool view_eror_processing); + bool save_in_field_ignore_value(bool view_error_processing); + + /* Mark field in read map. Updates also virtual fields */ + void register_field_in_read_map(); + + friend int cre_myisam(char * name, register TABLE *form, uint options, + ulonglong auto_increment_value); + friend class Copy_field; + friend class Item_avg_field; + friend class Item_std_field; + friend class Item_sum_num; + friend class Item_sum_sum; + friend class Item_sum_count; + friend class Item_sum_avg; + friend class Item_sum_std; + friend class Item_sum_min; + friend class Item_sum_max; + friend class Item_func_group_concat; + +private: + /* + Primitive for implementing last_null_byte(). + + SYNOPSIS + do_last_null_byte() + + DESCRIPTION + Primitive for the implementation of the last_null_byte() + function. This represents the inheritance interface and can be + overridden by subclasses. + */ + virtual size_t do_last_null_byte() const; + +/** + Retrieve the field metadata for fields. + + This default implementation returns 0 and saves 0 in the metadata_ptr + value. + + @param metadata_ptr First byte of field metadata + + @returns 0 no bytes written. +*/ + virtual int do_save_field_metadata(uchar *metadata_ptr) + { return 0; } + +protected: + uchar *pack_int(uchar *to, const uchar *from, size_t size) + { + memcpy(to, from, size); + return to + size; + } + + const uchar *unpack_int(uchar* to, const uchar *from, + const uchar *from_end, size_t size) + { + if (from + size > from_end) + return 0; + memcpy(to, from, size); + return from + size; + } + + uchar *pack_int16(uchar *to, const uchar *from) + { return pack_int(to, from, 2); } + const uchar *unpack_int16(uchar* to, const uchar *from, const uchar *from_end) + { return unpack_int(to, from, from_end, 2); } + uchar *pack_int24(uchar *to, const uchar *from) + { return pack_int(to, from, 3); } + const uchar *unpack_int24(uchar* to, const uchar *from, const uchar *from_end) + { return unpack_int(to, from, from_end, 3); } + uchar *pack_int32(uchar *to, const uchar *from) + { return pack_int(to, from, 4); } + const uchar *unpack_int32(uchar* to, const uchar *from, const uchar *from_end) + { return unpack_int(to, from, from_end, 4); } + uchar *pack_int64(uchar* to, const uchar *from) + { return pack_int(to, from, 8); } + const uchar *unpack_int64(uchar* to, const uchar *from, const uchar *from_end) + { return unpack_int(to, from, from_end, 8); } + + double pos_in_interval_val_real(Field *min, Field *max); + double pos_in_interval_val_str(Field *min, Field *max, uint data_offset); +}; + + +class Field_num :public Field { +protected: + int check_edom_and_important_data_truncation(const char *type, bool edom, + CHARSET_INFO *cs, + const char *str, uint length, + const char *end_of_num); + int check_edom_and_truncation(const char *type, bool edom, + CHARSET_INFO *cs, + const char *str, uint length, + const char *end_of_num); + int check_int(CHARSET_INFO *cs, const char *str, uint length, + const char *int_end, int error) + { + return check_edom_and_truncation("integer", + error == MY_ERRNO_EDOM || str == int_end, + cs, str, length, int_end); + } + bool get_int(CHARSET_INFO *cs, const char *from, uint len, + longlong *rnd, ulonglong unsigned_max, + longlong signed_min, longlong signed_max); + void prepend_zeros(String *value) const; + Item *get_equal_zerofill_const_item(THD *thd, const Context &ctx, + Item *const_item); +public: + const uint8 dec; + bool zerofill,unsigned_flag; // Purify cannot handle bit fields + Field_num(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, utype unireg_check_arg, + const char *field_name_arg, + uint8 dec_arg, bool zero_arg, bool unsigned_arg); + enum Item_result result_type () const { return INT_RESULT; } + enum Derivation derivation(void) const { return DERIVATION_NUMERIC; } + uint repertoire(void) const { return MY_REPERTOIRE_NUMERIC; } + CHARSET_INFO *charset(void) const { return &my_charset_numeric; } + Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item) + { + return (flags & ZEROFILL_FLAG) ? + get_equal_zerofill_const_item(thd, ctx, const_item) : + const_item; + } + void add_zerofill_and_unsigned(String &res) const; + friend class Create_field; + void make_field(Send_field *); + uint decimals() const { return (uint) dec; } + uint size_of() const { return sizeof(*this); } + bool eq_def(const Field *field) const; + Copy_func *get_copy_func(const Field *from) const + { + return do_field_int; + } + int save_in_field(Field *to) + { + return to->store(val_int(), MY_TEST(flags & UNSIGNED_FLAG)); + } + bool memcpy_field_possible(const Field *from) const + { + return real_type() == from->real_type() && + pack_length() == from->pack_length() && + !((flags & UNSIGNED_FLAG) && !(from->flags & UNSIGNED_FLAG)) && + decimals() == from->decimals(); + } + int store_decimal(const my_decimal *); + my_decimal *val_decimal(my_decimal *); + bool val_bool() { return val_int() != 0; } + uint is_equal(Create_field *new_field); + uint row_pack_length() const { return pack_length(); } + uint32 pack_length_from_metadata(uint field_metadata) { + uint32 length= pack_length(); + DBUG_PRINT("result", ("pack_length_from_metadata(%d): %u", + field_metadata, length)); + return length; + } + int store_time_dec(MYSQL_TIME *ltime, uint dec); + double pos_in_interval(Field *min, Field *max) + { + return pos_in_interval_val_real(min, max); + } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); +}; + + +class Field_str :public Field { +protected: + // TODO-10.2: Reuse DTCollation instead of these three members + CHARSET_INFO *field_charset; + enum Derivation field_derivation; + uint field_repertoire; +public: + bool can_be_substituted_to_equal_item(const Context &ctx, + const Item_equal *item_equal); + Field_str(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, utype unireg_check_arg, + const char *field_name_arg, CHARSET_INFO *charset); + Item_result result_type () const { return STRING_RESULT; } + uint decimals() const { return NOT_FIXED_DEC; } + int save_in_field(Field *to) { return save_in_field_str(to); } + bool memcpy_field_possible(const Field *from) const + { + return real_type() == from->real_type() && + pack_length() == from->pack_length() && + charset() == from->charset(); + } + int store(double nr); + int store(longlong nr, bool unsigned_val)=0; + int store_decimal(const my_decimal *); + int store(const char *to,uint length,CHARSET_INFO *cs)=0; + int store_hex_hybrid(const char *str, uint length) + { + return store(str, length, &my_charset_bin); + } + uint repertoire(void) const { return field_repertoire; } + CHARSET_INFO *charset(void) const { return field_charset; } + enum Derivation derivation(void) const { return field_derivation; } + void set_derivation(enum Derivation derivation_arg, + uint repertoire_arg) + { + field_derivation= derivation_arg; + field_repertoire= repertoire_arg; + } + bool binary() const { return field_charset == &my_charset_bin; } + uint32 max_display_length() { return field_length; } + friend class Create_field; + my_decimal *val_decimal(my_decimal *); + bool val_bool() { return val_real() != 0e0; } + virtual bool str_needs_quotes() { return TRUE; } + uint is_equal(Create_field *new_field); + bool eq_cmp_as_binary() { return MY_TEST(flags & BINARY_FLAG); } + virtual uint length_size() { return 0; } + double pos_in_interval(Field *min, Field *max) + { + return pos_in_interval_val_str(min, max, length_size()); + } + bool test_if_equality_guarantees_uniqueness(const Item *const_item) const; +}; + +/* base class for Field_string, Field_varstring and Field_blob */ + +class Field_longstr :public Field_str +{ +protected: + int report_if_important_data(const char *ptr, const char *end, + bool count_spaces); + bool check_string_copy_error(const String_copier *copier, + const char *end, CHARSET_INFO *cs); + int check_conversion_status(const String_copier *copier, + const char *end, CHARSET_INFO *cs, + bool count_spaces) + { + if (check_string_copy_error(copier, end, cs)) + return 2; + return report_if_important_data(copier->source_end_pos(), + end, count_spaces); + } + bool cmp_to_string_with_same_collation(const Item_bool_func *cond, + const Item *item) const; + bool cmp_to_string_with_stricter_collation(const Item_bool_func *cond, + const Item *item) const; +public: + Field_longstr(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, utype unireg_check_arg, + const char *field_name_arg, CHARSET_INFO *charset_arg) + :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, + field_name_arg, charset_arg) + {} + + int store_decimal(const my_decimal *d); + uint32 max_data_length() const; + + bool is_varchar_and_in_write_set() const + { + DBUG_ASSERT(table && table->write_set); + return bitmap_is_set(table->write_set, field_index); + } + bool match_collation_to_optimize_range() const { return true; } + + bool can_optimize_keypart_ref(const Item_bool_func *cond, + const Item *item) const; + bool can_optimize_hash_join(const Item_bool_func *cond, + const Item *item) const; + bool can_optimize_group_min_max(const Item_bool_func *cond, + const Item *const_item) const; + bool can_optimize_range(const Item_bool_func *cond, + const Item *item, + bool is_eq_func) const; +}; + +/* base class for float and double and decimal (old one) */ +class Field_real :public Field_num { +protected: + double get_double(const char *str, uint length, CHARSET_INFO *cs, int *err); +public: + bool not_fixed; + + Field_real(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, utype unireg_check_arg, + const char *field_name_arg, + uint8 dec_arg, bool zero_arg, bool unsigned_arg) + :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, + field_name_arg, dec_arg, zero_arg, unsigned_arg), + not_fixed(dec_arg >= FLOATING_POINT_DECIMALS) + {} + Item_result result_type () const { return REAL_RESULT; } + Copy_func *get_copy_func(const Field *from) const + { + return do_field_real; + } + int save_in_field(Field *to) { return to->store(val_real()); } + bool memcpy_field_possible(const Field *from) const + { + /* + Cannot do memcpy from a longer field to a shorter field, + e.g. a DOUBLE(53,10) into a DOUBLE(10,10). + But it should be OK the other way around. + */ + return Field_num::memcpy_field_possible(from) && + field_length >= from->field_length; + } + int store_decimal(const my_decimal *); + int store_time_dec(MYSQL_TIME *ltime, uint dec); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); + my_decimal *val_decimal(my_decimal *); + bool val_bool() { return val_real() != 0e0; } + uint32 max_display_length() { return field_length; } + uint size_of() const { return sizeof(*this); } + Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item); +}; + + +class Field_decimal :public Field_real { +public: + Field_decimal(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + uint8 dec_arg,bool zero_arg,bool unsigned_arg) + :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, + dec_arg, zero_arg, unsigned_arg) + {} + enum_field_types type() const { return MYSQL_TYPE_DECIMAL;} + enum ha_base_keytype key_type() const + { return zerofill ? HA_KEYTYPE_BINARY : HA_KEYTYPE_NUM; } + Copy_func *get_copy_func(const Field *from) const + { + return eq_def(from) ? get_identical_copy_func() : do_field_string; + } + int reset(void); + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, bool unsigned_val); + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + void overflow(bool negative); + bool zero_pack() const { return 0; } + void sql_type(String &str) const; + virtual uchar *pack(uchar* to, const uchar *from, uint max_length) + { + return Field::pack(to, from, max_length); + } +}; + + +/* New decimal/numeric field which use fixed point arithmetic */ +class Field_new_decimal :public Field_num { +private: + int do_save_field_metadata(uchar *first_byte); +public: + /* The maximum number of decimal digits can be stored */ + uint precision; + uint bin_size; + /* + Constructors take max_length of the field as a parameter - not the + precision as the number of decimal digits allowed. + So for example we need to count length from precision handling + CREATE TABLE ( DECIMAL(x,y)) + */ + Field_new_decimal(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + uint8 dec_arg, bool zero_arg, bool unsigned_arg); + Field_new_decimal(uint32 len_arg, bool maybe_null_arg, + const char *field_name_arg, uint8 dec_arg, + bool unsigned_arg); + enum_field_types type() const { return MYSQL_TYPE_NEWDECIMAL;} + enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } + Item_result result_type () const { return DECIMAL_RESULT; } + Copy_func *get_copy_func(const Field *from) const + { + // if (from->real_type() == MYSQL_TYPE_BIT) // QQ: why? + // return do_field_int; + return do_field_decimal; + } + int save_in_field(Field *to) + { + my_decimal buff; + return to->store_decimal(val_decimal(&buff)); + } + bool memcpy_field_possible(const Field *from) const + { + return Field_num::memcpy_field_possible(from) && + field_length == from->field_length; + } + int reset(void); + bool store_value(const my_decimal *decimal_value); + bool store_value(const my_decimal *decimal_value, int *native_error); + void set_value_on_overflow(my_decimal *decimal_value, bool sign); + int store(const char *to, uint length, CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, bool unsigned_val); + int store_time_dec(MYSQL_TIME *ltime, uint dec); + int store_decimal(const my_decimal *); + double val_real(void); + longlong val_int(void); + my_decimal *val_decimal(my_decimal *); + String *val_str(String*, String *); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); + bool val_bool() + { + my_decimal decimal_value; + my_decimal *val= val_decimal(&decimal_value); + return val ? !my_decimal_is_zero(val) : 0; + } + int cmp(const uchar *, const uchar *); + void sort_string(uchar *buff, uint length); + bool zero_pack() const { return 0; } + void sql_type(String &str) const; + uint32 max_display_length() { return field_length; } + uint size_of() const { return sizeof(*this); } + uint32 pack_length() const { return (uint32) bin_size; } + uint pack_length_from_metadata(uint field_metadata); + uint row_pack_length() const { return pack_length(); } + bool compatible_field_size(uint field_metadata, Relay_log_info *rli, + uint16 mflags, int *order_var); + uint is_equal(Create_field *new_field); + virtual const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, uint param_data); + static Field *create_from_item(MEM_ROOT *root, Item *); + Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item); +}; + + +class Field_tiny :public Field_num { +public: + Field_tiny(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + bool zero_arg, bool unsigned_arg) + :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, + 0, zero_arg,unsigned_arg) + {} + enum_field_types type() const { return MYSQL_TYPE_TINY;} + enum ha_base_keytype key_type() const + { return unsigned_flag ? HA_KEYTYPE_BINARY : HA_KEYTYPE_INT8; } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, bool unsigned_val); + int reset(void) { ptr[0]=0; return 0; } + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + bool send_binary(Protocol *protocol); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return 1; } + void sql_type(String &str) const; + uint32 max_display_length() { return 4; } + + virtual uchar *pack(uchar* to, const uchar *from, uint max_length) + { + *to= *from; + return to + 1; + } + + virtual const uchar *unpack(uchar* to, const uchar *from, + const uchar *from_end, uint param_data) + { + if (from == from_end) + return 0; + *to= *from; + return from + 1; + } +}; + + +class Field_short :public Field_num { +public: + Field_short(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + bool zero_arg, bool unsigned_arg) + :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, + 0, zero_arg,unsigned_arg) + {} + Field_short(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, + bool unsigned_arg) + :Field_num((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0, + NONE, field_name_arg, 0, 0, unsigned_arg) + {} + enum_field_types type() const { return MYSQL_TYPE_SHORT;} + enum ha_base_keytype key_type() const + { return unsigned_flag ? HA_KEYTYPE_USHORT_INT : HA_KEYTYPE_SHORT_INT;} + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, bool unsigned_val); + int reset(void) { ptr[0]=ptr[1]=0; return 0; } + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + bool send_binary(Protocol *protocol); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return 2; } + void sql_type(String &str) const; + uint32 max_display_length() { return 6; } + + virtual uchar *pack(uchar* to, const uchar *from, uint max_length) + { return pack_int16(to, from); } + + virtual const uchar *unpack(uchar* to, const uchar *from, + const uchar *from_end, uint param_data) + { return unpack_int16(to, from, from_end); } +}; + +class Field_medium :public Field_num { +public: + Field_medium(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + bool zero_arg, bool unsigned_arg) + :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, + 0, zero_arg,unsigned_arg) + {} + enum_field_types type() const { return MYSQL_TYPE_INT24;} + enum ha_base_keytype key_type() const + { return unsigned_flag ? HA_KEYTYPE_UINT24 : HA_KEYTYPE_INT24; } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, bool unsigned_val); + int reset(void) { ptr[0]=ptr[1]=ptr[2]=0; return 0; } + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + bool send_binary(Protocol *protocol); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return 3; } + void sql_type(String &str) const; + uint32 max_display_length() { return 8; } + + virtual uchar *pack(uchar* to, const uchar *from, uint max_length) + { + return Field::pack(to, from, max_length); + } +}; + + +class Field_long :public Field_num { +public: + Field_long(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + bool zero_arg, bool unsigned_arg) + :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, + 0, zero_arg,unsigned_arg) + {} + Field_long(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, + bool unsigned_arg) + :Field_num((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0, + NONE, field_name_arg,0,0,unsigned_arg) + {} + enum_field_types type() const { return MYSQL_TYPE_LONG;} + enum ha_base_keytype key_type() const + { return unsigned_flag ? HA_KEYTYPE_ULONG_INT : HA_KEYTYPE_LONG_INT; } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, bool unsigned_val); + int reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; return 0; } + double val_real(void); + longlong val_int(void); + bool send_binary(Protocol *protocol); + String *val_str(String*,String *); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return 4; } + void sql_type(String &str) const; + uint32 max_display_length() { return MY_INT32_NUM_DECIMAL_DIGITS; } + virtual uchar *pack(uchar* to, const uchar *from, + uint max_length __attribute__((unused))) + { + return pack_int32(to, from); + } + virtual const uchar *unpack(uchar* to, const uchar *from, + const uchar *from_end, + uint param_data __attribute__((unused))) + { + return unpack_int32(to, from, from_end); + } +}; + + +class Field_longlong :public Field_num { +public: + Field_longlong(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + bool zero_arg, bool unsigned_arg) + :Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, + 0, zero_arg,unsigned_arg) + {} + Field_longlong(uint32 len_arg,bool maybe_null_arg, + const char *field_name_arg, + bool unsigned_arg) + :Field_num((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0, + NONE, field_name_arg,0,0,unsigned_arg) + {} + enum_field_types type() const { return MYSQL_TYPE_LONGLONG;} + enum ha_base_keytype key_type() const + { return unsigned_flag ? HA_KEYTYPE_ULONGLONG : HA_KEYTYPE_LONGLONG; } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, bool unsigned_val); + int reset(void) + { + ptr[0]=ptr[1]=ptr[2]=ptr[3]=ptr[4]=ptr[5]=ptr[6]=ptr[7]=0; + return 0; + } + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + bool send_binary(Protocol *protocol); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return 8; } + void sql_type(String &str) const; + uint32 max_display_length() { return 20; } + virtual uchar *pack(uchar* to, const uchar *from, + uint max_length __attribute__((unused))) + { + return pack_int64(to, from); + } + const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, + uint param_data __attribute__((unused))) + { + return unpack_int64(to, from, from_end); + } + + bool set_max(); + bool is_max(); +}; + + +class Field_float :public Field_real { +public: + Field_float(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + uint8 dec_arg,bool zero_arg,bool unsigned_arg) + :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, + dec_arg, zero_arg, unsigned_arg) + { + if (dec_arg >= FLOATING_POINT_DECIMALS) + dec_arg= NOT_FIXED_DEC; + } + Field_float(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg, + uint8 dec_arg) + :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, (uint) 0, + NONE, field_name_arg, dec_arg, 0, 0) + { + if (dec_arg >= FLOATING_POINT_DECIMALS) + dec_arg= NOT_FIXED_DEC; + } + enum_field_types type() const { return MYSQL_TYPE_FLOAT;} + enum ha_base_keytype key_type() const { return HA_KEYTYPE_FLOAT; } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, bool unsigned_val); + int reset(void) { bzero(ptr,sizeof(float)); return 0; } + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + bool send_binary(Protocol *protocol); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return sizeof(float); } + uint row_pack_length() const { return pack_length(); } + void sql_type(String &str) const; +private: + int do_save_field_metadata(uchar *first_byte); +}; + + +class Field_double :public Field_real { +public: + Field_double(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + uint8 dec_arg,bool zero_arg,bool unsigned_arg) + :Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, + dec_arg, zero_arg, unsigned_arg) + { + if (dec_arg >= FLOATING_POINT_DECIMALS) + dec_arg= NOT_FIXED_DEC; + } + Field_double(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg, + uint8 dec_arg) + :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "" : 0, (uint) 0, + NONE, field_name_arg, dec_arg, 0, 0) + { + if (dec_arg >= FLOATING_POINT_DECIMALS) + dec_arg= NOT_FIXED_DEC; + } + Field_double(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg, + uint8 dec_arg, bool not_fixed_arg) + :Field_real((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "" : 0, (uint) 0, + NONE, field_name_arg, dec_arg, 0, 0) + { + not_fixed= not_fixed_arg; + if (dec_arg >= FLOATING_POINT_DECIMALS) + dec_arg= NOT_FIXED_DEC; + } + enum_field_types type() const { return MYSQL_TYPE_DOUBLE;} + enum ha_base_keytype key_type() const { return HA_KEYTYPE_DOUBLE; } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, bool unsigned_val); + int reset(void) { bzero(ptr,sizeof(double)); return 0; } + double val_real(void); + longlong val_int(void) + { + Converter_double_to_longlong conv(Field_double::val_real(), false); + if (conv.error()) + conv.push_warning(get_thd(), Field_double::val_real(), false); + return conv.result(); + } + String *val_str(String*,String *); + bool send_binary(Protocol *protocol); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return sizeof(double); } + uint row_pack_length() const { return pack_length(); } + void sql_type(String &str) const; +private: + int do_save_field_metadata(uchar *first_byte); +}; + + +/* Everything saved in this will disappear. It will always return NULL */ + +class Field_null :public Field_str { + static uchar null[1]; +public: + Field_null(uchar *ptr_arg, uint32 len_arg, + enum utype unireg_check_arg, const char *field_name_arg, + CHARSET_INFO *cs) + :Field_str(ptr_arg, len_arg, null, 1, + unireg_check_arg, field_name_arg, cs) + {} + enum_field_types type() const { return MYSQL_TYPE_NULL;} + Copy_func *get_copy_func(const Field *from) const + { + return do_field_string; + } + int store(const char *to, uint length, CHARSET_INFO *cs) + { null[0]=1; return 0; } + int store(double nr) { null[0]=1; return 0; } + int store(longlong nr, bool unsigned_val) { null[0]=1; return 0; } + int store_decimal(const my_decimal *d) { null[0]=1; return 0; } + int reset(void) { return 0; } + double val_real(void) { return 0.0;} + longlong val_int(void) { return 0;} + bool val_bool(void) { return false; } + my_decimal *val_decimal(my_decimal *) { return 0; } + String *val_str(String *value,String *value2) + { value2->length(0); return value2;} + int cmp(const uchar *a, const uchar *b) { return 0;} + void sort_string(uchar *buff, uint length) {} + uint32 pack_length() const { return 0; } + void sql_type(String &str) const; + uint size_of() const { return sizeof(*this); } + uint32 max_display_length() { return 4; } + void move_field_offset(my_ptrdiff_t ptr_diff) {} + bool can_optimize_keypart_ref(const Item_bool_func *cond, + const Item *item) const + { + DBUG_ASSERT(0); + return false; + } + bool can_optimize_group_min_max(const Item_bool_func *cond, + const Item *const_item) const + { + DBUG_ASSERT(0); + return false; + } +}; + + +class Field_temporal: public Field { +protected: + Item *get_equal_const_item_datetime(THD *thd, const Context &ctx, + Item *const_item); +public: + Field_temporal(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, utype unireg_check_arg, + const char *field_name_arg) + :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, + field_name_arg) + { flags|= BINARY_FLAG; } + Item_result result_type () const { return STRING_RESULT; } + int store_hex_hybrid(const char *str, uint length) + { + return store(str, length, &my_charset_bin); + } + Copy_func *get_copy_func(const Field *from) const; + int save_in_field(Field *to) + { + MYSQL_TIME ltime; + if (get_date(<ime, 0)) + return to->reset(); + return to->store_time_dec(<ime, decimals()); + } + bool memcpy_field_possible(const Field *from) const; + uint32 max_display_length() { return field_length; } + bool str_needs_quotes() { return TRUE; } + enum Derivation derivation(void) const { return DERIVATION_NUMERIC; } + uint repertoire(void) const { return MY_REPERTOIRE_NUMERIC; } + CHARSET_INFO *charset(void) const { return &my_charset_numeric; } + CHARSET_INFO *sort_charset(void) const { return &my_charset_bin; } + bool binary() const { return true; } + enum Item_result cmp_type () const { return TIME_RESULT; } + bool val_bool() { return val_real() != 0e0; } + uint is_equal(Create_field *new_field); + bool eq_def(const Field *field) const + { + return (Field::eq_def(field) && decimals() == field->decimals()); + } + my_decimal *val_decimal(my_decimal*); + void set_warnings(Sql_condition::enum_warning_level trunc_level, + const ErrConv *str, int was_cut, timestamp_type ts_type); + double pos_in_interval(Field *min, Field *max) + { + return pos_in_interval_val_real(min, max); + } + bool can_optimize_keypart_ref(const Item_bool_func *cond, + const Item *item) const; + bool can_optimize_group_min_max(const Item_bool_func *cond, + const Item *const_item) const; + bool can_optimize_range(const Item_bool_func *cond, + const Item *item, + bool is_eq_func) const + { + return true; + } +}; + + +/** + Abstract class for: + - DATE + - DATETIME + - DATETIME(1..6) + - DATETIME(0..6) - MySQL56 version +*/ +class Field_temporal_with_date: public Field_temporal { +protected: + int store_TIME_with_warning(MYSQL_TIME *ltime, const ErrConv *str, + int was_cut, int have_smth_to_conv); + virtual void store_TIME(MYSQL_TIME *ltime) = 0; + virtual bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, + ulonglong fuzzydate) const = 0; + bool validate_MMDD(bool not_zero_date, uint month, uint day, + ulonglong fuzzydate) const + { + if (!not_zero_date) + return fuzzydate & TIME_NO_ZERO_DATE; + if (!month || !day) + return fuzzydate & TIME_NO_ZERO_IN_DATE; + return false; + } +public: + Field_temporal_with_date(uchar *ptr_arg, uint32 len_arg, + uchar *null_ptr_arg, uchar null_bit_arg, + utype unireg_check_arg, + const char *field_name_arg) + :Field_temporal(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg) + {} + int store(const char *to, uint length, CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, bool unsigned_val); + int store_time_dec(MYSQL_TIME *ltime, uint dec); + int store_decimal(const my_decimal *); + bool validate_value_in_record(THD *thd, const uchar *record) const; +}; + + +class Field_timestamp :public Field_temporal { +protected: + int store_TIME_with_warning(THD *, MYSQL_TIME *, const ErrConv *, + int warnings, bool have_smth_to_conv); +public: + Field_timestamp(uchar *ptr_arg, uint32 len_arg, + uchar *null_ptr_arg, uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + TABLE_SHARE *share); + enum_field_types type() const { return MYSQL_TYPE_TIMESTAMP;} + enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, bool unsigned_val); + int store_time_dec(MYSQL_TIME *ltime, uint dec); + int store_decimal(const my_decimal *); + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + bool send_binary(Protocol *protocol); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return 4; } + void sql_type(String &str) const; + bool zero_pack() const { return 0; } + int set_time(); + bool set_explicit_default(Item *value); + int evaluate_update_default_function() + { + int res= 0; + if (has_update_default_function()) + res= set_time(); + return res; + } + /* Get TIMESTAMP field value as seconds since begging of Unix Epoch */ + virtual my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const; + my_time_t get_timestamp(ulong *sec_part) const + { + return get_timestamp(ptr, sec_part); + } + virtual void store_TIME(my_time_t timestamp, ulong sec_part) + { + int4store(ptr,timestamp); + } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); + uchar *pack(uchar *to, const uchar *from, + uint max_length __attribute__((unused))) + { + return pack_int32(to, from); + } + const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, + uint param_data __attribute__((unused))) + { + return unpack_int32(to, from, from_end); + } + bool validate_value_in_record(THD *thd, const uchar *record) const; + Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item) + { + return get_equal_const_item_datetime(thd, ctx, const_item); + } + uint size_of() const { return sizeof(*this); } +}; + + +/** + Abstract class for: + - TIMESTAMP(1..6) + - TIMESTAMP(0..6) - MySQL56 version +*/ +class Field_timestamp_with_dec :public Field_timestamp { +protected: + uint dec; +public: + Field_timestamp_with_dec(uchar *ptr_arg, + uchar *null_ptr_arg, uchar null_bit_arg, + enum utype unireg_check_arg, + const char *field_name_arg, + TABLE_SHARE *share, uint dec_arg) : + Field_timestamp(ptr_arg, + MAX_DATETIME_WIDTH + dec_arg + MY_TEST(dec_arg), null_ptr_arg, + null_bit_arg, unireg_check_arg, field_name_arg, share), + dec(dec_arg) + { + DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS); + } + uint decimals() const { return dec; } + enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } + uchar *pack(uchar *to, const uchar *from, uint max_length) + { return Field::pack(to, from, max_length); } + const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, + uint param_data) + { return Field::unpack(to, from, from_end, param_data); } + void make_field(Send_field *field); + void sort_string(uchar *to, uint length) + { + DBUG_ASSERT(length == pack_length()); + memcpy(to, ptr, length); + } + bool send_binary(Protocol *protocol); + double val_real(void); + my_decimal* val_decimal(my_decimal*); + int set_time(); +}; + + +class Field_timestamp_hires :public Field_timestamp_with_dec { +public: + Field_timestamp_hires(uchar *ptr_arg, + uchar *null_ptr_arg, uchar null_bit_arg, + enum utype unireg_check_arg, + const char *field_name_arg, + TABLE_SHARE *share, uint dec_arg) : + Field_timestamp_with_dec(ptr_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, share, dec_arg) + { + DBUG_ASSERT(dec); + } + my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const; + void store_TIME(my_time_t timestamp, ulong sec_part); + int cmp(const uchar *,const uchar *); + uint32 pack_length() const; + uint size_of() const { return sizeof(*this); } +}; + + +/** + TIMESTAMP(0..6) - MySQL56 version +*/ +class Field_timestampf :public Field_timestamp_with_dec { + int do_save_field_metadata(uchar *metadata_ptr) + { + *metadata_ptr= decimals(); + return 1; + } +public: + Field_timestampf(uchar *ptr_arg, + uchar *null_ptr_arg, uchar null_bit_arg, + enum utype unireg_check_arg, + const char *field_name_arg, + TABLE_SHARE *share, uint dec_arg) : + Field_timestamp_with_dec(ptr_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, share, dec_arg) + {} + enum_field_types real_type() const { return MYSQL_TYPE_TIMESTAMP2; } + enum_field_types binlog_type() const { return MYSQL_TYPE_TIMESTAMP2; } + uint32 pack_length() const + { + return my_timestamp_binary_length(dec); + } + uint row_pack_length() const { return pack_length(); } + uint pack_length_from_metadata(uint field_metadata) + { + DBUG_ENTER("Field_timestampf::pack_length_from_metadata"); + uint tmp= my_timestamp_binary_length(field_metadata); + DBUG_RETURN(tmp); + } + int cmp(const uchar *a_ptr,const uchar *b_ptr) + { + return memcmp(a_ptr, b_ptr, pack_length()); + } + bool set_max(); + bool is_max(); + void store_TIME(my_time_t timestamp, ulong sec_part); + my_time_t get_timestamp(const uchar *pos, ulong *sec_part) const; + uint size_of() const { return sizeof(*this); } +}; + + +class Field_year :public Field_tiny { +public: + Field_year(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg) + :Field_tiny(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, 1, 1) + {} + enum_field_types type() const { return MYSQL_TYPE_YEAR;} + Copy_func *get_copy_func(const Field *from) const + { + if (eq_def(from)) + return get_identical_copy_func(); + switch (from->cmp_type()) { + case STRING_RESULT: + return do_field_string; + case TIME_RESULT: + return do_field_temporal; + case DECIMAL_RESULT: + return do_field_decimal; + case REAL_RESULT: + return do_field_real; + case INT_RESULT: + break; + case ROW_RESULT: + default: + DBUG_ASSERT(0); + break; + } + return do_field_int; + } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, bool unsigned_val); + int store_time_dec(MYSQL_TIME *ltime, uint dec); + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); + bool send_binary(Protocol *protocol); + uint32 max_display_length() { return field_length; } + void sql_type(String &str) const; +}; + + +class Field_date :public Field_temporal_with_date { + void store_TIME(MYSQL_TIME *ltime); + bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const; +public: + Field_date(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg) + :Field_temporal_with_date(ptr_arg, MAX_DATE_WIDTH, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg) {} + enum_field_types type() const { return MYSQL_TYPE_DATE;} + enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; } + int reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; return 0; } + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return Field_date::get_TIME(ltime, ptr, fuzzydate); } + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + bool send_binary(Protocol *protocol); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return 4; } + void sql_type(String &str) const; + uchar *pack(uchar* to, const uchar *from, + uint max_length __attribute__((unused))) + { + return pack_int32(to, from); + } + const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, + uint param_data __attribute__((unused))) + { + return unpack_int32(to, from, from_end); + } + uint size_of() const { return sizeof(*this); } +}; + + +class Field_newdate :public Field_temporal_with_date { + void store_TIME(MYSQL_TIME *ltime); + bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const; +public: + Field_newdate(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg) + :Field_temporal_with_date(ptr_arg, MAX_DATE_WIDTH, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg) + {} + enum_field_types type() const { return MYSQL_TYPE_DATE;} + enum_field_types real_type() const { return MYSQL_TYPE_NEWDATE; } + enum ha_base_keytype key_type() const { return HA_KEYTYPE_UINT24; } + int reset(void) { ptr[0]=ptr[1]=ptr[2]=0; return 0; } + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + bool send_binary(Protocol *protocol); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return 3; } + void sql_type(String &str) const; + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return Field_newdate::get_TIME(ltime, ptr, fuzzydate); } + uint size_of() const { return sizeof(*this); } + Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item); +}; + + +class Field_time :public Field_temporal { + /* + when this Field_time instance is used for storing values for index lookups + (see class store_key, Field::new_key_field(), etc), the following + might be set to TO_DAYS(CURDATE()). See also Field_time::store_time_dec() + */ + long curdays; +protected: + virtual void store_TIME(MYSQL_TIME *ltime); + int store_TIME_with_warning(MYSQL_TIME *ltime, const ErrConv *str, + int was_cut, int have_smth_to_conv); + bool check_zero_in_date_with_warn(ulonglong fuzzydate); + static void do_field_time(Copy_field *copy); +public: + Field_time(uchar *ptr_arg, uint length_arg, uchar *null_ptr_arg, + uchar null_bit_arg, enum utype unireg_check_arg, + const char *field_name_arg) + :Field_temporal(ptr_arg, length_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg), curdays(0) + {} + enum_field_types type() const { return MYSQL_TYPE_TIME;} + enum ha_base_keytype key_type() const { return HA_KEYTYPE_INT24; } + Copy_func *get_copy_func(const Field *from) const + { + return from->cmp_type() == REAL_RESULT ? do_field_string : // MDEV-9344 + from->type() == MYSQL_TYPE_YEAR ? do_field_int : + from->type() == MYSQL_TYPE_BIT ? do_field_int : + eq_def(from) ? get_identical_copy_func() : + do_field_time; + } + bool memcpy_field_possible(const Field *from) const + { + return real_type() == from->real_type() && + decimals() == from->decimals(); + } + int store_time_dec(MYSQL_TIME *ltime, uint dec); + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, bool unsigned_val); + int store_decimal(const my_decimal *); + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); + bool send_binary(Protocol *protocol); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return 3; } + void sql_type(String &str) const; + uint size_of() const { return sizeof(*this); } + void set_curdays(THD *thd); + Field *new_key_field(MEM_ROOT *root, TABLE *new_table, + uchar *new_ptr, uint32 length, + uchar *new_null_ptr, uint new_null_bit); + Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item); +}; + + +/** + Abstract class for: + - TIME(1..6) + - TIME(0..6) - MySQL56 version +*/ +class Field_time_with_dec :public Field_time { +protected: + uint dec; +public: + Field_time_with_dec(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + uint dec_arg) + :Field_time(ptr_arg, MIN_TIME_WIDTH + dec_arg + MY_TEST(dec_arg), + null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg), + dec(dec_arg) + { + DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS); + } + uint decimals() const { return dec; } + enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } + longlong val_int(void); + double val_real(void); + void make_field(Send_field *); +}; + + +/** + TIME(1..6) +*/ +class Field_time_hires :public Field_time_with_dec { + longlong zero_point; + void store_TIME(MYSQL_TIME *ltime); +public: + Field_time_hires(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + uint dec_arg) + :Field_time_with_dec(ptr_arg, null_ptr_arg, + null_bit_arg, unireg_check_arg, field_name_arg, + dec_arg) + { + DBUG_ASSERT(dec); + zero_point= sec_part_shift( + ((TIME_MAX_VALUE_SECONDS+1LL)*TIME_SECOND_PART_FACTOR), dec); + } + int reset(void); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const; + uint size_of() const { return sizeof(*this); } +}; + + +/** + TIME(0..6) - MySQL56 version +*/ +class Field_timef :public Field_time_with_dec { + void store_TIME(MYSQL_TIME *ltime); + int do_save_field_metadata(uchar *metadata_ptr) + { + *metadata_ptr= decimals(); + return 1; + } +public: + Field_timef(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + uint dec_arg) + :Field_time_with_dec(ptr_arg, null_ptr_arg, + null_bit_arg, unireg_check_arg, field_name_arg, + dec_arg) + { + DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS); + } + enum_field_types real_type() const { return MYSQL_TYPE_TIME2; } + enum_field_types binlog_type() const { return MYSQL_TYPE_TIME2; } + uint32 pack_length() const + { + return my_time_binary_length(dec); + } + uint row_pack_length() const { return pack_length(); } + uint pack_length_from_metadata(uint field_metadata) + { + DBUG_ENTER("Field_timef::pack_length_from_metadata"); + uint tmp= my_time_binary_length(field_metadata); + DBUG_RETURN(tmp); + } + void sort_string(uchar *to, uint length) + { + DBUG_ASSERT(length == Field_timef::pack_length()); + memcpy(to, ptr, length); + } + int cmp(const uchar *a_ptr, const uchar *b_ptr) + { + return memcmp(a_ptr, b_ptr, pack_length()); + } + int reset(); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); + uint size_of() const { return sizeof(*this); } +}; + + +class Field_datetime :public Field_temporal_with_date { + void store_TIME(MYSQL_TIME *ltime); + bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const; +public: + Field_datetime(uchar *ptr_arg, uint length_arg, uchar *null_ptr_arg, + uchar null_bit_arg, enum utype unireg_check_arg, + const char *field_name_arg) + :Field_temporal_with_date(ptr_arg, length_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg) + { + if (unireg_check == TIMESTAMP_UN_FIELD || + unireg_check == TIMESTAMP_DNUN_FIELD) + flags|= ON_UPDATE_NOW_FLAG; + } + enum_field_types type() const { return MYSQL_TYPE_DATETIME;} + enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONGLONG; } + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + bool send_binary(Protocol *protocol); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return 8; } + void sql_type(String &str) const; + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return Field_datetime::get_TIME(ltime, ptr, fuzzydate); } + int set_time(); + int evaluate_update_default_function() + { + int res= 0; + if (has_update_default_function()) + res= set_time(); + return res; + } + uchar *pack(uchar* to, const uchar *from, + uint max_length __attribute__((unused))) + { + return pack_int64(to, from); + } + const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, + uint param_data __attribute__((unused))) + { + return unpack_int64(to, from, from_end); + } + Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item) + { + return get_equal_const_item_datetime(thd, ctx, const_item); + } + uint size_of() const { return sizeof(*this); } +}; + + +/** + Abstract class for: + - DATETIME(1..6) + - DATETIME(0..6) - MySQL56 version +*/ +class Field_datetime_with_dec :public Field_datetime { +protected: + uint dec; +public: + Field_datetime_with_dec(uchar *ptr_arg, uchar *null_ptr_arg, + uchar null_bit_arg, enum utype unireg_check_arg, + const char *field_name_arg, uint dec_arg) + :Field_datetime(ptr_arg, MAX_DATETIME_WIDTH + dec_arg + MY_TEST(dec_arg), + null_ptr_arg, null_bit_arg, unireg_check_arg, + field_name_arg), dec(dec_arg) + { + DBUG_ASSERT(dec <= TIME_SECOND_PART_DIGITS); + } + uint decimals() const { return dec; } + enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } + void make_field(Send_field *field); + bool send_binary(Protocol *protocol); + uchar *pack(uchar *to, const uchar *from, uint max_length) + { return Field::pack(to, from, max_length); } + const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, + uint param_data) + { return Field::unpack(to, from, from_end, param_data); } + void sort_string(uchar *to, uint length) + { + DBUG_ASSERT(length == pack_length()); + memcpy(to, ptr, length); + } + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); +}; + + +/** + DATETIME(1..6) +*/ +class Field_datetime_hires :public Field_datetime_with_dec { + void store_TIME(MYSQL_TIME *ltime); + bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const; +public: + Field_datetime_hires(uchar *ptr_arg, uchar *null_ptr_arg, + uchar null_bit_arg, enum utype unireg_check_arg, + const char *field_name_arg, uint dec_arg) + :Field_datetime_with_dec(ptr_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, dec_arg) + { + DBUG_ASSERT(dec); + } + int cmp(const uchar *,const uchar *); + uint32 pack_length() const; + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return Field_datetime_hires::get_TIME(ltime, ptr, fuzzydate); } + uint size_of() const { return sizeof(*this); } +}; + + +/** + DATETIME(0..6) - MySQL56 version +*/ +class Field_datetimef :public Field_datetime_with_dec { + void store_TIME(MYSQL_TIME *ltime); + bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, ulonglong fuzzydate) const; + int do_save_field_metadata(uchar *metadata_ptr) + { + *metadata_ptr= decimals(); + return 1; + } +public: + Field_datetimef(uchar *ptr_arg, uchar *null_ptr_arg, + uchar null_bit_arg, enum utype unireg_check_arg, + const char *field_name_arg, uint dec_arg) + :Field_datetime_with_dec(ptr_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, dec_arg) + {} + enum_field_types real_type() const { return MYSQL_TYPE_DATETIME2; } + enum_field_types binlog_type() const { return MYSQL_TYPE_DATETIME2; } + uint32 pack_length() const + { + return my_datetime_binary_length(dec); + } + uint row_pack_length() const { return pack_length(); } + uint pack_length_from_metadata(uint field_metadata) + { + DBUG_ENTER("Field_datetimef::pack_length_from_metadata"); + uint tmp= my_datetime_binary_length(field_metadata); + DBUG_RETURN(tmp); + } + int cmp(const uchar *a_ptr, const uchar *b_ptr) + { + return memcmp(a_ptr, b_ptr, pack_length()); + } + int reset(); + bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) + { return Field_datetimef::get_TIME(ltime, ptr, fuzzydate); } + uint size_of() const { return sizeof(*this); } +}; + + +static inline Field_timestamp * +new_Field_timestamp(MEM_ROOT *root,uchar *ptr, uchar *null_ptr, uchar null_bit, + enum Field::utype unireg_check, const char *field_name, + TABLE_SHARE *share, uint dec) +{ + if (dec==0) + return new (root) + Field_timestamp(ptr, MAX_DATETIME_WIDTH, null_ptr, + null_bit, unireg_check, field_name, share); + if (dec >= FLOATING_POINT_DECIMALS) + dec= MAX_DATETIME_PRECISION; + return new (root) + Field_timestamp_hires(ptr, null_ptr, null_bit, unireg_check, + field_name, share, dec); +} + +static inline Field_time * +new_Field_time(MEM_ROOT *root, uchar *ptr, uchar *null_ptr, uchar null_bit, + enum Field::utype unireg_check, const char *field_name, + uint dec) +{ + if (dec == 0) + return new (root) + Field_time(ptr, MIN_TIME_WIDTH, null_ptr, null_bit, unireg_check, + field_name); + if (dec >= FLOATING_POINT_DECIMALS) + dec= MAX_DATETIME_PRECISION; + return new (root) + Field_time_hires(ptr, null_ptr, null_bit, unireg_check, field_name, dec); +} + +static inline Field_datetime * +new_Field_datetime(MEM_ROOT *root, uchar *ptr, uchar *null_ptr, uchar null_bit, + enum Field::utype unireg_check, + const char *field_name, uint dec) +{ + if (dec == 0) + return new (root) + Field_datetime(ptr, MAX_DATETIME_WIDTH, null_ptr, null_bit, + unireg_check, field_name); + if (dec >= FLOATING_POINT_DECIMALS) + dec= MAX_DATETIME_PRECISION; + return new (root) + Field_datetime_hires(ptr, null_ptr, null_bit, + unireg_check, field_name, dec); +} + +class Field_string :public Field_longstr { + class Warn_filter_string: public Warn_filter + { + public: + Warn_filter_string(const THD *thd, const Field_string *field); + }; +public: + bool can_alter_field_type; + Field_string(uchar *ptr_arg, uint32 len_arg,uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + CHARSET_INFO *cs) + :Field_longstr(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, cs), + can_alter_field_type(1) {}; + Field_string(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, + CHARSET_INFO *cs) + :Field_longstr((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, 0, + NONE, field_name_arg, cs), + can_alter_field_type(1) {}; + + enum_field_types type() const + { + return ((can_alter_field_type && orig_table && + orig_table->s->db_create_options & HA_OPTION_PACK_RECORD && + field_length >= 4) && + orig_table->s->frm_version < FRM_VER_TRUE_VARCHAR ? + MYSQL_TYPE_VAR_STRING : MYSQL_TYPE_STRING); + } + enum ha_base_keytype key_type() const + { return binary() ? HA_KEYTYPE_BINARY : HA_KEYTYPE_TEXT; } + bool zero_pack() const { return 0; } + Copy_func *get_copy_func(const Field *from) const; + int reset(void) + { + charset()->cset->fill(charset(),(char*) ptr, field_length, + (has_charset() ? ' ' : 0)); + return 0; + } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(longlong nr, bool unsigned_val); + int store(double nr) { return Field_str::store(nr); } /* QQ: To be deleted */ + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + my_decimal *val_decimal(my_decimal *); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + void sql_type(String &str) const; + virtual uchar *pack(uchar *to, const uchar *from, + uint max_length); + virtual const uchar *unpack(uchar* to, const uchar *from, + const uchar *from_end,uint param_data); + uint pack_length_from_metadata(uint field_metadata) + { + DBUG_PRINT("debug", ("field_metadata: 0x%04x", field_metadata)); + if (field_metadata == 0) + return row_pack_length(); + return (((field_metadata >> 4) & 0x300) ^ 0x300) + (field_metadata & 0x00ff); + } + bool compatible_field_size(uint field_metadata, Relay_log_info *rli, + uint16 mflags, int *order_var); + uint row_pack_length() const { return field_length; } + int pack_cmp(const uchar *a,const uchar *b,uint key_length, + bool insert_or_update); + int pack_cmp(const uchar *b,uint key_length,bool insert_or_update); + uint packed_col_length(const uchar *to, uint length); + uint max_packed_col_length(uint max_length); + uint size_of() const { return sizeof(*this); } + enum_field_types real_type() const { return MYSQL_TYPE_STRING; } + bool has_charset(void) const + { return charset() == &my_charset_bin ? FALSE : TRUE; } + Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type); + virtual uint get_key_image(uchar *buff,uint length, imagetype type); +private: + int do_save_field_metadata(uchar *first_byte); +}; + + +class Field_varstring :public Field_longstr { + uchar *get_data() const + { + return ptr + length_bytes; + } + uint get_length() const + { + return length_bytes == 1 ? (uint) *ptr : uint2korr(ptr); + } +public: + /* + The maximum space available in a Field_varstring, in bytes. See + length_bytes. + */ + static const uint MAX_SIZE; + /* Store number of bytes used to store length (1 or 2) */ + uint32 length_bytes; + Field_varstring(uchar *ptr_arg, + uint32 len_arg, uint length_bytes_arg, + uchar *null_ptr_arg, uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + TABLE_SHARE *share, CHARSET_INFO *cs) + :Field_longstr(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, cs), + length_bytes(length_bytes_arg) + { + share->varchar_fields++; + } + Field_varstring(uint32 len_arg,bool maybe_null_arg, + const char *field_name_arg, + TABLE_SHARE *share, CHARSET_INFO *cs) + :Field_longstr((uchar*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0, 0, + NONE, field_name_arg, cs), + length_bytes(len_arg < 256 ? 1 :2) + { + share->varchar_fields++; + } + + enum_field_types type() const { return MYSQL_TYPE_VARCHAR; } + enum ha_base_keytype key_type() const; + uint row_pack_length() const { return field_length; } + bool zero_pack() const { return 0; } + int reset(void) { bzero(ptr,field_length+length_bytes); return 0; } + uint32 pack_length() const { return (uint32) field_length+length_bytes; } + uint32 key_length() const { return (uint32) field_length; } + uint32 sort_length() const + { + return (uint32) field_length + (field_charset == &my_charset_bin ? + length_bytes : 0); + } + Copy_func *get_copy_func(const Field *from) const; + bool memcpy_field_possible(const Field *from) const + { + return Field_str::memcpy_field_possible(from) && + length_bytes == ((Field_varstring*) from)->length_bytes; + } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(longlong nr, bool unsigned_val); + int store(double nr) { return Field_str::store(nr); } /* QQ: To be deleted */ + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + my_decimal *val_decimal(my_decimal *); + int cmp_max(const uchar *, const uchar *, uint max_length); + int cmp(const uchar *a,const uchar *b) + { + return cmp_max(a, b, ~0U); + } + void sort_string(uchar *buff,uint length); + uint get_key_image(uchar *buff,uint length, imagetype type); + void set_key_image(const uchar *buff,uint length); + void sql_type(String &str) const; + virtual uchar *pack(uchar *to, const uchar *from, uint max_length); + virtual const uchar *unpack(uchar* to, const uchar *from, + const uchar *from_end, uint param_data); + int cmp_binary(const uchar *a,const uchar *b, uint32 max_length=~0U); + int key_cmp(const uchar *,const uchar*); + int key_cmp(const uchar *str, uint length); + uint packed_col_length(const uchar *to, uint length); + uint max_packed_col_length(uint max_length); + uint32 data_length(); + uint size_of() const { return sizeof(*this); } + enum_field_types real_type() const { return MYSQL_TYPE_VARCHAR; } + bool has_charset(void) const + { return charset() == &my_charset_bin ? FALSE : TRUE; } + Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type); + Field *new_key_field(MEM_ROOT *root, TABLE *new_table, + uchar *new_ptr, uint32 length, + uchar *new_null_ptr, uint new_null_bit); + uint is_equal(Create_field *new_field); + void hash(ulong *nr, ulong *nr2); + uint length_size() { return length_bytes; } +private: + int do_save_field_metadata(uchar *first_byte); +}; + + +class Field_blob :public Field_longstr { +protected: + /** + The number of bytes used to represent the length of the blob. + */ + uint packlength; + + /** + The 'value'-object is a cache fronting the storage engine. + */ + String value; + /** + Cache for blob values when reading a row with a virtual blob + field. This is needed to not destroy the old cached value when + updating the blob with a new value when creating the new row. + */ + String read_value; + + static void do_copy_blob(Copy_field *copy); + static void do_conv_blob(Copy_field *copy); +public: + Field_blob(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + TABLE_SHARE *share, uint blob_pack_length, CHARSET_INFO *cs); + Field_blob(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, + CHARSET_INFO *cs) + :Field_longstr((uchar*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, 0, + NONE, field_name_arg, cs), + packlength(4) + { + flags|= BLOB_FLAG; + } + Field_blob(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, + CHARSET_INFO *cs, bool set_packlength) + :Field_longstr((uchar*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0, 0, + NONE, field_name_arg, cs) + { + flags|= BLOB_FLAG; + packlength= 4; + if (set_packlength) + { + packlength= len_arg <= 255 ? 1 : + len_arg <= 65535 ? 2 : + len_arg <= 16777215 ? 3 : 4; + } + } + Field_blob(uint32 packlength_arg) + :Field_longstr((uchar*) 0, 0, (uchar*) "", 0, NONE, "temp", system_charset_info), + packlength(packlength_arg) {} + /* Note that the default copy constructor is used, in clone() */ + enum_field_types type() const { return MYSQL_TYPE_BLOB;} + enum ha_base_keytype key_type() const + { return binary() ? HA_KEYTYPE_VARBINARY2 : HA_KEYTYPE_VARTEXT2; } + Copy_func *get_copy_func(const Field *from) const + { + /* + TODO: MDEV-9331 + if (from->type() == MYSQL_TYPE_BIT) + return do_field_int; + */ + if (!(from->flags & BLOB_FLAG) || from->charset() != charset()) + return do_conv_blob; + if (from->pack_length() != Field_blob::pack_length()) + return do_copy_blob; + return get_identical_copy_func(); + } + int store_field(Field *from) + { // Be sure the value is stored + from->val_str(&value); + if (table->copy_blobs || + (!value.is_alloced() && from->is_varchar_and_in_write_set())) + value.copy(); + return store(value.ptr(), value.length(), from->charset()); + } + bool memcpy_field_possible(const Field *from) const + { + return Field_str::memcpy_field_possible(from) && + !table->copy_blobs; + } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, bool unsigned_val); + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + my_decimal *val_decimal(my_decimal *); + int cmp_max(const uchar *, const uchar *, uint max_length); + int cmp(const uchar *a,const uchar *b) + { return cmp_max(a, b, ~0U); } + int cmp(const uchar *a, uint32 a_length, const uchar *b, uint32 b_length); + int cmp_binary(const uchar *a,const uchar *b, uint32 max_length=~0U); + int key_cmp(const uchar *,const uchar*); + int key_cmp(const uchar *str, uint length); + /* Never update the value of min_val for a blob field */ + bool update_min(Field *min_val, bool force_update) { return FALSE; } + /* Never update the value of max_val for a blob field */ + bool update_max(Field *max_val, bool force_update) { return FALSE; } + uint32 key_length() const { return 0; } + void sort_string(uchar *buff,uint length); + uint32 pack_length() const + { return (uint32) (packlength + portable_sizeof_char_ptr); } + + /** + Return the packed length without the pointer size added. + + This is used to determine the size of the actual data in the row + buffer. + + @returns The length of the raw data itself without the pointer. + */ + uint32 pack_length_no_ptr() const + { return (uint32) (packlength); } + uint row_pack_length() const { return pack_length_no_ptr(); } + uint32 sort_length() const; + uint32 value_length() { return get_length(); } + virtual uint32 max_data_length() const + { + return (uint32) (((ulonglong) 1 << (packlength*8)) -1); + } + int reset(void) { bzero(ptr, packlength+sizeof(uchar*)); return 0; } + void reset_fields() { bzero((uchar*) &value,sizeof(value)); bzero((uchar*) &read_value,sizeof(read_value)); } + uint32 get_field_buffer_size(void) { return value.alloced_length(); } + void store_length(uchar *i_ptr, uint i_packlength, uint32 i_number); + inline void store_length(uint32 number) + { + store_length(ptr, packlength, number); + } + inline uint32 get_length(uint row_offset= 0) const + { return get_length(ptr+row_offset, this->packlength); } + uint32 get_length(const uchar *ptr, uint packlength) const; + uint32 get_length(const uchar *ptr_arg) const + { return get_length(ptr_arg, this->packlength); } + inline uchar *get_ptr() const { return get_ptr(0); } + inline uchar *get_ptr(my_ptrdiff_t row_offset) const + { + uchar *s; + memcpy(&s, ptr + packlength + row_offset, sizeof(uchar*)); + return s; + } + inline void set_ptr(uchar *length, uchar *data) + { + memcpy(ptr,length,packlength); + memcpy(ptr+packlength, &data,sizeof(char*)); + } + void set_ptr_offset(my_ptrdiff_t ptr_diff, uint32 length, uchar *data) + { + uchar *ptr_ofs= ADD_TO_PTR(ptr,ptr_diff,uchar*); + store_length(ptr_ofs, packlength, length); + memcpy(ptr_ofs+packlength, &data, sizeof(char*)); + } + inline void set_ptr(uint32 length, uchar *data) + { + set_ptr_offset(0, length, data); + } + int copy_value(Field_blob *from); + uint get_key_image(uchar *buff,uint length, imagetype type); + void set_key_image(const uchar *buff,uint length); + Field *new_key_field(MEM_ROOT *root, TABLE *new_table, + uchar *new_ptr, uint32 length, + uchar *new_null_ptr, uint new_null_bit); + void sql_type(String &str) const; + inline bool copy() + { + uchar *tmp= get_ptr(); + if (value.copy((char*) tmp, get_length(), charset())) + { + Field_blob::reset(); + return 1; + } + tmp=(uchar*) value.ptr(); + memcpy(ptr+packlength, &tmp, sizeof(char*)); + return 0; + } + /* store value for the duration of the current read record */ + inline void swap_value_and_read_value() + { + read_value.swap(value); + } + inline void set_value(uchar *data) + { + /* Set value pointer. Lengths are not important */ + value.reset((char*) data, 1, 1, &my_charset_bin); + } + virtual uchar *pack(uchar *to, const uchar *from, uint max_length); + virtual const uchar *unpack(uchar *to, const uchar *from, + const uchar *from_end, uint param_data); + uint packed_col_length(const uchar *col_ptr, uint length); + uint max_packed_col_length(uint max_length); + void free() + { + value.free(); + read_value.free(); + } + inline void clear_temporary() + { + uchar *tmp= get_ptr(); + if (likely(value.ptr() == (char*) tmp)) + bzero((uchar*) &value, sizeof(value)); + else + { + /* + Currently read_value should never point to tmp, the following code + is mainly here to make things future proof. + */ + if (unlikely(read_value.ptr() == (char*) tmp)) + bzero((uchar*) &read_value, sizeof(read_value)); + } + } + uint size_of() const { return sizeof(*this); } + bool has_charset(void) const + { return charset() == &my_charset_bin ? FALSE : TRUE; } + uint32 max_display_length(); + uint32 char_length() const; + uint is_equal(Create_field *new_field); +private: + int do_save_field_metadata(uchar *first_byte); +}; + + +#ifdef HAVE_SPATIAL +class Field_geom :public Field_blob { +public: + enum geometry_type geom_type; + uint srid; + uint precision; + enum storage_type { GEOM_STORAGE_WKB= 0, GEOM_STORAGE_BINARY= 1}; + enum storage_type storage; + + Field_geom(uchar *ptr_arg, uchar *null_ptr_arg, uint null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + TABLE_SHARE *share, uint blob_pack_length, + enum geometry_type geom_type_arg, uint field_srid) + :Field_blob(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, + field_name_arg, share, blob_pack_length, &my_charset_bin) + { geom_type= geom_type_arg; srid= field_srid; } + Field_geom(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, + TABLE_SHARE *share, enum geometry_type geom_type_arg) + :Field_blob(len_arg, maybe_null_arg, field_name_arg, &my_charset_bin) + { geom_type= geom_type_arg; srid= 0; } + enum ha_base_keytype key_type() const { return HA_KEYTYPE_VARBINARY2; } + enum_field_types type() const { return MYSQL_TYPE_GEOMETRY; } + bool can_optimize_range(const Item_bool_func *cond, + const Item *item, + bool is_eq_func) const; + void sql_type(String &str) const; + uint is_equal(Create_field *new_field); + int store(const char *to, uint length, CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, bool unsigned_val); + int store_decimal(const my_decimal *); + uint size_of() const { return sizeof(*this); } + /** + Key length is provided only to support hash joins. (compared byte for byte) + Ex: SELECT .. FROM t1,t2 WHERE t1.field_geom1=t2.field_geom2. + + The comparison is not very relevant, as identical geometry might be + represented differently, but we need to support it either way. + */ + uint32 key_length() const { return packlength; } + + /** + Non-nullable GEOMETRY types cannot have defaults, + but the underlying blob must still be reset. + */ + int reset(void) { return Field_blob::reset() || !maybe_null(); } + + geometry_type get_geometry_type() { return geom_type; }; + static geometry_type geometry_type_merge(geometry_type, geometry_type); + uint get_srid() { return srid; } +}; + +uint gis_field_options_image(uchar *buff, List &create_fields); +uint gis_field_options_read(const uchar *buf, uint buf_len, + Field_geom::storage_type *st_type,uint *precision, uint *scale, uint *srid); + +#endif /*HAVE_SPATIAL*/ + + +class Field_enum :public Field_str { + static void do_field_enum(Copy_field *copy_field); +protected: + uint packlength; +public: + TYPELIB *typelib; + Field_enum(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + uint packlength_arg, + TYPELIB *typelib_arg, + CHARSET_INFO *charset_arg) + :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, charset_arg), + packlength(packlength_arg),typelib(typelib_arg) + { + flags|=ENUM_FLAG; + } + Field *make_new_field(MEM_ROOT *root, TABLE *new_table, bool keep_type); + enum_field_types type() const { return MYSQL_TYPE_STRING; } + enum Item_result cmp_type () const { return INT_RESULT; } + const Type_handler *cast_to_int_type_handler() const + { + return &type_handler_longlong; + } + enum ha_base_keytype key_type() const; + Copy_func *get_copy_func(const Field *from) const + { + if (eq_def(from)) + return get_identical_copy_func(); + if (real_type() == MYSQL_TYPE_ENUM && + from->real_type() == MYSQL_TYPE_ENUM) + return do_field_enum; + if (from->result_type() == STRING_RESULT) + return do_field_string; + return do_field_int; + } + int store_field(Field *from) + { + if (from->real_type() == MYSQL_TYPE_ENUM && from->val_int() == 0) + { + store_type(0); + return 0; + } + return from->save_in_field(this); + } + int save_in_field(Field *to) + { + if (to->result_type() != STRING_RESULT) + return to->store(val_int(), 0); + return save_in_field_str(to); + } + bool memcpy_field_possible(const Field *from) const { return false; } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, bool unsigned_val); + double val_real(void); + longlong val_int(void); + String *val_str(String*,String *); + int cmp(const uchar *,const uchar *); + void sort_string(uchar *buff,uint length); + uint32 pack_length() const { return (uint32) packlength; } + void store_type(ulonglong value); + void sql_type(String &str) const; + uint size_of() const { return sizeof(*this); } + enum_field_types real_type() const { return MYSQL_TYPE_ENUM; } + uint pack_length_from_metadata(uint field_metadata) + { return (field_metadata & 0x00ff); } + uint row_pack_length() const { return pack_length(); } + virtual bool zero_pack() const { return 0; } + bool optimize_range(uint idx, uint part) { return 0; } + bool eq_def(const Field *field) const; + bool has_charset(void) const { return TRUE; } + /* enum and set are sorted as integers */ + CHARSET_INFO *sort_charset(void) const { return &my_charset_bin; } + uint decimals() const { return 0; } + + virtual uchar *pack(uchar *to, const uchar *from, uint max_length); + virtual const uchar *unpack(uchar *to, const uchar *from, + const uchar *from_end, uint param_data); + + bool can_optimize_keypart_ref(const Item_bool_func *cond, + const Item *item) const; + bool can_optimize_group_min_max(const Item_bool_func *cond, + const Item *const_item) const + { + /* + Can't use GROUP_MIN_MAX optimization for ENUM and SET, + because the values are stored as numbers in index, + while MIN() and MAX() work as strings. + It would return the records with min and max enum numeric indexes. + "Bug#45300 MAX() and ENUM type" should be fixed first. + */ + return false; + } +private: + int do_save_field_metadata(uchar *first_byte); + uint is_equal(Create_field *new_field); +}; + + +class Field_set :public Field_enum { +public: + Field_set(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg, + uint32 packlength_arg, + TYPELIB *typelib_arg, CHARSET_INFO *charset_arg) + :Field_enum(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, + unireg_check_arg, field_name_arg, + packlength_arg, + typelib_arg,charset_arg), + empty_set_string("", 0, charset_arg) + { + flags=(flags & ~ENUM_FLAG) | SET_FLAG; + } + int store_field(Field *from) { return from->save_in_field(this); } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr) { return Field_set::store((longlong) nr, FALSE); } + int store(longlong nr, bool unsigned_val); + + virtual bool zero_pack() const { return 1; } + String *val_str(String*,String *); + void sql_type(String &str) const; + uint size_of() const { return sizeof(*this); } + enum_field_types real_type() const { return MYSQL_TYPE_SET; } + bool has_charset(void) const { return TRUE; } +private: + const String empty_set_string; +}; + + +/* + Note: + To use Field_bit::cmp_binary() you need to copy the bits stored in + the beginning of the record (the NULL bytes) to each memory you + want to compare (where the arguments point). + + This is the reason: + - Field_bit::cmp_binary() is only implemented in the base class + (Field::cmp_binary()). + - Field::cmp_binary() currenly use pack_length() to calculate how + long the data is. + - pack_length() includes size of the bits stored in the NULL bytes + of the record. +*/ +class Field_bit :public Field { +public: + uchar *bit_ptr; // position in record where 'uneven' bits store + uchar bit_ofs; // offset to 'uneven' high bits + uint bit_len; // number of 'uneven' high bits + uint bytes_in_rec; + Field_bit(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, uchar *bit_ptr_arg, uchar bit_ofs_arg, + enum utype unireg_check_arg, const char *field_name_arg); + enum_field_types type() const { return MYSQL_TYPE_BIT; } + enum ha_base_keytype key_type() const { return HA_KEYTYPE_BIT; } + uint32 key_length() const { return (uint32) (field_length + 7) / 8; } + uint32 max_data_length() const { return (field_length + 7) / 8; } + uint32 max_display_length() { return field_length; } + uint size_of() const { return sizeof(*this); } + Item_result result_type () const { return INT_RESULT; } + int reset(void) { + bzero(ptr, bytes_in_rec); + if (bit_ptr && (bit_len > 0)) // reset odd bits among null bits + clr_rec_bits(bit_ptr, bit_ofs, bit_len); + return 0; + } + Copy_func *get_copy_func(const Field *from) const + { + return do_field_int; + } + int save_in_field(Field *to) { return to->store(val_int(), true); } + bool memcpy_field_possible(const Field *from) const { return false; } + int store(const char *to, uint length, CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr, bool unsigned_val); + int store_decimal(const my_decimal *); + double val_real(void); + longlong val_int(void); + String *val_str(String*, String *); + virtual bool str_needs_quotes() { return TRUE; } + my_decimal *val_decimal(my_decimal *); + bool val_bool() { return val_int() != 0; } + int cmp(const uchar *a, const uchar *b) + { + DBUG_ASSERT(ptr == a || ptr == b); + if (ptr == a) + return Field_bit::key_cmp(b, bytes_in_rec + MY_TEST(bit_len)); + else + return Field_bit::key_cmp(a, bytes_in_rec + MY_TEST(bit_len)) * -1; + } + int cmp_binary_offset(uint row_offset) + { return cmp_offset(row_offset); } + int cmp_max(const uchar *a, const uchar *b, uint max_length); + int key_cmp(const uchar *a, const uchar *b) + { return cmp_binary((uchar *) a, (uchar *) b); } + int key_cmp(const uchar *str, uint length); + int cmp_offset(uint row_offset); + bool update_min(Field *min_val, bool force_update) + { + longlong val= val_int(); + bool update_fl= force_update || val < min_val->val_int(); + if (update_fl) + { + min_val->set_notnull(); + min_val->store(val, FALSE); + } + return update_fl; + } + bool update_max(Field *max_val, bool force_update) + { + longlong val= val_int(); + bool update_fl= force_update || val > max_val->val_int(); + if (update_fl) + { + max_val->set_notnull(); + max_val->store(val, FALSE); + } + return update_fl; + } + void store_field_value(uchar *val, uint len) + { + store(*((longlong *)val), TRUE); + } + double pos_in_interval(Field *min, Field *max) + { + return pos_in_interval_val_real(min, max); + } + void get_image(uchar *buff, uint length, CHARSET_INFO *cs) + { get_key_image(buff, length, itRAW); } + void set_image(const uchar *buff,uint length, CHARSET_INFO *cs) + { Field_bit::store((char *) buff, length, cs); } + uint get_key_image(uchar *buff, uint length, imagetype type); + void set_key_image(const uchar *buff, uint length) + { Field_bit::store((char*) buff, length, &my_charset_bin); } + void sort_string(uchar *buff, uint length) + { get_key_image(buff, length, itRAW); } + uint32 pack_length() const { return (uint32) (field_length + 7) / 8; } + uint32 pack_length_in_rec() const { return bytes_in_rec; } + uint pack_length_from_metadata(uint field_metadata); + uint row_pack_length() const + { return (bytes_in_rec + ((bit_len > 0) ? 1 : 0)); } + bool compatible_field_size(uint metadata, Relay_log_info *rli, + uint16 mflags, int *order_var); + void sql_type(String &str) const; + virtual uchar *pack(uchar *to, const uchar *from, uint max_length); + virtual const uchar *unpack(uchar *to, const uchar *from, + const uchar *from_end, uint param_data); + virtual void set_default(); + + Field *new_key_field(MEM_ROOT *root, TABLE *new_table, + uchar *new_ptr, uint32 length, + uchar *new_null_ptr, uint new_null_bit); + void set_bit_ptr(uchar *bit_ptr_arg, uchar bit_ofs_arg) + { + bit_ptr= bit_ptr_arg; + bit_ofs= bit_ofs_arg; + } + bool eq(Field *field) + { + return (Field::eq(field) && + bit_ptr == ((Field_bit *)field)->bit_ptr && + bit_ofs == ((Field_bit *)field)->bit_ofs); + } + uint is_equal(Create_field *new_field); + void move_field_offset(my_ptrdiff_t ptr_diff) + { + Field::move_field_offset(ptr_diff); + bit_ptr= ADD_TO_PTR(bit_ptr, ptr_diff, uchar*); + } + void hash(ulong *nr, ulong *nr2); + +private: + virtual size_t do_last_null_byte() const; + int do_save_field_metadata(uchar *first_byte); +}; + + +/** + BIT field represented as chars for non-MyISAM tables. + + @todo The inheritance relationship is backwards since Field_bit is + an extended version of Field_bit_as_char and not the other way + around. Hence, we should refactor it to fix the hierarchy order. + */ +class Field_bit_as_char: public Field_bit { +public: + Field_bit_as_char(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, + uchar null_bit_arg, + enum utype unireg_check_arg, const char *field_name_arg); + enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } + uint size_of() const { return sizeof(*this); } + int store(const char *to, uint length, CHARSET_INFO *charset); + int store(double nr) { return Field_bit::store(nr); } + int store(longlong nr, bool unsigned_val) + { return Field_bit::store(nr, unsigned_val); } + void sql_type(String &str) const; +}; + + +extern const LEX_STRING null_lex_str; + + +Field *make_field(TABLE_SHARE *share, MEM_ROOT *mem_root, + uchar *ptr, uint32 field_length, + uchar *null_pos, uchar null_bit, + uint pack_flag, enum_field_types field_type, + CHARSET_INFO *cs, + Field::geometry_type geom_type, uint srid, + Field::utype unireg_check, + TYPELIB *interval, const char *field_name); + +/* + Create field class for CREATE TABLE +*/ +class Column_definition: public Sql_alloc +{ + /** + Create "interval" from "interval_list". + @param mem_root - memory root to create the TYPELIB + instance and its values on + @param reuse_interval_list_values - determines if TYPELIB can reuse strings + from interval_list, or should always + allocate a copy on mem_root, even if + character set conversion is not needed + @retval false on success + @retval true on error (bad values, or EOM) + */ + bool create_interval_from_interval_list(MEM_ROOT *mem_root, + bool reuse_interval_list_values); + + /* + Calculate TYPELIB (set or enum) max and total lengths + + @param cs charset+collation pair of the interval + @param max_length length of the longest item + @param tot_length sum of the item lengths + + After this method call: + - ENUM uses max_length + - SET uses tot_length. + */ + void calculate_interval_lengths(uint32 *max_length, uint32 *tot_length) + { + const char **pos; + uint *len; + *max_length= *tot_length= 0; + for (pos= interval->type_names, len= interval->type_lengths; + *pos ; pos++, len++) + { + size_t length= charset->cset->numchars(charset, *pos, *pos + *len); + *tot_length+= length; + set_if_bigger(*max_length, (uint32)length); + } + } +public: + enum enum_column_versioning + { + VERSIONING_NOT_SET, + WITH_VERSIONING, + WITHOUT_VERSIONING + }; + + const char *field_name; + LEX_STRING comment; // Comment for field + Item *on_update; // ON UPDATE NOW() + enum enum_field_types sql_type; + /* + At various stages in execution this can be length of field in bytes or + max number of characters. + */ + ulonglong length; + /* + The value of `length' as set by parser: is the number of characters + for most of the types, or of bytes for BLOBs or numeric types. + */ + uint32 char_length; + uint decimals, flags, pack_length, key_length; + Field::utype unireg_check; + TYPELIB *interval; // Which interval to use + List interval_list; + CHARSET_INFO *charset; + uint32 srid; + Field::geometry_type geom_type; + engine_option_value *option_list; + + uint pack_flag; + + /* + This is additinal data provided for any computed(virtual) field. + In particular it includes a pointer to the item by which this field + can be computed from other fields. + */ + Virtual_column_info + *vcol_info, // Virtual field + *default_value, // Default value + *check_constraint; // Check constraint + + enum_column_versioning versioning; + + Column_definition(): + comment(null_lex_str), + on_update(NULL), sql_type(MYSQL_TYPE_NULL), length(0), decimals(0), + flags(0), pack_length(0), key_length(0), unireg_check(Field::NONE), + interval(0), charset(&my_charset_bin), + srid(0), geom_type(Field::GEOM_GEOMETRY), + option_list(NULL), + vcol_info(0), default_value(0), check_constraint(0), + versioning(VERSIONING_NOT_SET) + { + interval_list.empty(); + } + + Column_definition(THD *thd, Field *field, Field *orig_field); + void set_attributes(const Lex_field_type_st &type, CHARSET_INFO *cs); + void create_length_to_internal_length(void); + + /** + Prepare a SET/ENUM field. + Create "interval" from "interval_list" if needed, and adjust "length". + @param mem_root - Memory root to allocate TYPELIB and + its values on + @param reuse_interval_list_values - determines if TYPELIB can reuse value + buffers from interval_list, or should + always allocate a copy on mem_root, + even if character set conversion + is not needed + */ + bool prepare_interval_field(MEM_ROOT *mem_root, + bool reuse_interval_list_values); + + void prepare_interval_field_calc_length() + { + uint32 field_length, dummy; + if (sql_type == MYSQL_TYPE_SET) + { + calculate_interval_lengths(&dummy, &field_length); + length= field_length + (interval->count - 1); + } + else /* MYSQL_TYPE_ENUM */ + { + calculate_interval_lengths(&field_length, &dummy); + length= field_length; + } + set_if_smaller(length, MAX_FIELD_WIDTH - 1); + } + + bool prepare_blob_field(THD *thd); + + bool sp_prepare_create_field(THD *thd, MEM_ROOT *mem_root); + + bool prepare_create_field(uint *blob_columns, ulonglong table_flags); + + bool check(THD *thd); + + bool stored_in_db() const { return !vcol_info || vcol_info->stored_in_db; } + + ha_storage_media field_storage_type() const + { + return (ha_storage_media) + ((flags >> FIELD_FLAGS_STORAGE_MEDIA) & 3); + } + + column_format_type column_format() const + { + return (column_format_type) + ((flags >> FIELD_FLAGS_COLUMN_FORMAT) & 3); + } + + bool has_default_function() const + { + return unireg_check != Field::NONE; + } + + Field *make_field(TABLE_SHARE *share, MEM_ROOT *mem_root, + uchar *ptr, uchar *null_pos, uchar null_bit, + const char *field_name_arg) const + { + return ::make_field(share, mem_root, ptr, + (uint32)length, null_pos, null_bit, + pack_flag, sql_type, charset, + geom_type, srid, unireg_check, interval, + field_name_arg); + } + Field *make_field(TABLE_SHARE *share, MEM_ROOT *mem_root, + const char *field_name_arg) + { + return make_field(share, mem_root, (uchar *) 0, (uchar *) "", 0, + field_name_arg); + } + /* Return true if default is an expression that must be saved explicitely */ + bool has_default_expression(); + + bool has_default_now_unireg_check() const + { + return unireg_check == Field::TIMESTAMP_DN_FIELD + || unireg_check == Field::TIMESTAMP_DNUN_FIELD; + } +}; + + +class Create_field :public Column_definition +{ +public: + const char *change; // If done with alter table + const char *after; // Put column after this one + Field *field; // For alter table + TYPELIB *save_interval; // Temporary copy for the above + // Used only for UCS2 intervals + + /** structure with parsed options (for comparing fields in ALTER TABLE) */ + ha_field_option_struct *option_struct; + uint offset; + uint8 interval_id; // For rea_create_table + bool create_if_not_exists; // Used in ALTER TABLE IF NOT EXISTS + + Create_field(): + Column_definition(), change(0), after(0), + field(0), option_struct(NULL), + create_if_not_exists(false) + { } + Create_field(THD *thd, Field *old_field, Field *orig_field): + Column_definition(thd, old_field, orig_field), + change(old_field->field_name), after(0), + field(old_field), option_struct(old_field->option_struct), + create_if_not_exists(false) + { } + /* Used to make a clone of this object for ALTER/CREATE TABLE */ + Create_field *clone(MEM_ROOT *mem_root) const; +}; + + +/* + A class for sending info to the client +*/ + +class Send_field :public Sql_alloc { + public: + const char *db_name; + const char *table_name,*org_table_name; + const char *col_name,*org_col_name; + ulong length; + uint flags, decimals; + enum_field_types type; + Send_field() {} +}; + + +/* + A class for quick copying data to fields +*/ + +class Copy_field :public Sql_alloc { +public: + uchar *from_ptr,*to_ptr; + uchar *from_null_ptr,*to_null_ptr; + bool *null_row; + uint from_bit,to_bit; + /** + Number of bytes in the fields pointed to by 'from_ptr' and + 'to_ptr'. Usually this is the number of bytes that are copied from + 'from_ptr' to 'to_ptr'. + + For variable-length fields (VARCHAR), the first byte(s) describe + the actual length of the text. For VARCHARs with length + < 256 there is 1 length byte + >= 256 there is 2 length bytes + Thus, if from_field is VARCHAR(10), from_length (and in most cases + to_length) is 11. For VARCHAR(1024), the length is 1026. @see + Field_varstring::length_bytes + + Note that for VARCHARs, do_copy() will be do_varstring*() which + only copies the length-bytes (1 or 2) + the actual length of the + text instead of from/to_length bytes. + */ + uint from_length,to_length; + Field *from_field,*to_field; + String tmp; // For items + + Copy_field() {} + ~Copy_field() {} + void set(Field *to,Field *from,bool save); // Field to field + void set(uchar *to,Field *from); // Field to string + void (*do_copy)(Copy_field *); + void (*do_copy2)(Copy_field *); // Used to handle null values +}; + + +uint pack_length_to_packflag(uint type); +enum_field_types get_blob_type_from_length(ulong length); +uint32 calc_pack_length(enum_field_types type,uint32 length); +int set_field_to_null(Field *field); +int set_field_to_null_with_conversions(Field *field, bool no_conversions); +int convert_null_to_field_value_or_error(Field *field); +bool check_expression(Virtual_column_info *vcol, const char *name, + enum_vcol_info_type type); + +/* + The following are for the interface with the .frm file +*/ + +#define FIELDFLAG_DECIMAL 1U +#define FIELDFLAG_BINARY 1U // Shares same flag +#define FIELDFLAG_NUMBER 2U +#define FIELDFLAG_ZEROFILL 4U +#define FIELDFLAG_PACK 120U // Bits used for packing +#define FIELDFLAG_INTERVAL 256U // mangled with decimals! +#define FIELDFLAG_BITFIELD 512U // mangled with decimals! +#define FIELDFLAG_BLOB 1024U // mangled with decimals! +#define FIELDFLAG_GEOM 2048U // mangled with decimals! + +#define FIELDFLAG_TREAT_BIT_AS_CHAR 4096U /* use Field_bit_as_char */ +#define FIELDFLAG_LONG_DECIMAL 8192U +#define FIELDFLAG_WITHOUT_SYSTEM_VERSIONING 8192U +#define FIELDFLAG_NO_DEFAULT 16384U /* sql */ +#define FIELDFLAG_MAYBE_NULL 32768U // sql +#define FIELDFLAG_HEX_ESCAPE 0x10000U +#define FIELDFLAG_PACK_SHIFT 3 +#define FIELDFLAG_DEC_SHIFT 8 +#define FIELDFLAG_MAX_DEC 63U + +#define MTYP_TYPENR(type) (type & 127U) /* Remove bits from type */ + +#define f_is_dec(x) ((x) & FIELDFLAG_DECIMAL) +#define f_is_num(x) ((x) & FIELDFLAG_NUMBER) +#define f_is_zerofill(x) ((x) & FIELDFLAG_ZEROFILL) +#define f_is_packed(x) ((x) & FIELDFLAG_PACK) +#define f_packtype(x) (((x) >> FIELDFLAG_PACK_SHIFT) & 15) +#define f_decimals(x) ((uint8) (((x) >> FIELDFLAG_DEC_SHIFT) & FIELDFLAG_MAX_DEC)) +#define f_is_alpha(x) (!f_is_num(x)) +#define f_is_binary(x) ((x) & FIELDFLAG_BINARY) // 4.0- compatibility +#define f_is_enum(x) (((x) & (FIELDFLAG_INTERVAL | FIELDFLAG_NUMBER)) == FIELDFLAG_INTERVAL) +#define f_is_bitfield(x) (((x) & (FIELDFLAG_BITFIELD | FIELDFLAG_NUMBER)) == FIELDFLAG_BITFIELD) +#define f_is_blob(x) (((x) & (FIELDFLAG_BLOB | FIELDFLAG_NUMBER)) == FIELDFLAG_BLOB) +#define f_is_geom(x) (((x) & (FIELDFLAG_GEOM | FIELDFLAG_NUMBER)) == FIELDFLAG_GEOM) +#define f_settype(x) (((uint) (x)) << FIELDFLAG_PACK_SHIFT) +#define f_maybe_null(x) ((x) & FIELDFLAG_MAYBE_NULL) +#define f_no_default(x) ((x) & FIELDFLAG_NO_DEFAULT) +#define f_bit_as_char(x) ((x) & FIELDFLAG_TREAT_BIT_AS_CHAR) +#define f_is_hex_escape(x) ((x) & FIELDFLAG_HEX_ESCAPE) +#define f_without_system_versioning(x) ((x) & FIELDFLAG_WITHOUT_SYSTEM_VERSIONING) +#define f_hidden(x) ((x) & FIELDFLAG_HIDDEN) + +#endif /* FIELD_INCLUDED */ diff --git a/sql/handler.cc b/sql/handler.cc index 0b079676fc9..d5dff46a22e 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6570,16 +6570,16 @@ static bool create_sys_trx_field(THD *thd, const char *field_name, memset(f, 0, sizeof(*f)); f->field_name= field_name; f->charset= system_charset_info; + f->flags= NOT_NULL_FLAG | HIDDEN_FLAG; if (integer_fields) { f->sql_type= MYSQL_TYPE_LONGLONG; - f->flags= UNSIGNED_FLAG | NOT_NULL_FLAG; + f->flags|= UNSIGNED_FLAG; f->length= MY_INT64_NUM_DECIMAL_DIGITS; } else { f->sql_type= MYSQL_TYPE_TIMESTAMP2; - f->flags= NOT_NULL_FLAG; f->length= 6; } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 1af45c12331..090133b72ed 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -7568,6 +7568,14 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, if (!(item= field_iterator.create_item(thd))) DBUG_RETURN(TRUE); + if (item->type() == Item::FIELD_ITEM) + { + Item_field *f= static_cast(item); + DBUG_ASSERT(f->field); + if (f->field->flags & HIDDEN_FLAG) + continue; + } + /* cache the table for the Item_fields inserted by expanding stars */ if (item->type() == Item::FIELD_ITEM && tables->cacheable_table) ((Item_field *)item)->cached_table= tables; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index c4bc2028caf..a3e6565fa52 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2991,6 +2991,8 @@ bool Column_definition::prepare_create_field(uint *blob_columns, pack_flag|= FIELDFLAG_NO_DEFAULT; if (flags & WITHOUT_SYSTEM_VERSIONING_FLAG) pack_flag|= FIELDFLAG_WITHOUT_SYSTEM_VERSIONING; + if (flags & HIDDEN_FLAG) + pack_flag|= FIELDFLAG_HIDDEN; DBUG_RETURN(false); } diff --git a/sql/table.cc b/sql/table.cc index 3a75fbe8e48..a23589f530a 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -2020,6 +2020,9 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, if (f_without_system_versioning(pack_flag)) reg_field->flags|= WITHOUT_SYSTEM_VERSIONING_FLAG; + if (f_hidden(pack_flag)) + reg_field->flags|= HIDDEN_FLAG; + if (reg_field->unireg_check == Field::NEXT_NUMBER) share->found_next_number_field= field_ptr;