~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****************************************************************************
 
2
 
 
3
Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
 
4
 
 
5
This program is free software; you can redistribute it and/or modify it under
 
6
the terms of the GNU General Public License as published by the Free Software
 
7
Foundation; version 2 of the License.
 
8
 
 
9
This program is distributed in the hope that it will be useful, but WITHOUT
 
10
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 
11
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 
12
 
 
13
You should have received a copy of the GNU General Public License along with
 
14
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 
15
Place, Suite 330, Boston, MA 02111-1307 USA
 
16
 
 
17
*****************************************************************************/
 
18
 
 
19
/**************************************************//**
 
20
@file que/que0que.c
 
21
Query graph
 
22
 
 
23
Created 5/27/1996 Heikki Tuuri
 
24
*******************************************************/
 
25
 
 
26
#include "que0que.h"
 
27
 
 
28
#ifdef UNIV_NONINL
 
29
#include "que0que.ic"
 
30
#endif
 
31
 
 
32
#include "srv0que.h"
 
33
#include "usr0sess.h"
 
34
#include "trx0trx.h"
 
35
#include "trx0roll.h"
 
36
#include "row0undo.h"
 
37
#include "row0ins.h"
 
38
#include "row0upd.h"
 
39
#include "row0sel.h"
 
40
#include "row0purge.h"
 
41
#include "dict0crea.h"
 
42
#include "log0log.h"
 
43
#include "eval0proc.h"
 
44
#include "eval0eval.h"
 
45
#include "pars0types.h"
 
46
 
 
47
#define QUE_PARALLELIZE_LIMIT   (64 * 256 * 256 * 256)
 
48
#define QUE_ROUND_ROBIN_LIMIT   (64 * 256 * 256 * 256)
 
49
#define QUE_MAX_LOOPS_WITHOUT_CHECK     16
 
50
 
 
51
#ifdef UNIV_DEBUG
 
52
/* If the following flag is set TRUE, the module will print trace info
 
53
of SQL execution in the UNIV_SQL_DEBUG version */
 
54
UNIV_INTERN ibool       que_trace_on            = FALSE;
 
55
#endif /* UNIV_DEBUG */
 
56
 
 
57
/* Short introduction to query graphs
 
58
   ==================================
 
59
 
 
60
A query graph consists of nodes linked to each other in various ways. The
 
61
execution starts at que_run_threads() which takes a que_thr_t parameter.
 
62
que_thr_t contains two fields that control query graph execution: run_node
 
63
and prev_node. run_node is the next node to execute and prev_node is the
 
64
last node executed.
 
65
 
 
66
Each node has a pointer to a 'next' statement, i.e., its brother, and a
 
67
pointer to its parent node. The next pointer is NULL in the last statement
 
68
of a block.
 
69
 
 
70
Loop nodes contain a link to the first statement of the enclosed statement
 
71
list. While the loop runs, que_thr_step() checks if execution to the loop
 
72
node came from its parent or from one of the statement nodes in the loop. If
 
73
it came from the parent of the loop node it starts executing the first
 
74
statement node in the loop. If it came from one of the statement nodes in
 
75
the loop, then it checks if the statement node has another statement node
 
76
following it, and runs it if so.
 
77
 
 
78
To signify loop ending, the loop statements (see e.g. while_step()) set
 
79
que_thr_t->run_node to the loop node's parent node. This is noticed on the
 
80
next call of que_thr_step() and execution proceeds to the node pointed to by
 
81
the loop node's 'next' pointer.
 
82
 
 
83
For example, the code:
 
84
 
 
85
X := 1;
 
86
WHILE X < 5 LOOP
 
87
 X := X + 1;
 
88
 X := X + 1;
 
89
X := 5
 
90
 
 
91
will result in the following node hierarchy, with the X-axis indicating
 
92
'next' links and the Y-axis indicating parent/child links:
 
93
 
 
94
A - W - A
 
95
    |
 
96
    |
 
97
    A - A
 
98
 
 
99
A = assign_node_t, W = while_node_t. */
 
100
 
 
101
/* How a stored procedure containing COMMIT or ROLLBACK commands
 
102
is executed?
 
103
 
 
104
The commit or rollback can be seen as a subprocedure call.
 
105
The problem is that if there are several query threads
 
106
currently running within the transaction, their action could
 
107
mess the commit or rollback operation. Or, at the least, the
 
108
operation would be difficult to visualize and keep in control.
 
109
 
 
110
Therefore the query thread requesting a commit or a rollback
 
111
sends to the transaction a signal, which moves the transaction
 
112
to TRX_QUE_SIGNALED state. All running query threads of the
 
113
transaction will eventually notice that the transaction is now in
 
114
this state and voluntarily suspend themselves. Only the last
 
115
query thread which suspends itself will trigger handling of
 
116
the signal.
 
117
 
 
118
When the transaction starts to handle a rollback or commit
 
119
signal, it builds a query graph which, when executed, will
 
120
roll back or commit the incomplete transaction. The transaction
 
121
is moved to the TRX_QUE_ROLLING_BACK or TRX_QUE_COMMITTING state.
 
122
If specified, the SQL cursors opened by the transaction are closed.
 
123
When the execution of the graph completes, it is like returning
 
124
from a subprocedure: the query thread which requested the operation
 
125
starts running again. */
 
126
 
 
127
/**********************************************************************//**
 
128
Moves a thread from another state to the QUE_THR_RUNNING state. Increments
 
129
the n_active_thrs counters of the query graph and transaction.
 
130
***NOTE***: This is the only function in which such a transition is allowed
 
131
to happen! */
 
132
static
 
133
void
 
134
que_thr_move_to_run_state(
 
135
/*======================*/
 
136
        que_thr_t*      thr);   /*!< in: an query thread */
 
137
 
 
138
/***********************************************************************//**
 
139
Adds a query graph to the session's list of graphs. */
 
140
UNIV_INTERN
 
141
void
 
142
que_graph_publish(
 
143
/*==============*/
 
144
        que_t*  graph,  /*!< in: graph */
 
145
        sess_t* sess)   /*!< in: session */
 
146
{
 
147
        ut_ad(mutex_own(&kernel_mutex));
 
148
 
 
149
        UT_LIST_ADD_LAST(graphs, sess->graphs, graph);
 
150
}
 
151
 
 
152
/***********************************************************************//**
 
153
Creates a query graph fork node.
 
154
@return own: fork node */
 
155
UNIV_INTERN
 
156
que_fork_t*
 
157
que_fork_create(
 
158
/*============*/
 
159
        que_t*          graph,          /*!< in: graph, if NULL then this
 
160
                                        fork node is assumed to be the
 
161
                                        graph root */
 
162
        que_node_t*     parent,         /*!< in: parent node */
 
163
        ulint           fork_type,      /*!< in: fork type */
 
164
        mem_heap_t*     heap)           /*!< in: memory heap where created */
 
