~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

Tags: innodb-plugin-1.0.1
Imported 1.0.1 with clean - with no changes.

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
#ifdef UNIV_DEBUG
 
35
/* If the following flag is set TRUE, the module will print trace info
 
36
of SQL execution in the UNIV_SQL_DEBUG version */
 
37
UNIV_INTERN ibool       que_trace_on            = FALSE;
 
38
#endif /* UNIV_DEBUG */
 
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
UNIV_INTERN
 
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
UNIV_INTERN
 
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
UNIV_INTERN
 
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
UNIV_INTERN
 
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
UNIV_INTERN
 
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
UNIV_INTERN
 
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
        suspended_thr = NULL;
 
340
        completed_thr = NULL;
 
341
 
 
342
        /* Choose the query thread to run: usually there is just one thread,
 
343
        but in a parallelized select, which necessarily is non-scrollable,
 
344
        there may be several to choose from */
 
345
 
 
346
        /* First we try to find a query thread in the QUE_THR_COMMAND_WAIT
 
347
        state. Then we try to find a query thread in the QUE_THR_SUSPENDED
 
348
        state, finally we try to find a query thread in the QUE_THR_COMPLETED
 
349
        state */
 
350
 
 
351
        thr = UT_LIST_GET_FIRST(fork->thrs);
 
352
 
 
353
        /* We make a single pass over the thr list within which we note which
 
354
        threads are ready to run. */
 
355
        while (thr) {
 
356
                switch (thr->state) {
 
357
                case QUE_THR_COMMAND_WAIT:
 
358
 
 
359
                        /* We have to send the initial message to query thread
 
360
                        to start it */
 
361
 
 
362
                        que_thr_init_command(thr);
 
363
 
 
364
                        return(thr);
 
365
 
 
366
                case QUE_THR_SUSPENDED:
 
367
                        /* In this case the execution of the thread was
 
368
                        suspended: no initial message is needed because
 
369
                        execution can continue from where it was left */
 
370
                        if (!suspended_thr) {
 
371
                                suspended_thr = thr;
 
372
                        }
 
373
 
 
374
                        break;
 
375
 
 
376
                case QUE_THR_COMPLETED:
 
377
                        if (!completed_thr) {
 
378
                                completed_thr = thr;
 
379
                        }
 
380
 
 
381
                        break;
 
382
 
 
383
                case QUE_THR_LOCK_WAIT:
 
384
                        ut_error;
 
385
 
 
386
                }
 
387
 
 
388
                thr = UT_LIST_GET_NEXT(thrs, thr);
 
389
        }
 
390
 
 
391
        if (suspended_thr) {
 
392
 
 
393
                thr = suspended_thr;
 
394
                que_thr_move_to_run_state(thr);
 
395
 
 
396
        } else if (completed_thr) {
 
397
 
 
398
                thr = completed_thr;
 
399
                que_thr_init_command(thr);
 
400
        }
 
401
 
 
402
        return(thr);
 
403
}
 
404
 
 
405
/**************************************************************************
 
406
After signal handling is finished, returns control to a query graph error
 
407
handling routine. (Currently, just returns the control to the root of the
 
408
graph so that the graph can communicate an error message to the client.) */
 
409
UNIV_INTERN
 
410
void
 
411
que_fork_error_handle(
 
412
/*==================*/
 
413
        trx_t*  trx __attribute__((unused)),    /* in: trx */
 
414
        que_t*  fork)   /* in: query graph which was run before signal
 
415
                        handling started, NULL not allowed */
 
416
{
 
417
        que_thr_t*      thr;
 
418
 
 
419
        ut_ad(mutex_own(&kernel_mutex));
 
420
        ut_ad(trx->sess->state == SESS_ERROR);
 
421
        ut_ad(UT_LIST_GET_LEN(trx->reply_signals) == 0);
 
422
        ut_ad(UT_LIST_GET_LEN(trx->wait_thrs) == 0);
 
423
 
 
424
        thr = UT_LIST_GET_FIRST(fork->thrs);
 
425
 
 
426
        while (thr != NULL) {
 
427
                ut_ad(!thr->is_active);
 
428
                ut_ad(thr->state != QUE_THR_SIG_REPLY_WAIT);
 
429
                ut_ad(thr->state != QUE_THR_LOCK_WAIT);
 
430
 
 
431
                thr->run_node = thr;
 
432
                thr->prev_node = thr->child;
 
433
                thr->state = QUE_THR_COMPLETED;
 
434
 
 
435
                thr = UT_LIST_GET_NEXT(thrs, thr);
 
436
        }
 
437
 
 
438
        thr = UT_LIST_GET_FIRST(fork->thrs);
 
439
 
 
440
        que_thr_move_to_run_state(thr);
 
441
 
 
442
        ut_a(0);
 
443
        srv_que_task_enqueue_low(thr);
 
444
}
 
445
 
 
446
/********************************************************************
 
447
Tests if all the query threads in the same fork have a given state. */
 
448
UNIV_INLINE
 
449
ibool
 
450
que_fork_all_thrs_in_state(
 
451
/*=======================*/
 
452
                                /* out: TRUE if all the query threads in the
 
453
                                same fork were in the given state */
 
454
        que_fork_t*     fork,   /* in: query fork */
 
455
        ulint           state)  /* in: state */
 
456
{
 
457
        que_thr_t*      thr_node;
 
458
 
 
459
        thr_node = UT_LIST_GET_FIRST(fork->thrs);
 
460
 
 
461
        while (thr_node != NULL) {
 
462
                if (thr_node->state != state) {
 
463
 
 
464
                        return(FALSE);
 
465
                }
 
466
 
 
467
                thr_node = UT_LIST_GET_NEXT(thrs, thr_node);
 
468
        }
 
469
 
 
470
        return(TRUE);
 
471
}
 
