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