165
{
 
166
        que_fork_t*     fork;
 
167
 
 
168
        ut_ad(heap);
 
169
 
 
170
        fork = mem_heap_alloc(heap, sizeof(que_fork_t));
 
171
 
 
172
        fork->common.type = QUE_NODE_FORK;
 
173
        fork->n_active_thrs = 0;
 
174
 
 
175
        fork->state = QUE_FORK_COMMAND_WAIT;
 
176
 
 
177
        if (graph != NULL) {
 
178
                fork->graph = graph;
 
179
        } else {
 
180
                fork->graph = fork;
 
181
        }
 
182
 
 
183
        fork->common.parent = parent;
 
184
        fork->fork_type = fork_type;
 
185
 
 
186
        fork->caller = NULL;
 
187
 
 
188
        UT_LIST_INIT(fork->thrs);
 
189
 
 
190
        fork->sym_tab = NULL;
 
191
        fork->info = NULL;
 
192
 
 
193
        fork->heap = heap;
 
194
 
 
195
        return(fork);
 
196
}
 
197
 
 
198
/***********************************************************************//**
 
199
Creates a query graph thread node.
 
200
@return own: query thread node */
 
201
UNIV_INTERN
 
202
que_thr_t*
 
203
que_thr_create(
 
204
/*===========*/
 
205
        que_fork_t*     parent, /*!< in: parent node, i.e., a fork node */
 
206
        mem_heap_t*     heap)   /*!< in: memory heap where created */
 
207
{
 
208
        que_thr_t*      thr;
 
209
 
 
210
        ut_ad(parent && heap);
 
211
 
 
212
        thr = mem_heap_alloc(heap, sizeof(que_thr_t));
 
213
 
 
214
        thr->common.type = QUE_NODE_THR;
 
215
        thr->common.parent = parent;
 
216
 
 
217
        thr->magic_n = QUE_THR_MAGIC_N;
 
218
 
 
219
        thr->graph = parent->graph;
 
220
 
 
221
        thr->state = QUE_THR_COMMAND_WAIT;
 
222
 
 
223
        thr->is_active = FALSE;
 
224
 
 
225
        thr->run_node = NULL;
 
226
        thr->resource = 0;
 
227
        thr->lock_state = QUE_THR_LOCK_NOLOCK;
 
228
 
 
229
        UT_LIST_ADD_LAST(thrs, parent->thrs, thr);
 
230
 
 
231
        return(thr);
 
232
}
 
233
 
 
234
/**********************************************************************//**
 
235
Moves a suspended query thread to the QUE_THR_RUNNING state and may release
 
236
a single worker thread to execute it. This function should be used to end
 
237
the wait state of a query thread waiting for a lock or a stored procedure
 
238
completion. */
 
239
UNIV_INTERN
 
240
void
 
241
que_thr_end_wait(
 
242
/*=============*/
 
243
        que_thr_t*      thr,            /*!< in: query thread in the
 
244
                                        QUE_THR_LOCK_WAIT,
 
245
                                        or QUE_THR_PROCEDURE_WAIT, or
 
246
                                        QUE_THR_SIG_REPLY_WAIT state */
 
247
        que_thr_t**     next_thr)       /*!< in/out: next query thread to run;
 
248
                                        if the value which is passed in is
 
249
                                        a pointer to a NULL pointer, then the
 
250
                                        calling function can start running
 
251
                                        a new query thread; if NULL is passed
 
252
                                        as the parameter, it is ignored */
 
253
{
 
254
        ibool   was_active;
 
255
 
 
256
        ut_ad(mutex_own(&kernel_mutex));
 
257
        ut_ad(thr);
 
258
        ut_ad((thr->state == QUE_THR_LOCK_WAIT)
 
259
              || (thr->state == QUE_THR_PROCEDURE_WAIT)
 
260
              || (thr->state == QUE_THR_SIG_REPLY_WAIT));
 
261
        ut_ad(thr->run_node);
 
262
 
 
263
        thr->prev_node = thr->run_node;
 
264
 
 
265
        was_active = thr->is_active;
 
266
 
 
267
        que_thr_move_to_run_state(thr);
 
268
 
 
269
        if (was_active) {
 
270
 
 
271
                return;
 
272
        }
 
273
 
 
274
        if (next_thr && *next_thr == NULL) {
 
275
                *next_thr = thr;
 
276
        } else {
 
277
                ut_a(0);
 
278
                srv_que_task_enqueue_low(thr);
 
279
        }
 
280
}
 
281
 
 
282
/**********************************************************************//**
 
283
Same as que_thr_end_wait, but no parameter next_thr available. */
 
284
UNIV_INTERN
 
285
void
 
286
que_thr_end_wait_no_next_thr(
 
287
/*=========================*/
 
288
        que_thr_t*      thr)    /*!< in: query thread in the QUE_THR_LOCK_WAIT,
 
289
                                or QUE_THR_PROCEDURE_WAIT, or
 
290
                                QUE_THR_SIG_REPLY_WAIT state */
 
291
{
 
292
        ibool   was_active;
 
293
 
 
294
        ut_a(thr->state == QUE_THR_LOCK_WAIT);  /* In MySQL this is the
 
295
                                                only possible state here */
 
296
        ut_ad(mutex_own(&kernel_mutex));
 
297
        ut_ad(thr);
 
298
        ut_ad((thr->state == QUE_THR_LOCK_WAIT)
 
299
              || (thr->state == QUE_THR_PROCEDURE_WAIT)
 
300
              || (thr->state == QUE_THR_SIG_REPLY_WAIT));
 
301
 
 
302
        was_active = thr->is_active;
 
303
 
 
304
        que_thr_move_to_run_state(thr);
 
305
 
 
306
        if (was_active) {
 
307
 
 
308
                return;
 
309
        }
 
310
 
 
311
        /* In MySQL we let the OS thread (not just the query thread) to wait
 
312
        for the lock to be released: */
 
313
 
 
314
        srv_release_mysql_thread_if_suspended(thr);
 
315
 
 
316
        /* srv_que_task_enqueue_low(thr); */
 
317
}
 
318
 
 
319
/**********************************************************************//**
 
320
Inits a query thread for a command. */
 
321
UNIV_INLINE
 
322
void
 
323
que_thr_init_command(
 
324
/*=================*/
 
325
        que_thr_t*      thr)    /*!< in: query thread */
 
326
{
 
327
        thr->run_node = thr;
 
328
        thr->prev_node = thr->common.parent;
 
329
 
 
330
        que_thr_move_to_run_state(thr);
 
331
}
 
332
 
 
333
/**********************************************************************//**
 
334
Starts execution of a command in a query fork. Picks a query thread which
 
335
is not in the QUE_THR_RUNNING state and moves it to that state. If none
 
336
can be chosen, a situation which may arise in parallelized fetches, NULL
 
337
is returned.
 
338
@return a query thread of the graph moved to QUE_THR_RUNNING state, or
 
339
NULL; the query thread should be executed by que_run_threads by the
 
340
caller */
 
341
UNIV_INTERN
 
342
que_thr_t*
 
343
que_fork_start_command(
 
344
/*===================*/
 
345
        que_fork_t*     fork)   /*!< in: a query fork */
 