472
 
 
473
/**************************************************************************
 
474
Calls que_graph_free_recursive for statements in a statement list. */
 
475
static
 
476
void
 
477
que_graph_free_stat_list(
 
478
/*=====================*/
 
479
        que_node_t*     node)   /* in: first query graph node in the list */
 
480
{
 
481
        while (node) {
 
482
                que_graph_free_recursive(node);
 
483
 
 
484
                node = que_node_get_next(node);
 
485
        }
 
486
}
 
487
 
 
488
/**************************************************************************
 
489
Frees a query graph, but not the heap where it was created. Does not free
 
490
explicit cursor declarations, they are freed in que_graph_free. */
 
491
UNIV_INTERN
 
492
void
 
493
que_graph_free_recursive(
 
494
/*=====================*/
 
495
        que_node_t*     node)   /* in: query graph node */
 
496
{
 
497
        que_fork_t*     fork;
 
498
        que_thr_t*      thr;
 
499
        undo_node_t*    undo;
 
500
        sel_node_t*     sel;
 
501
        ins_node_t*     ins;
 
502
        upd_node_t*     upd;
 
503
        tab_node_t*     cre_tab;
 
504
        ind_node_t*     cre_ind;
 
505
 
 
506
        if (node == NULL) {
 
507
 
 
508
                return;
 
509
        }
 
510
 
 
511
        switch (que_node_get_type(node)) {
 
512
 
 
513
        case QUE_NODE_FORK:
 
514
                fork = node;
 
515
 
 
516
                thr = UT_LIST_GET_FIRST(fork->thrs);
 
517
 
 
518
                while (thr) {
 
519
                        que_graph_free_recursive(thr);
 
520
 
 
521
                        thr = UT_LIST_GET_NEXT(thrs, thr);
 
522
                }
 
523
 
 
524
                break;
 
525
        case QUE_NODE_THR:
 
526
 
 
527
                thr = node;
 
528
 
 
529
                if (thr->magic_n != QUE_THR_MAGIC_N) {
 
530
                        fprintf(stderr,
 
531
                                "que_thr struct appears corrupt;"
 
532
                                " magic n %lu\n",
 
533
                                (unsigned long) thr->magic_n);
 
534
                        mem_analyze_corruption(thr);
 
535
                        ut_error;
 
536
                }
 
537
 
 
538
                thr->magic_n = QUE_THR_MAGIC_FREED;
 
539
 
 
540
                que_graph_free_recursive(thr->child);
 
541
 
 
542
                break;
 
543
        case QUE_NODE_UNDO:
 
544
 
 
545
                undo = node;
 
546
 
 
547
                mem_heap_free(undo->heap);
 
548
 
 
549
                break;
 
550
        case QUE_NODE_SELECT:
 
551
 
 
552
                sel = node;
 
553
 
 
554
                sel_node_free_private(sel);
 
555
 
 
556
                break;
 
557
        case QUE_NODE_INSERT:
 
558
 
 
559
                ins = node;
 
560
 
 
561
                que_graph_free_recursive(ins->select);
 
562
 
 
563
                mem_heap_free(ins->entry_sys_heap);
 
564
 
 
565
                break;
 
566
        case QUE_NODE_UPDATE:
 
567
 
 
568
                upd = node;
 
569
 
 
570
                if (upd->in_mysql_interface) {
 
571
 
 
572
                        btr_pcur_free_for_mysql(upd->pcur);
 
573
                }
 
574
 
 
575
                que_graph_free_recursive(upd->cascade_node);
 
576
 
 
577
                if (upd->cascade_heap) {
 
578
                        mem_heap_free(upd->cascade_heap);
 
579
                }
 
580
 
 
581
                que_graph_free_recursive(upd->select);
 
582
 
 
583
                mem_heap_free(upd->heap);
 
584
 
 
585
                break;
 
586
        case QUE_NODE_CREATE_TABLE:
 
587
                cre_tab = node;
 
588
 
 
589
                que_graph_free_recursive(cre_tab->tab_def);
 
590
                que_graph_free_recursive(cre_tab->col_def);
 
591
                que_graph_free_recursive(cre_tab->commit_node);
 
592
 
 
593
                mem_heap_free(cre_tab->heap);
 
594
 
 
595
                break;
 
596
        case QUE_NODE_CREATE_INDEX:
 
597
                cre_ind = node;
 
598
 
 
599
                que_graph_free_recursive(cre_ind->ind_def);
 
600
                que_graph_free_recursive(cre_ind->field_def);
 
601
                que_graph_free_recursive(cre_ind->commit_node);
 
602
 
 
603
                mem_heap_free(cre_ind->heap);
 
604
 
 
605
                break;
 
606
        case QUE_NODE_PROC:
 
607
                que_graph_free_stat_list(((proc_node_t*)node)->stat_list);
 
608
 
 
609
                break;
 
610
        case QUE_NODE_IF:
 
611
                que_graph_free_stat_list(((if_node_t*)node)->stat_list);
 
612
                que_graph_free_stat_list(((if_node_t*)node)->else_part);
 
613
                que_graph_free_stat_list(((if_node_t*)node)->elsif_list);
 
614
 
 
615
                break;
 
616
        case QUE_NODE_ELSIF:
 
617
                que_graph_free_stat_list(((elsif_node_t*)node)->stat_list);
 
618
 
 
619
                break;
 
620
        case QUE_NODE_WHILE:
 
621
                que_graph_free_stat_list(((while_node_t*)node)->stat_list);
 
622
 
 
623
                break;
 
624
        case QUE_NODE_FOR:
 
625
                que_graph_free_stat_list(((for_node_t*)node)->stat_list);
 
626
 
 
627
                break;
 
628
 
 
629
        case QUE_NODE_ASSIGNMENT:
 
630
        case QUE_NODE_EXIT:
 
631
        case QUE_NODE_RETURN:
 
632
        case QUE_NODE_COMMIT:
 
633
        case QUE_NODE_ROLLBACK:
 
634
        case QUE_NODE_LOCK:
 
635
        case QUE_NODE_FUNC:
 
636
        case QUE_NODE_ORDER:
 
637
        case QUE_NODE_ROW_PRINTF:
 
638
        case QUE_NODE_OPEN:
 
639
        case QUE_NODE_FETCH:
 
640
                /* No need to do anything */
 
641
 
 
642
                break;
 
643
        default:
 
644
                fprintf(stderr,
 
645
                        "que_node struct appears corrupt; type %lu\n",
 
646
                        (unsigned long) que_node_get_type(node));
 
647
                mem_analyze_corruption(node);
 
648
                ut_error;
 
649
        }
 
650
}
 
