1 /*
2 Copyright (c) 2017, MariaDB Corporation, Alibaba Corporation
3 Copyrgiht (c) 2020, MariaDB Corporation.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; version 2 of the License.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include "mariadb.h"
20 #include "sql_class.h"
21 #include "sql_list.h"
22 #include "sql_sequence.h"
23 #include "ha_sequence.h"
24 #include "sql_base.h"
25 #include "sql_table.h" // write_bin_log
26 #include "transaction.h"
27 #include "lock.h"
28 #include "sql_acl.h"
29
30 struct Field_definition
31 {
32 const char *field_name;
33 uint length;
34 const Type_handler *type_handler;
35 LEX_CSTRING comment;
36 ulong flags;
37 };
38
39 /*
40 Structure for all SEQUENCE tables
41
42 Note that the first field is named "next_val" to all us to have
43 NEXTVAL a reserved word that will on access be changed to
44 NEXTVAL(sequence_table). For this to work, the table can't have
45 a column named NEXTVAL.
46 */
47
48 #define FL (NOT_NULL_FLAG | NO_DEFAULT_VALUE_FLAG)
49
50 static Field_definition sequence_structure[]=
51 {
52 {"next_not_cached_value", 21, &type_handler_slonglong,
53 {STRING_WITH_LEN("")}, FL},
54 {"minimum_value", 21, &type_handler_slonglong, {STRING_WITH_LEN("")}, FL},
55 {"maximum_value", 21, &type_handler_slonglong, {STRING_WITH_LEN("")}, FL},
56 {"start_value", 21, &type_handler_slonglong, {STRING_WITH_LEN("start value when sequences is created or value if RESTART is used")}, FL},
57 {"increment", 21, &type_handler_slonglong,
58 {STRING_WITH_LEN("increment value")}, FL},
59 {"cache_size", 21, &type_handler_ulonglong, {STRING_WITH_LEN("")},
60 FL | UNSIGNED_FLAG},
61 {"cycle_option", 1, &type_handler_utiny, {STRING_WITH_LEN("0 if no cycles are allowed, 1 if the sequence should begin a new cycle when maximum_value is passed")},
62 FL | UNSIGNED_FLAG },
63 {"cycle_count", 21, &type_handler_slonglong,
64 {STRING_WITH_LEN("How many cycles have been done")}, FL},
65 {NULL, 0, &type_handler_slonglong, {STRING_WITH_LEN("")}, 0}
66 };
67
68 #undef FL
69
70
71 #define MAX_AUTO_INCREMENT_VALUE 65535
72
73 /*
74 Check whether sequence values are valid.
75 Sets default values for fields that are not used, according to Oracle spec.
76
77 RETURN VALUES
78 false valid
79 true invalid
80 */
81
check_and_adjust(bool set_reserved_until)82 bool sequence_definition::check_and_adjust(bool set_reserved_until)
83 {
84 longlong max_increment;
85 DBUG_ENTER("sequence_definition::check");
86
87 if (!(real_increment= increment))
88 real_increment= global_system_variables.auto_increment_increment;
89
90 /*
91 If min_value is not set, set it to LONGLONG_MIN or 1, depending on
92 real_increment
93 */
94 if (!(used_fields & seq_field_used_min_value))
95 min_value= real_increment < 0 ? LONGLONG_MIN+1 : 1;
96
97 /*
98 If max_value is not set, set it to LONGLONG_MAX or -1, depending on
99 real_increment
100 */
101 if (!(used_fields & seq_field_used_max_value))
102 max_value= real_increment < 0 ? -1 : LONGLONG_MAX-1;
103
104 if (!(used_fields & seq_field_used_start))
105 {
106 /* Use min_value or max_value for start depending on real_increment */
107 start= real_increment < 0 ? max_value : min_value;
108 }
109
110 if (set_reserved_until)
111 reserved_until= start;
112
113 adjust_values(reserved_until);
114
115 /* To ensure that cache * real_increment will never overflow */
116 max_increment= (real_increment ?
117 llabs(real_increment) :
118 MAX_AUTO_INCREMENT_VALUE);
119
120 if (max_value >= start &&
121 max_value > min_value &&
122 start >= min_value &&
123 max_value != LONGLONG_MAX &&
124 min_value != LONGLONG_MIN &&
125 cache < (LONGLONG_MAX - max_increment) / max_increment &&
126 ((real_increment > 0 && reserved_until >= min_value) ||
127 (real_increment < 0 && reserved_until <= max_value)))
128 DBUG_RETURN(FALSE);
129
130 DBUG_RETURN(TRUE); // Error
131 }
132
133
134 /*
135 Read sequence values from a table
136 */
137
read_fields(TABLE * table)138 void sequence_definition::read_fields(TABLE *table)
139 {
140 MY_BITMAP *old_map= dbug_tmp_use_all_columns(table, &table->read_set);
141 reserved_until= table->field[0]->val_int();
142 min_value= table->field[1]->val_int();
143 max_value= table->field[2]->val_int();
144 start= table->field[3]->val_int();
145 increment= table->field[4]->val_int();
146 cache= table->field[5]->val_int();
147 cycle= table->field[6]->val_int();
148 round= table->field[7]->val_int();
149 dbug_tmp_restore_column_map(&table->read_set, old_map);
150 used_fields= ~(uint) 0;
151 print_dbug();
152 }
153
154
155 /*
156 Store sequence into a table row
157 */
158
store_fields(TABLE * table)159 void sequence_definition::store_fields(TABLE *table)
160 {
161 MY_BITMAP *old_map= dbug_tmp_use_all_columns(table, &table->write_set);
162
163 /* zero possible delete markers & null bits */
164 memcpy(table->record[0], table->s->default_values, table->s->null_bytes);
165 table->field[0]->store(reserved_until, 0);
166 table->field[1]->store(min_value, 0);
167 table->field[2]->store(max_value, 0);
168 table->field[3]->store(start, 0);
169 table->field[4]->store(increment, 0);
170 table->field[5]->store(cache, 0);
171 table->field[6]->store((longlong) cycle != 0, 0);
172 table->field[7]->store((longlong) round, 1);
173
174 dbug_tmp_restore_column_map(&table->write_set, old_map);
175 print_dbug();
176 }
177
178
179 /*
180 Check the sequence fields through seq_fields when creating a sequence.
181
182 RETURN VALUES
183 false Success
184 true Failure
185 */
186
check_sequence_fields(LEX * lex,List<Create_field> * fields)187 bool check_sequence_fields(LEX *lex, List<Create_field> *fields)
188 {
189 Create_field *field;
190 List_iterator_fast<Create_field> it(*fields);
191 uint field_count;
192 uint field_no;
193 const char *reason;
194 DBUG_ENTER("check_sequence_fields");
195
196 field_count= fields->elements;
197 if (field_count != array_elements(sequence_structure)-1)
198 {
199 reason= "Wrong number of columns";
200 goto err;
201 }
202 if (lex->alter_info.key_list.elements > 0)
203 {
204 reason= "Sequence tables cannot have any keys";
205 goto err;
206 }
207 if (lex->alter_info.check_constraint_list.elements > 0)
208 {
209 reason= "Sequence tables cannot have any constraints";
210 goto err;
211 }
212 if (lex->alter_info.flags & ALTER_ORDER)
213 {
214 reason= "ORDER BY";
215 goto err;
216 }
217
218 for (field_no= 0; (field= it++); field_no++)
219 {
220 Field_definition *field_def= &sequence_structure[field_no];
221 if (my_strcasecmp(system_charset_info, field_def->field_name,
222 field->field_name.str) ||
223 field->flags != field_def->flags ||
224 field->type_handler() != field_def->type_handler ||
225 field->check_constraint || field->vcol_info)
226 {
227 reason= field->field_name.str;
228 goto err;
229 }
230 }
231 DBUG_RETURN(FALSE);
232
233 err:
234 my_error(ER_SEQUENCE_INVALID_TABLE_STRUCTURE, MYF(0),
235 lex->first_select_lex()->table_list.first->db.str,
236 lex->first_select_lex()->table_list.first->table_name.str, reason);
237 DBUG_RETURN(TRUE);
238 }
239
240
241 /*
242 Create the fields for a SEQUENCE TABLE
243
244 RETURN VALUES
245 false Success
246 true Failure (out of memory)
247 */
248
prepare_sequence_fields(THD * thd,List<Create_field> * fields)249 bool prepare_sequence_fields(THD *thd, List<Create_field> *fields)
250 {
251 Field_definition *field_info;
252 DBUG_ENTER("prepare_sequence_fields");
253
254 for (field_info= sequence_structure; field_info->field_name ; field_info++)
255 {
256 Create_field *new_field;
257 LEX_CSTRING field_name= {field_info->field_name,
258 strlen(field_info->field_name)};
259
260 if (unlikely(!(new_field= new Create_field())))
261 DBUG_RETURN(TRUE); /* purify inspected */
262
263 new_field->field_name= field_name;
264 new_field->set_handler(field_info->type_handler);
265 new_field->length= field_info->length;
266 new_field->char_length= field_info->length;
267 new_field->comment= field_info->comment;
268 new_field->flags= field_info->flags;
269 if (unlikely(fields->push_back(new_field)))
270 DBUG_RETURN(TRUE); /* purify inspected */
271 }
272 DBUG_RETURN(FALSE);
273 }
274
275 /*
276 Initialize the sequence table record as part of CREATE SEQUENCE
277
278 Store one row with sequence information.
279
280 RETURN VALUES
281 false Success
282 true Failure. Error reported.
283
284 NOTES
285 This function is called as part of CREATE SEQUENCE. When called
286 there are now active transactions and no open tables.
287 There is also a MDL lock on the table.
288 */
289
sequence_insert(THD * thd,LEX * lex,TABLE_LIST * org_table_list)290 bool sequence_insert(THD *thd, LEX *lex, TABLE_LIST *org_table_list)
291 {
292 int error;
293 TABLE *table;
294 Reprepare_observer *save_reprepare_observer;
295 sequence_definition *seq= lex->create_info.seq_create_info;
296 bool temporary_table= org_table_list->table != 0;
297 Open_tables_backup open_tables_backup;
298 Query_tables_list query_tables_list_backup;
299 TABLE_LIST table_list; // For sequence table
300 DBUG_ENTER("sequence_insert");
301
302 /*
303 seq is 0 if sequence was created with CREATE TABLE instead of
304 CREATE SEQUENCE
305 */
306 if (!seq)
307 {
308 if (!(seq= new (thd->mem_root) sequence_definition))
309 DBUG_RETURN(TRUE);
310 }
311
312 /* If not temporary table */
313 if (!temporary_table)
314 {
315 /*
316 The following code works like open_system_tables_for_read()
317 The idea is:
318 - Copy the table_list object for the sequence that was created
319 - Backup the current state of open tables and create a new
320 environment for open tables without any tables opened
321 - open the newly sequence table for write
322 This is safe as the sequence table has a mdl lock thanks to the
323 create sequence statement that is calling this function
324 */
325
326 table_list.init_one_table(&org_table_list->db,
327 &org_table_list->table_name,
328 NULL, TL_WRITE_DEFAULT);
329 table_list.updating= 1;
330 table_list.open_strategy= TABLE_LIST::OPEN_IF_EXISTS;
331 table_list.open_type= OT_BASE_ONLY;
332
333 DBUG_ASSERT(!thd->locked_tables_mode ||
334 (thd->variables.option_bits & OPTION_TABLE_LOCK));
335 lex->reset_n_backup_query_tables_list(&query_tables_list_backup);
336 thd->reset_n_backup_open_tables_state(&open_tables_backup);
337
338 /*
339 The FOR CREATE flag is needed to ensure that ha_open() doesn't try to
340 read the not yet existing row in the sequence table
341 */
342 thd->open_options|= HA_OPEN_FOR_CREATE;
343 /*
344 We have to reset the reprepare observer to be able to open the
345 table under prepared statements.
346 */
347 save_reprepare_observer= thd->m_reprepare_observer;
348 thd->m_reprepare_observer= 0;
349 lex->sql_command= SQLCOM_CREATE_SEQUENCE;
350 error= open_and_lock_tables(thd, &table_list, FALSE,
351 MYSQL_LOCK_IGNORE_TIMEOUT |
352 MYSQL_OPEN_HAS_MDL_LOCK);
353 thd->open_options&= ~HA_OPEN_FOR_CREATE;
354 thd->m_reprepare_observer= save_reprepare_observer;
355 if (unlikely(error))
356 {
357 lex->restore_backup_query_tables_list(&query_tables_list_backup);
358 thd->restore_backup_open_tables_state(&open_tables_backup);
359 DBUG_RETURN(error);
360 }
361 table= table_list.table;
362 }
363 else
364 table= org_table_list->table;
365
366 seq->reserved_until= seq->start;
367 error= seq->write_initial_sequence(table);
368 {
369 uint save_unsafe_rollback_flags=
370 thd->transaction->stmt.m_unsafe_rollback_flags;
371 if (trans_commit_stmt(thd))
372 error= 1;
373 thd->transaction->stmt.m_unsafe_rollback_flags=
374 save_unsafe_rollback_flags;
375 }
376 if (trans_commit_implicit(thd))
377 error= 1;
378
379 if (!temporary_table)
380 {
381 close_thread_tables(thd);
382 lex->restore_backup_query_tables_list(&query_tables_list_backup);
383 thd->restore_backup_open_tables_state(&open_tables_backup);
384
385 /* OPTION_TABLE_LOCK was reset in trans_commit_implicit */
386 if (thd->locked_tables_mode)
387 thd->variables.option_bits|= OPTION_TABLE_LOCK;
388 }
389 DBUG_RETURN(error);
390 }
391
392
393 /* Create a SQUENCE object */
394
SEQUENCE()395 SEQUENCE::SEQUENCE() :all_values_used(0), initialized(SEQ_UNINTIALIZED)
396 {
397 mysql_rwlock_init(key_LOCK_SEQUENCE, &mutex);
398 }
399
~SEQUENCE()400 SEQUENCE::~SEQUENCE()
401 {
402 mysql_rwlock_destroy(&mutex);
403 }
404
405 /*
406 The following functions is to ensure that we when reserve new values
407 trough sequence object sequence we have only one writer at at time.
408 A sequence table can have many readers (trough normal SELECT's).
409
410 We mark that we have a write lock in the table object so that
411 ha_sequence::ha_write() can check if we have a lock. If already locked, then
412 ha_write() knows that we are running a sequence operation. If not, then
413 ha_write() knows that it's an INSERT.
414 */
415
write_lock(TABLE * table)416 void SEQUENCE::write_lock(TABLE *table)
417 {
418 DBUG_ASSERT(((ha_sequence*) table->file)->is_locked() == 0);
419 mysql_rwlock_wrlock(&mutex);
420 ((ha_sequence*) table->file)->write_lock();
421 }
write_unlock(TABLE * table)422 void SEQUENCE::write_unlock(TABLE *table)
423 {
424 ((ha_sequence*) table->file)->unlock();
425 mysql_rwlock_unlock(&mutex);
426 }
read_lock(TABLE * table)427 void SEQUENCE::read_lock(TABLE *table)
428 {
429 if (!((ha_sequence*) table->file)->is_locked())
430 mysql_rwlock_rdlock(&mutex);
431 }
read_unlock(TABLE * table)432 void SEQUENCE::read_unlock(TABLE *table)
433 {
434 if (!((ha_sequence*) table->file)->is_locked())
435 mysql_rwlock_unlock(&mutex);
436 }
437
438 /**
439 Read values from the sequence tables to table_share->sequence.
440 This is called from ha_open() when the table is not yet locked
441 */
442
read_initial_values(TABLE * table)443 int SEQUENCE::read_initial_values(TABLE *table)
444 {
445 int error= 0;
446 enum thr_lock_type save_lock_type;
447 MDL_request mdl_request; // Empty constructor!
448 DBUG_ENTER("SEQUENCE::read_initial_values");
449
450 if (likely(initialized != SEQ_UNINTIALIZED))
451 DBUG_RETURN(0);
452 write_lock(table);
453 if (likely(initialized == SEQ_UNINTIALIZED))
454 {
455 MYSQL_LOCK *lock;
456 bool mdl_lock_used= 0;
457 THD *thd= table->in_use;
458 bool has_active_transaction= !thd->transaction->stmt.is_empty();
459 /*
460 There is already a mdl_ticket for this table. However, for list_fields
461 the MDL lock is of type MDL_SHARED_HIGH_PRIO which is not usable
462 for doing a table lock. Get a proper read lock to solve this.
463 */
464 if (table->mdl_ticket == 0)
465 {
466 MDL_request_list mdl_requests;
467 mdl_lock_used= 1;
468 /*
469 This happens if first request is SHOW CREATE TABLE or LIST FIELDS
470 where we don't have a mdl lock on the table
471 */
472
473 MDL_REQUEST_INIT(&mdl_request, MDL_key::TABLE, table->s->db.str,
474 table->s->table_name.str, MDL_SHARED_READ,
475 MDL_EXPLICIT);
476 mdl_requests.push_front(&mdl_request);
477 if (thd->mdl_context.acquire_locks(&mdl_requests,
478 thd->variables.lock_wait_timeout))
479 {
480 write_unlock(table);
481 DBUG_RETURN(HA_ERR_LOCK_WAIT_TIMEOUT);
482 }
483 }
484 save_lock_type= table->reginfo.lock_type;
485 table->reginfo.lock_type= TL_READ;
486 if (!(lock= mysql_lock_tables(thd, &table, 1,
487 MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY)))
488 {
489 if (mdl_lock_used)
490 thd->mdl_context.release_lock(mdl_request.ticket);
491 write_unlock(table);
492
493 if (!has_active_transaction && !thd->transaction->stmt.is_empty() &&
494 !thd->in_sub_stmt)
495 trans_commit_stmt(thd);
496 DBUG_RETURN(HA_ERR_LOCK_WAIT_TIMEOUT);
497 }
498 DBUG_ASSERT(table->reginfo.lock_type == TL_READ);
499 if (likely(!(error= read_stored_values(table))))
500 initialized= SEQ_READY_TO_USE;
501 mysql_unlock_tables(thd, lock);
502 if (mdl_lock_used)
503 thd->mdl_context.release_lock(mdl_request.ticket);
504
505 /* Reset value to default */
506 table->reginfo.lock_type= save_lock_type;
507 /*
508 Doing mysql_lock_tables() may have started a read only transaction.
509 If that happend, it's better that we commit it now, as a lot of
510 code assumes that there is no active stmt transaction directly after
511 open_tables().
512 But we also don't want to commit the stmt transaction while in a
513 substatement, see MDEV-15977.
514 */
515 if (!has_active_transaction && !thd->transaction->stmt.is_empty() &&
516 !thd->in_sub_stmt)
517 trans_commit_stmt(thd);
518 }
519 write_unlock(table);
520 DBUG_RETURN(error);
521 }
522
523
524 /*
525 Do the actiual reading of data from sequence table and
526 update values in the sequence object.
527
528 Called once from when table is opened
529 */
530
read_stored_values(TABLE * table)531 int SEQUENCE::read_stored_values(TABLE *table)
532 {
533 int error;
534 DBUG_ENTER("SEQUENCE::read_stored_values");
535
536 MY_BITMAP *save_read_set= tmp_use_all_columns(table, &table->read_set);
537 error= table->file->ha_read_first_row(table->record[0], MAX_KEY);
538 tmp_restore_column_map(&table->read_set, save_read_set);
539
540 if (unlikely(error))
541 {
542 table->file->print_error(error, MYF(0));
543 DBUG_RETURN(error);
544 }
545 read_fields(table);
546 adjust_values(reserved_until);
547
548 all_values_used= 0;
549 DBUG_RETURN(0);
550 }
551
552
553 /*
554 Adjust values after reading a the stored state
555 */
556
adjust_values(longlong next_value)557 void sequence_definition::adjust_values(longlong next_value)
558 {
559 next_free_value= next_value;
560 if (!(real_increment= increment))
561 {
562 longlong offset= 0;
563 longlong off, to_add;
564 /* Use auto_increment_increment and auto_increment_offset */
565
566 if ((real_increment= global_system_variables.auto_increment_increment)
567 != 1)
568 offset= (global_system_variables.auto_increment_offset %
569 global_system_variables.auto_increment_increment);
570
571 /*
572 Ensure that next_free_value has the right offset, so that we
573 can generate a serie by just adding real_increment.
574 */
575 off= next_free_value % real_increment;
576 if (off < 0)
577 off+= real_increment;
578 to_add= (real_increment + offset - off) % real_increment;
579
580 /*
581 Check if add will make next_free_value bigger than max_value,
582 taken into account that next_free_value or max_value addition
583 may overflow
584 */
585 if (next_free_value > max_value - to_add ||
586 next_free_value + to_add > max_value)
587 next_free_value= max_value+1;
588 else
589 {
590 next_free_value+= to_add;
591 DBUG_ASSERT(llabs(next_free_value % real_increment) == offset);
592 }
593 }
594 }
595
596
597 /**
598 Write initial sequence information for CREATE and ALTER to sequence table
599 */
600
write_initial_sequence(TABLE * table)601 int sequence_definition::write_initial_sequence(TABLE *table)
602 {
603 int error;
604 MY_BITMAP *save_write_set;
605
606 store_fields(table);
607 /* Store the sequence values in table share */
608 table->s->sequence->copy(this);
609 /*
610 Sequence values will be replicated as a statement
611 like 'create sequence'. So disable row logging for this table & statement
612 */
613 table->file->row_logging= table->file->row_logging_init= 0;
614 save_write_set= table->write_set;
615 table->write_set= &table->s->all_set;
616 table->s->sequence->initialized= SEQUENCE::SEQ_IN_PREPARE;
617 error= table->file->ha_write_row(table->record[0]);
618 table->s->sequence->initialized= SEQUENCE::SEQ_UNINTIALIZED;
619 table->write_set= save_write_set;
620 if (unlikely(error))
621 table->file->print_error(error, MYF(0));
622 else
623 {
624 /*
625 Sequence structure is up to date and table has one row,
626 sequence is now usable
627 */
628 table->s->sequence->initialized= SEQUENCE::SEQ_READY_TO_USE;
629 }
630 return error;
631 }
632
633
634 /**
635 Store current sequence values into the sequence table
636 */
637
write(TABLE * table,bool all_fields)638 int sequence_definition::write(TABLE *table, bool all_fields)
639 {
640 int error;
641 MY_BITMAP *save_rpl_write_set, *save_write_set, *save_read_set;
642 DBUG_ASSERT(((ha_sequence*) table->file)->is_locked());
643
644 save_rpl_write_set= table->rpl_write_set;
645 if (likely(!all_fields))
646 {
647 /* Only write next_value and round to binary log */
648 table->rpl_write_set= &table->def_rpl_write_set;
649 bitmap_clear_all(table->rpl_write_set);
650 bitmap_set_bit(table->rpl_write_set, NEXT_FIELD_NO);
651 bitmap_set_bit(table->rpl_write_set, ROUND_FIELD_NO);
652 }
653 else
654 table->rpl_write_set= &table->s->all_set;
655
656 /* Update table */
657 save_write_set= table->write_set;
658 save_read_set= table->read_set;
659 table->read_set= table->write_set= &table->s->all_set;
660 table->file->column_bitmaps_signal();
661 store_fields(table);
662 if (unlikely((error= table->file->ha_write_row(table->record[0]))))
663 table->file->print_error(error, MYF(0));
664 table->rpl_write_set= save_rpl_write_set;
665 table->read_set= save_read_set;
666 table->write_set= save_write_set;
667 table->file->column_bitmaps_signal();
668 return error;
669 }
670
671
672 /**
673 Get next value for sequence
674
675 @param in table Sequence table
676 @param in second_round
677 1 if recursive call (out of values once)
678 @param out error Set this to <> 0 in case of error
679 push_warning_printf(WARN_LEVEL_WARN) has been called
680
681
682 @retval 0 Next number or error. Check error variable
683 # Next sequence number
684
685 NOTES:
686 Return next_free_value and increment next_free_value to next allowed
687 value or reserved_value if out of range
688 if next_free_value >= reserved_value reserve a new range by writing
689 a record to the sequence table.
690
691 The state of the variables:
692 next_free_value contains next value to use. It may be
693 bigger than max_value or less than min_value if end of sequence.
694 reserved_until contains the last value written to the file. All
695 values up to this one can be used.
696 If next_free_value >= reserved_until we have to reserve new
697 values from the sequence.
698 */
699
next_value(TABLE * table,bool second_round,int * error)700 longlong SEQUENCE::next_value(TABLE *table, bool second_round, int *error)
701 {
702 longlong res_value, org_reserved_until, add_to;
703 bool out_of_values;
704 DBUG_ENTER("SEQUENCE::next_value");
705
706 *error= 0;
707 if (!second_round)
708 write_lock(table);
709
710 res_value= next_free_value;
711 next_free_value= increment_value(next_free_value);
712
713 if ((real_increment > 0 && res_value < reserved_until) ||
714 (real_increment < 0 && res_value > reserved_until))
715 {
716 write_unlock(table);
717 DBUG_RETURN(res_value);
718 }
719
720 if (all_values_used)
721 goto err;
722
723 org_reserved_until= reserved_until;
724
725 /*
726 Out of cached values, reserve 'cache' new ones
727 The cache value is checked on insert so the following can't
728 overflow
729 */
730 add_to= cache ? real_increment * cache : real_increment;
731 out_of_values= 0;
732
733 if (real_increment > 0)
734 {
735 if (reserved_until > max_value - add_to ||
736 reserved_until + add_to > max_value)
737 {
738 reserved_until= max_value + 1;
739 out_of_values= res_value >= reserved_until;
740 }
741 else
742 reserved_until+= add_to;
743 }
744 else
745 {
746 if (reserved_until + add_to < min_value ||
747 reserved_until < min_value - add_to)
748 {
749 reserved_until= min_value - 1;
750 out_of_values= res_value <= reserved_until;
751 }
752 else
753 reserved_until+= add_to;
754 }
755 if (out_of_values)
756 {
757 if (!cycle || second_round)
758 goto err;
759 round++;
760 reserved_until= real_increment >0 ? min_value : max_value;
761 adjust_values(reserved_until); // Fix next_free_value
762 /*
763 We have to do everything again to ensure that the given range was
764 not empty, which could happen if increment == 0
765 */
766 DBUG_RETURN(next_value(table, 1, error));
767 }
768
769 if (unlikely((*error= write(table, 0))))
770 {
771 reserved_until= org_reserved_until;
772 next_free_value= res_value;
773 }
774
775 write_unlock(table);
776 DBUG_RETURN(res_value);
777
778 err:
779 write_unlock(table);
780 my_error(ER_SEQUENCE_RUN_OUT, MYF(0), table->s->db.str,
781 table->s->table_name.str);
782 *error= ER_SEQUENCE_RUN_OUT;
783 all_values_used= 1;
784 DBUG_RETURN(0);
785 }
786
787
788 /*
789 The following functions is to detect if a table has been dropped
790 and re-created since last call to PREVIOUS VALUE.
791
792 This is needed as we don't delete dropped sequences from THD->sequence
793 for DROP TABLE.
794 */
795
check_version(TABLE * table)796 bool SEQUENCE_LAST_VALUE::check_version(TABLE *table)
797 {
798 DBUG_ASSERT(table->s->tabledef_version.length == MY_UUID_SIZE);
799 return memcmp(table->s->tabledef_version.str, table_version,
800 MY_UUID_SIZE) != 0;
801 }
802
set_version(TABLE * table)803 void SEQUENCE_LAST_VALUE::set_version(TABLE *table)
804 {
805 memcpy(table_version, table->s->tabledef_version.str, MY_UUID_SIZE);
806 }
807
808 /**
809 Set the next value for sequence
810
811 @param in table Sequence table
812 @param in next_val Next free value
813 @param in next_round Round for 'next_value' (in case of cycles)
814 @param in is_used 1 if next_val is already used
815
816 @retval 0 ok, value adjusted
817 -1 value was less than current value
818 1 error when storing value
819
820 @comment
821 A new value is set only if "nextval,next_round" is less than
822 "next_free_value,round". This is needed as in replication
823 setvalue() calls may come out to the slave out-of-order.
824 Storing only the highest value ensures that sequence object will always
825 contain the highest used value when the slave is promoted to a master.
826 */
827
set_value(TABLE * table,longlong next_val,ulonglong next_round,bool is_used)828 int SEQUENCE::set_value(TABLE *table, longlong next_val, ulonglong next_round,
829 bool is_used)
830 {
831 int error= -1;
832 bool needs_to_be_stored= 0;
833 longlong org_reserved_until= reserved_until;
834 longlong org_next_free_value= next_free_value;
835 ulonglong org_round= round;
836 DBUG_ENTER("SEQUENCE::set_value");
837
838 write_lock(table);
839 if (is_used)
840 next_val= increment_value(next_val);
841
842 if (round > next_round)
843 goto end; // error = -1
844 if (round == next_round)
845 {
846 if (real_increment > 0 ?
847 next_val < next_free_value :
848 next_val > next_free_value)
849 goto end; // error = -1
850 if (next_val == next_free_value)
851 {
852 error= 0;
853 goto end;
854 }
855 }
856 else if (cycle == 0)
857 {
858 // round < next_round && no cycles, which is impossible
859 my_error(ER_SEQUENCE_RUN_OUT, MYF(0), table->s->db.str,
860 table->s->table_name.str);
861 error= 1;
862 goto end;
863 }
864 else
865 needs_to_be_stored= 1;
866
867 round= next_round;
868 adjust_values(next_val);
869 if ((real_increment > 0 ?
870 next_free_value > reserved_until :
871 next_free_value < reserved_until) ||
872 needs_to_be_stored)
873 {
874 reserved_until= next_free_value;
875 if (write(table, 0))
876 {
877 reserved_until= org_reserved_until;
878 next_free_value= org_next_free_value;
879 round= org_round;
880 error= 1;
881 goto end;
882 }
883 }
884 error= 0;
885
886 end:
887 write_unlock(table);
888 DBUG_RETURN(error);
889 }
890
891
execute(THD * thd)892 bool Sql_cmd_alter_sequence::execute(THD *thd)
893 {
894 int error= 0;
895 int trapped_errors= 0;
896 LEX *lex= thd->lex;
897 TABLE_LIST *first_table= lex->query_tables;
898 TABLE *table;
899 sequence_definition *new_seq= lex->create_info.seq_create_info;
900 SEQUENCE *seq;
901 No_such_table_error_handler no_such_table_handler;
902 DBUG_ENTER("Sql_cmd_alter_sequence::execute");
903
904 if (check_access(thd, ALTER_ACL, first_table->db.str,
905 &first_table->grant.privilege,
906 &first_table->grant.m_internal,
907 0, 0))
908 DBUG_RETURN(TRUE); /* purecov: inspected */
909
910 if (check_grant(thd, ALTER_ACL, first_table, FALSE, 1, FALSE))
911 DBUG_RETURN(TRUE); /* purecov: inspected */
912
913 #ifdef WITH_WSREP
914 if (WSREP_ON && WSREP(thd) &&
915 wsrep_to_isolation_begin(thd, first_table->db.str,
916 first_table->table_name.str,
917 first_table))
918 DBUG_RETURN(TRUE);
919 #endif /* WITH_WSREP */
920 if (if_exists())
921 thd->push_internal_handler(&no_such_table_handler);
922 error= open_and_lock_tables(thd, first_table, FALSE, 0);
923 if (if_exists())
924 {
925 trapped_errors= no_such_table_handler.safely_trapped_errors();
926 thd->pop_internal_handler();
927 }
928 if (unlikely(error))
929 {
930 if (trapped_errors)
931 {
932 StringBuffer<FN_REFLEN> tbl_name;
933 tbl_name.append(&first_table->db);
934 tbl_name.append('.');
935 tbl_name.append(&first_table->table_name);
936 push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
937 ER_UNKNOWN_SEQUENCES,
938 ER_THD(thd, ER_UNKNOWN_SEQUENCES),
939 tbl_name.c_ptr_safe());
940 my_ok(thd);
941 DBUG_RETURN(FALSE);
942 }
943 DBUG_RETURN(TRUE);
944 }
945
946 table= first_table->table;
947 seq= table->s->sequence;
948
949 seq->write_lock(table);
950 new_seq->reserved_until= seq->reserved_until;
951
952 /* Copy from old sequence those fields that the user didn't specified */
953 if (!(new_seq->used_fields & seq_field_used_increment))
954 new_seq->increment= seq->increment;
955 if (!(new_seq->used_fields & seq_field_used_min_value))
956 new_seq->min_value= seq->min_value;
957 if (!(new_seq->used_fields & seq_field_used_max_value))
958 new_seq->max_value= seq->max_value;
959 if (!(new_seq->used_fields & seq_field_used_start))
960 new_seq->start= seq->start;
961 if (!(new_seq->used_fields & seq_field_used_cache))
962 new_seq->cache= seq->cache;
963 if (!(new_seq->used_fields & seq_field_used_cycle))
964 new_seq->cycle= seq->cycle;
965
966 /* If we should restart from a new value */
967 if (new_seq->used_fields & seq_field_used_restart)
968 {
969 if (!(new_seq->used_fields & seq_field_used_restart_value))
970 new_seq->restart= new_seq->start;
971 new_seq->reserved_until= new_seq->restart;
972 }
973
974 /* Let check_and_adjust think all fields are used */
975 new_seq->used_fields= ~0;
976 if (new_seq->check_and_adjust(0))
977 {
978 my_error(ER_SEQUENCE_INVALID_DATA, MYF(0),
979 first_table->db.str,
980 first_table->table_name.str);
981 error= 1;
982 seq->write_unlock(table);
983 goto end;
984 }
985
986 if (likely(!(error= new_seq->write(table, 1))))
987 {
988 /* Store the sequence values in table share */
989 seq->copy(new_seq);
990 }
991 else
992 table->file->print_error(error, MYF(0));
993 seq->write_unlock(table);
994 if (trans_commit_stmt(thd))
995 error= 1;
996 if (trans_commit_implicit(thd))
997 error= 1;
998 if (likely(!error))
999 error= write_bin_log(thd, 1, thd->query(), thd->query_length());
1000 if (likely(!error))
1001 my_ok(thd);
1002
1003 end:
1004 DBUG_RETURN(error);
1005 }
1006