346
{
 
347
        que_thr_t*      thr;
 
348
        que_thr_t*      suspended_thr = NULL;
 
349
        que_thr_t*      completed_thr = NULL;
 
350
 
 
351
        fork->state = QUE_FORK_ACTIVE;
 
352
 
 
353
        fork->last_sel_node = NULL;
 
354
 
 
355
        suspended_thr = NULL;
 
356
        completed_thr = NULL;
 
357
 
 
358
        /* Choose the query thread to run: usually there is just one thread,
 
359
        but in a parallelized select, which necessarily is non-scrollable,
 
360
        there may be several to choose from */
 
361
 
 
362
        /* First we try to find a query thread in the QUE_THR_COMMAND_WAIT
 
363
        state. Then we try to find a query thread in the QUE_THR_SUSPENDED
 
364
        state, finally we try to find a query thread in the QUE_THR_COMPLETED
 
365
        state */
 
366
 
 
367
        thr = UT_LIST_GET_FIRST(fork->thrs);
 
368
 
 
369
        /* We make a single pass over the thr list within which we note which
 
370
        threads are ready to run. */
 
371
        while (thr) {
 
372
                switch (thr->state) {
 
373
                case QUE_THR_COMMAND_WAIT:
 
374
 
 
375
                        /* We have to send the initial message to query thread
 
376
                        to start it */
 
377
 
 
378
                        que_thr_init_command(thr);
 
379
 
 
380
                        return(thr);
 
381
 
 
382
                case QUE_THR_SUSPENDED:
 
383
                        /* In this case the execution of the thread was
 
384
                        suspended: no initial message is needed because
 
385
                        execution can continue from where it was left */
 
386
                        if (!suspended_thr) {
 
387
                                suspended_thr = thr;
 
388
                        }
 
389
 
 
390
                        break;
 
391
 
 
392
                case QUE_THR_COMPLETED:
 
393
                        if (!completed_thr) {
 
394
                                completed_thr = thr;
 
395
                        }
 
396
 
 
397
                        break;
 
398
 
 
399
                case QUE_THR_LOCK_WAIT:
 
400
                        ut_error;
 
401
 
 
402
                }
 
403
 
 
404
                thr = UT_LIST_GET_NEXT(thrs, thr);
 
405
        }
 
406
 
 
407
        if (suspended_thr) {
 
408
 
 
409
                thr = suspended_thr;
 
410
                que_thr_move_to_run_state(thr);
 
411
 
 
412
        } else if (completed_thr) {
 
413
 
 
414
                thr = completed_thr;
 
415
                que_thr_init_command(thr);
 
416
        }
 
417
 
 
418
        return(thr);
 
419
}
 
420
 
 
421
/**********************************************************************//**
 
422
After signal handling is finished, returns control to a query graph error
 
423
handling routine. (Currently, just returns the control to the root of the
 
424
graph so that the graph can communicate an error message to the client.) */
 
425
UNIV_INTERN
 
426
void
 
427
que_fork_error_handle(
 
428
/*==================*/
 
429
        trx_t*  trx __attribute__((unused)),    /*!< in: trx */
 
430
        que_t*  fork)   /*!< in: query graph which was run before signal
 
431
                        handling started, NULL not allowed */
 
432
{
 
433
        que_thr_t*      thr;
 
434
 
 
435
        ut_ad(mutex_own(&kernel_mutex));
 
436
        ut_ad(trx->sess->state == SESS_ERROR);
 
437
        ut_ad(UT_LIST_GET_LEN(trx->reply_signals) == 0);
 
438
        ut_ad(UT_LIST_GET_LEN(trx->wait_thrs) == 0);
 
439
 
 
440
        thr = UT_LIST_GET_FIRST(fork->thrs);
 
441
 
 
442
        while (thr != NULL) {
 
443
                ut_ad(!thr->is_active);
 
444
                ut_ad(thr->state != QUE_THR_SIG_REPLY_WAIT);
 
445
                ut_ad(thr->state != QUE_THR_LOCK_WAIT);
 
446
 
 
447
                thr->run_node = thr;
 
448
                thr->prev_node = thr->child;
 
449
                thr->state = QUE_THR_COMPLETED;
 
450
 
 
451
                thr = UT_LIST_GET_NEXT(thrs, thr);
 
452
        }
 
453
 
 
454
        thr = UT_LIST_GET_FIRST(fork->thrs);
 
455
 
 
456
        que_thr_move_to_run_state(thr);
 
457
 
 
458
        ut_a(0);
 
459
        srv_que_task_enqueue_low(thr);
 
460
}
 
461
 
 
462
/****************************************************************//**
 
463
Tests if all the query threads in the same fork have a given state.
 
464
@return TRUE if all the query threads in the same fork were in the
 
465
given state */
 
466
UNIV_INLINE
 
467
ibool
 
468
que_fork_all_thrs_in_state(
 
469
/*=======================*/
 
470
        que_fork_t*     fork,   /*!< in: query fork */
 
471
        ulint           state)  /*!< in: state */
 
472
{
 
473
        que_thr_t*      thr_node;
 
474
 
 
475
        thr_node = UT_LIST_GET_FIRST(fork->thrs);
 
476
 
 
477
        while (thr_node != NULL) {
 
478
                if (thr_node->state != state) {
 
479
 
 
480
                        return(FALSE);
 
481
                }
 
482
 
 
483
                thr_node = UT_LIST_GET_NEXT(thrs, thr_node);
 
484
        }
 
485
 
 
486
        return(TRUE);
 
487
}
 
488
 
 
489
/**********************************************************************//**
 
490
Calls que_graph_free_recursive for statements in a statement list. */
 
491
static
 
492
void
 
493
que_graph_free_stat_list(
 
494
/*=====================*/
 
495
        que_node_t*     node)   /*!< in: first query graph node in the list */
 
496
{
 
497
        while (node) {
 
498
                que_graph_free_recursive(node);
 
499
 
 
500
                node = que_node_get_next(node);
 
501
        }
 
502
}
 
503
 
 
504
/**********************************************************************//**
 
505
Frees a query graph, but not the heap where it was created. Does not free
 
506
explicit cursor declarations, they are freed in que_graph_free. */
 
507
UNIV_INTERN
 
508
void
 
509
que_graph_free_recursive(
 
510
/*=====================*/
 
511
        que_node_t*     node)   /*!< in: query graph node */
 