651
 
 
652
/**************************************************************************
 
653
Frees a query graph. */
 
654
UNIV_INTERN
 
655
void
 
656
que_graph_free(
 
657
/*===========*/
 
658
        que_t*  graph)  /* in: query graph; we assume that the memory
 
659
                        heap where this graph was created is private
 
660
                        to this graph: if not, then use
 
661
                        que_graph_free_recursive and free the heap
 
662
                        afterwards! */
 
663
{
 
664
        ut_ad(graph);
 
665
 
 
666
        if (graph->sym_tab) {
 
667
                /* The following call frees dynamic memory allocated
 
668
                for variables etc. during execution. Frees also explicit
 
669
                cursor definitions. */
 
670
 
 
671
                sym_tab_free_private(graph->sym_tab);
 
672
        }
 
673
 
 
674
        if (graph->info && graph->info->graph_owns_us) {
 
675
                pars_info_free(graph->info);
 
676
        }
 
677
 
 
678
        que_graph_free_recursive(graph);
 
679
 
 
680
        mem_heap_free(graph->heap);
 
681
}
 
682
 
 
683
/**************************************************************************
 
684
Checks if the query graph is in a state where it should be freed, and
 
685
frees it in that case. If the session is in a state where it should be
 
686
closed, also this is done. */
 
687
UNIV_INTERN
 
688
ibool
 
689
que_graph_try_free(
 
690
/*===============*/
 
691
                        /* out: TRUE if freed */
 
692
        que_t*  graph)  /* in: query graph */
 
693
{
 
694
        sess_t* sess;
 
695
 
 
696
        ut_ad(mutex_own(&kernel_mutex));
 
697
 
 
698
        sess = (graph->trx)->sess;
 
699
 
 
700
        if ((graph->state == QUE_FORK_BEING_FREED)
 
701
            && (graph->n_active_thrs == 0)) {
 
702
 
 
703
                UT_LIST_REMOVE(graphs, sess->graphs, graph);
 
704
                que_graph_free(graph);
 
705
 
 
706
                sess_try_close(sess);
 
707
 
 
708
                return(TRUE);
 
709
        }
 
710
 
 
711
        return(FALSE);
 
712
}
 
713
 
 
714
/********************************************************************
 
715
Performs an execution step on a thr node. */
 
716
static
 
717
que_thr_t*
 
718
que_thr_node_step(
 
719
/*==============*/
 
720
                                /* out: query thread to run next, or NULL
 
721
                                if none */
 
722
        que_thr_t*      thr)    /* in: query thread where run_node must
 
723
                                be the thread node itself */
 
724
{
 
725
        ut_ad(thr->run_node == thr);
 
726
 
 
727
        if (thr->prev_node == thr->common.parent) {
 
728
                /* If control to the node came from above, it is just passed
 
729
                on */
 
730
 
 
731
                thr->run_node = thr->child;
 
732
 
 
733
                return(thr);
 
734
        }
 
735
 
 
736
        mutex_enter(&kernel_mutex);
 
737
 
 
738
        if (que_thr_peek_stop(thr)) {
 
739
 
 
740
                mutex_exit(&kernel_mutex);
 
741
 
 
742
                return(thr);
 
743
        }
 
744
 
 
745
        /* Thread execution completed */
 
746
 
 
747
        thr->state = QUE_THR_COMPLETED;
 
748
 
 
749
        mutex_exit(&kernel_mutex);
 
750
 
 
751
        return(NULL);
 
752
}
 
753
 
 
754
/**************************************************************************
 
755
Moves a thread from another state to the QUE_THR_RUNNING state. Increments
 
756
the n_active_thrs counters of the query graph and transaction if thr was
 
757
not active.
 
758
***NOTE***: This and ..._mysql are  the only functions in which such a
 
759
transition is allowed to happen! */
 
760
static
 
761
void
 
762
que_thr_move_to_run_state(
 
763
/*======================*/
 
764
        que_thr_t*      thr)    /* in: an query thread */
 
