~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/innobase/que/que0que.c

  • Committer: Brian Aker
  • Date: 2009-07-11 19:23:04 UTC
  • mfrom: (1089.1.14 merge)
  • Revision ID: brian@gaz-20090711192304-ootijyl5yf9jq9kd
Merge Brian

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/******************************************************
2
 
Query graph
3
 
 
4
 
(c) 1996 Innobase Oy
5
 
 
6
 
Created 5/27/1996 Heikki Tuuri
7
 
*******************************************************/
8
 
 
9
 
#include "que0que.h"
10
 
 
11
 
#ifdef UNIV_NONINL
12
 
#include "que0que.ic"
13
 
#endif
14
 
 
15
 
#include "srv0que.h"
16
 
#include "usr0sess.h"
17
 
#include "trx0trx.h"
18
 
#include "trx0roll.h"
19
 
#include "row0undo.h"
20
 
#include "row0ins.h"
21
 
#include "row0upd.h"
22
 
#include "row0sel.h"
23
 
#include "row0purge.h"
24
 
#include "dict0crea.h"
25
 
#include "log0log.h"
26
 
#include "eval0proc.h"
27
 
#include "eval0eval.h"
28
 
#include "pars0types.h"
29
 
 
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
33
 
 
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;
37
 
 
38
 
ibool   que_always_false        = FALSE;
39
 
 
40
 
/* Short introduction to query graphs
41
 
   ==================================
42
 
 
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
47
 
last node executed.
48
 
 
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
51
 
of a block.
52
 
 
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.
60
 
 
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.
65
 
 
66
 
For example, the code:
67
 
 
68
 
X := 1;
69
 
WHILE X < 5 LOOP
70
 
 X := X + 1;
71
 
 X := X + 1;
72
 
X := 5
73
 
 
74
 
will result in the following node hierarchy, with the X-axis indicating
75
 
'next' links and the Y-axis indicating parent/child links:
76
 
 
77
 
A - W - A
78
 
    |
79
 
    |
80
 
    A - A
81
 
 
82
 
A = assign_node_t, W = while_node_t. */
83
 
 
84
 
/* How a stored procedure containing COMMIT or ROLLBACK commands
85
 
is executed?
86
 
 
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.
92
 
 
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
99
 
the signal.
100
 
 
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. */
109
 
 
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
114
 
to happen! */
115
 
static
116
 
void
117
 
que_thr_move_to_run_state(
118
 
/*======================*/
119
 
        que_thr_t*      thr);   /* in: an query thread */
120
 
 
121
 
/***************************************************************************
122
 
Adds a query graph to the session's list of graphs. */
123
 
 
124
 
void
125
 
que_graph_publish(
126
 
/*==============*/
127
 
        que_t*  graph,  /* in: graph */
128
 
        sess_t* sess)   /* in: session */
129
 
{
130
 
        ut_ad(mutex_own(&kernel_mutex));
131
 
 
132
 
        UT_LIST_ADD_LAST(graphs, sess->graphs, graph);
133
 
}
134
 
 
135
 
/***************************************************************************
136
 
Creates a query graph fork node. */
137
 
 
138
 
que_fork_t*
139
 