512
{
 
513
        que_fork_t*     fork;
 
514
        que_thr_t*      thr;
 
515
        undo_node_t*    undo;
 
516
        sel_node_t*     sel;
 
517
        ins_node_t*     ins;
 
518
        upd_node_t*     upd;
 
519
        tab_node_t*     cre_tab;
 
520
        ind_node_t*     cre_ind;
 
521
        purge_node_t*   purge;
 
522
 
 
523
        if (node == NULL) {
 
524
 
 
525
                return;
 
526
        }
 
527
 
 
528
        switch (que_node_get_type(node)) {
 
529
 
 
530
        case QUE_NODE_FORK:
 
531
                fork = node;
 
532
 
 
533
                thr = UT_LIST_GET_FIRST(fork->thrs);
 
534
 
 
535
                while (thr) {
 
536
                        que_graph_free_recursive(thr);
 
537
 
 
538
                        thr = UT_LIST_GET_NEXT(thrs, thr);
 
539
                }
 
540
 
 
541
                break;
 
542
        case QUE_NODE_THR:
 
543
 
 
544
                thr = node;
 
545
 
 
546
                if (thr->magic_n != QUE_THR_MAGIC_N) {
 
547
                        fprintf(stderr,
 
548
                                "que_thr struct appears corrupt;"
 
549
                                " magic n %lu\n",
 
550
                                (unsigned long) thr->magic_n);
 
551
                        mem_analyze_corruption(thr);
 
552
                        ut_error;
 
553
                }
 
554
 
 
555
                thr->magic_n = QUE_THR_MAGIC_FREED;
 
556
 
 
557
                que_graph_free_recursive(thr->child);
 
558
 
 
559
                break;
 
560
        case QUE_NODE_UNDO:
 
561
 
 
562
                undo = node;
 
563
 
 
564
                mem_heap_free(undo->heap);
 
565
 
 
566
                break;
 
567
        case QUE_NODE_SELECT:
 
568
 
 
569
                sel = node;
 
570
 
 
571
                sel_node_free_private(sel);
 
572
 
 
573
                break;
 
574
        case QUE_NODE_INSERT:
 
575
 
 
576
                ins = node;
 
577
 
 
578
                que_graph_free_recursive(ins->select);
 
579
 
 
580
                mem_heap_free(ins->entry_sys_heap);
 
581
 
 
582
                break;
 
583
        case QUE_NODE_PURGE:
 
584
                purge = node;
 
585
 
 
586
                mem_heap_free(purge->heap);
 
587
 
 
588
                break;
 
589
 
 
590
        case QUE_NODE_UPDATE:
 
591
 
 
592
                upd = node;
 
593
 
 
594
                if (upd->in_mysql_interface) {
 
595
 
 
596
                        btr_pcur_free_for_mysql(upd->pcur);
 
597
                }
 
598
 
 
599
                que_graph_free_recursive(upd->cascade_node);
 
600
 
 
601
                if (upd->cascade_heap) {
 
602
                        mem_heap_free(upd->cascade_heap);
 
603
                }
 
604
 
 
605
                que_graph_free_recursive(upd->select);
 
606
 
 
607
                mem_heap_free(upd->heap);
 
608
 
 
609
                break;
 
610
        case QUE_NODE_CREATE_TABLE:
 
611
                cre_tab = node;
 
612
 
 
613
                que_graph_free_recursive(cre_tab->tab_def);
 
614
                que_graph_free_recursive(cre_tab->col_def);
 
615
                que_graph_free_recursive(cre_tab->commit_node);
 
616
 
 
617
                mem_heap_free(cre_tab->heap);
 
618
 
 
619
                break;
 
620
        case QUE_NODE_CREATE_INDEX:
 
621
                cre_ind = node;
 
622
 
 
623
                que_graph_free_recursive(cre_ind->ind_def);
 
624
                que_graph_free_recursive(cre_ind->field_def);
 
625
                que_graph_free_recursive(cre_ind->commit_node);
 
626
 
 
627
                mem_heap_free(cre_ind->heap);
 
628
 
 
629
                break;
 
630
        case QUE_NODE_PROC:
 
631
                que_graph_free_stat_list(((proc_node_t*)node)->stat_list);
 
632
 
 
633
                break;
 
634
        case QUE_NODE_IF:
 
635
                que_graph_free_stat_list(((if_node_t*)node)->stat_list);
 
636
                que_graph_free_stat_list(((if_node_t*)node)->else_part);
 
637
                que_graph_free_stat_list(((if_node_t*)node)->elsif_list);
 
638
 
 
639
                break;
 
640
        case QUE_NODE_ELSIF:
 
641
                que_graph_free_stat_list(((elsif_node_t*)node)->stat_list);
 
642
 
 
643
                break;
 
644
        case QUE_NODE_WHILE:
 
645
                que_graph_free_stat_list(((while_node_t*)node)->stat_list);
 
646
 
 
647
                break;
 
648
        case QUE_NODE_FOR:
 
649
                que_graph_free_stat_list(((for_node_t*)node)->stat_list);
 
650
 
 
651
                break;
 
652
 
 
653
        case QUE_NODE_ASSIGNMENT:
 
654
        case QUE_NODE_EXIT:
 
655
        case QUE_NODE_RETURN:
 
656
        case QUE_NODE_COMMIT:
 
657
        case QUE_NODE_ROLLBACK:
 
658
        case QUE_NODE_LOCK:
 
659
        case QUE_NODE_FUNC:
 
660
        case QUE_NODE_ORDER:
 
661
        case QUE_NODE_ROW_PRINTF:
 
662
        case QUE_NODE_OPEN:
 
663
        case QUE_NODE_FETCH:
 
664
                /* No need to do anything */
 
665
 
 
666
                break;
 
667
        default:
 
668
                fprintf(stderr,
 
669
                        "que_node struct appears corrupt; type %lu\n",
 
670
                        (unsigned long) que_node_get_type(node));
 
671
                mem_analyze_corruption(node);
 
672
                ut_error;
 
673
        }
 
674
}
 
675
 
 
676
/**********************************************************************//**
 
677
Frees a query graph. */
 
678
UNIV_INTERN
 
679
void
 
680
que_graph_free(
 
681
/*===========*/
 
682
        que_t*  graph)  /*!< in: query graph; we assume that the memory
 
683
                        heap where this graph was created is private
 
684
                        to this graph: if not, then use
 
685
                        que_graph_free_recursive and free the heap
 
686
                        afterwards! */
 
687
{
 
688
        ut_ad(graph);
 
689
 
 
690
        if (graph->sym_tab) {
 
691
                /* The following call frees dynamic memory allocated
 
692
                for variables etc. during execution. Frees also explicit
 
693
                cursor definitions. */
 
694
 
 
695
                sym_tab_free_private(graph->sym_tab);
 
696
        }
 
697
 
 
698
        if (graph->info && graph->info->graph_owns_us) {
 
699
                pars_info_free(graph->info);
 
700
        }
 
701
 
 
702
        que_graph_free_recursive(graph);
 
703
 
 
704
        mem_heap_free(graph->heap);
 
705
}
 
706
 
 
707
/****************************************************************//**
 
708
Performs an execution step on a thr node.
 
709
@return query thread to run next, or NULL if none */
 
710
static
 
711
que_thr_t*
 
712
que_thr_node_step(
 
713
/*==============*/
 
714
        que_thr_t*      thr)    /*!< in: query thread where run_node must
 
715
                                be the thread node itself */
 
716
{
 
717
        ut_ad(thr->run_node == thr);
 
718
 
 
719
        if (thr->prev_node == thr->common.parent) {
 
720
                /* If control to the node came from above, it is just passed
 
721
                on */
 
722
 
 
723
                thr->run_node = thr->child;
 
724
 
 
725
                return(thr);
 
726
        }
 
727
 
 
728
        mutex_enter(&kernel_mutex);
 
729
 
 
730
        if (que_thr_peek_stop(thr)) {
 
731
 
 
732
                mutex_exit(&kernel_mutex);
 
733
 
 
734
                return(thr);
 
735
        }
 
736
 
 
737
        /* Thread execution completed */
 
738
 
 
739
        thr->state = QUE_THR_COMPLETED;
 
740
 
 
741
        mutex_exit(&kernel_mutex);
 
742
 
 
743
        return(NULL);
 
744
}
 