765
{
 
766
        trx_t*  trx;
 
767
 
 
768
        ut_ad(thr->state != QUE_THR_RUNNING);
 
769
 
 
770
        trx = thr_get_trx(thr);
 
771
 
 
772
        if (!thr->is_active) {
 
773
 
 
774
                (thr->graph)->n_active_thrs++;
 
775
 
 
776
                trx->n_active_thrs++;
 
777
 
 
778
                thr->is_active = TRUE;
 
779
 
 
780
                ut_ad((thr->graph)->n_active_thrs == 1);
 
781
                ut_ad(trx->n_active_thrs == 1);
 
782
        }
 
783
 
 
784
        thr->state = QUE_THR_RUNNING;
 
785
}
 
786
 
 
787
/**************************************************************************
 
788
Decrements the query thread reference counts in the query graph and the
 
789
transaction. May start signal handling, e.g., a rollback.
 
790
*** NOTE ***:
 
791
This and que_thr_stop_for_mysql are the only functions where the reference
 
792
count can be decremented and this function may only be called from inside
 
793
que_run_threads or que_thr_check_if_switch! These restrictions exist to make
 
794
the rollback code easier to maintain. */
 
795
static
 
796
void
 
797
que_thr_dec_refer_count(
 
798
/*====================*/
 
799
        que_thr_t*      thr,            /* in: query thread */
 
800
        que_thr_t**     next_thr)       /* in/out: next query thread to run;
 
801
                                        if the value which is passed in is
 
802
                                        a pointer to a NULL pointer, then the
 
803
                                        calling function can start running
 
804
                                        a new query thread */
 
805
{
 
806
        que_fork_t*     fork;
 
807
        trx_t*          trx;
 
808
        ulint           fork_type;
 
809
        ibool           stopped;
 
810
 
 
811
        fork = thr->common.parent;
 
812
        trx = thr_get_trx(thr);
 
813
 
 
814
        mutex_enter(&kernel_mutex);
 
815
 
 
816
        ut_a(thr->is_active);
 
817
 
 
818
        if (thr->state == QUE_THR_RUNNING) {
 
819
 
 
820
                stopped = que_thr_stop(thr);
 
821
 
 
822
                if (!stopped) {
 
823
                        /* The reason for the thr suspension or wait was
 
824
                        already canceled before we came here: continue
 
825
                        running the thread */
 
826
 
 
827
                        /* fputs("!!!!!!!! Wait already ended: continue thr\n",
 
828
                        stderr); */
 
829
 
 
830
                        if (next_thr && *next_thr == NULL) {
 
831
                                /* Normally srv_suspend_mysql_thread resets
 
832
                                the state to DB_SUCCESS before waiting, but
 
833
                                in this case we have to do it here,
 
834
                                otherwise nobody does it. */
 
835
                                trx->error_state = DB_SUCCESS;
 
836
 
 
837
                                *next_thr = thr;
 
838
                        } else {
 
839
                                ut_error;
 
840
                                srv_que_task_enqueue_low(thr);
 
841
                        }
 
842
 
 
843
                        mutex_exit(&kernel_mutex);
 
844
 
 
845
                        return;
 
846
                }
 
847
        }
 
848
 
 
849
        ut_ad(fork->n_active_thrs == 1);
 
850
        ut_ad(trx->n_active_thrs == 1);
 
851
 
 
852
        fork->n_active_thrs--;
 
853
        trx->n_active_thrs--;
 
854
 
 
855
        thr->is_active = FALSE;
 
856
 
 
857
        if (trx->n_active_thrs > 0) {
 
858
 
 
859
                mutex_exit(&kernel_mutex);
 
860
 
 
861
                return;
 
862
        }
 
863
 
 
864
        fork_type = fork->fork_type;
 
865
 
 
866
        /* Check if all query threads in the same fork are completed */
 
867
 
 
868
        if (que_fork_all_thrs_in_state(fork, QUE_THR_COMPLETED)) {
 
869
 
 
870
                switch (fork_type) {
 
871
                case QUE_FORK_ROLLBACK:
 
872
                        /* This is really the undo graph used in rollback,
 
873
                        no roll_node in this graph */
 
874
 
 
875
                        ut_ad(UT_LIST_GET_LEN(trx->signals) > 0);
 
876
                        ut_ad(trx->handling_signals == TRUE);
 
877
 
 
878
                        trx_finish_rollback_off_kernel(fork, trx, next_thr);
 
879
                        break;
 
880
 
 
881
                case QUE_FORK_PURGE:
 
882
                case QUE_FORK_RECOVERY:
 
883
                case QUE_FORK_MYSQL_INTERFACE:
 
884
 
 
885
                        /* Do nothing */
 
886
                        break;
 
887
 
 
888
                default:
 
889
                        ut_error;       /* not used in MySQL */
 
890
                }
 
891
        }
 
892
 
 
893
        if (UT_LIST_GET_LEN(trx->signals) > 0 && trx->n_active_thrs == 0) {
 
894
 
 
895
                /* If the trx is signaled and its query thread count drops to
 
896
                zero, then we start processing a signal; from it we may get
 
897
                a new query thread to run */
 
898
 
 
899
                trx_sig_start_handle(trx, next_thr);
 
900
        }
 
901
 
 
902
        if (trx->handling_signals && UT_LIST_GET_LEN(trx->signals) == 0) {
 
903
 
 
904
                trx_end_signal_handling(trx);
 
905
        }
 
906
 
 
907
        mutex_exit(&kernel_mutex);
 
908
}
 
909
 
 
910
/**************************************************************************
 
911
Stops a query thread if graph or trx is in a state requiring it. The
 
912
conditions are tested in the order (1) graph, (2) trx. The kernel mutex has
 
913
to be reserved. */
 
914
UNIV_INTERN
 
915
ibool
 
