~drizzle-trunk/drizzle/development

641.2.2 by Monty Taylor
InnoDB Plugin 1.0.3
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
1802.10.2 by Monty Taylor
Update all of the copyright headers to include the correct address.
14
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15
St, Fifth Floor, Boston, MA 02110-1301 USA
641.2.2 by Monty Taylor
InnoDB Plugin 1.0.3
16
17
*****************************************************************************/
18
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
19
/**************************************************//**
20
@file que/que0que.c
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
127
/**********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
/*======================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
136
	que_thr_t*	thr);	/*!< in: an query thread */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
137
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
138
/***********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
139
Adds a query graph to the session's list of graphs. */
140
UNIV_INTERN
141
void
142
que_graph_publish(
143
/*==============*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
144
	que_t*	graph,	/*!< in: graph */
145
	sess_t*	sess)	/*!< in: session */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
146
{
147
	ut_ad(mutex_own(&kernel_mutex));
148
149
	UT_LIST_ADD_LAST(graphs, sess->graphs, graph);
150
}
151
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
152
/***********************************************************************//**
153
Creates a query graph fork node.
154
@return	own: fork node */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
155
UNIV_INTERN
156
que_fork_t*
157
que_fork_create(
158
/*============*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
159
	que_t*		graph,		/*!< in: graph, if NULL then this
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
160
					fork node is assumed to be the
161
					graph root */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
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 */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
198
/***********************************************************************//**
199
Creates a query graph thread node.
200
@return	own: query thread node */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
201
UNIV_INTERN
202
que_thr_t*
203
que_thr_create(
204
/*===========*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
205
	que_fork_t*	parent,	/*!< in: parent node, i.e., a fork node */
206
	mem_heap_t*	heap)	/*!< in: memory heap where created */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
234
/**********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
/*=============*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
243
	que_thr_t*	thr,		/*!< in: query thread in the
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
244
					QUE_THR_LOCK_WAIT,
245
					or QUE_THR_PROCEDURE_WAIT, or
246
					QUE_THR_SIG_REPLY_WAIT state */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
247
	que_thr_t**	next_thr)	/*!< in/out: next query thread to run;
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
282
/**********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
/*=========================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
288
	que_thr_t*	thr)	/*!< in: query thread in the QUE_THR_LOCK_WAIT,
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
319
/**********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
320
Inits a query thread for a command. */
321
UNIV_INLINE
322
void
323
que_thr_init_command(
324
/*=================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
325
	que_thr_t*	thr)	/*!< in: query thread */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
326
{
327
	thr->run_node = thr;
328
	thr->prev_node = thr->common.parent;
329
330
	que_thr_move_to_run_state(thr);
331
}
332
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
333
/**********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
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 */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
341
UNIV_INTERN
342
que_thr_t*
343
que_fork_start_command(
344
/*===================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
345
	que_fork_t*	fork)	/*!< in: a query fork */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
421
/**********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
/*==================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
429
	trx_t*	trx __attribute__((unused)),	/*!< in: trx */
430
	que_t*	fork)	/*!< in: query graph which was run before signal
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
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 */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
466
UNIV_INLINE
467
ibool
468
que_fork_all_thrs_in_state(
469
/*=======================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
470
	que_fork_t*	fork,	/*!< in: query fork */
471
	ulint		state)	/*!< in: state */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
489
/**********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
490
Calls que_graph_free_recursive for statements in a statement list. */
491
static
492
void
493
que_graph_free_stat_list(
494
/*=====================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
495
	que_node_t*	node)	/*!< in: first query graph node in the list */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
496
{
497
	while (node) {
498
		que_graph_free_recursive(node);
499
500
		node = que_node_get_next(node);
501
	}
502
}
503
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
504
/**********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
/*=====================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
511
	que_node_t*	node)	/*!< in: query graph node */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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;
1819.5.106 by stewart at flamingspork
[patch 106/129] Merge patch for revision 1915 from InnoDB SVN:
521
	purge_node_t*	purge;
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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;
1819.5.106 by stewart at flamingspork
[patch 106/129] Merge patch for revision 1915 from InnoDB SVN:
583
	case QUE_NODE_PURGE:
584
		purge = node;
585
586
		mem_heap_free(purge->heap);
587
588
		break;
589
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
676
/**********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
677
Frees a query graph. */
678
UNIV_INTERN
679
void
680
que_graph_free(
681
/*===========*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
682
	que_t*	graph)	/*!< in: query graph; we assume that the memory
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
707
/****************************************************************//**
708
Performs an execution step on a thr node.
709
@return	query thread to run next, or NULL if none */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
710
static
711
que_thr_t*
712
que_thr_node_step(
713
/*==============*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
714
	que_thr_t*	thr)	/*!< in: query thread where run_node must
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
746
/**********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
/*======================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
756
	que_thr_t*	thr)	/*!< in: an query thread */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
779
/**********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
/*====================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
791
	que_thr_t*	thr,		/*!< in: query thread */
792
	que_thr_t**	next_thr)	/*!< in/out: next query thread to run;
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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:
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
881
			ut_error;	/*!< not used in MySQL */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
902
/**********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
905
to be reserved.
906
@return	TRUE if stopped */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
907
UNIV_INTERN
908
ibool
909
que_thr_stop(
910
/*=========*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
911
	que_thr_t*	thr)	/*!< in: query thread */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
949
/**********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
/*===================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
958
	que_thr_t*	thr)	/*!< in: query thread */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
996
/**********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
/*================================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1004
	que_thr_t*	thr,	/*!< in: an query thread */
1005
	trx_t*		trx)	/*!< in: transaction */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1029
/**********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
/*============================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1036
	que_thr_t*	thr,	/*!< in: query thread */
1037
	trx_t*		trx)	/*!< in: transaction */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1062
/****************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1063
Get the first containing loop node (e.g. while_node_t or for_node_t) for the
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1064
given node, or NULL if the node is not within a loop.
1065
@return	containing loop node, or NULL. */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1066
UNIV_INTERN
1067
que_node_t*
1068
que_node_get_containing_loop_node(
1069
/*==============================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1070
	que_node_t*	node)	/*!< in: node */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1093
/**********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1094
Prints info of an SQL query graph node. */
1095
UNIV_INTERN
1096
void
1097
que_node_print_info(
1098
/*================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1099
	que_node_t*	node)	/*!< in: query graph node */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
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 */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1160
UNIV_INLINE
1161
que_thr_t*
1162
que_thr_step(
1163
/*=========*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1164
	que_thr_t*	thr)	/*!< in: query thread */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1278
/**********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
/*================*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1284
	que_thr_t*	thr)	/*!< in: query thread */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1338
/**********************************************************************//**
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1339
Run a query thread. Handles lock waits. */
1340
UNIV_INTERN
1341
void
1342
que_run_threads(
1343
/*============*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1344
	que_thr_t*	thr)	/*!< in: query thread */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1393
/*********************************************************************//**
1394
Evaluate the given SQL.
1395
@return	error code or DB_SUCCESS */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1396
UNIV_INTERN
1397
ulint
1398
que_eval_sql(
1399
/*=========*/
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1400
	pars_info_t*	info,	/*!< in: info struct, or NULL */
1401
	const char*	sql,	/*!< in: SQL string */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1402
	ibool		reserve_dict_mutex,
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1403
				/*!< in: if TRUE, acquire/release
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
1404
				dict_sys->mutex around call to pars_sql. */
641.2.3 by Monty Taylor
InnoDB Plugin 1.0.4
1405
	trx_t*		trx)	/*!< in: trx */
641.1.2 by Monty Taylor
Imported 1.0.1 with clean - with no changes.
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
}