745
 
 
746
/**********************************************************************//**
 
747
Moves a thread from another state to the QUE_THR_RUNNING state. Increments
 
748
the n_active_thrs counters of the query graph and transaction if thr was
 
749
not active.
 
750
***NOTE***: This and ..._mysql are  the only functions in which such a
 
751
transition is allowed to happen! */
 
752
static
 
753
void
 
754
que_thr_move_to_run_state(
 
755
/*======================*/
 
756
        que_thr_t*      thr)    /*!< in: an query thread */
 
757
{
 
758
        trx_t*  trx;
 
759
 
 
760
        ut_ad(thr->state != QUE_THR_RUNNING);
 
761
 
 
762
        trx = thr_get_trx(thr);
 
763
 
 
764
        if (!thr->is_active) {
 
765
 
 
766
                (thr->graph)->n_active_thrs++;
 
767
 
 
768
                trx->n_active_thrs++;
 
769
 
 
770
                thr->is_active = TRUE;
 
771
 
 
772
                ut_ad((thr->graph)->n_active_thrs == 1);
 
773
                ut_ad(trx->n_active_thrs == 1);
 
774
        }
 
775
 
 
776
        thr->state = QUE_THR_RUNNING;
 
777
}
 
778
 
 
779
/**********************************************************************//**
 
780
Decrements the query thread reference counts in the query graph and the
 
781
transaction. May start signal handling, e.g., a rollback.
 
782
*** NOTE ***:
 
783
This and que_thr_stop_for_mysql are the only functions where the reference
 
784
count can be decremented and this function may only be called from inside
 
785
que_run_threads or que_thr_check_if_switch! These restrictions exist to make
 
786
the rollback code easier to maintain. */
 
787
static
 
788
void
 
789
que_thr_dec_refer_count(
 
790
/*====================*/
 
791
        que_thr_t*      thr,            /*!< in: query thread */
 
792
        que_thr_t**     next_thr)       /*!< in/out: next query thread to run;
 
793
                                        if the value which is passed in is
 
794
                                        a pointer to a NULL pointer, then the
 
795
                                        calling function can start running
 
796
                                        a new query thread */
 
797
{
 
798
        que_fork_t*     fork;
 
799
        trx_t*          trx;
 
800
        ulint           fork_type;
 
801
        ibool           stopped;
 
802
 
 
803
        fork = thr->common.parent;
 
804
        trx = thr_get_trx(thr);
 
805
 
 
806
        mutex_enter(&kernel_mutex);
 
807
 
 
808
        ut_a(thr->is_active);
 
809
 
 
810
        if (thr->state == QUE_THR_RUNNING) {
 
811
 
 
812
                stopped = que_thr_stop(thr);
 
813
 
 
814
                if (!stopped) {
 
815
                        /* The reason for the thr suspension or wait was
 
816
                        already canceled before we came here: continue
 
817
                        running the thread */
 
818
 
 
819
                        /* fputs("!!!!!!!! Wait already ended: continue thr\n",
 
820
                        stderr); */
 
821
 
 
822
                        if (next_thr && *next_thr == NULL) {
 
823
                                /* Normally srv_suspend_mysql_thread resets
 
824
                                the state to DB_SUCCESS before waiting, but
 
825
                                in this case we have to do it here,
 
826
                                otherwise nobody does it. */
 
827
                                trx->error_state = DB_SUCCESS;
 
828
 
 
829
                                *next_thr = thr;
 
830
                        } else {
 
831
                                ut_error;
 
832
                                srv_que_task_enqueue_low(thr);
 
833
                        }
 
834
 
 
835
                        mutex_exit(&kernel_mutex);
 
836
 
 
837
                        return;
 
838
                }
 
839
        }
 
840
 
 
841
        ut_ad(fork->n_active_thrs == 1);
 
842
        ut_ad(trx->n_active_thrs == 1);
 
843
 
 
844
        fork->n_active_thrs--;
 
845
        trx->n_active_thrs--;
 
846
 
 
847
        thr->is_active = FALSE;
 
848
 
 
849
        if (trx->n_active_thrs > 0) {
 
850
 
 
851
                mutex_exit(&kernel_mutex);
 
852
 
 
853
                return;
 
854
        }
 
855
 
 
856
        fork_type = fork->fork_type;
 
857
 
 
858
        /* Check if all query threads in the same fork are completed */
 
859
 
 
860
        if (que_fork_all_thrs_in_state(fork, QUE_THR_COMPLETED)) {
 
861
 
 
862
                switch (fork_type) {
 
863
                case QUE_FORK_ROLLBACK:
 
864
                        /* This is really the undo graph used in rollback,
 
865
                        no roll_node in this graph */
 
866
 
 
867
                        ut_ad(UT_LIST_GET_LEN(trx->signals) > 0);
 
868
                        ut_ad(trx->handling_signals == TRUE);
 
869
 
 
870
                        trx_finish_rollback_off_kernel(fork, trx, next_thr);
 
871
                        break;
 
872
 
 
873
                case QUE_FORK_PURGE:
 
874
                case QUE_FORK_RECOVERY:
 
875
                case QUE_FORK_MYSQL_INTERFACE:
 
876
 
 
877
                        /* Do nothing */
 
878
                        break;
 
879
 
 
880
                default:
 
881
                        ut_error;       /*!< not used in MySQL */
 
882
                }
 
883
        }
 
884
 
 
885
        if (UT_LIST_GET_LEN(trx->signals) > 0 && trx->n_active_thrs == 0) {
 
886
 
 
887
                /* If the trx is signaled and its query thread count drops to
 
888
                zero, then we start processing a signal; from it we may get
 
889
                a new query thread to run */
 
890
 
 
891
                trx_sig_start_handle(trx, next_thr);
 
892
        }
 
893
 
 
894
        if (trx->handling_signals && UT_LIST_GET_LEN(trx->signals) == 0) {
 
895
 
 
896
                trx_end_signal_handling(trx);
 
897
        }
 
898
 
 
899
        mutex_exit(&kernel_mutex);
 
900
}
 
901
 
 
902
/**********************************************************************//**
 
903
Stops a query thread if graph or trx is in a state requiring it. The
 
904
conditions are tested in the order (1) graph, (2) trx. The kernel mutex has
 
905
to be reserved.
 
906
@return TRUE if stopped */
 
907
UNIV_INTERN
 
908
ibool
 
909
que_thr_stop(
 
910
/*=========*/
 
911
        que_thr_t*      thr)    /*!< in: query thread */
 