que_fork_create(
140
 
/*============*/
141
 
                                        /* out, own: fork node */
142
 
        que_t*          graph,          /* in: graph, if NULL then this
143
 
                                        fork node is assumed to be the
144
 
                                        graph root */
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 */
148
 
{
149
 
        que_fork_t*     fork;
150
 
 
151
 
        ut_ad(heap);
152
 
 
153
 
        fork = mem_heap_alloc(heap, sizeof(que_fork_t));
154
 
 
155
 
        fork->common.type = QUE_NODE_FORK;
156
 
        fork->n_active_thrs = 0;
157
 
 
158
 
        fork->state = QUE_FORK_COMMAND_WAIT;
159
 
 
160
 
        if (graph != NULL) {
161
 
                fork->graph = graph;
162
 
        } else {
163
 
                fork->graph = fork;
164
 
        }
165
 
 
166
 
        fork->common.parent = parent;
167
 
        fork->fork_type = fork_type;
168
 
 
169
 
        fork->caller = NULL;
170
 
 
171
 
        UT_LIST_INIT(fork->thrs);
172
 
 
173
 
        fork->sym_tab = NULL;
174
 
        fork->info = NULL;
175
 
 
176
 
        fork->heap = heap;
177
 
 
178
 
        return(fork);
179
 
}
180
 
 
181
 
/***************************************************************************
182
 
Creates a query graph thread node. */
183
 
 
184
 
que_thr_t*
185
 
que_thr_create(
186
 
/*===========*/
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 */
190
 
{
191
 
        que_thr_t*      thr;
192
 
 
193
 
        ut_ad(parent && heap);
194
 
 
195
 
        thr = mem_heap_alloc(heap, sizeof(que_thr_t));
196
 
 
197
 
        thr->common.type = QUE_NODE_THR;
198
 
        thr->common.parent = parent;
199
 
 
200
 
        thr->magic_n = QUE_THR_MAGIC_N;
201
 
 
202
 
        thr->graph = parent->graph;
203
 
 
204
 
        thr->state = QUE_THR_COMMAND_WAIT;
205
 
 
206
 
        thr->is_active = FALSE;
207
 
 
208
 
        thr->run_node = NULL;
209
 
        thr->resource = 0;
210
 
        thr->lock_state = QUE_THR_LOCK_NOLOCK;
211
 
 
212
 
        UT_LIST_ADD_LAST(thrs, parent->thrs, thr);
213
 
 
214
 
        return(thr);
215
 
}
216
 
 
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
221
 
completion. */
222
 
 
223
 
void
224
 
que_thr_end_wait(
225
 
/*=============*/
226
 
        que_thr_t*      thr,            /* in: query thread in the
227
 
                                        QUE_THR_LOCK_WAIT,
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 */
236
 
{
237
 
        ibool   was_active;
238
 
 
239
 
        ut_ad(mutex_own(&kernel_mutex));
240
 
        ut_ad(thr);
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);
245
 
 
246
 
        thr->prev_node = thr->run_node;
247
 
 
248
 
        was_active = thr->is_active;
249
 
 
250
 
        que_thr_move_to_run_state(thr);
251
 
 
252
 
        if (was_active) {
253
 
 
254
 
                return;
255
 
        }
256
 
 
257
 
        if (next_thr && *next_thr == NULL) {
258
 
                *next_thr = thr;
259
 
        } else {
260
 
                ut_a(0);
261
 
                srv_que_task_enqueue_low(thr);
262
 
        }
263
 
}
264
 
 
265
 
/**************************************************************************
266
 
Same as que_thr_end_wait, but no parameter next_thr available. */
267
 
 
268
 
void
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 */
274
 
{
275
 
        ibool   was_active;
276
 
 
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));
280
 
        ut_ad(thr);
281
 
        ut_ad((thr->state == QUE_THR_LOCK_WAIT)
282
 
              || (thr->state == QUE_THR_PROCEDURE_WAIT)
283
 
              || (thr->state == QUE_THR_SIG_REPLY_WAIT));
284
 
 
285
 
        was_active = thr->is_active;
286
 
 
287
 
        que_thr_move_to_run_state(thr);
288
 
 
289
 
        if (was_active) {
290
 
 
291
 
                return;
292
 
        }
293
 
 
294
 
        /* In MySQL we let the OS thread (not just the query thread) to wait
295
 
        for the lock to be released: */
296
 
 
297
 
        srv_release_mysql_thread_if_suspended(thr);
298
 
 
299
 
        /* srv_que_task_enqueue_low(thr); */
300
 
}
301
 
 
302
 
/**************************************************************************
303
 
Inits a query thread for a command. */
304
 
UNIV_INLINE
305
 
void
306
 
que_thr_init_command(
307
 
/*=================*/
308
 
        que_thr_t*      thr)    /* in: query thread */
309
 
{
310
 
        thr->run_node = thr;
311
 
        thr->prev_node = thr->common.parent;
312
 
 
313
 
        que_thr_move_to_run_state(thr);
314
 
}
315
 
 
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
320
 
is returned. */
321
 
 
322
 
que_thr_t*
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
328
 
                                by the caller */
329
 
        que_fork_t*     fork)   /* in: a query fork */
330
 
{
331
 
        que_thr_t*      thr;
332
 
        que_thr_t*      suspended_thr = NULL;
333
 
        que_thr_t*      completed_thr = NULL;
334
 
 
335
 
        fork->state = QUE_FORK_ACTIVE;
336
 
 
337
 
        fork->last_sel_node = NULL;
338
 
 
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 */
342
 
 
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
346
 
        state */
347
 
 
348
 
        thr = UT_LIST_GET_FIRST(fork->thrs);
349
 
 
350
 
        /* We make a single pass over the thr list within which we note which
351
 
        threads are ready to run. */
352
 
        while (thr) {
353
 
                switch (thr->state) {
354
 
                case QUE_THR_COMMAND_WAIT:
355
 
 
356
 
                        /* We have to send the initial message to query thread
357
 
                        to start it */
358
 
 
359
 
                        que_thr_init_command(thr);
360
 
 
361
 
                        return(thr);
362
 
 
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) {
368
 
                                suspended_thr = thr;
369
 
                        }
370
 
 
371
 
                        break;
372
 
 
373
 
                case QUE_THR_COMPLETED:
374
 
                        if (!completed_thr) {
375
 
                                completed_thr = thr;
376
 
                        }
377
 
 
378
 
                        break;
379
 
 
380
 
                case QUE_THR_LOCK_WAIT:
381
 
                        ut_error;
382
 
 
383
 
                }
384
 
 
385
 
                thr = UT_LIST_GET_NEXT(thrs, thr);
386
 
        }
387
 
 
388
 
        if (suspended_thr) {
389
 
 
390
 
                thr = suspended_thr;
391
 
                que_thr_move_to_run_state(thr);
392
 
 
393
 
        } else if (completed_thr) {
394
 
 
395
 
                thr = completed_thr;
396
 
                que_thr_init_command(thr);
397
 
        }
398
 
 
399
 
        return(thr);
400
 
}
401
 
 
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.) */
406
 
 
407
 
void
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 */
413
 
{
414
 
        que_thr_t*      thr;
415
 
 
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);
420
 
 
421
 
        thr = UT_LIST_GET_FIRST(fork->thrs);
422
 
 
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);
427
 
 
428
 
                thr->run_node = thr;
