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