916
que_thr_stop(
 
917
/*=========*/
 
918
                                /* out: TRUE if stopped */
 
919
        que_thr_t*      thr)    /* in: query thread */
 
920
{
 
921
        trx_t*  trx;
 
922
        que_t*  graph;
 
923
        ibool   ret     = TRUE;
 
924
 
 
925
        ut_ad(mutex_own(&kernel_mutex));
 
926
 
 
927
        graph = thr->graph;
 
928
        trx = graph->trx;
 
929
 
 
930
        if (graph->state == QUE_FORK_COMMAND_WAIT) {
 
931
                thr->state = QUE_THR_SUSPENDED;
 
932
 
 
933
        } else if (trx->que_state == TRX_QUE_LOCK_WAIT) {
 
934
 
 
935
                UT_LIST_ADD_FIRST(trx_thrs, trx->wait_thrs, thr);
 
936
                thr->state = QUE_THR_LOCK_WAIT;
 
937
 
 
938
        } else if (trx->error_state != DB_SUCCESS
 
939
                   && trx->error_state != DB_LOCK_WAIT) {
 
940
 
 
941
                /* Error handling built for the MySQL interface */
 
942
                thr->state = QUE_THR_COMPLETED;
 
943
 
 
944
        } else if (UT_LIST_GET_LEN(trx->signals) > 0
 
945
                   && graph->fork_type != QUE_FORK_ROLLBACK) {
 
946
 
 
947
                thr->state = QUE_THR_SUSPENDED;
 
948
        } else {
 
949
                ut_ad(graph->state == QUE_FORK_ACTIVE);
 
950
 
 
951
                ret = FALSE;
 
952
        }
 
953
 
 
954
        return(ret);
 
955
}
 
956
 
 
957
/**************************************************************************
 
958
A patch for MySQL used to 'stop' a dummy query thread used in MySQL. The
 
959
query thread is stopped and made inactive, except in the case where
 
960
it was put to the lock wait state in lock0lock.c, but the lock has already
 
961
been granted or the transaction chosen as a victim in deadlock resolution. */
 
962
UNIV_INTERN
 
963
void
 
964
que_thr_stop_for_mysql(
 
965
/*===================*/
 
966
        que_thr_t*      thr)    /* in: query thread */
 
967
{
 
968
        trx_t*  trx;
 
969
 
 
970
        trx = thr_get_trx(thr);
 
971
 
 
972
        mutex_enter(&kernel_mutex);
 
973
 
 
974
        if (thr->state == QUE_THR_RUNNING) {
 
975
 
 
976
                if (trx->error_state != DB_SUCCESS
 
977
                    && trx->error_state != DB_LOCK_WAIT) {
 
978
 
 
979
                        /* Error handling built for the MySQL interface */
 
980
                        thr->state = QUE_THR_COMPLETED;
 
981
                } else {
 
982
                        /* It must have been a lock wait but the lock was
 
983
                        already released, or this transaction was chosen
 
984
                        as a victim in selective deadlock resolution */
 
985
 
 
986
                        mutex_exit(&kernel_mutex);
 
987
 
 
988
                        return;
 
989
                }
 
990
        }
 
991
 
 
992
        ut_ad(thr->is_active == TRUE);
 
993
        ut_ad(trx->n_active_thrs == 1);
 
994
        ut_ad(thr->graph->n_active_thrs == 1);
 
995
 
 
996
        thr->is_active = FALSE;
 
997
        (thr->graph)->n_active_thrs--;
 
998
 
 
999
        trx->n_active_thrs--;
 
1000
 
 
1001
        mutex_exit(&kernel_mutex);
 
1002
}
 
1003
 
 
1004
/**************************************************************************
 
1005
Moves a thread from another state to the QUE_THR_RUNNING state. Increments
 
1006
the n_active_thrs counters of the query graph and transaction if thr was
 
1007
not active. */
 
1008
UNIV_INTERN
 
1009
void
 
1010
que_thr_move_to_run_state_for_mysql(
 
1011
/*================================*/
 
1012
        que_thr_t*      thr,    /* in: an query thread */
 
1013
        trx_t*          trx)    /* in: transaction */
 
1014
{
 
1015
        if (thr->magic_n != QUE_THR_MAGIC_N) {
 
1016
                fprintf(stderr,
 
1017
                        "que_thr struct appears corrupt; magic n %lu\n",
 
1018
                        (unsigned long) thr->magic_n);
 
1019
 
 
1020
                mem_analyze_corruption(thr);
 
1021
 
 
1022
                ut_error;
 
1023
        }
 
1024
 
 
1025
        if (!thr->is_active) {
 
1026
 
 
1027
                thr->graph->n_active_thrs++;
 
1028
 
 
1029
                trx->n_active_thrs++;
 
1030
 
 
1031
                thr->is_active = TRUE;
 
1032
        }
 
1033
 
 
1034
        thr->state = QUE_THR_RUNNING;
 
1035
}
 
1036
 
 
1037
/**************************************************************************
 
1038
A patch for MySQL used to 'stop' a dummy query thread used in MySQL
 
1039
select, when there is no error or lock wait. */
 
1040
UNIV_INTERN
 
1041
void
 
1042
que_thr_stop_for_mysql_no_error(
 
1043
/*============================*/
 
1044
        que_thr_t*      thr,    /* in: query thread */
 
1045
        trx_t*          trx)    /* in: transaction */
 
