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