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