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
35
/* If the following flag is set TRUE, the module will print trace info
36
of SQL execution in the UNIV_SQL_DEBUG version */
37
UNIV_INTERN ibool que_trace_on = FALSE;
38
#endif /* UNIV_DEBUG */
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
suspended_thr = NULL;
340
completed_thr = NULL;
342
/* Choose the query thread to run: usually there is just one thread,
343
but in a parallelized select, which necessarily is non-scrollable,
344
there may be several to choose from */
346
/* First we try to find a query thread in the QUE_THR_COMMAND_WAIT
347
state. Then we try to find a query thread in the QUE_THR_SUSPENDED
348
state, finally we try to find a query thread in the QUE_THR_COMPLETED
351
thr = UT_LIST_GET_FIRST(fork->thrs);
353
/* We make a single pass over the thr list within which we note which
354
threads are ready to run. */
356
switch (thr->state) {
357
case QUE_THR_COMMAND_WAIT:
359
/* We have to send the initial message to query thread
362
que_thr_init_command(thr);
366
case QUE_THR_SUSPENDED:
367
/* In this case the execution of the thread was
368
suspended: no initial message is needed because
369
execution can continue from where it was left */
370
if (!suspended_thr) {
376
case QUE_THR_COMPLETED:
377
if (!completed_thr) {
383
case QUE_THR_LOCK_WAIT:
388
thr = UT_LIST_GET_NEXT(thrs, thr);
394
que_thr_move_to_run_state(thr);
396
} else if (completed_thr) {
399
que_thr_init_command(thr);
405
/**************************************************************************
406
After signal handling is finished, returns control to a query graph error
407
handling routine. (Currently, just returns the control to the root of the
408
graph so that the graph can communicate an error message to the client.) */
411
que_fork_error_handle(
412
/*==================*/
413
trx_t* trx __attribute__((unused)), /* in: trx */
414
que_t* fork) /* in: query graph which was run before signal
415
handling started, NULL not allowed */
419
ut_ad(mutex_own(&kernel_mutex));
420
ut_ad(trx->sess->state == SESS_ERROR);
421
ut_ad(UT_LIST_GET_LEN(trx->reply_signals) == 0);
422
ut_ad(UT_LIST_GET_LEN(trx->wait_thrs) == 0);
424
thr = UT_LIST_GET_FIRST(fork->thrs);
426
while (thr != NULL) {
427
ut_ad(!thr->is_active);
428
ut_ad(thr->state != QUE_THR_SIG_REPLY_WAIT);
429
ut_ad(thr->state != QUE_THR_LOCK_WAIT);
432
thr->prev_node = thr->child;
433
thr->state = QUE_THR_COMPLETED;
435
thr = UT_LIST_GET_NEXT(thrs, thr);
438
thr = UT_LIST_GET_FIRST(fork->thrs);
440
que_thr_move_to_run_state(thr);
443
srv_que_task_enqueue_low(thr);
446
/********************************************************************
447
Tests if all the query threads in the same fork have a given state. */
450
que_fork_all_thrs_in_state(
451
/*=======================*/
452
/* out: TRUE if all the query threads in the
453
same fork were in the given state */
454
que_fork_t* fork, /* in: query fork */
455
ulint state) /* in: state */
459
thr_node = UT_LIST_GET_FIRST(fork->thrs);
461
while (thr_node != NULL) {
462
if (thr_node->state != state) {
467
thr_node = UT_LIST_GET_NEXT(thrs, thr_node);
473
/**************************************************************************
474
Calls que_graph_free_recursive for statements in a statement list. */
477
que_graph_free_stat_list(
478
/*=====================*/
479
que_node_t* node) /* in: first query graph node in the list */
482
que_graph_free_recursive(node);
484
node = que_node_get_next(node);
488
/**************************************************************************
489
Frees a query graph, but not the heap where it was created. Does not free
490
explicit cursor declarations, they are freed in que_graph_free. */
493
que_graph_free_recursive(
494
/*=====================*/
495
que_node_t* node) /* in: query graph node */
511
switch (que_node_get_type(node)) {
516
thr = UT_LIST_GET_FIRST(fork->thrs);
519
que_graph_free_recursive(thr);
521
thr = UT_LIST_GET_NEXT(thrs, thr);
529
if (thr->magic_n != QUE_THR_MAGIC_N) {
531
"que_thr struct appears corrupt;"
533
(unsigned long) thr->magic_n);
534
mem_analyze_corruption(thr);
538
thr->magic_n = QUE_THR_MAGIC_FREED;
540
que_graph_free_recursive(thr->child);
547
mem_heap_free(undo->heap);
550
case QUE_NODE_SELECT:
554
sel_node_free_private(sel);
557
case QUE_NODE_INSERT:
561
que_graph_free_recursive(ins->select);
563
mem_heap_free(ins->entry_sys_heap);
566
case QUE_NODE_UPDATE:
570
if (upd->in_mysql_interface) {
572
btr_pcur_free_for_mysql(upd->pcur);
575
que_graph_free_recursive(upd->cascade_node);
577
if (upd->cascade_heap) {
578
mem_heap_free(upd->cascade_heap);
581
que_graph_free_recursive(upd->select);
583
mem_heap_free(upd->heap);
586
case QUE_NODE_CREATE_TABLE:
589
que_graph_free_recursive(cre_tab->tab_def);
590
que_graph_free_recursive(cre_tab->col_def);
591
que_graph_free_recursive(cre_tab->commit_node);
593
mem_heap_free(cre_tab->heap);
596
case QUE_NODE_CREATE_INDEX:
599
que_graph_free_recursive(cre_ind->ind_def);
600
que_graph_free_recursive(cre_ind->field_def);
601
que_graph_free_recursive(cre_ind->commit_node);
603
mem_heap_free(cre_ind->heap);
607
que_graph_free_stat_list(((proc_node_t*)node)->stat_list);
611
que_graph_free_stat_list(((if_node_t*)node)->stat_list);
612
que_graph_free_stat_list(((if_node_t*)node)->else_part);
613
que_graph_free_stat_list(((if_node_t*)node)->elsif_list);
617
que_graph_free_stat_list(((elsif_node_t*)node)->stat_list);
621
que_graph_free_stat_list(((while_node_t*)node)->stat_list);
625
que_graph_free_stat_list(((for_node_t*)node)->stat_list);
629
case QUE_NODE_ASSIGNMENT:
631
case QUE_NODE_RETURN:
632
case QUE_NODE_COMMIT:
633
case QUE_NODE_ROLLBACK:
637
case QUE_NODE_ROW_PRINTF:
640
/* No need to do anything */
645
"que_node struct appears corrupt; type %lu\n",
646
(unsigned long) que_node_get_type(node));
647
mem_analyze_corruption(node);
652
/**************************************************************************
653
Frees a query graph. */
658
que_t* graph) /* in: query graph; we assume that the memory
659
heap where this graph was created is private
660
to this graph: if not, then use
661
que_graph_free_recursive and free the heap
666
if (graph->sym_tab) {
667
/* The following call frees dynamic memory allocated
668
for variables etc. during execution. Frees also explicit
669
cursor definitions. */
671
sym_tab_free_private(graph->sym_tab);
674
if (graph->info && graph->info->graph_owns_us) {
675
pars_info_free(graph->info);
678
que_graph_free_recursive(graph);
680
mem_heap_free(graph->heap);
683
/**************************************************************************
684
Checks if the query graph is in a state where it should be freed, and
685
frees it in that case. If the session is in a state where it should be
686
closed, also this is done. */
691
/* out: TRUE if freed */
692
que_t* graph) /* in: query graph */
696
ut_ad(mutex_own(&kernel_mutex));
698
sess = (graph->trx)->sess;
700
if ((graph->state == QUE_FORK_BEING_FREED)
701
&& (graph->n_active_thrs == 0)) {
703
UT_LIST_REMOVE(graphs, sess->graphs, graph);
704
que_graph_free(graph);
706
sess_try_close(sess);
714
/********************************************************************
715
Performs an execution step on a thr node. */
720
/* out: query thread to run next, or NULL
722
que_thr_t* thr) /* in: query thread where run_node must
723
be the thread node itself */
725
ut_ad(thr->run_node == thr);
727
if (thr->prev_node == thr->common.parent) {
728
/* If control to the node came from above, it is just passed
731
thr->run_node = thr->child;
736
mutex_enter(&kernel_mutex);
738
if (que_thr_peek_stop(thr)) {
740
mutex_exit(&kernel_mutex);
745
/* Thread execution completed */
747
thr->state = QUE_THR_COMPLETED;
749
mutex_exit(&kernel_mutex);
754
/**************************************************************************
755
Moves a thread from another state to the QUE_THR_RUNNING state. Increments
756
the n_active_thrs counters of the query graph and transaction if thr was
758
***NOTE***: This and ..._mysql are the only functions in which such a
759
transition is allowed to happen! */
762
que_thr_move_to_run_state(
763
/*======================*/
764
que_thr_t* thr) /* in: an query thread */
768
ut_ad(thr->state != QUE_THR_RUNNING);
770
trx = thr_get_trx(thr);
772
if (!thr->is_active) {
774
(thr->graph)->n_active_thrs++;
776
trx->n_active_thrs++;
778
thr->is_active = TRUE;
780
ut_ad((thr->graph)->n_active_thrs == 1);
781
ut_ad(trx->n_active_thrs == 1);
784
thr->state = QUE_THR_RUNNING;
787
/**************************************************************************
788
Decrements the query thread reference counts in the query graph and the
789
transaction. May start signal handling, e.g., a rollback.
791
This and que_thr_stop_for_mysql are the only functions where the reference
792
count can be decremented and this function may only be called from inside
793
que_run_threads or que_thr_check_if_switch! These restrictions exist to make
794
the rollback code easier to maintain. */
797
que_thr_dec_refer_count(
798
/*====================*/
799
que_thr_t* thr, /* in: query thread */
800
que_thr_t** next_thr) /* in/out: next query thread to run;
801
if the value which is passed in is
802
a pointer to a NULL pointer, then the
803
calling function can start running
804
a new query thread */
811
fork = thr->common.parent;
812
trx = thr_get_trx(thr);
814
mutex_enter(&kernel_mutex);
816
ut_a(thr->is_active);
818
if (thr->state == QUE_THR_RUNNING) {
820
stopped = que_thr_stop(thr);
823
/* The reason for the thr suspension or wait was
824
already canceled before we came here: continue
825
running the thread */
827
/* fputs("!!!!!!!! Wait already ended: continue thr\n",
830
if (next_thr && *next_thr == NULL) {
831
/* Normally srv_suspend_mysql_thread resets
832
the state to DB_SUCCESS before waiting, but
833
in this case we have to do it here,
834
otherwise nobody does it. */
835
trx->error_state = DB_SUCCESS;
840
srv_que_task_enqueue_low(thr);
843
mutex_exit(&kernel_mutex);
849
ut_ad(fork->n_active_thrs == 1);
850
ut_ad(trx->n_active_thrs == 1);
852
fork->n_active_thrs--;
853
trx->n_active_thrs--;
855
thr->is_active = FALSE;
857
if (trx->n_active_thrs > 0) {
859
mutex_exit(&kernel_mutex);
864
fork_type = fork->fork_type;
866
/* Check if all query threads in the same fork are completed */
868
if (que_fork_all_thrs_in_state(fork, QUE_THR_COMPLETED)) {
871
case QUE_FORK_ROLLBACK:
872
/* This is really the undo graph used in rollback,
873
no roll_node in this graph */
875
ut_ad(UT_LIST_GET_LEN(trx->signals) > 0);
876
ut_ad(trx->handling_signals == TRUE);
878
trx_finish_rollback_off_kernel(fork, trx, next_thr);
882
case QUE_FORK_RECOVERY:
883
case QUE_FORK_MYSQL_INTERFACE:
889
ut_error; /* not used in MySQL */
893
if (UT_LIST_GET_LEN(trx->signals) > 0 && trx->n_active_thrs == 0) {
895
/* If the trx is signaled and its query thread count drops to
896
zero, then we start processing a signal; from it we may get
897
a new query thread to run */
899
trx_sig_start_handle(trx, next_thr);
902
if (trx->handling_signals && UT_LIST_GET_LEN(trx->signals) == 0) {
904
trx_end_signal_handling(trx);
907
mutex_exit(&kernel_mutex);
910
/**************************************************************************
911
Stops a query thread if graph or trx is in a state requiring it. The
912
conditions are tested in the order (1) graph, (2) trx. The kernel mutex has
918
/* out: TRUE if stopped */
919
que_thr_t* thr) /* in: query thread */
925
ut_ad(mutex_own(&kernel_mutex));
930
if (graph->state == QUE_FORK_COMMAND_WAIT) {
931
thr->state = QUE_THR_SUSPENDED;
933
} else if (trx->que_state == TRX_QUE_LOCK_WAIT) {
935
UT_LIST_ADD_FIRST(trx_thrs, trx->wait_thrs, thr);
936
thr->state = QUE_THR_LOCK_WAIT;
938
} else if (trx->error_state != DB_SUCCESS
939
&& trx->error_state != DB_LOCK_WAIT) {
941
/* Error handling built for the MySQL interface */
942
thr->state = QUE_THR_COMPLETED;
944
} else if (UT_LIST_GET_LEN(trx->signals) > 0
945
&& graph->fork_type != QUE_FORK_ROLLBACK) {
947
thr->state = QUE_THR_SUSPENDED;
949
ut_ad(graph->state == QUE_FORK_ACTIVE);
957
/**************************************************************************
958
A patch for MySQL used to 'stop' a dummy query thread used in MySQL. The
959
query thread is stopped and made inactive, except in the case where
960
it was put to the lock wait state in lock0lock.c, but the lock has already
961
been granted or the transaction chosen as a victim in deadlock resolution. */
964
que_thr_stop_for_mysql(
965
/*===================*/
966
que_thr_t* thr) /* in: query thread */
970
trx = thr_get_trx(thr);
972
mutex_enter(&kernel_mutex);
974
if (thr->state == QUE_THR_RUNNING) {
976
if (trx->error_state != DB_SUCCESS
977
&& trx->error_state != DB_LOCK_WAIT) {
979
/* Error handling built for the MySQL interface */
980
thr->state = QUE_THR_COMPLETED;
982
/* It must have been a lock wait but the lock was
983
already released, or this transaction was chosen
984
as a victim in selective deadlock resolution */
986
mutex_exit(&kernel_mutex);
992
ut_ad(thr->is_active == TRUE);
993
ut_ad(trx->n_active_thrs == 1);
994
ut_ad(thr->graph->n_active_thrs == 1);
996
thr->is_active = FALSE;
997
(thr->graph)->n_active_thrs--;
999
trx->n_active_thrs--;
1001
mutex_exit(&kernel_mutex);
1004
/**************************************************************************
1005
Moves a thread from another state to the QUE_THR_RUNNING state. Increments
1006
the n_active_thrs counters of the query graph and transaction if thr was
1010
que_thr_move_to_run_state_for_mysql(
1011
/*================================*/
1012
que_thr_t* thr, /* in: an query thread */
1013
trx_t* trx) /* in: transaction */
1015
if (thr->magic_n != QUE_THR_MAGIC_N) {
1017
"que_thr struct appears corrupt; magic n %lu\n",
1018
(unsigned long) thr->magic_n);
1020
mem_analyze_corruption(thr);
1025
if (!thr->is_active) {
1027
thr->graph->n_active_thrs++;
1029
trx->n_active_thrs++;
1031
thr->is_active = TRUE;
1034
thr->state = QUE_THR_RUNNING;
1037
/**************************************************************************
1038
A patch for MySQL used to 'stop' a dummy query thread used in MySQL
1039
select, when there is no error or lock wait. */
1042
que_thr_stop_for_mysql_no_error(
1043
/*============================*/
1044
que_thr_t* thr, /* in: query thread */
1045
trx_t* trx) /* in: transaction */
1047
ut_ad(thr->state == QUE_THR_RUNNING);
1048
ut_ad(thr->is_active == TRUE);
1049
ut_ad(trx->n_active_thrs == 1);
1050
ut_ad(thr->graph->n_active_thrs == 1);
1052
if (thr->magic_n != QUE_THR_MAGIC_N) {
1054
"que_thr struct appears corrupt; magic n %lu\n",
1055
(unsigned long) thr->magic_n);
1057
mem_analyze_corruption(thr);
1062
thr->state = QUE_THR_COMPLETED;
1064
thr->is_active = FALSE;
1065
(thr->graph)->n_active_thrs--;
1067
trx->n_active_thrs--;
1070
/********************************************************************
1071
Get the first containing loop node (e.g. while_node_t or for_node_t) for the
1072
given node, or NULL if the node is not within a loop. */
1075
que_node_get_containing_loop_node(
1076
/*==============================*/
1077
/* out: containing loop node, or NULL. */
1078
que_node_t* node) /* in: node */
1085
node = que_node_get_parent(node);
1091
type = que_node_get_type(node);
1093
if ((type == QUE_NODE_FOR) || (type == QUE_NODE_WHILE)) {
1101
/**************************************************************************
1102
Prints info of an SQL query graph node. */
1105
que_node_print_info(
1106
/*================*/
1107
que_node_t* node) /* in: query graph node */
1112
type = que_node_get_type(node);
1114
if (type == QUE_NODE_SELECT) {
1116
} else if (type == QUE_NODE_INSERT) {
1118
} else if (type == QUE_NODE_UPDATE) {
1120
} else if (type == QUE_NODE_WHILE) {
1122
} else if (type == QUE_NODE_ASSIGNMENT) {
1124
} else if (type == QUE_NODE_IF) {
1126
} else if (type == QUE_NODE_FETCH) {
1128
} else if (type == QUE_NODE_OPEN) {
1130
} else if (type == QUE_NODE_PROC) {
1131
str = "STORED PROCEDURE";
1132
} else if (type == QUE_NODE_FUNC) {
1134
} else if (type == QUE_NODE_LOCK) {
1136
} else if (type == QUE_NODE_THR) {
1137
str = "QUERY THREAD";
1138
} else if (type == QUE_NODE_COMMIT) {
1140
} else if (type == QUE_NODE_UNDO) {
1142
} else if (type == QUE_NODE_PURGE) {
1144
} else if (type == QUE_NODE_ROLLBACK) {
1146
} else if (type == QUE_NODE_CREATE_TABLE) {
1147
str = "CREATE TABLE";
1148
} else if (type == QUE_NODE_CREATE_INDEX) {
1149
str = "CREATE INDEX";
1150
} else if (type == QUE_NODE_FOR) {
1152
} else if (type == QUE_NODE_RETURN) {
1154
} else if (type == QUE_NODE_EXIT) {
1157
str = "UNKNOWN NODE TYPE";
1160
fprintf(stderr, "Node type %lu: %s, address %p\n",
1161
(ulong) type, str, (void*) node);
1164
/**************************************************************************
1165
Performs an execution step on a query thread. */
1170
/* out: query thread to run next: it may
1171
differ from the input parameter if, e.g., a
1172
subprocedure call is made */
1173
que_thr_t* thr) /* in: query thread */
1180
trx = thr_get_trx(thr);
1182
ut_ad(thr->state == QUE_THR_RUNNING);
1183
ut_a(trx->error_state == DB_SUCCESS);
1187
node = thr->run_node;
1188
type = que_node_get_type(node);
1194
fputs("To execute: ", stderr);
1195
que_node_print_info(node);
1198
if (type & QUE_NODE_CONTROL_STAT) {
1199
if ((thr->prev_node != que_node_get_parent(node))
1200
&& que_node_get_next(thr->prev_node)) {
1202
/* The control statements, like WHILE, always pass the
1203
control to the next child statement if there is any
1206
thr->run_node = que_node_get_next(thr->prev_node);
1208
} else if (type == QUE_NODE_IF) {
1210
} else if (type == QUE_NODE_FOR) {
1212
} else if (type == QUE_NODE_PROC) {
1214
/* We can access trx->undo_no without reserving
1215
trx->undo_mutex, because there cannot be active query
1216
threads doing updating or inserting at the moment! */
1218
if (thr->prev_node == que_node_get_parent(node)) {
1219
trx->last_sql_stat_start.least_undo_no
1224
} else if (type == QUE_NODE_WHILE) {
1229
} else if (type == QUE_NODE_ASSIGNMENT) {
1231
} else if (type == QUE_NODE_SELECT) {
1232
thr = row_sel_step(thr);
1233
} else if (type == QUE_NODE_INSERT) {
1234
thr = row_ins_step(thr);
1235
} else if (type == QUE_NODE_UPDATE) {
1236
thr = row_upd_step(thr);
1237
} else if (type == QUE_NODE_FETCH) {
1238
thr = fetch_step(thr);
1239
} else if (type == QUE_NODE_OPEN) {
1240
thr = open_step(thr);
1241
} else if (type == QUE_NODE_FUNC) {
1242
proc_eval_step(thr);
1244
} else if (type == QUE_NODE_LOCK) {
1248
thr = que_lock_step(thr);
1250
} else if (type == QUE_NODE_THR) {
1251
thr = que_thr_node_step(thr);
1252
} else if (type == QUE_NODE_COMMIT) {
1253
thr = trx_commit_step(thr);
1254
} else if (type == QUE_NODE_UNDO) {
1255
thr = row_undo_step(thr);
1256
} else if (type == QUE_NODE_PURGE) {
1257
thr = row_purge_step(thr);
1258
} else if (type == QUE_NODE_RETURN) {
1259
thr = return_step(thr);
1260
} else if (type == QUE_NODE_EXIT) {
1261
thr = exit_step(thr);
1262
} else if (type == QUE_NODE_ROLLBACK) {
1263
thr = trx_rollback_step(thr);
1264
} else if (type == QUE_NODE_CREATE_TABLE) {
1265
thr = dict_create_table_step(thr);
1266
} else if (type == QUE_NODE_CREATE_INDEX) {
1267
thr = dict_create_index_step(thr);
1268
} else if (type == QUE_NODE_ROW_PRINTF) {
1269
thr = row_printf_step(thr);
1274
if (type == QUE_NODE_EXIT) {
1275
old_thr->prev_node = que_node_get_containing_loop_node(node);
1277
old_thr->prev_node = node;
1281
ut_a(thr_get_trx(thr)->error_state == DB_SUCCESS);
1287
/**************************************************************************
1288
Run a query thread until it finishes or encounters e.g. a lock wait. */
1291
que_run_threads_low(
1292
/*================*/
1293
que_thr_t* thr) /* in: query thread */
1295
que_thr_t* next_thr;
1296
ulint cumul_resource;
1299
ut_ad(thr->state == QUE_THR_RUNNING);
1300
ut_a(thr_get_trx(thr)->error_state == DB_SUCCESS);
1301
ut_ad(!mutex_own(&kernel_mutex));
1303
/* cumul_resource counts how much resources the OS thread (NOT the
1304
query thread) has spent in this function */
1306
loop_count = QUE_MAX_LOOPS_WITHOUT_CHECK;
1309
/* Check that there is enough space in the log to accommodate
1310
possible log entries by this query step; if the operation can touch
1311
more than about 4 pages, checks must be made also within the query
1316
/* Perform the actual query step: note that the query thread
1317
may change if, e.g., a subprocedure call is made */
1319
/*-------------------------*/
1320
next_thr = que_thr_step(thr);
1321
/*-------------------------*/
1323
ut_a(!next_thr || (thr_get_trx(next_thr)->error_state == DB_SUCCESS));
1327
if (next_thr != thr) {
1328
ut_a(next_thr == NULL);
1330
/* This can change next_thr to a non-NULL value if there was
1331
a lock wait that already completed. */
1332
que_thr_dec_refer_count(thr, &next_thr);
1334
if (next_thr == NULL) {
1339
loop_count = QUE_MAX_LOOPS_WITHOUT_CHECK;
1347
/**************************************************************************
1348
Run a query thread. Handles lock waits. */
1353
que_thr_t* thr) /* in: query thread */
1356
ut_a(thr_get_trx(thr)->error_state == DB_SUCCESS);
1357
que_run_threads_low(thr);
1359
mutex_enter(&kernel_mutex);
1361
switch (thr->state) {
1363
case QUE_THR_RUNNING:
1364
/* There probably was a lock wait, but it already ended
1365
before we came here: continue running thr */
1367
mutex_exit(&kernel_mutex);
1371
case QUE_THR_LOCK_WAIT:
1372
mutex_exit(&kernel_mutex);
1374
/* The ..._mysql_... function works also for InnoDB's
1375
internal threads. Let us wait that the lock wait ends. */
1377
srv_suspend_mysql_thread(thr);
1379
if (thr_get_trx(thr)->error_state != DB_SUCCESS) {
1380
/* thr was chosen as a deadlock victim or there was
1381
a lock wait timeout */
1383
que_thr_dec_refer_count(thr, NULL);
1390
case QUE_THR_COMPLETED:
1391
case QUE_THR_COMMAND_WAIT:
1399
mutex_exit(&kernel_mutex);
1402
/*************************************************************************
1403
Evaluate the given SQL. */
1408
/* out: error code or DB_SUCCESS */
1409
pars_info_t* info, /* in: info struct, or NULL */
1410
const char* sql, /* in: SQL string */
1411
ibool reserve_dict_mutex,
1412
/* in: if TRUE, acquire/release
1413
dict_sys->mutex around call to pars_sql. */
1414
trx_t* trx) /* in: trx */
1419
ut_a(trx->error_state == DB_SUCCESS);
1421
if (reserve_dict_mutex) {
1422
mutex_enter(&dict_sys->mutex);
1425
graph = pars_sql(info, sql);
1427
if (reserve_dict_mutex) {
1428
mutex_exit(&dict_sys->mutex);
1436
graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
1438
ut_a(thr = que_fork_start_command(graph));
1440
que_run_threads(thr);
1442
que_graph_free(graph);
1444
return(trx->error_state);