1
/******************************************************
6
Created 5/27/1996 Heikki Tuuri
7
*******************************************************/
23
#include "row0purge.h"
24
#include "dict0crea.h"
26
#include "eval0proc.h"
27
#include "eval0eval.h"
28
#include "pars0types.h"
30
#define QUE_PARALLELIZE_LIMIT (64 * 256 * 256 * 256)
31
#define QUE_ROUND_ROBIN_LIMIT (64 * 256 * 256 * 256)
32
#define QUE_MAX_LOOPS_WITHOUT_CHECK 16
34
/* If the following flag is set TRUE, the module will print trace info
35
of SQL execution in the UNIV_SQL_DEBUG version */
36
ibool que_trace_on = FALSE;
38
ibool que_always_false = FALSE;
40
/* Short introduction to query graphs
41
==================================
43
A query graph consists of nodes linked to each other in various ways. The
44
execution starts at que_run_threads() which takes a que_thr_t parameter.
45
que_thr_t contains two fields that control query graph execution: run_node
46
and prev_node. run_node is the next node to execute and prev_node is the
49
Each node has a pointer to a 'next' statement, i.e., its brother, and a
50
pointer to its parent node. The next pointer is NULL in the last statement
53
Loop nodes contain a link to the first statement of the enclosed statement
54
list. While the loop runs, que_thr_step() checks if execution to the loop
55
node came from its parent or from one of the statement nodes in the loop. If
56
it came from the parent of the loop node it starts executing the first
57
statement node in the loop. If it came from one of the statement nodes in
58
the loop, then it checks if the statement node has another statement node
59
following it, and runs it if so.
61
To signify loop ending, the loop statements (see e.g. while_step()) set
62
que_thr_t->run_node to the loop node's parent node. This is noticed on the
63
next call of que_thr_step() and execution proceeds to the node pointed to by
64
the loop node's 'next' pointer.
66
For example, the code:
74
will result in the following node hierarchy, with the X-axis indicating
75
'next' links and the Y-axis indicating parent/child links:
82
A = assign_node_t, W = while_node_t. */
84
/* How a stored procedure containing COMMIT or ROLLBACK commands
87
The commit or rollback can be seen as a subprocedure call.
88
The problem is that if there are several query threads
89
currently running within the transaction, their action could
90
mess the commit or rollback operation. Or, at the least, the
91
operation would be difficult to visualize and keep in control.
93
Therefore the query thread requesting a commit or a rollback
94
sends to the transaction a signal, which moves the transaction
95
to TRX_QUE_SIGNALED state. All running query threads of the
96
transaction will eventually notice that the transaction is now in
97
this state and voluntarily suspend themselves. Only the last
98
query thread which suspends itself will trigger handling of
101
When the transaction starts to handle a rollback or commit
102
signal, it builds a query graph which, when executed, will
103
roll back or commit the incomplete transaction. The transaction
104
is moved to the TRX_QUE_ROLLING_BACK or TRX_QUE_COMMITTING state.
105
If specified, the SQL cursors opened by the transaction are closed.
106
When the execution of the graph completes, it is like returning
107
from a subprocedure: the query thread which requested the operation
108
starts running again. */
110
/**************************************************************************
111
Moves a thread from another state to the QUE_THR_RUNNING state. Increments
112
the n_active_thrs counters of the query graph and transaction.
113
***NOTE***: This is the only function in which such a transition is allowed
117
que_thr_move_to_run_state(
118
/*======================*/
119
que_thr_t* thr); /* in: an query thread */
121
/***************************************************************************
122
Adds a query graph to the session's list of graphs. */
127
que_t* graph, /* in: graph */
128
sess_t* sess) /* in: session */
130
ut_ad(mutex_own(&kernel_mutex));
132
UT_LIST_ADD_LAST(graphs, sess->graphs, graph);
135
/***************************************************************************
136
Creates a query graph fork node. */
141
/* out, own: fork node */
142
que_t* graph, /* in: graph, if NULL then this
143
fork node is assumed to be the
145
que_node_t* parent, /* in: parent node */
146
ulint fork_type, /* in: fork type */
147
mem_heap_t* heap) /* in: memory heap where created */
153
fork = mem_heap_alloc(heap, sizeof(que_fork_t));
155
fork->common.type = QUE_NODE_FORK;
156
fork->n_active_thrs = 0;
158
fork->state = QUE_FORK_COMMAND_WAIT;
166
fork->common.parent = parent;
167
fork->fork_type = fork_type;
171
UT_LIST_INIT(fork->thrs);
173
fork->sym_tab = NULL;
181
/***************************************************************************
182
Creates a query graph thread node. */
187
/* out, own: query thread node */
188
que_fork_t* parent, /* in: parent node, i.e., a fork node */
189
mem_heap_t* heap) /* in: memory heap where created */
193
ut_ad(parent && heap);
195
thr = mem_heap_alloc(heap, sizeof(que_thr_t));
197
thr->common.type = QUE_NODE_THR;
198
thr->common.parent = parent;
200
thr->magic_n = QUE_THR_MAGIC_N;
202
thr->graph = parent->graph;
204
thr->state = QUE_THR_COMMAND_WAIT;
206
thr->is_active = FALSE;
208
thr->run_node = NULL;
210
thr->lock_state = QUE_THR_LOCK_NOLOCK;
212
UT_LIST_ADD_LAST(thrs, parent->thrs, thr);
217
/**************************************************************************
218
Moves a suspended query thread to the QUE_THR_RUNNING state and may release
219
a single worker thread to execute it. This function should be used to end
220
the wait state of a query thread waiting for a lock or a stored procedure
226
que_thr_t* thr, /* in: query thread in the
228
or QUE_THR_PROCEDURE_WAIT, or
229
QUE_THR_SIG_REPLY_WAIT state */
230
que_thr_t** next_thr) /* in/out: next query thread to run;
231
if the value which is passed in is
232
a pointer to a NULL pointer, then the
233
calling function can start running
234
a new query thread; if NULL is passed
235
as the parameter, it is ignored */
239
ut_ad(mutex_own(&kernel_mutex));
241
ut_ad((thr->state == QUE_THR_LOCK_WAIT)
242
|| (thr->state == QUE_THR_PROCEDURE_WAIT)
243
|| (thr->state == QUE_THR_SIG_REPLY_WAIT));
244
ut_ad(thr->run_node);
246
thr->prev_node = thr->run_node;
248
was_active = thr->is_active;
250
que_thr_move_to_run_state(thr);
257
if (next_thr && *next_thr == NULL) {
261
srv_que_task_enqueue_low(thr);
265
/**************************************************************************
266
Same as que_thr_end_wait, but no parameter next_thr available. */
269
que_thr_end_wait_no_next_thr(
270
/*=========================*/
271
que_thr_t* thr) /* in: query thread in the QUE_THR_LOCK_WAIT,
272
or QUE_THR_PROCEDURE_WAIT, or
273
QUE_THR_SIG_REPLY_WAIT state */
277
ut_a(thr->state == QUE_THR_LOCK_WAIT); /* In MySQL this is the
278
only possible state here */
279
ut_ad(mutex_own(&kernel_mutex));
281
ut_ad((thr->state == QUE_THR_LOCK_WAIT)
282
|| (thr->state == QUE_THR_PROCEDURE_WAIT)
283
|| (thr->state == QUE_THR_SIG_REPLY_WAIT));
285
was_active = thr->is_active;
287
que_thr_move_to_run_state(thr);
294
/* In MySQL we let the OS thread (not just the query thread) to wait
295
for the lock to be released: */
297
srv_release_mysql_thread_if_suspended(thr);
299
/* srv_que_task_enqueue_low(thr); */
302
/**************************************************************************
303
Inits a query thread for a command. */
306
que_thr_init_command(
307
/*=================*/
308
que_thr_t* thr) /* in: query thread */
311
thr->prev_node = thr->common.parent;
313
que_thr_move_to_run_state(thr);
316
/**************************************************************************
317
Starts execution of a command in a query fork. Picks a query thread which
318
is not in the QUE_THR_RUNNING state and moves it to that state. If none
319
can be chosen, a situation which may arise in parallelized fetches, NULL
323
que_fork_start_command(
324
/*===================*/
325
/* out: a query thread of the graph moved to
326
QUE_THR_RUNNING state, or NULL; the query
327
thread should be executed by que_run_threads
329
que_fork_t* fork) /* in: a query fork */
332
que_thr_t* suspended_thr = NULL;
333
que_thr_t* completed_thr = NULL;
335
fork->state = QUE_FORK_ACTIVE;
337
fork->last_sel_node = NULL;
339
/* Choose the query thread to run: usually there is just one thread,
340
but in a parallelized select, which necessarily is non-scrollable,
341
there may be several to choose from */
343
/* First we try to find a query thread in the QUE_THR_COMMAND_WAIT
344
state. Then we try to find a query thread in the QUE_THR_SUSPENDED
345
state, finally we try to find a query thread in the QUE_THR_COMPLETED
348
thr = UT_LIST_GET_FIRST(fork->thrs);
350
/* We make a single pass over the thr list within which we note which
351
threads are ready to run. */
353
switch (thr->state) {
354
case QUE_THR_COMMAND_WAIT:
356
/* We have to send the initial message to query thread
359
que_thr_init_command(thr);
363
case QUE_THR_SUSPENDED:
364
/* In this case the execution of the thread was
365
suspended: no initial message is needed because
366
execution can continue from where it was left */
367
if (!suspended_thr) {
373
case QUE_THR_COMPLETED:
374
if (!completed_thr) {
380
case QUE_THR_LOCK_WAIT:
385
thr = UT_LIST_GET_NEXT(thrs, thr);
391
que_thr_move_to_run_state(thr);
393
} else if (completed_thr) {
396
que_thr_init_command(thr);
402
/**************************************************************************
403
After signal handling is finished, returns control to a query graph error
404
handling routine. (Currently, just returns the control to the root of the
405
graph so that the graph can communicate an error message to the client.) */
408
que_fork_error_handle(
409
/*==================*/
410
trx_t* trx __attribute__((unused)), /* in: trx */
411
que_t* fork) /* in: query graph which was run before signal
412
handling started, NULL not allowed */
416
ut_ad(mutex_own(&kernel_mutex));
417
ut_ad(trx->sess->state == SESS_ERROR);
418
ut_ad(UT_LIST_GET_LEN(trx->reply_signals) == 0);
419
ut_ad(UT_LIST_GET_LEN(trx->wait_thrs) == 0);
421
thr = UT_LIST_GET_FIRST(fork->thrs);
423
while (thr != NULL) {
424
ut_ad(!thr->is_active);
425
ut_ad(thr->state != QUE_THR_SIG_REPLY_WAIT);
426
ut_ad(thr->state != QUE_THR_LOCK_WAIT);
429
thr->prev_node = thr->child;
430
thr->state = QUE_THR_COMPLETED;
432
thr = UT_LIST_GET_NEXT(thrs, thr);
435
thr = UT_LIST_GET_FIRST(fork->thrs);
437
que_thr_move_to_run_state(thr);
440
srv_que_task_enqueue_low(thr);
443
/********************************************************************
444
Tests if all the query threads in the same fork have a given state. */
447
que_fork_all_thrs_in_state(
448
/*=======================*/
449
/* out: TRUE if all the query threads in the
450
same fork were in the given state */
451
que_fork_t* fork, /* in: query fork */
452
ulint state) /* in: state */
456
thr_node = UT_LIST_GET_FIRST(fork->thrs);
458
while (thr_node != NULL) {
459
if (thr_node->state != state) {
464
thr_node = UT_LIST_GET_NEXT(thrs, thr_node);
470
/**************************************************************************
471
Calls que_graph_free_recursive for statements in a statement list. */
474
que_graph_free_stat_list(
475
/*=====================*/
476
que_node_t* node) /* in: first query graph node in the list */
479
que_graph_free_recursive(node);
481
node = que_node_get_next(node);
485
/**************************************************************************
486
Frees a query graph, but not the heap where it was created. Does not free
487
explicit cursor declarations, they are freed in que_graph_free. */
490
que_graph_free_recursive(
491
/*=====================*/
492
que_node_t* node) /* in: query graph node */
508
switch (que_node_get_type(node)) {
513
thr = UT_LIST_GET_FIRST(fork->thrs);
516
que_graph_free_recursive(thr);
518
thr = UT_LIST_GET_NEXT(thrs, thr);
526
if (thr->magic_n != QUE_THR_MAGIC_N) {
528
"que_thr struct appears corrupt;"
530
(unsigned long) thr->magic_n);
531
mem_analyze_corruption(thr);
535
thr->magic_n = QUE_THR_MAGIC_FREED;
537
que_graph_free_recursive(thr->child);
544
mem_heap_free(undo->heap);
547
case QUE_NODE_SELECT:
551
sel_node_free_private(sel);
554
case QUE_NODE_INSERT:
558
que_graph_free_recursive(ins->select);
560
mem_heap_free(ins->entry_sys_heap);
563
case QUE_NODE_UPDATE:
567
if (upd->in_mysql_interface) {
569
btr_pcur_free_for_mysql(upd->pcur);
572
que_graph_free_recursive(upd->cascade_node);
574
if (upd->cascade_heap) {
575
mem_heap_free(upd->cascade_heap);
578
que_graph_free_recursive(upd->select);
580
mem_heap_free(upd->heap);
583
case QUE_NODE_CREATE_TABLE:
586
que_graph_free_recursive(cre_tab->tab_def);
587
que_graph_free_recursive(cre_tab->col_def);
588
que_graph_free_recursive(cre_tab->commit_node);
590
mem_heap_free(cre_tab->heap);
593
case QUE_NODE_CREATE_INDEX:
596
que_graph_free_recursive(cre_ind->ind_def);
597
que_graph_free_recursive(cre_ind->field_def);
598
que_graph_free_recursive(cre_ind->commit_node);
600
mem_heap_free(cre_ind->heap);
604
que_graph_free_stat_list(((proc_node_t*)node)->stat_list);
608
que_graph_free_stat_list(((if_node_t*)node)->stat_list);
609
que_graph_free_stat_list(((if_node_t*)node)->else_part);
610
que_graph_free_stat_list(((if_node_t*)node)->elsif_list);
614
que_graph_free_stat_list(((elsif_node_t*)node)->stat_list);
618
que_graph_free_stat_list(((while_node_t*)node)->stat_list);
622
que_graph_free_stat_list(((for_node_t*)node)->stat_list);
626
case QUE_NODE_ASSIGNMENT:
628
case QUE_NODE_RETURN:
629
case QUE_NODE_COMMIT:
630
case QUE_NODE_ROLLBACK:
634
case QUE_NODE_ROW_PRINTF:
637
/* No need to do anything */
642
"que_node struct appears corrupt; type %lu\n",
643
(unsigned long) que_node_get_type(node));
644
mem_analyze_corruption(node);
649
/**************************************************************************
650
Frees a query graph. */
655
que_t* graph) /* in: query graph; we assume that the memory
656
heap where this graph was created is private
657
to this graph: if not, then use
658
que_graph_free_recursive and free the heap
663
if (graph->sym_tab) {
664
/* The following call frees dynamic memory allocated
665
for variables etc. during execution. Frees also explicit
666
cursor definitions. */
668
sym_tab_free_private(graph->sym_tab);
671
if (graph->info && graph->info->graph_owns_us) {
672
pars_info_free(graph->info);
675
que_graph_free_recursive(graph);
677
mem_heap_free(graph->heap);
680
/**************************************************************************
681
Checks if the query graph is in a state where it should be freed, and
682
frees it in that case. If the session is in a state where it should be
683
closed, also this is done. */
688
/* out: TRUE if freed */
689
que_t* graph) /* in: query graph */
693
ut_ad(mutex_own(&kernel_mutex));
695
sess = (graph->trx)->sess;
697
if ((graph->state == QUE_FORK_BEING_FREED)
698
&& (graph->n_active_thrs == 0)) {
700
UT_LIST_REMOVE(graphs, sess->graphs, graph);
701
que_graph_free(graph);
703
sess_try_close(sess);
711
/********************************************************************
712
Performs an execution step on a thr node. */
717
/* out: query thread to run next, or NULL
719
que_thr_t* thr) /* in: query thread where run_node must
720
be the thread node itself */
722
ut_ad(thr->run_node == thr);
724
if (thr->prev_node == thr->common.parent) {
725
/* If control to the node came from above, it is just passed
728
thr->run_node = thr->child;
733
mutex_enter(&kernel_mutex);
735
if (que_thr_peek_stop(thr)) {
737
mutex_exit(&kernel_mutex);
742
/* Thread execution completed */
744
thr->state = QUE_THR_COMPLETED;
746
mutex_exit(&kernel_mutex);
751
/**************************************************************************
752
Moves a thread from another state to the QUE_THR_RUNNING state. Increments
753
the n_active_thrs counters of the query graph and transaction if thr was
755
***NOTE***: This and ..._mysql are the only functions in which such a
756
transition is allowed to happen! */
759
que_thr_move_to_run_state(
760
/*======================*/
761
que_thr_t* thr) /* in: an query thread */
765
ut_ad(thr->state != QUE_THR_RUNNING);
767
trx = thr_get_trx(thr);
769
if (!thr->is_active) {
771
(thr->graph)->n_active_thrs++;
773
trx->n_active_thrs++;
775
thr->is_active = TRUE;
777
ut_ad((thr->graph)->n_active_thrs == 1);
778
ut_ad(trx->n_active_thrs == 1);
781
thr->state = QUE_THR_RUNNING;
784
/**************************************************************************
785
Decrements the query thread reference counts in the query graph and the
786
transaction. May start signal handling, e.g., a rollback.
788
This and que_thr_stop_for_mysql are the only functions where the reference
789
count can be decremented and this function may only be called from inside
790
que_run_threads or que_thr_check_if_switch! These restrictions exist to make
791
the rollback code easier to maintain. */
794
que_thr_dec_refer_count(
795
/*====================*/
796
que_thr_t* thr, /* in: query thread */
797
que_thr_t** next_thr) /* in/out: next query thread to run;
798
if the value which is passed in is
799
a pointer to a NULL pointer, then the
800
calling function can start running
801
a new query thread */
809
fork = thr->common.parent;
810
trx = thr_get_trx(thr);
813
mutex_enter(&kernel_mutex);
815
ut_a(thr->is_active);
817
if (thr->state == QUE_THR_RUNNING) {
819
stopped = que_thr_stop(thr);
822
/* The reason for the thr suspension or wait was
823
already canceled before we came here: continue
824
running the thread */
826
/* fputs("!!!!!!!! Wait already ended: continue thr\n",
829
if (next_thr && *next_thr == NULL) {
830
/* Normally srv_suspend_mysql_thread resets
831
the state to DB_SUCCESS before waiting, but
832
in this case we have to do it here,
833
otherwise nobody does it. */
834
trx->error_state = DB_SUCCESS;
839
srv_que_task_enqueue_low(thr);
842
mutex_exit(&kernel_mutex);
848
ut_ad(fork->n_active_thrs == 1);
849
ut_ad(trx->n_active_thrs == 1);
851
fork->n_active_thrs--;
852
trx->n_active_thrs--;
854
thr->is_active = FALSE;
856
if (trx->n_active_thrs > 0) {
858
mutex_exit(&kernel_mutex);
863
fork_type = fork->fork_type;
865
/* Check if all query threads in the same fork are completed */
867
if (que_fork_all_thrs_in_state(fork, QUE_THR_COMPLETED)) {
869
if (fork_type == QUE_FORK_ROLLBACK) {
870
/* This is really the undo graph used in rollback,
871
no roll_node in this graph */
873
ut_ad(UT_LIST_GET_LEN(trx->signals) > 0);
874
ut_ad(trx->handling_signals == TRUE);
876
trx_finish_rollback_off_kernel(fork, trx, next_thr);
878
} else if (fork_type == QUE_FORK_PURGE) {
881
} else if (fork_type == QUE_FORK_RECOVERY) {
884
} else if (fork_type == QUE_FORK_MYSQL_INTERFACE) {
888
ut_error; /* not used in MySQL */
892
if (UT_LIST_GET_LEN(trx->signals) > 0 && trx->n_active_thrs == 0) {
894
/* If the trx is signaled and its query thread count drops to
895
zero, then we start processing a signal; from it we may get
896
a new query thread to run */
898
trx_sig_start_handle(trx, next_thr);
901
if (trx->handling_signals && UT_LIST_GET_LEN(trx->signals) == 0) {
903
trx_end_signal_handling(trx);
906
mutex_exit(&kernel_mutex);
909
/**************************************************************************
910
Stops a query thread if graph or trx is in a state requiring it. The
911
conditions are tested in the order (1) graph, (2) trx. The kernel mutex has
917
/* out: TRUE if stopped */
918
que_thr_t* thr) /* in: query thread */
924
ut_ad(mutex_own(&kernel_mutex));
929
if (graph->state == QUE_FORK_COMMAND_WAIT) {
930
thr->state = QUE_THR_SUSPENDED;
932
} else if (trx->que_state == TRX_QUE_LOCK_WAIT) {
934
UT_LIST_ADD_FIRST(trx_thrs, trx->wait_thrs, thr);
935
thr->state = QUE_THR_LOCK_WAIT;
937
} else if (trx->error_state != DB_SUCCESS
938
&& trx->error_state != DB_LOCK_WAIT) {
940
/* Error handling built for the MySQL interface */
941
thr->state = QUE_THR_COMPLETED;
943
} else if (UT_LIST_GET_LEN(trx->signals) > 0
944
&& graph->fork_type != QUE_FORK_ROLLBACK) {
946
thr->state = QUE_THR_SUSPENDED;
948
ut_ad(graph->state == QUE_FORK_ACTIVE);
956
/**************************************************************************
957
A patch for MySQL used to 'stop' a dummy query thread used in MySQL. The
958
query thread is stopped and made inactive, except in the case where
959
it was put to the lock wait state in lock0lock.c, but the lock has already
960
been granted or the transaction chosen as a victim in deadlock resolution. */
963
que_thr_stop_for_mysql(
964
/*===================*/
965
que_thr_t* thr) /* in: query thread */
969
trx = thr_get_trx(thr);
971
mutex_enter(&kernel_mutex);
973
if (thr->state == QUE_THR_RUNNING) {
975
if (trx->error_state != DB_SUCCESS
976
&& trx->error_state != DB_LOCK_WAIT) {
978
/* Error handling built for the MySQL interface */
979
thr->state = QUE_THR_COMPLETED;
981
/* It must have been a lock wait but the lock was
982
already released, or this transaction was chosen
983
as a victim in selective deadlock resolution */
985
mutex_exit(&kernel_mutex);
991
ut_ad(thr->is_active == TRUE);
992
ut_ad(trx->n_active_thrs == 1);
993
ut_ad(thr->graph->n_active_thrs == 1);
995
thr->is_active = FALSE;
996
(thr->graph)->n_active_thrs--;
998
trx->n_active_thrs--;
1000
mutex_exit(&kernel_mutex);
1003
/**************************************************************************
1004
Moves a thread from another state to the QUE_THR_RUNNING state. Increments
1005
the n_active_thrs counters of the query graph and transaction if thr was
1009
que_thr_move_to_run_state_for_mysql(
1010
/*================================*/
1011
que_thr_t* thr, /* in: an query thread */
1012
trx_t* trx) /* in: transaction */
1014
if (thr->magic_n != QUE_THR_MAGIC_N) {
1016
"que_thr struct appears corrupt; magic n %lu\n",
1017
(unsigned long) thr->magic_n);
1019
mem_analyze_corruption(thr);
1024
if (!thr->is_active) {
1026
thr->graph->n_active_thrs++;
1028
trx->n_active_thrs++;
1030
thr->is_active = TRUE;
1033
thr->state = QUE_THR_RUNNING;
1036
/**************************************************************************
1037
A patch for MySQL used to 'stop' a dummy query thread used in MySQL
1038
select, when there is no error or lock wait. */
1041
que_thr_stop_for_mysql_no_error(
1042
/*============================*/
1043
que_thr_t* thr, /* in: query thread */
1044
trx_t* trx) /* in: transaction */
1046
ut_ad(thr->state == QUE_THR_RUNNING);
1047
ut_ad(thr->is_active == TRUE);
1048
ut_ad(trx->n_active_thrs == 1);
1049
ut_ad(thr->graph->n_active_thrs == 1);
1051
if (thr->magic_n != QUE_THR_MAGIC_N) {
1053
"que_thr struct appears corrupt; magic n %lu\n",
1054
(unsigned long) thr->magic_n);
1056
mem_analyze_corruption(thr);
1061
thr->state = QUE_THR_COMPLETED;
1063
thr->is_active = FALSE;
1064
(thr->graph)->n_active_thrs--;
1066
trx->n_active_thrs--;
1069
/********************************************************************
1070
Get the first containing loop node (e.g. while_node_t or for_node_t) for the
1071
given node, or NULL if the node is not within a loop. */
1074
que_node_get_containing_loop_node(
1075
/*==============================*/
1076
/* out: containing loop node, or NULL. */
1077
que_node_t* node) /* in: node */
1084
node = que_node_get_parent(node);
1090
type = que_node_get_type(node);
1092
if ((type == QUE_NODE_FOR) || (type == QUE_NODE_WHILE)) {
1100
/**************************************************************************
1101
Prints info of an SQL query graph node. */
1104
que_node_print_info(
1105
/*================*/
1106
que_node_t* node) /* in: query graph node */
1111
type = que_node_get_type(node);
1113
if (type == QUE_NODE_SELECT) {
1115
} else if (type == QUE_NODE_INSERT) {
1117
} else if (type == QUE_NODE_UPDATE) {
1119
} else if (type == QUE_NODE_WHILE) {
1121
} else if (type == QUE_NODE_ASSIGNMENT) {
1123
} else if (type == QUE_NODE_IF) {
1125
} else if (type == QUE_NODE_FETCH) {
1127
} else if (type == QUE_NODE_OPEN) {
1129
} else if (type == QUE_NODE_PROC) {
1130
str = "STORED PROCEDURE";
1131
} else if (type == QUE_NODE_FUNC) {
1133
} else if (type == QUE_NODE_LOCK) {
1135
} else if (type == QUE_NODE_THR) {
1136
str = "QUERY THREAD";
1137
} else if (type == QUE_NODE_COMMIT) {
1139
} else if (type == QUE_NODE_UNDO) {
1141
} else if (type == QUE_NODE_PURGE) {
1143
} else if (type == QUE_NODE_ROLLBACK) {
1145
} else if (type == QUE_NODE_CREATE_TABLE) {
1146
str = "CREATE TABLE";
1147
} else if (type == QUE_NODE_CREATE_INDEX) {
1148
str = "CREATE INDEX";
1149
} else if (type == QUE_NODE_FOR) {
1151
} else if (type == QUE_NODE_RETURN) {
1153
} else if (type == QUE_NODE_EXIT) {
1156
str = "UNKNOWN NODE TYPE";
1159
fprintf(stderr, "Node type %lu: %s, address %p\n",
1160
(ulong) type, str, (void*) node);
1163
/**************************************************************************
1164
Performs an execution step on a query thread. */
1169
/* out: query thread to run next: it may
1170
differ from the input parameter if, e.g., a
1171
subprocedure call is made */
1172
que_thr_t* thr) /* in: query thread */
1179
trx = thr_get_trx(thr);
1181
ut_ad(thr->state == QUE_THR_RUNNING);
1182
ut_a(trx->error_state == DB_SUCCESS);
1186
node = thr->run_node;
1187
type = que_node_get_type(node);
1193
fputs("To execute: ", stderr);
1194
que_node_print_info(node);
1197
if (type & QUE_NODE_CONTROL_STAT) {
1198
if ((thr->prev_node != que_node_get_parent(node))
1199
&& que_node_get_next(thr->prev_node)) {
1201
/* The control statements, like WHILE, always pass the
1202
control to the next child statement if there is any
1205
thr->run_node = que_node_get_next(thr->prev_node);
1207
} else if (type == QUE_NODE_IF) {
1209
} else if (type == QUE_NODE_FOR) {
1211
} else if (type == QUE_NODE_PROC) {
1213
/* We can access trx->undo_no without reserving
1214
trx->undo_mutex, because there cannot be active query
1215
threads doing updating or inserting at the moment! */
1217
if (thr->prev_node == que_node_get_parent(node)) {
1218
trx->last_sql_stat_start.least_undo_no
1223
} else if (type == QUE_NODE_WHILE) {
1228
} else if (type == QUE_NODE_ASSIGNMENT) {
1230
} else if (type == QUE_NODE_SELECT) {
1231
thr = row_sel_step(thr);
1232
} else if (type == QUE_NODE_INSERT) {
1233
thr = row_ins_step(thr);
1234
} else if (type == QUE_NODE_UPDATE) {
1235
thr = row_upd_step(thr);
1236
} else if (type == QUE_NODE_FETCH) {
1237
thr = fetch_step(thr);
1238
} else if (type == QUE_NODE_OPEN) {
1239
thr = open_step(thr);
1240
} else if (type == QUE_NODE_FUNC) {
1241
proc_eval_step(thr);
1243
} else if (type == QUE_NODE_LOCK) {
1247
thr = que_lock_step(thr);
1249
} else if (type == QUE_NODE_THR) {
1250
thr = que_thr_node_step(thr);
1251
} else if (type == QUE_NODE_COMMIT) {
1252
thr = trx_commit_step(thr);
1253
} else if (type == QUE_NODE_UNDO) {
1254
thr = row_undo_step(thr);
1255
} else if (type == QUE_NODE_PURGE) {
1256
thr = row_purge_step(thr);
1257
} else if (type == QUE_NODE_RETURN) {
1258
thr = return_step(thr);
1259
} else if (type == QUE_NODE_EXIT) {
1260
thr = exit_step(thr);
1261
} else if (type == QUE_NODE_ROLLBACK) {
1262
thr = trx_rollback_step(thr);
1263
} else if (type == QUE_NODE_CREATE_TABLE) {
1264
thr = dict_create_table_step(thr);
1265
} else if (type == QUE_NODE_CREATE_INDEX) {
1266
thr = dict_create_index_step(thr);
1267
} else if (type == QUE_NODE_ROW_PRINTF) {
1268
thr = row_printf_step(thr);
1273
if (type == QUE_NODE_EXIT) {
1274
old_thr->prev_node = que_node_get_containing_loop_node(node);
1276
old_thr->prev_node = node;
1280
ut_a(thr_get_trx(thr)->error_state == DB_SUCCESS);
1286
/**************************************************************************
1287
Run a query thread until it finishes or encounters e.g. a lock wait. */
1290
que_run_threads_low(
1291
/*================*/
1292
que_thr_t* thr) /* in: query thread */
1294
que_thr_t* next_thr;
1295
ulint cumul_resource;
1298
ut_ad(thr->state == QUE_THR_RUNNING);
1299
ut_a(thr_get_trx(thr)->error_state == DB_SUCCESS);
1300
ut_ad(!mutex_own(&kernel_mutex));
1302
/* cumul_resource counts how much resources the OS thread (NOT the
1303
query thread) has spent in this function */
1305
loop_count = QUE_MAX_LOOPS_WITHOUT_CHECK;
1308
/* Check that there is enough space in the log to accommodate
1309
possible log entries by this query step; if the operation can touch
1310
more than about 4 pages, checks must be made also within the query
1315
/* Perform the actual query step: note that the query thread
1316
may change if, e.g., a subprocedure call is made */
1318
/*-------------------------*/
1319
next_thr = que_thr_step(thr);
1320
/*-------------------------*/
1322
ut_a(!next_thr || (thr_get_trx(next_thr)->error_state == DB_SUCCESS));
1326
if (next_thr != thr) {
1327
ut_a(next_thr == NULL);
1329
/* This can change next_thr to a non-NULL value if there was
1330
a lock wait that already completed. */
1331
que_thr_dec_refer_count(thr, &next_thr);
1333
if (next_thr == NULL) {
1338
loop_count = QUE_MAX_LOOPS_WITHOUT_CHECK;
1346
/**************************************************************************
1347
Run a query thread. Handles lock waits. */
1351
que_thr_t* thr) /* in: query thread */
1354
ut_a(thr_get_trx(thr)->error_state == DB_SUCCESS);
1355
que_run_threads_low(thr);
1357
mutex_enter(&kernel_mutex);
1359
switch (thr->state) {
1361
case QUE_THR_RUNNING:
1362
/* There probably was a lock wait, but it already ended
1363
before we came here: continue running thr */
1365
mutex_exit(&kernel_mutex);
1369
case QUE_THR_LOCK_WAIT:
1370
mutex_exit(&kernel_mutex);
1372
/* The ..._mysql_... function works also for InnoDB's
1373
internal threads. Let us wait that the lock wait ends. */
1375
srv_suspend_mysql_thread(thr);
1377
if (thr_get_trx(thr)->error_state != DB_SUCCESS) {
1378
/* thr was chosen as a deadlock victim or there was
1379
a lock wait timeout */
1381
que_thr_dec_refer_count(thr, NULL);
1388
case QUE_THR_COMPLETED:
1389
case QUE_THR_COMMAND_WAIT:
1397
mutex_exit(&kernel_mutex);
1400
/*************************************************************************
1401
Evaluate the given SQL. */
1406
/* out: error code or DB_SUCCESS */
1407
pars_info_t* info, /* in: info struct, or NULL */
1408
const char* sql, /* in: SQL string */
1409
ibool reserve_dict_mutex,
1410
/* in: if TRUE, acquire/release
1411
dict_sys->mutex around call to pars_sql. */
1412
trx_t* trx) /* in: trx */
1417
ut_a(trx->error_state == DB_SUCCESS);
1419
if (reserve_dict_mutex) {
1420
mutex_enter(&dict_sys->mutex);
1423
graph = pars_sql(info, sql);
1425
if (reserve_dict_mutex) {
1426
mutex_exit(&dict_sys->mutex);
1434
graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
1436
ut_a(thr = que_fork_start_command(graph));
1438
que_run_threads(thr);
1440
que_graph_free(graph);
1442
return(trx->error_state);