1046
{
 
1047
        ut_ad(thr->state == QUE_THR_RUNNING);
 
1048
        ut_ad(thr->is_active == TRUE);
 
1049
        ut_ad(trx->n_active_thrs == 1);
 
1050
        ut_ad(thr->graph->n_active_thrs == 1);
 
1051
 
 
1052
        if (thr->magic_n != QUE_THR_MAGIC_N) {
 
1053
                fprintf(stderr,
 
1054
                        "que_thr struct appears corrupt; magic n %lu\n",
 
1055
                        (unsigned long) thr->magic_n);
 
1056
 
 
1057
                mem_analyze_corruption(thr);
 
1058
 
 
1059
                ut_error;
 
1060
        }
 
1061
 
 
1062
        thr->state = QUE_THR_COMPLETED;
 
1063
 
 
1064
        thr->is_active = FALSE;
 
1065
        (thr->graph)->n_active_thrs--;
 
1066
 
 
1067
        trx->n_active_thrs--;
 
1068
}
 
1069
 
 
1070
/********************************************************************
 
1071
Get the first containing loop node (e.g. while_node_t or for_node_t) for the
 
1072
given node, or NULL if the node is not within a loop. */
 
1073
UNIV_INTERN
 
1074
que_node_t*
 
1075
que_node_get_containing_loop_node(
 
1076
/*==============================*/
 
1077
                                /* out: containing loop node, or NULL. */
 
1078
        que_node_t*     node)   /* in: node */
 
1079
{
 
1080
        ut_ad(node);
 
1081
 
 
1082
        for (;;) {
 
1083
                ulint   type;
 
1084
 
 
1085
                node = que_node_get_parent(node);
 
1086
 
 
1087
                if (!node) {
 
1088
                        break;
 
1089
                }
 
1090
 
 
1091
                type = que_node_get_type(node);
 
1092
 
 
1093
                if ((type == QUE_NODE_FOR) || (type == QUE_NODE_WHILE)) {
 
1094
                        break;
 
1095
                }
 
1096
        }
 
1097
 
 
1098
        return(node);
 
1099
}
 
1100
 
 
1101
/**************************************************************************
 
1102
Prints info of an SQL query graph node. */
 
1103
UNIV_INTERN
 
1104
void
 
1105
que_node_print_info(
 
1106
/*================*/
 
1107
        que_node_t*     node)   /* in: query graph node */
 
1108
{
 
1109
        ulint           type;
 
1110
        const char*     str;
 
1111
 
 
1112
        type = que_node_get_type(node);
 
1113
 
 
1114
        if (type == QUE_NODE_SELECT) {
 
1115
                str = "SELECT";
 
1116
        } else if (type == QUE_NODE_INSERT) {
 
1117
                str = "INSERT";
 
1118
        } else if (type == QUE_NODE_UPDATE) {
 
1119
                str = "UPDATE";
 
1120
        } else if (type == QUE_NODE_WHILE) {
 
1121
                str = "WHILE";
 
1122
        } else if (type == QUE_NODE_ASSIGNMENT) {
 
1123
                str = "ASSIGNMENT";
 
1124
        } else if (type == QUE_NODE_IF) {
 
1125
                str = "IF";
 
1126
        } else if (type == QUE_NODE_FETCH) {
 
1127
                str = "FETCH";
 
1128
        } else if (type == QUE_NODE_OPEN) {
 
1129
                str = "OPEN";
 
1130
        } else if (type == QUE_NODE_PROC) {
 
1131
                str = "STORED PROCEDURE";
 
1132
        } else if (type == QUE_NODE_FUNC) {
 
1133
                str = "FUNCTION";
 
1134
        } else if (type == QUE_NODE_LOCK) {
 
1135
                str = "LOCK";
 
1136
        } else if (type == QUE_NODE_THR) {
 
1137
                str = "QUERY THREAD";
 
1138
        } else if (type == QUE_NODE_COMMIT) {
 
1139
                str = "COMMIT";
 
1140
        } else if (type == QUE_NODE_UNDO) {
 
1141
                str = "UNDO ROW";
 
1142
        } else if (type == QUE_NODE_PURGE) {
 
1143
                str = "PURGE ROW";
 
1144
        } else if (type == QUE_NODE_ROLLBACK) {
 
1145
                str = "ROLLBACK";
 
1146
        } else if (type == QUE_NODE_CREATE_TABLE) {
 
1147
                str = "CREATE TABLE";
 
1148
        } else if (type == QUE_NODE_CREATE_INDEX) {
 
1149
                str = "CREATE INDEX";
 
1150
        } else if (type == QUE_NODE_FOR) {
 
1151
                str = "FOR LOOP";
 
1152
        } else if (type == QUE_NODE_RETURN) {
 
1153
                str = "RETURN";
 
1154
        } else if (type == QUE_NODE_EXIT) {
 
1155
                str = "EXIT";
 
1156
        } else {
 
1157
                str = "UNKNOWN NODE TYPE";
 
1158
        }
 
1159
 
 
1160
        fprintf(stderr, "Node type %lu: %s, address %p\n",
 
1161
                (ulong) type, str, (void*) node);
 
1162
}
 
1163
 
 
1164
/**************************************************************************
 
1165
Performs an execution step on a query thread. */
 
1166
UNIV_INLINE
 
1167
que_thr_t*
 
1168
que_thr_step(
 
1169
/*=========*/
 
1170
                                /* out: query thread to run next: it may
 
1171
                                differ from the input parameter if, e.g., a
 
1172
                                subprocedure call is made */
 
1173
        que_thr_t*      thr)    /* in: query thread */
 