912
{
 
913
        trx_t*  trx;
 
914
        que_t*  graph;
 
915
        ibool   ret     = TRUE;
 
916
 
 
917
        ut_ad(mutex_own(&kernel_mutex));
 
918
 
 
919
        graph = thr->graph;
 
920
        trx = graph->trx;
 
921
 
 
922
        if (graph->state == QUE_FORK_COMMAND_WAIT) {
 
923
                thr->state = QUE_THR_SUSPENDED;
 
924
 
 
925
        } else if (trx->que_state == TRX_QUE_LOCK_WAIT) {
 
926
 
 
927
                UT_LIST_ADD_FIRST(trx_thrs, trx->wait_thrs, thr);
 
928
                thr->state = QUE_THR_LOCK_WAIT;
 
929
 
 
930
        } else if (trx->error_state != DB_SUCCESS
 
931
                   && trx->error_state != DB_LOCK_WAIT) {
 
932
 
 
933
                /* Error handling built for the MySQL interface */
 
934
                thr->state = QUE_THR_COMPLETED;
 
935
 
 
936
        } else if (UT_LIST_GET_LEN(trx->signals) > 0
 
937
                   && graph->fork_type != QUE_FORK_ROLLBACK) {
 
938
 
 
939
                thr->state = QUE_THR_SUSPENDED;
 
940
        } else {
 
941
                ut_ad(graph->state == QUE_FORK_ACTIVE);
 
942
 
 
943
                ret = FALSE;
 
944
        }
 
945
 
 
946
        return(ret);
 
947
}
 
948
 
 
949
/**********************************************************************//**
 
950
A patch for MySQL used to 'stop' a dummy query thread used in MySQL. The
 
951
query thread is stopped and made inactive, except in the case where
 
952
it was put to the lock wait state in lock0lock.c, but the lock has already
 
953
been granted or the transaction chosen as a victim in deadlock resolution. */
 
954
UNIV_INTERN
 
955
void
 
956
que_thr_stop_for_mysql(
 
957
/*===================*/
 
958
        que_thr_t*      thr)    /*!< in: query thread */
 
959
{
 
960
        trx_t*  trx;
 
961
 
 
962
        trx = thr_get_trx(thr);
 
963
 
 
964
        mutex_enter(&kernel_mutex);
 
965
 
 
966
        if (thr->state == QUE_THR_RUNNING) {
 
967
 
 
968
                if (trx->error_state != DB_SUCCESS
 
969
                    && trx->error_state != DB_LOCK_WAIT) {
 
970
 
 
971
                        /* Error handling built for the MySQL interface */
 
972
                        thr->state = QUE_THR_COMPLETED;
 
973
                } else {
 
974
                        /* It must have been a lock wait but the lock was
 
975
                        already released, or this transaction was chosen
 
976
                        as a victim in selective deadlock resolution */
 
977
 
 
978
                        mutex_exit(&kernel_mutex);
 
979
 
 
980
                        return;
 
981
                }
 
982
        }
 
983
 
 
984
        ut_ad(thr->is_active == TRUE);
 
985
        ut_ad(trx->n_active_thrs == 1);
 
986
        ut_ad(thr->graph->n_active_thrs == 1);
 
987
 
 
988
        thr->is_active = FALSE;
 
989
        (thr->graph)->n_active_thrs--;
 
990
 
 
991
        trx->n_active_thrs--;
 
992
 
 
993
        mutex_exit(&kernel_mutex);
 
994
}
 
995
 
 
996
/**********************************************************************//**
 
997
Moves a thread from another state to the QUE_THR_RUNNING state. Increments
 
998
the n_active_thrs counters of the query graph and transaction if thr was
 
999
not active. */
 
1000
UNIV_INTERN
 
1001
void
 
1002
que_thr_move_to_run_state_for_mysql(
 
1003
/*================================*/
 
1004
        que_thr_t*      thr,    /*!< in: an query thread */
 
1005
        trx_t*          trx)    /*!< in: transaction */
 
1006
{
 
1007
        if (thr->magic_n != QUE_THR_MAGIC_N) {
 
1008
                fprintf(stderr,
 
1009
                        "que_thr struct appears corrupt; magic n %lu\n",
 
1010
                        (unsigned long) thr->magic_n);
 
1011
 
 
1012
                mem_analyze_corruption(thr);
 
1013
 
 
1014
                ut_error;
 
1015
        }
 
1016
 
 
1017
        if (!thr->is_active) {
 
1018
 
 
1019
                thr->graph->n_active_thrs++;
 
1020
 
 
1021
                trx->n_active_thrs++;
 
1022
 
 
1023
                thr->is_active = TRUE;
 
1024
        }
 
1025
 
 
1026
        thr->state = QUE_THR_RUNNING;
 
1027
}
 
1028
 
 
1029
/**********************************************************************//**
 
1030
A patch for MySQL used to 'stop' a dummy query thread used in MySQL
 
1031
select, when there is no error or lock wait. */
 
1032
UNIV_INTERN
 
1033
void
 
1034
que_thr_stop_for_mysql_no_error(
 
1035
/*============================*/
 
1036
        que_thr_t*      thr,    /*!< in: query thread */
 
1037
        trx_t*          trx)    /*!< in: transaction */
 
1038
{
 
1039
        ut_ad(thr->state == QUE_THR_RUNNING);
 
1040
        ut_ad(thr->is_active == TRUE);
 
1041
        ut_ad(trx->n_active_thrs == 1);
 
1042
        ut_ad(thr->graph->n_active_thrs == 1);
 
1043
 
 
1044
        if (thr->magic_n != QUE_THR_MAGIC_N) {
 
1045
                fprintf(stderr,
 
1046
                        "que_thr struct appears corrupt; magic n %lu\n",
 
1047
                        (unsigned long) thr->magic_n);
 
1048
 
 
1049
                mem_analyze_corruption(thr);
 
1050
 
 
1051
                ut_error;
 
1052
        }
 
1053
 
 
1054
        thr->state = QUE_THR_COMPLETED;
 
1055
 
 
1056
        thr->is_active = FALSE;
 
1057
        (thr->graph)->n_active_thrs--;
 
1058
 
 
1059
        trx->n_active_thrs--;
 
1060
}
 
1061
 
 
1062
/****************************************************************//**
 
1063
Get the first containing loop node (e.g. while_node_t or for_node_t) for the
 
1064
given node, or NULL if the node is not within a loop.
 
1065
@return containing loop node, or NULL. */
 
1066
UNIV_INTERN
 
1067
que_node_t*
 
1068
que_node_get_containing_loop_node(
 
1069
/*==============================*/
 
1070
        que_node_t*     node)   /*!< in: node */
 
1071
{
 
1072
        ut_ad(node);
 
1073
 
 
1074
        for (;;) {
 
1075
                ulint   type;
 
1076
 
 
1077
                node = que_node_get_parent(node);
 
1078
 
 
1079
                if (!node) {
 
1080
                        break;
 
1081
                }
 
1082
 
 
1083
                type = que_node_get_type(node);
 
1084
 
 
1085
                if ((type == QUE_NODE_FOR) || (type == QUE_NODE_WHILE)) {
 
1086
                        break;
 
1087
                }
 
1088
        }
 
1089
 
 
1090
        return(node);
 
1091
}
 
1092
 
 
1093
/**********************************************************************//**
 
1094
Prints info of an SQL query graph node. */
 
1095
UNIV_INTERN
 
1096
void
 
1097
que_node_print_info(
 
1098
/*================*/
 
1099
        que_node_t*     node)   /*!< in: query graph node */
 