429
 
                thr->prev_node = thr->child;
430
 
                thr->state = QUE_THR_COMPLETED;
431
 
 
432
 
                thr = UT_LIST_GET_NEXT(thrs, thr);
433
 
        }
434
 
 
435
 
        thr = UT_LIST_GET_FIRST(fork->thrs);
436
 
 
437
 
        que_thr_move_to_run_state(thr);
438
 
 
439
 
        ut_a(0);
440
 
        srv_que_task_enqueue_low(thr);
441
 
}
442
 
 
443
 
/********************************************************************
444
 
Tests if all the query threads in the same fork have a given state. */
445
 
UNIV_INLINE
446
 
ibool
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 */
453
 
{
454
 
        que_thr_t*      thr_node;
455
 
 
456
 
        thr_node = UT_LIST_GET_FIRST(fork->thrs);
457
 
 
458
 
        while (thr_node != NULL) {
459
 
                if (thr_node->state != state) {
460
 
 
461
 
                        return(FALSE);
462
 
                }
463
 
 
464
 
                thr_node = UT_LIST_GET_NEXT(thrs, thr_node);
465
 
        }
466
 
 
467
 
        return(TRUE);
468
 
}
469
 
 
470
 
/**************************************************************************
471
 
Calls que_graph_free_recursive for statements in a statement list. */
472
 
static
473
 
void
474
 
que_graph_free_stat_list(
475
 
/*=====================*/
476
 
        que_node_t*     node)   /* in: first query graph node in the list */
477
 
{
478
 
        while (node) {
479
 
                que_graph_free_recursive(node);
480
 
 
481
 
                node = que_node_get_next(node);
482
 
        }
483
 
}
484
 
 
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. */
488
 
 
489
 
void
490
 
que_graph_free_recursive(
491
 
/*=====================*/
492
 
        que_node_t*     node)   /* in: query graph node */
493
 
{
494
 
        que_fork_t*     fork;
495
 
        que_thr_t*      thr;
496
 
        undo_node_t*    undo;
497
 
        sel_node_t*     sel;
498
 
        ins_node_t*     ins;
499
 
        upd_node_t*     upd;
500
 
        tab_node_t*     cre_tab;
501
 
        ind_node_t*     cre_ind;
502
 
 
503
 
        if (node == NULL) {
504
 
 
505
 
                return;
506
 
        }
507
 
 
508
 
        switch (que_node_get_type(node)) {
509
 
 
510
 
        case QUE_NODE_FORK:
511
 
                fork = node;
512
 
 
513
 
                thr = UT_LIST_GET_FIRST(fork->thrs);
514
 
 
515
 
                while (thr) {
516
 
                        que_graph_free_recursive(thr);
517
 
 
518
 
                        thr = UT_LIST_GET_NEXT(thrs, thr);
519
 
                }
520
 
 
521
 
                break;
522
 
        case QUE_NODE_THR:
523
 
 
524
 
                thr = node;
525
 
 
526
 
                if (thr->magic_n != QUE_THR_MAGIC_N) {
527
 
                        fprintf(stderr,
528
 
                                "que_thr struct appears corrupt;"
529
 
                                " magic n %lu\n",
530
 
                                (unsigned long) thr->magic_n);
531
 
                        mem_analyze_corruption(thr);
532
 
                        ut_error;
533
 
                }
534
 
 
535
 
                thr->magic_n = QUE_THR_MAGIC_FREED;
536
 
 
537
 
                que_graph_free_recursive(thr->child);
538
 
 
539
 
                break;
540
 
        case QUE_NODE_UNDO:
541
 
 
542
 
                undo = node;
543
 
 
544
 
                mem_heap_free(undo->heap);
545
 
 
546
 
                break;
547
 
        case QUE_NODE_SELECT:
548
 
 
549
 
                sel = node;
550
 
 
551
 
                sel_node_free_private(sel);
552
 
 
553
 
                break;
554
 
        case QUE_NODE_INSERT:
555
 
 
556
 
                ins = node;
557
 
 
558
 
                que_graph_free_recursive(ins->select);
559
 
 
560
 
                mem_heap_free(ins->entry_sys_heap);
561
 
 
562
 
                break;
563
 
        case QUE_NODE_UPDATE:
564
 
 
565
 
                upd = node;
566
 
 
567
 
                if (upd->in_mysql_interface) {
568
 
 
569
 
                        btr_pcur_free_for_mysql(upd->pcur);
570
 
                }
571
 
 
572
 
                que_graph_free_recursive(upd->cascade_node);
573
 
 
574
 
                if (upd->cascade_heap) {
575
 
                        mem_heap_free(upd->cascade_heap);
576
 
                }
577
 
 
578
 
                que_graph_free_recursive(upd->select);
579
 
 
580
 
                mem_heap_free(upd->heap);
581
 
 
582
 
                break;
583
 
        case QUE_NODE_CREATE_TABLE:
584
 
                cre_tab = node;
585
 
 
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);
589
 
 
590
 
                mem_heap_free(cre_tab->heap);
591
 
 
592
 
                break;
593
 
        case QUE_NODE_CREATE_INDEX:
594
 
                cre_ind = node;
595
 
 
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);
599
 
 
600
 
                mem_heap_free(cre_ind->heap);
601
 
 
602
 
                break;
