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