diff options
Diffstat (limited to 'sql/sql_sequence.h')
-rw-r--r-- | sql/sql_sequence.h | 152 |
1 files changed, 127 insertions, 25 deletions
diff --git a/sql/sql_sequence.h b/sql/sql_sequence.h index 29c589e67cd..4b3f102509b 100644 --- a/sql/sql_sequence.h +++ b/sql/sql_sequence.h @@ -25,12 +25,35 @@ #define seq_field_used_cycle 32 #define seq_field_used_restart 64 #define seq_field_used_restart_value 128 +#define seq_field_used_as 256 +#define seq_field_specified_min_value 512 +#define seq_field_specified_max_value 1024 /* Field position in sequence table for some fields we refer to directly */ #define NEXT_FIELD_NO 0 #define MIN_VALUE_FIELD_NO 1 #define ROUND_FIELD_NO 7 +#include "mysql_com.h" +#include "sql_type_int.h" + +class Create_field; +class Type_handler; + +struct Sequence_field_definition +{ + const char *field_name; + uint length; + const Type_handler *type_handler; + LEX_CSTRING comment; + ulong flags; +}; + +struct Sequence_row_definition +{ + Sequence_field_definition fields[9]; +}; + /** sequence_definition is used when defining a sequence as part of create */ @@ -39,33 +62,56 @@ class sequence_definition :public Sql_alloc { public: sequence_definition(): - min_value(1), max_value(LONGLONG_MAX-1), start(1), increment(1), - cache(1000), round(0), restart(0), cycle(0), used_fields(0) + min_value_from_parser(1, false), + max_value_from_parser(LONGLONG_MAX-1, false), start_from_parser(1, false), + increment(1), cache(1000), round(0), restart_from_parser(0, false), + cycle(0), used_fields(0), + /* + We use value type and is_unsigned instead of a handler because + Type_handler is incomplete, which we cannot initialise here with + &type_handler_slonglong. + */ + value_type(MYSQL_TYPE_LONGLONG), is_unsigned(false) {} longlong reserved_until; longlong min_value; longlong max_value; longlong start; + Longlong_hybrid min_value_from_parser; + Longlong_hybrid max_value_from_parser; + Longlong_hybrid start_from_parser; longlong increment; longlong cache; ulonglong round; longlong restart; // alter sequence restart value + Longlong_hybrid restart_from_parser; bool cycle; uint used_fields; // Which fields where used in CREATE + enum_field_types value_type; // value type of the sequence + bool is_unsigned; - bool check_and_adjust(bool set_reserved_until); + Type_handler const *value_type_handler(); + /* max value for the value type, e.g. 32767 for smallint. */ + longlong value_type_max(); + /* min value for the value type, e.g. -32768 for smallint. */ + longlong value_type_min(); + bool check_and_adjust(THD *thd, bool set_reserved_until); void store_fields(TABLE *table); void read_fields(TABLE *table); int write_initial_sequence(TABLE *table); int write(TABLE *table, bool all_fields); /* This must be called after sequence data has been updated */ void adjust_values(longlong next_value); + longlong truncate_value(const Longlong_hybrid& original); inline void print_dbug() { DBUG_PRINT("sequence", ("reserved: %lld start: %lld increment: %lld min_value: %lld max_value: %lld cache: %lld round: %lld", reserved_until, start, increment, min_value, max_value, cache, round)); } + static bool is_allowed_value_type(enum_field_types type); + bool prepare_sequence_fields(List<Create_field> *fields, bool alter); + protected: /* The following values are the values from sequence_definition @@ -107,31 +153,90 @@ public: longlong next_value(TABLE *table, bool second_round, int *error); int set_value(TABLE *table, longlong next_value, ulonglong round_arg, bool is_used); - longlong increment_value(longlong value) + + bool all_values_used; + seq_init initialized; + +private: + /** + Check that a value is within a relevant bound + + If increasing sequence, check that the value is lower than an + upper bound, otherwise check that the value is higher than a lower + bound. + + @param in value The value to check + @param in upper The upper bound + @param in lower The lower bound + @param in increasing Which bound to check + + @retval true The value is within the bound. + false The value is out of the bound. + */ + bool within_bound(const longlong value, const longlong upper, + const longlong lower, bool increasing) + { + return + (is_unsigned && increasing && (ulonglong) value < (ulonglong) upper) || + (is_unsigned && !increasing && (ulonglong) value > (ulonglong) lower) || + (!is_unsigned && increasing && value < upper) || + (!is_unsigned && !increasing && value > lower); + } + + /** + Increment a value, subject to truncation + + Truncating to the nearer value between max_value + 1 and min_value + - 1 + + @param in value The original value + @param in increment The increment to add to the value + + @return The value after increment and possible truncation + */ + longlong increment_value(longlong value, const longlong increment) { - if (real_increment > 0) + if (is_unsigned) { - if (value > max_value - real_increment || - value + real_increment > max_value) - value= max_value + 1; + if (increment > 0) + { + if (/* in case value + increment overflows */ + (ulonglong) value > + (ulonglong) max_value - (ulonglong) increment || + /* in case max_value - increment underflows */ + (ulonglong) value + (ulonglong) increment > + (ulonglong) max_value) + value= max_value + 1; + else + value+= increment; + } else - value+= real_increment; - } - else - { - if (value + real_increment < min_value || - value < min_value - real_increment) - value= min_value - 1; + { + if ((ulonglong) value - (ulonglong) (-increment) < + (ulonglong) min_value || + (ulonglong) value < + (ulonglong) min_value + (ulonglong) (-increment)) + value= min_value - 1; + else + value+= increment; + } + } else + if (increment > 0) + { + if (value > max_value - increment || value + increment > max_value) + value= max_value + 1; + else + value+= increment; + } else - value+= real_increment; - } + { + if (value + increment < min_value || value < min_value - increment) + value= min_value - 1; + else + value+= increment; + } return value; } - - bool all_values_used; - seq_init initialized; - -private: mysql_rwlock_t mutex; }; @@ -159,9 +264,6 @@ public: uchar table_version[MY_UUID_SIZE]; }; - -class Create_field; -extern bool prepare_sequence_fields(THD *thd, List<Create_field> *fields); extern bool check_sequence_fields(LEX *lex, List<Create_field> *fields); extern bool sequence_insert(THD *thd, LEX *lex, TABLE_LIST *table_list); #endif /* SQL_SEQUENCE_INCLUDED */ |