603
 
        case QUE_NODE_PROC:
604
 
                que_graph_free_stat_list(((proc_node_t*)node)->stat_list);
605
 
 
606
 
                break;
607
 
        case QUE_NODE_IF:
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);
611
 
 
612
 
                break;
613
 
        case QUE_NODE_ELSIF:
614
 
                que_graph_free_stat_list(((elsif_node_t*)node)->stat_list);
615
 
 
616
 
                break;
617
 
        case QUE_NODE_WHILE:
618
 
                que_graph_free_stat_list(((while_node_t*)node)->stat_list);
619
 
 
620
 
                break;
621
 
        case QUE_NODE_FOR:
622
 
                que_graph_free_stat_list(((for_node_t*)node)->stat_list);
623
 
 
624
 
                break;
625
 
 
626
 
        case QUE_NODE_ASSIGNMENT:
627
 
        case QUE_NODE_EXIT:
628
 
        case QUE_NODE_RETURN:
629
 
        case QUE_NODE_COMMIT:
630
 
        case QUE_NODE_ROLLBACK:
631
 
        case QUE_NODE_LOCK:
632
 
        case QUE_NODE_FUNC:
633
 
        case QUE_NODE_ORDER:
634
 
        case QUE_NODE_ROW_PRINTF:
635
 
        case QUE_NODE_OPEN:
636
 
        case QUE_NODE_FETCH:
637
 
                /* No need to do anything */
638
 
 
639
 
                break;
640
 
        default:
641
 
                fprintf(stderr,
642
 
                        "que_node struct appears corrupt; type %lu\n",
643
 
                        (unsigned long) que_node_get_type(node));
644
 
                mem_analyze_corruption(node);
645
 
                ut_error;
646
 
        }
647
 
}
648
 
 
649
 
/**************************************************************************
650
 
Frees a query graph. */
651
 
 
652
 
void
653
 
que_graph_free(
654
 
/*===========*/
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
659
 
                        afterwards! */
660
 
{
661
 
        ut_ad(graph);
662
 
 
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. */
667
 
 
668
 
                sym_tab_free_private(graph->sym_tab);
669
 
        }
670
 
 
671
 
        if (graph->info && graph->info->graph_owns_us) {
672
 
                pars_info_free(graph->info);
673
 
        }
674
 
 
675
 
        que_graph_free_recursive(graph);
676
 
 
677
 
        mem_heap_free(graph->heap);
678
 
}
679
 
 
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. */
684
 
 
685
 
ibool
686
 
que_graph_try_free(
687
 
/*===============*/
688
 
                        /* out: TRUE if freed */
689
 
        que_t*  graph)  /* in: query graph */
690
 
{
691
 
        sess_t* sess;
692
 
 
693
 
        ut_ad(mutex_own(&kernel_mutex));
694
 
 
695
 
        sess = (graph->trx)->sess;
696
 
 
697
 
        if ((graph->state == QUE_FORK_BEING_FREED)
698
 
            && (graph->n_active_thrs == 0)) {
699
 
 
700
 
                UT_LIST_REMOVE(graphs, sess->graphs, graph);
701
 
                que_graph_free(graph);
702
 
 
703
 
                sess_try_close(sess);
704
 
 
705
 
                return(TRUE);
706
 
        }
707
 
 
708
 
        return(FALSE);
709
 
}
710
 
 
711
 
/********************************************************************
712
 
Performs an execution step on a thr node. */
713
 
static
714
 
que_thr_t*
715
 
que_thr_node_step(
716
 
/*==============*/
717
 
                                /* out: query thread to run next, or NULL
718
 
                                if none */
719
 
        que_thr_t*      thr)    /* in: query thread where run_node must
720
 
                                be the thread node itself */
721
 
{
722
 
        ut_ad(thr->run_node == thr);
723
 
 
724
 
        if (thr->prev_node == thr->common.parent) {
725
 
                /* If control to the node came from above, it is just passed
726
 
                on */
727
 
 
728
 
                thr->run_node = thr->child;
729
 
 
730
 
                return(thr);
731
 
        }
732
 
 
733
 
        mutex_enter(&kernel_mutex);
734
 
 
735
 
        if (que_thr_peek_stop(thr)) {
736
 
 
737
 
                mutex_exit(&kernel_mutex);
738
 
 
739
 
                return(thr);
740
 
        }
741
 
 
742
 
        /* Thread execution completed */
743
 
 
744
 
        thr->state = QUE_THR_COMPLETED;
745
 
 
746
 
        mutex_exit(&kernel_mutex);
747
 
 
748
 
        return(NULL);
749
 
}
750
 
 
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
754
 
not active.
755
 
***NOTE***: This and ..._mysql are  the only functions in which such a
756
 
transition is allowed to happen! */
757
 
static
758
 
void
759
 
que_thr_move_to_run_state(
760
 
/*======================*/
761
 
        que_thr_t*      thr)    /* in: an query thread */
762
 