1174
{
 
1175
        que_node_t*     node;
 
1176
        que_thr_t*      old_thr;
 
1177
        trx_t*          trx;
 
1178
        ulint           type;
 
1179
 
 
1180
        trx = thr_get_trx(thr);
 
1181
 
 
1182
        ut_ad(thr->state == QUE_THR_RUNNING);
 
1183
        ut_a(trx->error_state == DB_SUCCESS);
 
1184
 
 
1185
        thr->resource++;
 
1186
 
 
1187
        node = thr->run_node;
 
1188
        type = que_node_get_type(node);
 
1189
 
 
1190
        old_thr = thr;
 
1191
 
 
1192
#ifdef UNIV_DEBUG
 
1193
        if (que_trace_on) {
 
1194
                fputs("To execute: ", stderr);
 
1195
                que_node_print_info(node);
 
1196
        }
 
1197
#endif
 
1198
        if (type & QUE_NODE_CONTROL_STAT) {
 
1199
                if ((thr->prev_node != que_node_get_parent(node))
 
1200
                    && que_node_get_next(thr->prev_node)) {
 
1201
 
 
1202
                        /* The control statements, like WHILE, always pass the
 
1203
                        control to the next child statement if there is any
 
1204
                        child left */
 
1205
 
 
1206
                        thr->run_node = que_node_get_next(thr->prev_node);
 
1207
 
 
1208
                } else if (type == QUE_NODE_IF) {
 
1209
                        if_step(thr);
 
1210
                } else if (type == QUE_NODE_FOR) {
 
1211
                        for_step(thr);
 
1212
                } else if (type == QUE_NODE_PROC) {
 
1213
 
 
1214
                        /* We can access trx->undo_no without reserving
 
1215
                        trx->undo_mutex, because there cannot be active query
 
1216
                        threads doing updating or inserting at the moment! */
 
1217
 
 
1218
                        if (thr->prev_node == que_node_get_parent(node)) {
 
1219
                                trx->last_sql_stat_start.least_undo_no
 
1220
                                        = trx->undo_no;
 
1221
                        }
 
1222
 
 
1223
                        proc_step(thr);
 
1224
                } else if (type == QUE_NODE_WHILE) {
 
1225
                        while_step(thr);
 
1226
                } else {
 
1227
                        ut_error;
 
1228
                }
 
1229
        } else if (type == QUE_NODE_ASSIGNMENT) {
 
1230
                assign_step(thr);
 
1231
        } else if (type == QUE_NODE_SELECT) {
 
1232
                thr = row_sel_step(thr);
 
1233
        } else if (type == QUE_NODE_INSERT) {
 
1234
                thr = row_ins_step(thr);
 
1235
        } else if (type == QUE_NODE_UPDATE) {
 
1236
                thr = row_upd_step(thr);
 
1237
        } else if (type == QUE_NODE_FETCH) {
 
1238
                thr = fetch_step(thr);
 
1239
        } else if (type == QUE_NODE_OPEN) {
 
1240
                thr = open_step(thr);
 
1241
        } else if (type == QUE_NODE_FUNC) {
 
1242
                proc_eval_step(thr);
 
1243
 
 
1244
        } else if (type == QUE_NODE_LOCK) {
 
1245
 
 
1246
                ut_error;
 
1247
                /*
 
1248
                thr = que_lock_step(thr);
 
1249
                */
 
1250
        } else if (type == QUE_NODE_THR) {
 
1251
                thr = que_thr_node_step(thr);
 
1252
        } else if (type == QUE_NODE_COMMIT) {
 
1253
                thr = trx_commit_step(thr);
 
1254
        } else if (type == QUE_NODE_UNDO) {
 
1255
                thr = row_undo_step(thr);
 
1256
        } else if (type == QUE_NODE_PURGE) {
 
1257
                thr = row_purge_step(thr);
 
1258
        } else if (type == QUE_NODE_RETURN) {
 
1259
                thr = return_step(thr);
 
1260
        } else if (type == QUE_NODE_EXIT) {
 
1261
                thr = exit_step(thr);
 
1262
        } else if (type == QUE_NODE_ROLLBACK) {
 
1263
                thr = trx_rollback_step(thr);
 
1264
        } else if (type == QUE_NODE_CREATE_TABLE) {
 
1265
                thr = dict_create_table_step(thr);
 
1266
        } else if (type == QUE_NODE_CREATE_INDEX) {
 
1267
                thr = dict_create_index_step(thr);
 
1268
        } else if (type == QUE_NODE_ROW_PRINTF) {
 
1269
                thr = row_printf_step(thr);
 
1270
        } else {
 
1271
                ut_error;
 
1272
        }
 
1273
 
 
1274
        if (type == QUE_NODE_EXIT) {
 
1275
                old_thr->prev_node = que_node_get_containing_loop_node(node);
 
1276
        } else {
 
1277
                old_thr->prev_node = node;
 
1278
        }
 
1279
 
 
1280
        if (thr) {
 
1281
                ut_a(thr_get_trx(thr)->error_state == DB_SUCCESS);
 
1282
        }
 
1283
 
 
1284
        return(thr);
 
1285
}
 
1286
 
 
1287
/**************************************************************************
 
1288
Run a query thread until it finishes or encounters e.g. a lock wait. */
 
1289
static
 
1290
void
 
1291
que_run_threads_low(
 
1292
/*================*/
 
1293
        que_thr_t*      thr)    /* in: query thread */
 
