~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

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_MYSQL_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_MYSQL_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
}