{
763
 
        trx_t*  trx;
764
 
 
765
 
        ut_ad(thr->state != QUE_THR_RUNNING);
766
 
 
767
 
        trx = thr_get_trx(thr);
768
 
 
769
 
        if (!thr->is_active) {
770
 
 
771
 
                (thr->graph)->n_active_thrs++;
772
 
 
773
 
                trx->n_active_thrs++;
774
 
 
775
 
                thr->is_active = TRUE;
776
 
 
777
 
                ut_ad((thr->graph)->n_active_thrs == 1);
778
 
                ut_ad(trx->n_active_thrs == 1);
779
 
        }
780
 
 
781
 
        thr->state = QUE_THR_RUNNING;
782
 
}
783
 
 
784
 
/**************************************************************************
785
 
Decrements the query thread reference counts in the query graph and the
786
 
transaction. May start signal handling, e.g., a rollback.
787
 
*** NOTE ***:
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. */
792
 
static
793
 
void
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 */
802
 
{
803
 
        que_fork_t*     fork;
804
 
        trx_t*          trx;
805
 
        sess_t*         sess;
806
 
        ulint           fork_type;
807
 
        ibool           stopped;
808
 
 
809
 
        fork = thr->common.parent;
810
 
        trx = thr_get_trx(thr);
811
 
        sess = trx->sess;
812
 
 
813
 
        mutex_enter(&kernel_mutex);
814
 
 
815
 
        ut_a(thr->is_active);
816
 
 
817
 
        if (thr->state == QUE_THR_RUNNING) {
818
 
 
819
 
                stopped = que_thr_stop(thr);
820
 
 
821
 
                if (!stopped) {
822
 
                        /* The reason for the thr suspension or wait was
823
 
                        already canceled before we came here: continue
824
 
                        running the thread */
825
 
 
826
 
                        /* fputs("!!!!!!!! Wait already ended: continue thr\n",
827
 
                        stderr); */
828
 
 
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;
835
 
 
836
 
                                *next_thr = thr;
837
 
                        } else {
838
 
                                ut_a(0);
839
 
                                srv_que_task_enqueue_low(thr);
840
 
                        }
841
 
 
842
 
                        mutex_exit(&kernel_mutex);
843
 
 
844
 
                        return;
845
 
                }
846
 
        }
847
 
 
848
 
        ut_ad(fork->n_active_thrs == 1);
849
 
        ut_ad(trx->n_active_thrs == 1);
850
 
 
851
 
        fork->n_active_thrs--;
852
 
        trx->n_active_thrs--;
853
 
 
854
 
        thr->is_active = FALSE;
855
 
 
856
 
        if (trx->n_active_thrs > 0) {
857
 
 
858
 
                mutex_exit(&kernel_mutex);
859
 
 
860
 
                return;
861
 
        }
862
 
 
863
 
        fork_type = fork->fork_type;
864
 
 
865
 
        /* Check if all query threads in the same fork are completed */
866
 
 
867
 
        if (que_fork_all_thrs_in_state(fork, QUE_THR_COMPLETED)) {
868
 
 
869
 
                if (fork_type == QUE_FORK_ROLLBACK) {
870
 
                        /* This is really the undo graph used in rollback,
871
 
                        no roll_node in this graph */
872
 
 
873
 
                        ut_ad(UT_LIST_GET_LEN(trx->signals) > 0);
874
 
                        ut_ad(trx->handling_signals == TRUE);
875
 
 
876
 
                        trx_finish_rollback_off_kernel(fork, trx, next_thr);
877
 
 
878
 
                } else if (fork_type == QUE_FORK_PURGE) {
879
 
 
880
 
                        /* Do nothing */
881
 
                } else if (fork_type == QUE_FORK_RECOVERY) {
882
 
 
883
 
                        /* Do nothing */
884
 
                } else if (fork_type == QUE_FORK_DRIZZLE_INTERFACE) {
885
 
 
886
 
                        /* Do nothing */
887
 
                } else {
888
 
                        ut_error;       /* not used in MySQL */
889
 
                }
890
 
        }
891
 
 
892
 
        if (UT_LIST_GET_LEN(trx->signals) > 0 && trx->n_active_thrs == 0) {
893
 
 
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 */
897
 
 
898
 
                trx_sig_start_handle(trx, next_thr);
899
 
        }
900
 
 
901
 
        if (trx->handling_signals && UT_LIST_GET_LEN(trx->signals) == 0) {
902
 
 
903
 
                trx_end_signal_handling(trx);
904
 
        }
905
 
 
906
 
        mutex_exit(&kernel_mutex);
907
 
}
908
 
 
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
912
 
to be reserved. */
913
 
 
914
 
ibool
915
 
que_thr_stop(
916
 
/*=========*/
917
 
                                /* out: TRUE if stopped */
918
 
        que_thr_t*      thr)    /* in: query thread */
919
 