1294
{
 
1295
        que_thr_t*      next_thr;
 
1296
        ulint           cumul_resource;
 
1297
        ulint           loop_count;
 
1298
 
 
1299
        ut_ad(thr->state == QUE_THR_RUNNING);
 
1300
        ut_a(thr_get_trx(thr)->error_state == DB_SUCCESS);
 
1301
        ut_ad(!mutex_own(&kernel_mutex));
 
1302
 
 
1303
        /* cumul_resource counts how much resources the OS thread (NOT the
 
1304
        query thread) has spent in this function */
 
1305
 
 
1306
        loop_count = QUE_MAX_LOOPS_WITHOUT_CHECK;
 
1307
        cumul_resource = 0;
 
1308
loop:
 
1309
        /* Check that there is enough space in the log to accommodate
 
1310
        possible log entries by this query step; if the operation can touch
 
1311
        more than about 4 pages, checks must be made also within the query
 
1312
        step! */
 
1313
 
 
1314
        log_free_check();
 
1315
 
 
1316
        /* Perform the actual query step: note that the query thread
 
1317
        may change if, e.g., a subprocedure call is made */
 
1318
 
 
1319
        /*-------------------------*/
 
1320
        next_thr = que_thr_step(thr);
 
1321
        /*-------------------------*/
 
1322
 
 
1323
        ut_a(!next_thr || (thr_get_trx(next_thr)->error_state == DB_SUCCESS));
 
1324
 
 
1325
        loop_count++;
 
1326
 
 
1327
        if (next_thr != thr) {
 
1328
                ut_a(next_thr == NULL);
 
1329
 
 
1330
                /* This can change next_thr to a non-NULL value if there was
 
1331
                a lock wait that already completed. */
 
1332
                que_thr_dec_refer_count(thr, &next_thr);
 
1333
 
 
1334
                if (next_thr == NULL) {
 
1335
 
 
1336
                        return;
 
1337
                }
 
1338
 
 
1339
                loop_count = QUE_MAX_LOOPS_WITHOUT_CHECK;
 
1340
 
 
1341
                thr = next_thr;
 
1342
        }
 
1343
 
 
1344
        goto loop;
 
1345
}
 
1346
 
 
1347
/**************************************************************************
 
1348
Run a query thread. Handles lock waits. */
 
1349
UNIV_INTERN
 
1350
void
 
1351
que_run_threads(
 
1352
/*============*/
 
1353
        que_thr_t*      thr)    /* in: query thread */
 
1354
{
 
1355
loop:
 
1356
        ut_a(thr_get_trx(thr)->error_state == DB_SUCCESS);
 
1357
        que_run_threads_low(thr);
 
1358
 
 
1359
        mutex_enter(&kernel_mutex);
 
1360
 
 
1361
        switch (thr->state) {
 
1362
 
 
1363
        case QUE_THR_RUNNING:
 
1364
                /* There probably was a lock wait, but it already ended
 
1365
                before we came here: continue running thr */
 
1366
 
 
1367
                mutex_exit(&kernel_mutex);
 
1368
 
 
1369
                goto loop;
 
1370
 
 
1371
        case QUE_THR_LOCK_WAIT:
 
1372
                mutex_exit(&kernel_mutex);
 
1373
 
 
1374
                /* The ..._mysql_... function works also for InnoDB's
 
1375
                internal threads. Let us wait that the lock wait ends. */
 
1376
 
 
1377
                srv_suspend_mysql_thread(thr);
 
1378
 
 
1379
                if (thr_get_trx(thr)->error_state != DB_SUCCESS) {
 
1380
                        /* thr was chosen as a deadlock victim or there was
 
1381
                        a lock wait timeout */
 
1382
 
 
1383
                        que_thr_dec_refer_count(thr, NULL);
 
1384
 
 
1385
                        return;
 
1386
                }
 
1387
 
 
1388
                goto loop;
 
1389
 
 
1390
        case QUE_THR_COMPLETED:
 
1391
        case QUE_THR_COMMAND_WAIT:
 
1392
                /* Do nothing */
 
1393
                break;
 
1394
 
 
1395
        default:
 
1396
                ut_error;
 
1397
        }
 
1398
 
 
1399
        mutex_exit(&kernel_mutex);
 
1400
}
 
1401
 
 
1402
/*************************************************************************
 
1403
Evaluate the given SQL. */
 
1404
UNIV_INTERN
 
1405
ulint
 
1406
que_eval_sql(
 
1407
/*=========*/
 
1408
                                /* out: error code or DB_SUCCESS */
 
1409
        pars_info_t*    info,   /* in: info struct, or NULL */
 
1410
        const char*     sql,    /* in: SQL string */
 
1411
        ibool           reserve_dict_mutex,
 
1412
                                /* in: if TRUE, acquire/release
 
1413
                                dict_sys->mutex around call to pars_sql. */
 
1414
        trx_t*          trx)    /* in: trx */
 
1415
{
 
1416
        que_thr_t*      thr;
 
1417
        que_t*          graph;
 
1418
 
 
1419
        ut_a(trx->error_state == DB_SUCCESS);
 
1420
 
 
1421
        if (reserve_dict_mutex) {
 
1422
                mutex_enter(&dict_sys->mutex);
 
1423
        }
 
1424
 
 
1425
        graph = pars_sql(info, sql);
 
1426
 
 
1427
        if (reserve_dict_mutex) {
 
1428
                mutex_exit(&dict_sys->mutex);
 
1429
        }
 
1430
 
 
1431
        ut_a(graph);
 
1432
 
 
1433
        graph->trx = trx;
 
1434
        trx->graph = NULL;
 
1435
 
 
1436
        graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
 
1437
 
 
1438
        ut_a(thr = que_fork_start_command(graph));
 
1439
 
 
1440
        que_run_threads(thr);
 
1441
 
 
1442
        que_graph_free(graph);
 
1443
 
 
1444
        return(trx->error_state);
 
1445
}