1100
{
 
1101
        ulint           type;
 
1102
        const char*     str;
 
1103
 
 
1104
        type = que_node_get_type(node);
 
1105
 
 
1106
        if (type == QUE_NODE_SELECT) {
 
1107
                str = "SELECT";
 
1108
        } else if (type == QUE_NODE_INSERT) {
 
1109
                str = "INSERT";
 
1110
        } else if (type == QUE_NODE_UPDATE) {
 
1111
                str = "UPDATE";
 
1112
        } else if (type == QUE_NODE_WHILE) {
 
1113
                str = "WHILE";
 
1114
        } else if (type == QUE_NODE_ASSIGNMENT) {
 
1115
                str = "ASSIGNMENT";
 
1116
        } else if (type == QUE_NODE_IF) {
 
1117
                str = "IF";
 
1118
        } else if (type == QUE_NODE_FETCH) {
 
1119
                str = "FETCH";
 
1120
        } else if (type == QUE_NODE_OPEN) {
 
1121
                str = "OPEN";
 
1122
        } else if (type == QUE_NODE_PROC) {
 
1123
                str = "STORED PROCEDURE";
 
1124
        } else if (type == QUE_NODE_FUNC) {
 
1125
                str = "FUNCTION";
 
1126
        } else if (type == QUE_NODE_LOCK) {
 
1127
                str = "LOCK";
 
1128
        } else if (type == QUE_NODE_THR) {
 
1129
                str = "QUERY THREAD";
 
1130
        } else if (type == QUE_NODE_COMMIT) {
 
1131
                str = "COMMIT";
 
1132
        } else if (type == QUE_NODE_UNDO) {
 
1133
                str = "UNDO ROW";
 
1134
        } else if (type == QUE_NODE_PURGE) {
 
1135
                str = "PURGE ROW";
 
1136
        } else if (type == QUE_NODE_ROLLBACK) {
 
1137
                str = "ROLLBACK";
 
1138
        } else if (type == QUE_NODE_CREATE_TABLE) {
 
1139
                str = "CREATE TABLE";
 
1140
        } else if (type == QUE_NODE_CREATE_INDEX) {
 
1141
                str = "CREATE INDEX";
 
1142
        } else if (type == QUE_NODE_FOR) {
 
1143
                str = "FOR LOOP";
 
1144
        } else if (type == QUE_NODE_RETURN) {
 
1145
                str = "RETURN";
 
1146
        } else if (type == QUE_NODE_EXIT) {
 
1147
                str = "EXIT";
 
1148
        } else {
 
1149
                str = "UNKNOWN NODE TYPE";
 
1150
        }
 
1151
 
 
1152
        fprintf(stderr, "Node type %lu: %s, address %p\n",
 
1153
                (ulong) type, str, (void*) node);
 
1154
}
 
1155
 
 
1156
/**********************************************************************//**
 
1157
Performs an execution step on a query thread.
 
1158
@return query thread to run next: it may differ from the input
 
1159
parameter if, e.g., a subprocedure call is made */
 
1160
UNIV_INLINE
 
1161
que_thr_t*
 
1162
que_thr_step(
 
1163
/*=========*/
 
1164
        que_thr_t*      thr)    /*!< in: query thread */
 
1165
{
 
1166
        que_node_t*     node;
 
1167
        que_thr_t*      old_thr;
 
1168
        trx_t*          trx;
 
1169
        ulint           type;
 
1170
 
 
1171
        trx = thr_get_trx(thr);
 
1172
 
 
1173
        ut_ad(thr->state == QUE_THR_RUNNING);
 
1174
        ut_a(trx->error_state == DB_SUCCESS);
 
1175
 
 
1176
        thr->resource++;
 
1177
 
 
1178
        node = thr->run_node;
 
1179
        type = que_node_get_type(node);
 
1180
 
 
1181
        old_thr = thr;
 
1182
 
 
1183
#ifdef UNIV_DEBUG
 
1184
        if (que_trace_on) {
 
1185
                fputs("To execute: ", stderr);
 
1186
                que_node_print_info(node);
 
1187
        }
 
1188
#endif
 
1189
        if (type & QUE_NODE_CONTROL_STAT) {
 
1190
                if ((thr->prev_node != que_node_get_parent(node))
 
1191
                    && que_node_get_next(thr->prev_node)) {
 
1192
 
 
1193
                        /* The control statements, like WHILE, always pass the
 
1194
                        control to the next child statement if there is any
 
1195
                        child left */
 
1196
 
 
1197
                        thr->run_node = que_node_get_next(thr->prev_node);
 
1198
 
 
1199
                } else if (type == QUE_NODE_IF) {
 
1200
                        if_step(thr);
 
1201
                } else if (type == QUE_NODE_FOR) {
 
1202
                        for_step(thr);
 
1203
                } else if (type == QUE_NODE_PROC) {
 
1204
 
 
1205
                        /* We can access trx->undo_no without reserving
 
1206
                        trx->undo_mutex, because there cannot be active query
 
1207
                        threads doing updating or inserting at the moment! */
 
1208
 
 
1209
                        if (thr->prev_node == que_node_get_parent(node)) {
 
1210
                                trx->last_sql_stat_start.least_undo_no
 
1211
                                        = trx->undo_no;
 
1212
                        }
 
1213
 
 
1214
                        proc_step(thr);
 
1215
                } else if (type == QUE_NODE_WHILE) {
 
1216
                        while_step(thr);
 
1217
                } else {
 
1218
                        ut_error;
 
1219
                }
 
1220
        } else if (type == QUE_NODE_ASSIGNMENT) {
 
1221
                assign_step(thr);
 
1222
        } else if (type == QUE_NODE_SELECT) {
 
1223
                thr = row_sel_step(thr);
 
1224
        } else if (type == QUE_NODE_INSERT) {
 
1225
                thr = row_ins_step(thr);
 
1226
        } else if (type == QUE_NODE_UPDATE) {
 
1227
                thr = row_upd_step(thr);
 
1228
        } else if (type == QUE_NODE_FETCH) {
 
1229
                thr = fetch_step(thr);
 
1230
        } else if (type == QUE_NODE_OPEN) {
 
1231
                thr = open_step(thr);
 
1232
        } else if (type == QUE_NODE_FUNC) {
 
1233
                proc_eval_step(thr);
 
1234
 
 
1235
        } else if (type == QUE_NODE_LOCK) {
 
1236
 
 
1237
                ut_error;
 
1238
                /*
 
1239
                thr = que_lock_step(thr);
 
1240
                */
 
1241
        } else if (type == QUE_NODE_THR) {
 
1242
                thr = que_thr_node_step(thr);
 
1243
        } else if (type == QUE_NODE_COMMIT) {
 
1244
                thr = trx_commit_step(thr);
 
1245
        } else if (type == QUE_NODE_UNDO) {
 
1246
                thr = row_undo_step(thr);
 
1247
        } else if (type == QUE_NODE_PURGE) {
 
1248
                thr = row_purge_step(thr);
 
1249
        } else if (type == QUE_NODE_RETURN) {
 
1250
                thr = return_step(thr);
 
1251
        } else if (type == QUE_NODE_EXIT) {
 
1252
                thr = exit_step(thr);
 
1253
        } else if (type == QUE_NODE_ROLLBACK) {
 
1254
                thr = trx_rollback_step(thr);
 
1255
        } else if (type == QUE_NODE_CREATE_TABLE) {
 
1256
                thr = dict_create_table_step(thr);
 
1257
        } else if (type == QUE_NODE_CREATE_INDEX) {
 
1258
                thr = dict_create_index_step(thr);
 
1259
        } else if (type == QUE_NODE_ROW_PRINTF) {
 
1260
                thr = row_printf_step(thr);
 
1261
        } else {
 
1262
                ut_error;
 
1263
        }
 
1264
 
 
1265
        if (type == QUE_NODE_EXIT) {
 
1266
                old_thr->prev_node = que_node_get_containing_loop_node(node);
 
1267
        } else {
 
1268
                old_thr->prev_node = node;
 
1269
        }
 
1270
 
 
1271
        if (thr) {
 
1272
                ut_a(thr_get_trx(thr)->error_state == DB_SUCCESS);
 
1273
        }
 
1274
 
 
1275
        return(thr);
 
1276
}
 