{
920
 
        trx_t*  trx;
921
 
        que_t*  graph;
922
 
        ibool   ret     = TRUE;
923
 
 
924
 
        ut_ad(mutex_own(&kernel_mutex));
925
 
 
926
 
        graph = thr->graph;
927
 
        trx = graph->trx;
928
 
 
929
 
        if (graph->state == QUE_FORK_COMMAND_WAIT) {
930
 
                thr->state = QUE_THR_SUSPENDED;
931
 
 
932
 
        } else if (trx->que_state == TRX_QUE_LOCK_WAIT) {
933
 
 
934
 
                UT_LIST_ADD_FIRST(trx_thrs, trx->wait_thrs, thr);
935
 
                thr->state = QUE_THR_LOCK_WAIT;
936
 
 
937
 
        } else if (trx->error_state != DB_SUCCESS
938
 
                   && trx->error_state != DB_LOCK_WAIT) {
939
 
 
940
 
                /* Error handling built for the MySQL interface */
941
 
                thr->state = QUE_THR_COMPLETED;
942
 
 
943
 
        } else if (UT_LIST_GET_LEN(trx->signals) > 0
944
 
                   && graph->fork_type != QUE_FORK_ROLLBACK) {
945
 
 
946
 
                thr->state = QUE_THR_SUSPENDED;
947
 
        } else {
948
 
                ut_ad(graph->state == QUE_FORK_ACTIVE);
949
 
 
950
 
                ret = FALSE;
951
 
        }
952
 
 
953
 
        return(ret);
954
 
}
955
 
 
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. */
961
 
 
962
 
void
963
 
que_thr_stop_for_mysql(
964
 
/*===================*/
965
 
        que_thr_t*      thr)    /* in: query thread */
966
 
{
967
 
        trx_t*  trx;
968
 
 
969
 
        trx = thr_get_trx(thr);
970
 
 
971
 
        mutex_enter(&kernel_mutex);
972
 
 
973
 
        if (thr->state == QUE_THR_RUNNING) {
974
 
 
975
 
                if (trx->error_state != DB_SUCCESS
976
 
                    && trx->error_state != DB_LOCK_WAIT) {
977
 
 
978
 
                        /* Error handling built for the MySQL interface */
979
 
                        thr->state = QUE_THR_COMPLETED;
980
 
                } else {
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 */
984
 
 
985
 
                        mutex_exit(&kernel_mutex);
986
 
 
987
 
                        return;
988
 
                }
989
 
        }
990
 
 
991
 
        ut_ad(thr->is_active == TRUE);
992
 
        ut_ad(trx->n_active_thrs == 1);
993
 
        ut_ad(thr->graph->n_active_thrs == 1);
994
 
 
995
 
        thr->is_active = FALSE;
996
 
        (thr->graph)->n_active_thrs--;
997
 
 
998
 
        trx->n_active_thrs--;
999
 
 
1000
 
        mutex_exit(&kernel_mutex);
1001
 
}
1002
 
 
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
1006
 
not active. */
1007
 
 
1008
 
void
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 */
1013
 
{
1014
 
        if (thr->magic_n != QUE_THR_MAGIC_N) {
1015
 
                fprintf(stderr,
1016
 
                        "que_thr struct appears corrupt; magic n %lu\n",
1017
 
                        (unsigned long) thr->magic_n);
1018
 
 
1019
 
                mem_analyze_corruption(thr);
1020
 
 
1021
 
                ut_error;
1022
 
        }
1023
 
 
1024
 
        if (!thr->is_active) {
1025
 
 
1026
 
                thr->graph->n_active_thrs++;
1027
 
 
1028
 
                trx->n_active_thrs++;
1029
 
 
1030
 
                thr->is_active = TRUE;
1031
 
        }
1032
 
 
1033
 
        thr->state = QUE_THR_RUNNING;
1034
 
}
1035
 
 
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. */
1039
 
 
1040
 
void
1041
 
que_thr_stop_for_mysql_no_error(
1042
 
/*============================*/
1043
 
        que_thr_t*      thr,    /* in: query thread */
1044
 
        trx_t*          trx)    /* in: transaction */
1045
 
{
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);
1050
 
 
1051
 
        if (thr->magic_n != QUE_THR_MAGIC_N) {
1052
 
                fprintf(stderr,
1053
 
                        "que_thr struct appears corrupt; magic n %lu\n",
1054
 
                        (unsigned long) thr->magic_n);
1055
 
 
1056
 
                mem_analyze_corruption(thr);
1057
 
 
1058
 
                ut_error;
1059
 
        }
1060
 
 
1061
 
        thr->state = QUE_THR_COMPLETED;
1062
 
 
1063
 
        thr->is_active = FALSE;
1064
 
        (thr->graph)->n_active_thrs--;
1065
 
 
1066
 
        trx->n_active_thrs--;
1067
 
}
1068
 
 
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. */
1072
 
 
1073
 
que_node_t*
1074
 
que_node_get_containing_loop_node(
1075
 
/*==============================*/
1076
 
                                /* out: containing loop node, or NULL. */
1077
 
        que_node_t*     node)   /* in: node */
1078
 
{
1079
 
        ut_ad(node);
1080
 
 
1081
 
        for (;;) {
1082
 
                ulint   type;
1083
 
 
1084
 
                node = que_node_get_parent(node);
1085
 
 
1086
 
                if (!node) {
1087
 
                        break;
1088
 
                }
1089
 
 
1090
 
                type = que_node_get_type(node);
1091
 
 
1092
 
                if ((type == QUE_NODE_FOR) || (type == QUE_NODE_WHILE)) {
1093
 
                        break;
1094
 
                }
1095
 
        }
1096
 
 
1097
 
        return(node);
1098
 
}
1099
 
 
1100
 
/**************************************************************************
1101
 
Prints info of an SQL query graph node. */
1102
 
 
1103
 
void
1104
 
que_node_print_info(
1105
 
/*================*/
1106
 
        que_node_t*     node)   /* in: query graph node */
1107
 
