-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
/
Copy pathsql_sequence.h
287 lines (256 loc) · 9.17 KB
/
sql_sequence.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
/* Copyright (c) 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
*/
#ifndef SQL_SEQUENCE_INCLUDED
#define SQL_SEQUENCE_INCLUDED
#define seq_field_used_min_value 1
#define seq_field_used_max_value 2
#define seq_field_used_start 4
#define seq_field_used_increment 8
#define seq_field_used_cache 16
#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
*/
class sequence_definition :public Sql_alloc
{
public:
sequence_definition():
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;
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
merged with global auto_increment_offset and auto_increment_increment
*/
longlong real_increment;
longlong next_free_value;
};
/**
SEQUENCE is in charge of managing the sequence values.
It's also responsible to generate new values and updating the sequence
table (engine=SQL_SEQUENCE) trough it's specialized handler interface.
If increment is 0 then the sequence will be be using
auto_increment_increment and auto_increment_offset variables, just like
AUTO_INCREMENT is using.
*/
class SEQUENCE :public sequence_definition
{
public:
enum seq_init { SEQ_UNINTIALIZED, SEQ_IN_PREPARE, SEQ_IN_ALTER,
SEQ_READY_TO_USE };
SEQUENCE();
~SEQUENCE();
int read_initial_values(TABLE *table);
int read_stored_values(TABLE *table);
void write_lock(TABLE *table);
void write_unlock(TABLE *table);
void read_lock(TABLE *table);
void read_unlock(TABLE *table);
void copy(sequence_definition *seq)
{
sequence_definition::operator= (*seq);
adjust_values(reserved_until);
all_values_used= 0;
}
longlong next_value(TABLE *table, bool second_round, int *error);
int set_value(TABLE *table, longlong next_value, ulonglong round_arg,
bool is_used);
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 (is_unsigned)
{
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 ||
/* in case both overflow and underflow happens (very
rarely, if not impossible) */
(ulonglong) value > (ulonglong) max_value)
/* Cast to ulonglong then back, in case max_value ==
LONGLONG_MAX as a ulonglong */
value= (longlong) ((ulonglong) max_value + 1);
else
value = (longlong) ((ulonglong) value + (ulonglong) increment);
}
else
{
if ((ulonglong) value - (ulonglong) (-increment) <
(ulonglong) min_value ||
(ulonglong) value <
(ulonglong) min_value + (ulonglong) (-increment) ||
(ulonglong) value < (ulonglong) min_value)
/* Cast to ulonglong then back, in case min_value ==
LONGLONG_MAX + 1 as a ulonglong */
value= (longlong) ((ulonglong) min_value - 1);
else
value = (longlong) ((ulonglong) value - (ulonglong) (-increment));
}
} else
if (increment > 0)
{
if (value >
(longlong) ((ulonglong) max_value - (ulonglong) increment) ||
(longlong) ((ulonglong) value + (ulonglong) increment) >
max_value ||
value > max_value)
value= max_value + 1;
else
value+= increment;
}
else
{
if ((longlong) ((ulonglong) value + (ulonglong) increment) <
min_value ||
value <
(longlong) ((ulonglong) min_value - (ulonglong) increment) ||
value < min_value)
value= min_value - 1;
else
value+= increment;
}
return value;
}
mysql_rwlock_t mutex;
};
/**
Class to cache last value of NEXT VALUE from the sequence
*/
class SEQUENCE_LAST_VALUE
{
public:
SEQUENCE_LAST_VALUE(uchar *key_arg, uint length_arg)
:key(key_arg), length(length_arg)
{}
~SEQUENCE_LAST_VALUE()
{ my_free((void*) key); }
/* Returns 1 if table hasn't been dropped or re-created */
bool check_version(TABLE *table);
void set_version(TABLE *table);
const uchar *key;
uint length;
bool null_value;
longlong value;
uchar table_version[MY_UUID_SIZE];
};
extern bool check_sequence_fields(LEX *lex, List<Create_field> *fields,
const LEX_CSTRING db,
const LEX_CSTRING table_name);
extern bool sequence_insert(THD *thd, LEX *lex, TABLE_LIST *table_list);
#endif /* SQL_SEQUENCE_INCLUDED */