1277
 
 
1278
/**********************************************************************//**
 
1279
Run a query thread until it finishes or encounters e.g. a lock wait. */
 
1280
static
 
1281
void
 
1282
que_run_threads_low(
 
1283
/*================*/
 
1284
        que_thr_t*      thr)    /*!< in: query thread */
 
1285
{
 
1286
        que_thr_t*      next_thr;
 
1287
        ulint           cumul_resource;
 
1288
        ulint           loop_count;
 
1289
 
 
1290
        ut_ad(thr->state == QUE_THR_RUNNING);
 
1291
        ut_a(thr_get_trx(thr)->error_state == DB_SUCCESS);
 
1292
        ut_ad(!mutex_own(&kernel_mutex));
 
1293
 
 
1294
        /* cumul_resource counts how much resources the OS thread (NOT the
 
1295
        query thread) has spent in this function */
 
1296
 
 
1297
        loop_count = QUE_MAX_LOOPS_WITHOUT_CHECK;
 
1298
        cumul_resource = 0;
 
1299
loop:
 
1300
        /* Check that there is enough space in the log to accommodate
 
1301
        possible log entries by this query step; if the operation can touch
 
1302
        more than about 4 pages, checks must be made also within the query
 
1303
        step! */
 
1304
 
 
1305
        log_free_check();
 
1306
 
 
1307
        /* Perform the actual query step: note that the query thread
 
1308
        may change if, e.g., a subprocedure call is made */
 
1309
 
 
1310
        /*-------------------------*/
 
1311
        next_thr = que_thr_step(thr);
 
1312
        /*-------------------------*/
 
1313
 
 
1314
        ut_a(!next_thr || (thr_get_trx(next_thr)->error_state == DB_SUCCESS));
 
1315
 
 
1316
        loop_count++;
 
1317
 
 
1318
        if (next_thr != thr) {
 
1319
                ut_a(next_thr == NULL);
 
1320
 
 
1321
                /* This can change next_thr to a non-NULL value if there was
 
1322
                a lock wait that already completed. */
 
1323
                que_thr_dec_refer_count(thr, &next_thr);
 
1324
 
 
1325
                if (next_thr == NULL) {
 
1326
 
 
1327
                        return;
 
1328
                }
 
1329
 
 
1330
                loop_count = QUE_MAX_LOOPS_WITHOUT_CHECK;
 
1331
 
 
1332
                thr = next_thr;
 
1333
        }
 
1334
 
 
1335
        goto loop;
 
1336
}
 
1337
 
 
1338
/**********************************************************************//**
 
1339
Run a query thread. Handles lock waits. */
 
1340
UNIV_INTERN
 
1341
void
 
1342
que_run_threads(
 
1343
/*============*/
 
1344
        que_thr_t*      thr)    /*!< in: query thread */
 
1345
{
 
1346
loop:
 
1347
        ut_a(thr_get_trx(thr)->error_state == DB_SUCCESS);
 
1348
        que_run_threads_low(thr);
 
1349
 
 
1350
        mutex_enter(&kernel_mutex);
 
1351
 
 
1352
        switch (thr->state) {
 
1353
 
 
1354
        case QUE_THR_RUNNING:
 
1355
                /* There probably was a lock wait, but it already ended
 
1356
                before we came here: continue running thr */
 
1357
 
 
1358
                mutex_exit(&kernel_mutex);
 
1359
 
 
1360
                goto loop;
 
1361
 
 
1362
        case QUE_THR_LOCK_WAIT:
 
1363
                mutex_exit(&kernel_mutex);
 
1364
 
 
1365
                /* The ..._mysql_... function works also for InnoDB's
 
1366
                internal threads. Let us wait that the lock wait ends. */
 
1367
 
 
1368
                srv_suspend_mysql_thread(thr);
 
1369
 
 
1370
                if (thr_get_trx(thr)->error_state != DB_SUCCESS) {
 
1371
                        /* thr was chosen as a deadlock victim or there was
 
1372
                        a lock wait timeout */
 
1373
 
 
1374
                        que_thr_dec_refer_count(thr, NULL);
 
1375
 
 
1376
                        return;
 
1377
                }
 
1378
 
 
1379
                goto loop;
 
1380
 
 
1381
        case QUE_THR_COMPLETED:
 
1382
        case QUE_THR_COMMAND_WAIT:
 
1383
                /* Do nothing */
 
1384
                break;
 
1385
 
 
1386
        default:
 
1387
                ut_error;
 
1388
        }
 
1389
 
 
1390
        mutex_exit(&kernel_mutex);
 
1391
}
 
1392
 
 
1393
/*********************************************************************//**
 
1394
Evaluate the given SQL.
 
1395
@return error code or DB_SUCCESS */
 
1396
UNIV_INTERN
 
1397
ulint
 
1398
que_eval_sql(
 
1399
/*=========*/
 
1400
        pars_info_t*    info,   /*!< in: info struct, or NULL */
 
1401
        const char*     sql,    /*!< in: SQL string */
 
1402
        ibool           reserve_dict_mutex,
 
1403
                                /*!< in: if TRUE, acquire/release
 
1404
                                dict_sys->mutex around call to pars_sql. */
 
1405
        trx_t*          trx)    /*!< in: trx */
 
1406
{
 
1407
        que_thr_t*      thr;
 
1408
        que_t*          graph;
 
1409
 
 
1410
        ut_a(trx->error_state == DB_SUCCESS);
 
1411
 
 
1412
        if (reserve_dict_mutex) {
 
1413
                mutex_enter(&dict_sys->mutex);
 
1414
        }
 
1415
 
 
1416
        graph = pars_sql(info, sql);
 
1417
 
 
1418
        if (reserve_dict_mutex) {
 
1419
                mutex_exit(&dict_sys->mutex);
 
1420
        }
 
1421
 
 
1422
        ut_a(graph);
 
1423
 
 
1424
        graph->trx = trx;
 
1425
        trx->graph = NULL;
 
1426
 
 
1427
        graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
 
1428
 
 
1429
        ut_a(thr = que_fork_start_command(graph));
 
1430
 
 
1431
        que_run_threads(thr);
 
1432
 
 
1433
        que_graph_free(graph);
 
1434
 
 
1435
        return(trx->error_state);
 
1436
}