{
1108
 
        ulint           type;
1109
 
        const char*     str;
1110
 
 
1111
 
        type = que_node_get_type(node);
1112
 
 
1113
 
        if (type == QUE_NODE_SELECT) {
1114
 
                str = "SELECT";
1115
 
        } else if (type == QUE_NODE_INSERT) {
1116
 
                str = "INSERT";
1117
 
        } else if (type == QUE_NODE_UPDATE) {
1118
 
                str = "UPDATE";
1119
 
        } else if (type == QUE_NODE_WHILE) {
1120
 
                str = "WHILE";
1121
 
        } else if (type == QUE_NODE_ASSIGNMENT) {
1122
 
                str = "ASSIGNMENT";
1123
 
        } else if (type == QUE_NODE_IF) {
1124
 
                str = "IF";
1125
 
        } else if (type == QUE_NODE_FETCH) {
1126
 
                str = "FETCH";
1127
 
        } else if (type == QUE_NODE_OPEN) {
1128
 
                str = "OPEN";
1129
 
        } else if (type == QUE_NODE_PROC) {
1130
 
                str = "STORED PROCEDURE";
1131
 
        } else if (type == QUE_NODE_FUNC) {
1132
 
                str = "FUNCTION";
1133
 
        } else if (type == QUE_NODE_LOCK) {
1134
 
                str = "LOCK";
1135
 
        } else if (type == QUE_NODE_THR) {
1136
 
                str = "QUERY THREAD";
1137
 
        } else if (type == QUE_NODE_COMMIT) {
1138
 
                str = "COMMIT";
1139
 
        } else if (type == QUE_NODE_UNDO) {
1140
 
                str = "UNDO ROW";
1141
 
        } else if (type == QUE_NODE_PURGE) {
1142
 
                str = "PURGE ROW";
1143
 
        } else if (type == QUE_NODE_ROLLBACK) {
1144
 
                str = "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) {
1150
 
                str = "FOR LOOP";
1151
 
        } else if (type == QUE_NODE_RETURN) {
1152
 
                str = "RETURN";
1153
 
        } else if (type == QUE_NODE_EXIT) {
1154
 
                str = "EXIT";
1155
 
        } else {
1156
 
                str = "UNKNOWN NODE TYPE";
1157
 
        }
1158
 
 
1159
 
        fprintf(stderr, "Node type %lu: %s, address %p\n",
1160
 
                (ulong) type, str, (void*) node);
1161
 
}
1162
 
 
1163
 
/**************************************************************************
1164
 
Performs an execution step on a query thread. */
1165
 
UNIV_INLINE
1166
 
que_thr_t*
1167
 
que_thr_step(
1168
 
/*=========*/
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 */
1173
 
{
1174
 
        que_node_t*     node;
1175
 
        que_thr_t*      old_thr;
1176
 
        trx_t*          trx;
1177
 
        ulint           type;
1178
 
 
1179
 
        trx = thr_get_trx(thr);
1180
 
 
1181
 
        ut_ad(thr->state == QUE_THR_RUNNING);
1182
 
        ut_a(trx->error_state == DB_SUCCESS);
1183
 
 
1184
 
        thr->resource++;
1185
 
 
1186
 
        node = thr->run_node;
1187
 
        type = que_node_get_type(node);
1188
 
 
1189
 
        old_thr = thr;
1190
 
 
1191
 
#ifdef UNIV_DEBUG
1192
 
        if (que_trace_on) {
1193
 
                fputs("To execute: ", stderr);
1194
 
                que_node_print_info(node);
1195
 
        }
1196
 
#endif
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)) {
1200
 
 
1201
 
                        /* The control statements, like WHILE, always pass the
1202
 
                        control to the next child statement if there is any
1203
 
                        child left */
1204
 
 
1205
 
                        thr->run_node = que_node_get_next(thr->prev_node);
1206
 
 
1207
 
                } else if (type == QUE_NODE_IF) {
1208
 
                        if_step(thr);
1209
 
                } else if (type == QUE_NODE_FOR) {
1210
 
                        for_step(thr);
1211
 
                } else if (type == QUE_NODE_PROC) {
1212
 
 
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! */
1216
 
 
1217
 
                        if (thr->prev_node == que_node_get_parent(node)) {
1218
 
                                trx->last_sql_stat_start.least_undo_no
1219
 
                                        = trx->undo_no;
1220
 
                        }
1221
 
 
1222
 
                        proc_step(thr);
1223
 
                } else if (type == QUE_NODE_WHILE) {
1224
 
                        while_step(thr);
1225
 
                } else {
1226
 
                        ut_error;
1227
 
                }
1228
 
        } else if (type == QUE_NODE_ASSIGNMENT) {
1229
 
                assign_step(thr);
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);
1242
 
 
1243
 
        } else if (type == QUE_NODE_LOCK) {
1244
 
 
1245
 
                ut_error;
1246
 
                /*
1247
 
                thr = que_lock_step(thr);
1248
 
                */
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);
1269
 
        } else {
1270
 
                ut_error;
1271
 
        }
1272
 
 
1273
 
        if (type == QUE_NODE_EXIT) {
1274
 
                old_thr->prev_node = que_node_get_containing_loop_node(node);
1275
 
        } else {
1276
 
                old_thr->prev_node = node;
1277
 
        }
