1 /*****************************************************************************
2
3 Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
4 Copyright (c) 2017, 2021, MariaDB Corporation.
5
6 This program is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free Software
8 Foundation; version 2 of the License.
9
10 This program is distributed in the hope that it will be useful, but WITHOUT
11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along with
15 this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
17
18 *****************************************************************************/
19
20 /**************************************************//**
21 @file que/que0que.cc
22 Query graph
23
24 Created 5/27/1996 Heikki Tuuri
25 *******************************************************/
26
27 #include "que0que.h"
28 #include "trx0trx.h"
29 #include "trx0roll.h"
30 #include "row0undo.h"
31 #include "row0ins.h"
32 #include "row0upd.h"
33 #include "row0sel.h"
34 #include "row0purge.h"
35 #include "dict0crea.h"
36 #include "log0log.h"
37 #include "eval0proc.h"
38
39 #define QUE_MAX_LOOPS_WITHOUT_CHECK 16
40
41 /* Short introduction to query graphs
42 ==================================
43
44 A query graph consists of nodes linked to each other in various ways. The
45 execution starts at que_run_threads() which takes a que_thr_t parameter.
46 que_thr_t contains two fields that control query graph execution: run_node
47 and prev_node. run_node is the next node to execute and prev_node is the
48 last node executed.
49
50 Each node has a pointer to a 'next' statement, i.e., its brother, and a
51 pointer to its parent node. The next pointer is NULL in the last statement
52 of a block.
53
54 Loop nodes contain a link to the first statement of the enclosed statement
55 list. While the loop runs, que_thr_step() checks if execution to the loop
56 node came from its parent or from one of the statement nodes in the loop. If
57 it came from the parent of the loop node it starts executing the first
58 statement node in the loop. If it came from one of the statement nodes in
59 the loop, then it checks if the statement node has another statement node
60 following it, and runs it if so.
61
62 To signify loop ending, the loop statements (see e.g. while_step()) set
63 que_thr_t->run_node to the loop node's parent node. This is noticed on the
64 next call of que_thr_step() and execution proceeds to the node pointed to by
65 the loop node's 'next' pointer.
66
67 For example, the code:
68
69 X := 1;
70 WHILE X < 5 LOOP
71 X := X + 1;
72 X := X + 1;
73 X := 5
74
75 will result in the following node hierarchy, with the X-axis indicating
76 'next' links and the Y-axis indicating parent/child links:
77
78 A - W - A
79 |
80 |
81 A - A
82
83 A = assign_node_t, W = while_node_t. */
84
85 /* How a stored procedure containing COMMIT or ROLLBACK commands
86 is executed?
87
88 The commit or rollback can be seen as a subprocedure call.
89
90 When the transaction starts to handle a rollback or commit.
91 It builds a query graph which, when executed, will roll back
92 or commit the incomplete transaction. The transaction
93 is moved to the TRX_QUE_ROLLING_BACK or TRX_QUE_COMMITTING state.
94 If specified, the SQL cursors opened by the transaction are closed.
95 When the execution of the graph completes, it is like returning
96 from a subprocedure: the query thread which requested the operation
97 starts running again. */
98
99 /**********************************************************************//**
100 Moves a thread from another state to the QUE_THR_RUNNING state. Increments
101 the n_active_thrs counters of the query graph and transaction.
102 ***NOTE***: This is the only function in which such a transition is allowed
103 to happen! */
104 static
105 void
106 que_thr_move_to_run_state(
107 /*======================*/
108 que_thr_t* thr); /*!< in: an query thread */
109
110 /***********************************************************************//**
111 Creates a query graph fork node.
112 @return own: fork node */
113 que_fork_t*
que_fork_create(que_t * graph,que_node_t * parent,ulint fork_type,mem_heap_t * heap)114 que_fork_create(
115 /*============*/
116 que_t* graph, /*!< in: graph, if NULL then this
117 fork node is assumed to be the
118 graph root */
119 que_node_t* parent, /*!< in: parent node */
120 ulint fork_type, /*!< in: fork type */
121 mem_heap_t* heap) /*!< in: memory heap where created */
122 {
123 que_fork_t* fork;
124
125 ut_ad(heap);
126
127 fork = static_cast<que_fork_t*>(mem_heap_zalloc(heap, sizeof(*fork)));
128
129 fork->heap = heap;
130
131 fork->fork_type = fork_type;
132
133 fork->common.parent = parent;
134
135 fork->common.type = QUE_NODE_FORK;
136
137 fork->state = QUE_FORK_COMMAND_WAIT;
138
139 fork->graph = (graph != NULL) ? graph : fork;
140
141 UT_LIST_INIT(fork->thrs, &que_thr_t::thrs);
142
143 return(fork);
144 }
145
146
147 /** Creates a query graph thread node.
148 @param[in] parent parent node, i.e., a fork node
149 @param[in] heap memory heap where created
150 @param[in] prebuilt row prebuilt structure
151 @return own: query thread node */
152 que_thr_t*
que_thr_create(que_fork_t * parent,mem_heap_t * heap,row_prebuilt_t * prebuilt)153 que_thr_create(
154 que_fork_t* parent,
155 mem_heap_t* heap,
156 row_prebuilt_t* prebuilt)
157 {
158 que_thr_t* thr;
159
160 ut_ad(parent != NULL);
161 ut_ad(heap != NULL);
162
163 thr = static_cast<que_thr_t*>(mem_heap_zalloc(heap, sizeof(*thr)));
164
165 thr->graph = parent->graph;
166
167 thr->common.parent = parent;
168
169 thr->magic_n = QUE_THR_MAGIC_N;
170
171 thr->common.type = QUE_NODE_THR;
172
173 thr->state = QUE_THR_COMMAND_WAIT;
174
175 thr->lock_state = QUE_THR_LOCK_NOLOCK;
176
177 thr->prebuilt = prebuilt;
178
179 UT_LIST_ADD_LAST(parent->thrs, thr);
180
181 return(thr);
182 }
183
184 /**********************************************************************//**
185 Moves a suspended query thread to the QUE_THR_RUNNING state and may release
186 a worker thread to execute it. This function should be used to end
187 the wait state of a query thread waiting for a lock or a stored procedure
188 completion.
189 @return the query thread that needs to be released. */
190 que_thr_t*
que_thr_end_lock_wait(trx_t * trx)191 que_thr_end_lock_wait(
192 /*==================*/
193 trx_t* trx) /*!< in: transaction with que_state in
194 QUE_THR_LOCK_WAIT */
195 {
196 que_thr_t* thr;
197 ibool was_active;
198
199 ut_ad(lock_mutex_own());
200 ut_ad(trx_mutex_own(trx));
201
202 thr = trx->lock.wait_thr;
203
204 ut_ad(thr != NULL);
205
206 ut_ad(trx->lock.que_state == TRX_QUE_LOCK_WAIT);
207 /* In MySQL this is the only possible state here */
208 ut_a(thr->state == QUE_THR_LOCK_WAIT);
209
210 was_active = thr->is_active;
211
212 que_thr_move_to_run_state(thr);
213
214 trx->lock.que_state = TRX_QUE_RUNNING;
215
216 trx->lock.wait_thr = NULL;
217
218 /* In MySQL we let the OS thread (not just the query thread) to wait
219 for the lock to be released: */
220
221 return((!was_active && thr != NULL) ? thr : NULL);
222 }
223
224 /**********************************************************************//**
225 Inits a query thread for a command. */
226 UNIV_INLINE
227 void
que_thr_init_command(que_thr_t * thr)228 que_thr_init_command(
229 /*=================*/
230 que_thr_t* thr) /*!< in: query thread */
231 {
232 thr->run_node = thr;
233 thr->prev_node = thr->common.parent;
234
235 que_thr_move_to_run_state(thr);
236 }
237
238 /**********************************************************************//**
239 Round robin scheduler.
240 @return a query thread of the graph moved to QUE_THR_RUNNING state, or
241 NULL; the query thread should be executed by que_run_threads by the
242 caller */
243 que_thr_t*
que_fork_scheduler_round_robin(que_fork_t * fork,que_thr_t * thr)244 que_fork_scheduler_round_robin(
245 /*===========================*/
246 que_fork_t* fork, /*!< in: a query fork */
247 que_thr_t* thr) /*!< in: current pos */
248 {
249 trx_mutex_enter(fork->trx);
250
251 /* If no current, start first available. */
252 if (thr == NULL) {
253 thr = UT_LIST_GET_FIRST(fork->thrs);
254 } else {
255 thr = UT_LIST_GET_NEXT(thrs, thr);
256 }
257
258 if (thr) {
259
260 fork->state = QUE_FORK_ACTIVE;
261
262 fork->last_sel_node = NULL;
263
264 switch (thr->state) {
265 case QUE_THR_COMMAND_WAIT:
266 case QUE_THR_COMPLETED:
267 ut_a(!thr->is_active);
268 que_thr_init_command(thr);
269 break;
270
271 case QUE_THR_SUSPENDED:
272 case QUE_THR_LOCK_WAIT:
273 default:
274 ut_error;
275
276 }
277 }
278
279 trx_mutex_exit(fork->trx);
280
281 return(thr);
282 }
283
284 /**********************************************************************//**
285 Starts execution of a command in a query fork. Picks a query thread which
286 is not in the QUE_THR_RUNNING state and moves it to that state. If none
287 can be chosen, a situation which may arise in parallelized fetches, NULL
288 is returned.
289 @return a query thread of the graph moved to QUE_THR_RUNNING state, or
290 NULL; the query thread should be executed by que_run_threads by the
291 caller */
292 que_thr_t*
que_fork_start_command(que_fork_t * fork)293 que_fork_start_command(
294 /*===================*/
295 que_fork_t* fork) /*!< in: a query fork */
296 {
297 que_thr_t* thr;
298 que_thr_t* suspended_thr = NULL;
299 que_thr_t* completed_thr = NULL;
300
301 fork->state = QUE_FORK_ACTIVE;
302
303 fork->last_sel_node = NULL;
304
305 suspended_thr = NULL;
306 completed_thr = NULL;
307
308 /* Choose the query thread to run: usually there is just one thread,
309 but in a parallelized select, which necessarily is non-scrollable,
310 there may be several to choose from */
311
312 /* First we try to find a query thread in the QUE_THR_COMMAND_WAIT
313 state. Then we try to find a query thread in the QUE_THR_SUSPENDED
314 state, finally we try to find a query thread in the QUE_THR_COMPLETED
315 state */
316
317 /* We make a single pass over the thr list within which we note which
318 threads are ready to run. */
319 for (thr = UT_LIST_GET_FIRST(fork->thrs);
320 thr != NULL;
321 thr = UT_LIST_GET_NEXT(thrs, thr)) {
322
323 switch (thr->state) {
324 case QUE_THR_COMMAND_WAIT:
325
326 /* We have to send the initial message to query thread
327 to start it */
328
329 que_thr_init_command(thr);
330
331 return(thr);
332
333 case QUE_THR_SUSPENDED:
334 /* In this case the execution of the thread was
335 suspended: no initial message is needed because
336 execution can continue from where it was left */
337 if (!suspended_thr) {
338 suspended_thr = thr;
339 }
340
341 break;
342
343 case QUE_THR_COMPLETED:
344 if (!completed_thr) {
345 completed_thr = thr;
346 }
347
348 break;
349
350 case QUE_THR_RUNNING:
351 case QUE_THR_LOCK_WAIT:
352 ut_error;
353 }
354 }
355
356 if (suspended_thr) {
357
358 thr = suspended_thr;
359 que_thr_move_to_run_state(thr);
360
361 } else if (completed_thr) {
362
363 thr = completed_thr;
364 que_thr_init_command(thr);
365 } else {
366 ut_error;
367 }
368
369 return(thr);
370 }
371
372 /**********************************************************************//**
373 Calls que_graph_free_recursive for statements in a statement list. */
374 static
375 void
que_graph_free_stat_list(que_node_t * node)376 que_graph_free_stat_list(
377 /*=====================*/
378 que_node_t* node) /*!< in: first query graph node in the list */
379 {
380 while (node) {
381 que_graph_free_recursive(node);
382
383 node = que_node_get_next(node);
384 }
385 }
386
387 /**********************************************************************//**
388 Frees a query graph, but not the heap where it was created. Does not free
389 explicit cursor declarations, they are freed in que_graph_free. */
390 void
que_graph_free_recursive(que_node_t * node)391 que_graph_free_recursive(
392 /*=====================*/
393 que_node_t* node) /*!< in: query graph node */
394 {
395 que_fork_t* fork;
396 que_thr_t* thr;
397 undo_node_t* undo;
398 sel_node_t* sel;
399 ins_node_t* ins;
400 upd_node_t* upd;
401 tab_node_t* cre_tab;
402 ind_node_t* cre_ind;
403 purge_node_t* purge;
404
405 DBUG_ENTER("que_graph_free_recursive");
406
407 if (node == NULL) {
408
409 DBUG_VOID_RETURN;
410 }
411
412 DBUG_PRINT("que_graph_free_recursive",
413 ("node: %p, type: " ULINTPF, node,
414 que_node_get_type(node)));
415
416 switch (que_node_get_type(node)) {
417
418 case QUE_NODE_FORK:
419 fork = static_cast<que_fork_t*>(node);
420
421 thr = UT_LIST_GET_FIRST(fork->thrs);
422
423 while (thr) {
424 que_graph_free_recursive(thr);
425
426 thr = UT_LIST_GET_NEXT(thrs, thr);
427 }
428
429 break;
430 case QUE_NODE_THR:
431
432 thr = static_cast<que_thr_t*>(node);
433
434 ut_a(thr->magic_n == QUE_THR_MAGIC_N);
435
436 thr->magic_n = QUE_THR_MAGIC_FREED;
437
438 que_graph_free_recursive(thr->child);
439
440 break;
441 case QUE_NODE_UNDO:
442
443 undo = static_cast<undo_node_t*>(node);
444
445 mem_heap_free(undo->heap);
446
447 break;
448 case QUE_NODE_SELECT:
449
450 sel = static_cast<sel_node_t*>(node);
451
452 sel_node_free_private(sel);
453
454 break;
455 case QUE_NODE_INSERT:
456
457 ins = static_cast<ins_node_t*>(node);
458
459 que_graph_free_recursive(ins->select);
460 ins->select = NULL;
461
462 ins->~ins_node_t();
463
464 if (ins->entry_sys_heap != NULL) {
465 mem_heap_free(ins->entry_sys_heap);
466 ins->entry_sys_heap = NULL;
467 }
468
469 break;
470 case QUE_NODE_PURGE:
471 purge = static_cast<purge_node_t*>(node);
472
473 mem_heap_free(purge->heap);
474
475 break;
476
477 case QUE_NODE_UPDATE:
478 upd = static_cast<upd_node_t*>(node);
479
480 if (upd->in_mysql_interface) {
481
482 btr_pcur_free_for_mysql(upd->pcur);
483 upd->in_mysql_interface = false;
484 }
485
486 que_graph_free_recursive(upd->cascade_node);
487
488 if (upd->cascade_heap) {
489 mem_heap_free(upd->cascade_heap);
490 upd->cascade_heap = NULL;
491 }
492
493 que_graph_free_recursive(upd->select);
494 upd->select = NULL;
495
496 if (upd->heap != NULL) {
497 mem_heap_free(upd->heap);
498 upd->heap = NULL;
499 }
500
501 break;
502 case QUE_NODE_CREATE_TABLE:
503 cre_tab = static_cast<tab_node_t*>(node);
504
505 que_graph_free_recursive(cre_tab->tab_def);
506 que_graph_free_recursive(cre_tab->col_def);
507 que_graph_free_recursive(cre_tab->v_col_def);
508
509 mem_heap_free(cre_tab->heap);
510
511 break;
512 case QUE_NODE_CREATE_INDEX:
513 cre_ind = static_cast<ind_node_t*>(node);
514
515 que_graph_free_recursive(cre_ind->ind_def);
516 que_graph_free_recursive(cre_ind->field_def);
517
518 mem_heap_free(cre_ind->heap);
519
520 break;
521 case QUE_NODE_PROC:
522 que_graph_free_stat_list(((proc_node_t*) node)->stat_list);
523
524 break;
525 case QUE_NODE_IF:
526 que_graph_free_stat_list(((if_node_t*) node)->stat_list);
527 que_graph_free_stat_list(((if_node_t*) node)->else_part);
528 que_graph_free_stat_list(((if_node_t*) node)->elsif_list);
529
530 break;
531 case QUE_NODE_ELSIF:
532 que_graph_free_stat_list(((elsif_node_t*) node)->stat_list);
533
534 break;
535 case QUE_NODE_WHILE:
536 que_graph_free_stat_list(((while_node_t*) node)->stat_list);
537
538 break;
539 case QUE_NODE_FOR:
540 que_graph_free_stat_list(((for_node_t*) node)->stat_list);
541
542 break;
543
544 case QUE_NODE_ASSIGNMENT:
545 case QUE_NODE_EXIT:
546 case QUE_NODE_RETURN:
547 case QUE_NODE_COMMIT:
548 case QUE_NODE_ROLLBACK:
549 case QUE_NODE_LOCK:
550 case QUE_NODE_FUNC:
551 case QUE_NODE_ORDER:
552 case QUE_NODE_ROW_PRINTF:
553 case QUE_NODE_OPEN:
554 case QUE_NODE_FETCH:
555 /* No need to do anything */
556
557 break;
558 default:
559 ut_error;
560 }
561
562 DBUG_VOID_RETURN;
563 }
564
565 /**********************************************************************//**
566 Frees a query graph. */
567 void
que_graph_free(que_t * graph)568 que_graph_free(
569 /*===========*/
570 que_t* graph) /*!< in: query graph; we assume that the memory
571 heap where this graph was created is private
572 to this graph: if not, then use
573 que_graph_free_recursive and free the heap
574 afterwards! */
575 {
576 ut_ad(graph);
577
578 if (graph->sym_tab) {
579 /* The following call frees dynamic memory allocated
580 for variables etc. during execution. Frees also explicit
581 cursor definitions. */
582
583 sym_tab_free_private(graph->sym_tab);
584 }
585
586 if (graph->info && graph->info->graph_owns_us) {
587 pars_info_free(graph->info);
588 }
589
590 que_graph_free_recursive(graph);
591
592 mem_heap_free(graph->heap);
593 }
594
595 /****************************************************************//**
596 Performs an execution step on a thr node.
597 @return query thread to run next, or NULL if none */
598 static
599 que_thr_t*
que_thr_node_step(que_thr_t * thr)600 que_thr_node_step(
601 /*==============*/
602 que_thr_t* thr) /*!< in: query thread where run_node must
603 be the thread node itself */
604 {
605 ut_ad(thr->run_node == thr);
606
607 if (thr->prev_node == thr->common.parent) {
608 /* If control to the node came from above, it is just passed
609 on */
610
611 thr->run_node = thr->child;
612
613 return(thr);
614 }
615
616 trx_mutex_enter(thr_get_trx(thr));
617
618 if (que_thr_peek_stop(thr)) {
619
620 trx_mutex_exit(thr_get_trx(thr));
621
622 return(thr);
623 }
624
625 /* Thread execution completed */
626
627 thr->state = QUE_THR_COMPLETED;
628
629 trx_mutex_exit(thr_get_trx(thr));
630
631 return(NULL);
632 }
633
634 /**********************************************************************//**
635 Moves a thread from another state to the QUE_THR_RUNNING state. Increments
636 the n_active_thrs counters of the query graph and transaction if thr was
637 not active.
638 ***NOTE***: This and ..._mysql are the only functions in which such a
639 transition is allowed to happen! */
640 static
641 void
que_thr_move_to_run_state(que_thr_t * thr)642 que_thr_move_to_run_state(
643 /*======================*/
644 que_thr_t* thr) /*!< in: an query thread */
645 {
646 ut_ad(thr->state != QUE_THR_RUNNING);
647
648 if (!thr->is_active) {
649 trx_t* trx;
650
651 trx = thr_get_trx(thr);
652
653 thr->graph->n_active_thrs++;
654
655 trx->lock.n_active_thrs++;
656
657 thr->is_active = TRUE;
658 }
659
660 thr->state = QUE_THR_RUNNING;
661 }
662
663 /**********************************************************************//**
664 Stops a query thread if graph or trx is in a state requiring it. The
665 conditions are tested in the order (1) graph, (2) trx.
666 @return TRUE if stopped */
667 ibool
que_thr_stop(que_thr_t * thr)668 que_thr_stop(
669 /*=========*/
670 que_thr_t* thr) /*!< in: query thread */
671 {
672 que_t* graph;
673 trx_t* trx = thr_get_trx(thr);
674
675 graph = thr->graph;
676
677 ut_ad(trx_mutex_own(trx));
678
679 if (graph->state == QUE_FORK_COMMAND_WAIT) {
680
681 thr->state = QUE_THR_SUSPENDED;
682
683 } else if (trx->lock.que_state == TRX_QUE_LOCK_WAIT) {
684
685 trx->lock.wait_thr = thr;
686 thr->state = QUE_THR_LOCK_WAIT;
687
688 } else if (trx->error_state != DB_SUCCESS
689 && trx->error_state != DB_LOCK_WAIT) {
690
691 /* Error handling built for the MySQL interface */
692 thr->state = QUE_THR_COMPLETED;
693
694 } else if (graph->fork_type == QUE_FORK_ROLLBACK) {
695
696 thr->state = QUE_THR_SUSPENDED;
697 } else {
698 ut_ad(graph->state == QUE_FORK_ACTIVE);
699
700 return(FALSE);
701 }
702
703 return(TRUE);
704 }
705
706 /**********************************************************************//**
707 Decrements the query thread reference counts in the query graph and the
708 transaction.
709 *** NOTE ***:
710 This and que_thr_stop_for_mysql are the only functions where the reference
711 count can be decremented and this function may only be called from inside
712 que_run_threads! These restrictions exist to make the rollback code easier
713 to maintain. */
714 static
715 void
que_thr_dec_refer_count(que_thr_t * thr,que_thr_t ** next_thr)716 que_thr_dec_refer_count(
717 /*====================*/
718 que_thr_t* thr, /*!< in: query thread */
719 que_thr_t** next_thr) /*!< in/out: next query thread to run;
720 if the value which is passed in is
721 a pointer to a NULL pointer, then the
722 calling function can start running
723 a new query thread */
724 {
725 trx_t* trx;
726 que_fork_t* fork;
727
728 trx = thr_get_trx(thr);
729
730 ut_a(thr->is_active);
731 ut_ad(trx_mutex_own(trx));
732
733 if (thr->state == QUE_THR_RUNNING) {
734
735 if (!que_thr_stop(thr)) {
736
737 ut_a(next_thr != NULL && *next_thr == NULL);
738
739 /* The reason for the thr suspension or wait was
740 already canceled before we came here: continue
741 running the thread.
742
743 This is also possible because in trx_commit_step() we
744 assume a single query thread. We set the query thread
745 state to QUE_THR_RUNNING. */
746
747 /* fprintf(stderr,
748 "Wait already ended: trx: %p\n", trx); */
749
750 /* Normally srv_suspend_mysql_thread resets
751 the state to DB_SUCCESS before waiting, but
752 in this case we have to do it here,
753 otherwise nobody does it. */
754
755 trx->error_state = DB_SUCCESS;
756
757 *next_thr = thr;
758
759 return;
760 }
761 }
762
763 fork = static_cast<que_fork_t*>(thr->common.parent);
764
765 --trx->lock.n_active_thrs;
766
767 --fork->n_active_thrs;
768
769 thr->is_active = FALSE;
770 }
771
772 /**********************************************************************//**
773 A patch for MySQL used to 'stop' a dummy query thread used in MySQL. The
774 query thread is stopped and made inactive, except in the case where
775 it was put to the lock wait state in lock0lock.cc, but the lock has already
776 been granted or the transaction chosen as a victim in deadlock resolution. */
777 void
que_thr_stop_for_mysql(que_thr_t * thr)778 que_thr_stop_for_mysql(
779 /*===================*/
780 que_thr_t* thr) /*!< in: query thread */
781 {
782 trx_t* trx;
783
784 trx = thr_get_trx(thr);
785
786 trx_mutex_enter(trx);
787
788 if (thr->state == QUE_THR_RUNNING) {
789
790 if (trx->error_state != DB_SUCCESS
791 && trx->error_state != DB_LOCK_WAIT) {
792
793 /* Error handling built for the MySQL interface */
794 thr->state = QUE_THR_COMPLETED;
795 } else {
796 /* It must have been a lock wait but the lock was
797 already released, or this transaction was chosen
798 as a victim in selective deadlock resolution */
799
800 trx_mutex_exit(trx);
801
802 return;
803 }
804 }
805
806 ut_ad(thr->is_active == TRUE);
807 ut_ad(trx->lock.n_active_thrs == 1);
808 ut_ad(thr->graph->n_active_thrs == 1);
809
810 thr->is_active = FALSE;
811 thr->graph->n_active_thrs--;
812
813 trx->lock.n_active_thrs--;
814
815 trx_mutex_exit(trx);
816 }
817
818 /**********************************************************************//**
819 Moves a thread from another state to the QUE_THR_RUNNING state. Increments
820 the n_active_thrs counters of the query graph and transaction if thr was
821 not active. */
822 void
que_thr_move_to_run_state_for_mysql(que_thr_t * thr,trx_t * trx)823 que_thr_move_to_run_state_for_mysql(
824 /*================================*/
825 que_thr_t* thr, /*!< in: an query thread */
826 trx_t* trx) /*!< in: transaction */
827 {
828 ut_a(thr->magic_n == QUE_THR_MAGIC_N);
829
830 if (!thr->is_active) {
831
832 thr->graph->n_active_thrs++;
833
834 trx->lock.n_active_thrs++;
835
836 thr->is_active = TRUE;
837 }
838
839 thr->state = QUE_THR_RUNNING;
840 }
841
842 /**********************************************************************//**
843 A patch for MySQL used to 'stop' a dummy query thread used in MySQL
844 select, when there is no error or lock wait. */
845 void
que_thr_stop_for_mysql_no_error(que_thr_t * thr,trx_t * trx)846 que_thr_stop_for_mysql_no_error(
847 /*============================*/
848 que_thr_t* thr, /*!< in: query thread */
849 trx_t* trx) /*!< in: transaction */
850 {
851 ut_ad(thr->state == QUE_THR_RUNNING);
852 ut_ad(thr->is_active == TRUE);
853 ut_ad(trx->lock.n_active_thrs == 1);
854 ut_ad(thr->graph->n_active_thrs == 1);
855 ut_a(thr->magic_n == QUE_THR_MAGIC_N);
856
857 thr->state = QUE_THR_COMPLETED;
858
859 thr->is_active = FALSE;
860 thr->graph->n_active_thrs--;
861
862 trx->lock.n_active_thrs--;
863 }
864
865 /****************************************************************//**
866 Get the first containing loop node (e.g. while_node_t or for_node_t) for the
867 given node, or NULL if the node is not within a loop.
868 @return containing loop node, or NULL. */
869 que_node_t*
que_node_get_containing_loop_node(que_node_t * node)870 que_node_get_containing_loop_node(
871 /*==============================*/
872 que_node_t* node) /*!< in: node */
873 {
874 ut_ad(node);
875
876 for (;;) {
877 ulint type;
878
879 node = que_node_get_parent(node);
880
881 if (!node) {
882 break;
883 }
884
885 type = que_node_get_type(node);
886
887 if ((type == QUE_NODE_FOR) || (type == QUE_NODE_WHILE)) {
888 break;
889 }
890 }
891
892 return(node);
893 }
894
895 #ifndef DBUG_OFF
896 /** Gets information of an SQL query graph node.
897 @return type description */
898 static MY_ATTRIBUTE((warn_unused_result, nonnull))
899 const char*
que_node_type_string(const que_node_t * node)900 que_node_type_string(
901 /*=================*/
902 const que_node_t* node) /*!< in: query graph node */
903 {
904 switch (que_node_get_type(node)) {
905 case QUE_NODE_SELECT:
906 return("SELECT");
907 case QUE_NODE_INSERT:
908 return("INSERT");
909 case QUE_NODE_UPDATE:
910 return("UPDATE");
911 case QUE_NODE_WHILE:
912 return("WHILE");
913 case QUE_NODE_ASSIGNMENT:
914 return("ASSIGNMENT");
915 case QUE_NODE_IF:
916 return("IF");
917 case QUE_NODE_FETCH:
918 return("FETCH");
919 case QUE_NODE_OPEN:
920 return("OPEN");
921 case QUE_NODE_PROC:
922 return("STORED PROCEDURE");
923 case QUE_NODE_FUNC:
924 return("FUNCTION");
925 case QUE_NODE_LOCK:
926 return("LOCK");
927 case QUE_NODE_THR:
928 return("QUERY THREAD");
929 case QUE_NODE_COMMIT:
930 return("COMMIT");
931 case QUE_NODE_UNDO:
932 return("UNDO ROW");
933 case QUE_NODE_PURGE:
934 return("PURGE ROW");
935 case QUE_NODE_ROLLBACK:
936 return("ROLLBACK");
937 case QUE_NODE_CREATE_TABLE:
938 return("CREATE TABLE");
939 case QUE_NODE_CREATE_INDEX:
940 return("CREATE INDEX");
941 case QUE_NODE_FOR:
942 return("FOR LOOP");
943 case QUE_NODE_RETURN:
944 return("RETURN");
945 case QUE_NODE_EXIT:
946 return("EXIT");
947 default:
948 ut_ad(0);
949 return("UNKNOWN NODE TYPE");
950 }
951 }
952 #endif /* !DBUG_OFF */
953
954 /**********************************************************************//**
955 Performs an execution step on a query thread.
956 @return query thread to run next: it may differ from the input
957 parameter if, e.g., a subprocedure call is made */
958 UNIV_INLINE
959 que_thr_t*
que_thr_step(que_thr_t * thr)960 que_thr_step(
961 /*=========*/
962 que_thr_t* thr) /*!< in: query thread */
963 {
964 que_node_t* node;
965 que_thr_t* old_thr;
966 trx_t* trx;
967 ulint type;
968
969 trx = thr_get_trx(thr);
970
971 ut_ad(thr->state == QUE_THR_RUNNING);
972 ut_a(trx->error_state == DB_SUCCESS);
973
974 thr->resource++;
975
976 node = thr->run_node;
977 type = que_node_get_type(node);
978
979 old_thr = thr;
980
981 DBUG_PRINT("ib_que", ("Execute %u (%s) at %p",
982 unsigned(type), que_node_type_string(node),
983 (const void*) node));
984
985 if (type & QUE_NODE_CONTROL_STAT) {
986 if ((thr->prev_node != que_node_get_parent(node))
987 && que_node_get_next(thr->prev_node)) {
988
989 /* The control statements, like WHILE, always pass the
990 control to the next child statement if there is any
991 child left */
992
993 thr->run_node = que_node_get_next(thr->prev_node);
994
995 } else if (type == QUE_NODE_IF) {
996 if_step(thr);
997 } else if (type == QUE_NODE_FOR) {
998 for_step(thr);
999 } else if (type == QUE_NODE_PROC) {
1000 if (thr->prev_node == que_node_get_parent(node)) {
1001 trx->last_sql_stat_start.least_undo_no
1002 = trx->undo_no;
1003 }
1004
1005 proc_step(thr);
1006 } else if (type == QUE_NODE_WHILE) {
1007 while_step(thr);
1008 } else {
1009 ut_error;
1010 }
1011 } else if (type == QUE_NODE_ASSIGNMENT) {
1012 assign_step(thr);
1013 } else if (type == QUE_NODE_SELECT) {
1014 thr = row_sel_step(thr);
1015 } else if (type == QUE_NODE_INSERT) {
1016 trx_start_if_not_started_xa(thr_get_trx(thr), true);
1017 thr = row_ins_step(thr);
1018 } else if (type == QUE_NODE_UPDATE) {
1019 trx_start_if_not_started_xa(thr_get_trx(thr), true);
1020 thr = row_upd_step(thr);
1021 } else if (type == QUE_NODE_FETCH) {
1022 thr = fetch_step(thr);
1023 } else if (type == QUE_NODE_OPEN) {
1024 thr = open_step(thr);
1025 } else if (type == QUE_NODE_FUNC) {
1026 proc_eval_step(thr);
1027
1028 } else if (type == QUE_NODE_LOCK) {
1029
1030 ut_error;
1031 } else if (type == QUE_NODE_THR) {
1032 thr = que_thr_node_step(thr);
1033 } else if (type == QUE_NODE_COMMIT) {
1034 thr = trx_commit_step(thr);
1035 } else if (type == QUE_NODE_UNDO) {
1036 thr = row_undo_step(thr);
1037 } else if (type == QUE_NODE_PURGE) {
1038 thr = row_purge_step(thr);
1039 } else if (type == QUE_NODE_RETURN) {
1040 thr = return_step(thr);
1041 } else if (type == QUE_NODE_EXIT) {
1042 thr = exit_step(thr);
1043 } else if (type == QUE_NODE_ROLLBACK) {
1044 thr = trx_rollback_step(thr);
1045 } else if (type == QUE_NODE_CREATE_TABLE) {
1046 thr = dict_create_table_step(thr);
1047 } else if (type == QUE_NODE_CREATE_INDEX) {
1048 thr = dict_create_index_step(thr);
1049 } else if (type == QUE_NODE_ROW_PRINTF) {
1050 thr = row_printf_step(thr);
1051 } else {
1052 ut_error;
1053 }
1054
1055 if (type == QUE_NODE_EXIT) {
1056 old_thr->prev_node = que_node_get_containing_loop_node(node);
1057 } else {
1058 old_thr->prev_node = node;
1059 }
1060
1061 if (thr) {
1062 ut_a(thr_get_trx(thr)->error_state == DB_SUCCESS);
1063 }
1064
1065 return(thr);
1066 }
1067
1068 /**********************************************************************//**
1069 Run a query thread until it finishes or encounters e.g. a lock wait. */
1070 static
1071 void
que_run_threads_low(que_thr_t * thr)1072 que_run_threads_low(
1073 /*================*/
1074 que_thr_t* thr) /*!< in: query thread */
1075 {
1076 trx_t* trx;
1077 que_thr_t* next_thr;
1078
1079 ut_ad(thr->state == QUE_THR_RUNNING);
1080 ut_a(thr_get_trx(thr)->error_state == DB_SUCCESS);
1081 ut_ad(!trx_mutex_own(thr_get_trx(thr)));
1082
1083 /* cumul_resource counts how much resources the OS thread (NOT the
1084 query thread) has spent in this function */
1085
1086 trx = thr_get_trx(thr);
1087
1088 do {
1089 /* Check that there is enough space in the log to accommodate
1090 possible log entries by this query step; if the operation can
1091 touch more than about 4 pages, checks must be made also within
1092 the query step! */
1093
1094 log_free_check();
1095
1096 /* Perform the actual query step: note that the query thread
1097 may change if, e.g., a subprocedure call is made */
1098
1099 /*-------------------------*/
1100 next_thr = que_thr_step(thr);
1101 /*-------------------------*/
1102
1103 trx_mutex_enter(trx);
1104
1105 ut_a(next_thr == NULL || trx->error_state == DB_SUCCESS);
1106
1107 if (next_thr != thr) {
1108 ut_a(next_thr == NULL);
1109
1110 /* This can change next_thr to a non-NULL value
1111 if there was a lock wait that already completed. */
1112
1113 que_thr_dec_refer_count(thr, &next_thr);
1114
1115 if (next_thr != NULL) {
1116
1117 thr = next_thr;
1118 }
1119 }
1120
1121 ut_ad(trx == thr_get_trx(thr));
1122
1123 trx_mutex_exit(trx);
1124
1125 } while (next_thr != NULL);
1126 }
1127
1128 /**********************************************************************//**
1129 Run a query thread. Handles lock waits. */
1130 void
que_run_threads(que_thr_t * thr)1131 que_run_threads(
1132 /*============*/
1133 que_thr_t* thr) /*!< in: query thread */
1134 {
1135 ut_ad(!trx_mutex_own(thr_get_trx(thr)));
1136
1137 loop:
1138 ut_a(thr_get_trx(thr)->error_state == DB_SUCCESS);
1139
1140 que_run_threads_low(thr);
1141
1142 switch (thr->state) {
1143
1144 case QUE_THR_RUNNING:
1145 /* There probably was a lock wait, but it already ended
1146 before we came here: continue running thr */
1147
1148 goto loop;
1149
1150 case QUE_THR_LOCK_WAIT:
1151 lock_wait_suspend_thread(thr);
1152
1153 trx_mutex_enter(thr_get_trx(thr));
1154
1155 ut_a(thr_get_trx(thr)->id != 0);
1156
1157 if (thr_get_trx(thr)->error_state != DB_SUCCESS) {
1158 /* thr was chosen as a deadlock victim or there was
1159 a lock wait timeout */
1160
1161 que_thr_dec_refer_count(thr, NULL);
1162 trx_mutex_exit(thr_get_trx(thr));
1163 break;
1164 }
1165
1166 trx_mutex_exit(thr_get_trx(thr));
1167 goto loop;
1168
1169 case QUE_THR_COMPLETED:
1170 case QUE_THR_COMMAND_WAIT:
1171 /* Do nothing */
1172 break;
1173
1174 default:
1175 ut_error;
1176 }
1177 }
1178
1179 /*********************************************************************//**
1180 Evaluate the given SQL.
1181 @return error code or DB_SUCCESS */
1182 dberr_t
que_eval_sql(pars_info_t * info,const char * sql,bool reserve_dict_mutex,trx_t * trx)1183 que_eval_sql(
1184 /*=========*/
1185 pars_info_t* info, /*!< in: info struct, or NULL */
1186 const char* sql, /*!< in: SQL string */
1187 bool reserve_dict_mutex,
1188 /*!< in: whether to acquire/release
1189 dict_sys.mutex around call to pars_sql. */
1190 trx_t* trx) /*!< in: trx */
1191 {
1192 que_thr_t* thr;
1193 que_t* graph;
1194
1195 DBUG_ENTER("que_eval_sql");
1196 DBUG_PRINT("que_eval_sql", ("query: %s", sql));
1197
1198 ut_a(trx->error_state == DB_SUCCESS);
1199
1200 if (reserve_dict_mutex) {
1201 mutex_enter(&dict_sys.mutex);
1202 }
1203
1204 graph = pars_sql(info, sql);
1205
1206 if (reserve_dict_mutex) {
1207 mutex_exit(&dict_sys.mutex);
1208 }
1209
1210 graph->trx = trx;
1211 trx->graph = NULL;
1212
1213 graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
1214
1215 ut_a(thr = que_fork_start_command(graph));
1216
1217 que_run_threads(thr);
1218
1219 if (reserve_dict_mutex) {
1220 mutex_enter(&dict_sys.mutex);
1221 }
1222
1223 que_graph_free(graph);
1224
1225 if (reserve_dict_mutex) {
1226 mutex_exit(&dict_sys.mutex);
1227 }
1228
1229 DBUG_RETURN(trx->error_state);
1230 }
1231