1278
 
 
1279
 
        if (thr) {
1280
 
                ut_a(thr_get_trx(thr)->error_state == DB_SUCCESS);
1281
 
        }
1282
 
 
1283
 
        return(thr);
1284
 
}
1285
 
 
1286
 
/**************************************************************************
1287
 
Run a query thread until it finishes or encounters e.g. a lock wait. */
1288
 
static
1289
 
void
1290
 
que_run_threads_low(
1291
 
/*================*/
1292
 
        que_thr_t*      thr)    /* in: query thread */
1293
 
{
1294
 
        que_thr_t*      next_thr;
1295
 
        ulint           cumul_resource;
1296
 
        ulint           loop_count;
1297
 
 
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));
1301
 
 
1302
 
        /* cumul_resource counts how much resources the OS thread (NOT the
1303
 
        query thread) has spent in this function */
1304
 
 
1305
 
        loop_count = QUE_MAX_LOOPS_WITHOUT_CHECK;
1306
 
        cumul_resource = 0;
1307
 
loop:
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
1311
 
        step! */
1312
 
 
1313
 
        log_free_check();
1314
 
 
1315
 
        /* Perform the actual query step: note that the query thread
1316
 
        may change if, e.g., a subprocedure call is made */
1317
 
 
1318
 
        /*-------------------------*/
1319
 
        next_thr = que_thr_step(thr);
1320
 
        /*-------------------------*/
1321
 
 
1322
 
        ut_a(!next_thr || (thr_get_trx(next_thr)->error_state == DB_SUCCESS));
1323
 
 
1324
 
        loop_count++;
1325
 
 
1326
 
        if (next_thr != thr) {
1327
 
                ut_a(next_thr == NULL);
1328
 
 
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);
1332
 
 
1333
 
                if (next_thr == NULL) {
1334
 
 
1335
 
                        return;
1336
 
                }
1337
 
 
1338
 
                loop_count = QUE_MAX_LOOPS_WITHOUT_CHECK;
1339
 
 
1340
 
                thr = next_thr;
1341
 
        }
1342
 
 
1343
 
        goto loop;
1344
 
}
1345
 
 
1346
 
/**************************************************************************
1347
 
Run a query thread. Handles lock waits. */
1348
 
void
1349
 
que_run_threads(
1350
 
/*============*/
1351
 
        que_thr_t*      thr)    /* in: query thread */
1352
 
{
1353
 
loop:
1354
 
        ut_a(thr_get_trx(thr)->error_state == DB_SUCCESS);
1355
 
        que_run_threads_low(thr);
1356
 
 
1357
 
        mutex_enter(&kernel_mutex);
1358
 
 
1359
 
        switch (thr->state) {
1360
 
 
1361
 
        case QUE_THR_RUNNING:
1362
 
                /* There probably was a lock wait, but it already ended
1363
 
                before we came here: continue running thr */
1364
 
 
1365
 
                mutex_exit(&kernel_mutex);
1366
 
 
1367
 
                goto loop;
1368
 
 
1369
 
        case QUE_THR_LOCK_WAIT:
1370
 
                mutex_exit(&kernel_mutex);
1371
 
 
1372
 
                /* The ..._mysql_... function works also for InnoDB's
1373
 
                internal threads. Let us wait that the lock wait ends. */
1374
 
 
1375
 
                srv_suspend_mysql_thread(thr);
1376
 
 
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 */
1380
 
 
1381
 
                        que_thr_dec_refer_count(thr, NULL);
1382
 
 
1383
 
                        return;
1384
 
                }
1385
 
 
1386
 
                goto loop;
1387
 
 
1388
 
        case QUE_THR_COMPLETED:
1389
 
        case QUE_THR_COMMAND_WAIT:
1390
 
                /* Do nothing */
1391
 
                break;
1392
 
 
1393
 
        default:
1394
 
                ut_error;
1395
 
        }
1396
 
 
1397
 
        mutex_exit(&kernel_mutex);
1398
 
}
1399
 
 
1400
 
/*************************************************************************
1401
 
Evaluate the given SQL. */
1402
 
 
1403
 
ulint
1404
 
que_eval_sql(
1405
 
/*=========*/
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 */
1413
 
{
1414
 
        que_thr_t*      thr;
1415
 
        que_t*          graph;
1416
 
 
1417
 
        ut_a(trx->error_state == DB_SUCCESS);
1418
 
 
1419
 
        if (reserve_dict_mutex) {
1420
 
                mutex_enter(&dict_sys->mutex);
1421
 
        }
1422
 
 
1423
 
        graph = pars_sql(info, sql);
1424
 
 
1425
 
        if (reserve_dict_mutex) {
1426
 
                mutex_exit(&dict_sys->mutex);
1427
 
        }
1428
 
 
1429
 
        ut_a(graph);
1430
 
 
1431
 
        graph->trx = trx;
1432
 
        trx->graph = NULL;
1433
 
 
1434
 
        graph->fork_type = QUE_FORK_DRIZZLE_INTERFACE;
1435
 
 
1436
 
        ut_a(thr = que_fork_start_command(graph));
1437
 
 
1438
 
        que_run_threads(thr);
1439
 
 
1440
 
        que_graph_free(graph);
1441
 
 
1442
 
        return(trx->error_state);
1443
 
}