MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
que0que.cc
Go to the documentation of this file.
1 /*****************************************************************************
2 
3 Copyright (c) 1996, 2012, Oracle and/or its affiliates. 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.,
15 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
16 
17 *****************************************************************************/
18 
19 /**************************************************/
26 #include "que0que.h"
27 
28 #ifdef UNIV_NONINL
29 #include "que0que.ic"
30 #endif
31 
32 #include "usr0sess.h"
33 #include "trx0trx.h"
34 #include "trx0roll.h"
35 #include "row0undo.h"
36 #include "row0ins.h"
37 #include "row0upd.h"
38 #include "row0sel.h"
39 #include "row0purge.h"
40 #include "dict0crea.h"
41 #include "log0log.h"
42 #include "eval0proc.h"
43 #include "lock0lock.h"
44 #include "eval0eval.h"
45 #include "pars0types.h"
46 
47 #define QUE_MAX_LOOPS_WITHOUT_CHECK 16
48 
49 #ifdef UNIV_DEBUG
50 /* If the following flag is set TRUE, the module will print trace info
51 of SQL execution in the UNIV_SQL_DEBUG version */
52 UNIV_INTERN ibool que_trace_on = FALSE;
53 #endif /* UNIV_DEBUG */
54 
55 /* Short introduction to query graphs
56  ==================================
57 
58 A query graph consists of nodes linked to each other in various ways. The
59 execution starts at que_run_threads() which takes a que_thr_t parameter.
60 que_thr_t contains two fields that control query graph execution: run_node
61 and prev_node. run_node is the next node to execute and prev_node is the
62 last node executed.
63 
64 Each node has a pointer to a 'next' statement, i.e., its brother, and a
65 pointer to its parent node. The next pointer is NULL in the last statement
66 of a block.
67 
68 Loop nodes contain a link to the first statement of the enclosed statement
69 list. While the loop runs, que_thr_step() checks if execution to the loop
70 node came from its parent or from one of the statement nodes in the loop. If
71 it came from the parent of the loop node it starts executing the first
72 statement node in the loop. If it came from one of the statement nodes in
73 the loop, then it checks if the statement node has another statement node
74 following it, and runs it if so.
75 
76 To signify loop ending, the loop statements (see e.g. while_step()) set
77 que_thr_t->run_node to the loop node's parent node. This is noticed on the
78 next call of que_thr_step() and execution proceeds to the node pointed to by
79 the loop node's 'next' pointer.
80 
81 For example, the code:
82 
83 X := 1;
84 WHILE X < 5 LOOP
85  X := X + 1;
86  X := X + 1;
87 X := 5
88 
89 will result in the following node hierarchy, with the X-axis indicating
90 'next' links and the Y-axis indicating parent/child links:
91 
92 A - W - A
93  |
94  |
95  A - A
96 
97 A = assign_node_t, W = while_node_t. */
98 
99 /* How a stored procedure containing COMMIT or ROLLBACK commands
100 is executed?
101 
102 The commit or rollback can be seen as a subprocedure call.
103 
104 When the transaction starts to handle a rollback or commit.
105 It builds a query graph which, when executed, will roll back
106 or commit the incomplete transaction. The transaction
107 is moved to the TRX_QUE_ROLLING_BACK or TRX_QUE_COMMITTING state.
108 If specified, the SQL cursors opened by the transaction are closed.
109 When the execution of the graph completes, it is like returning
110 from a subprocedure: the query thread which requested the operation
111 starts running again. */
112 
113 /**********************************************************************/
118 static
119 void
120 que_thr_move_to_run_state(
121 /*======================*/
122  que_thr_t* thr);
124 /***********************************************************************/
127 UNIV_INTERN
128 que_fork_t*
130 /*============*/
131  que_t* graph,
134  que_node_t* parent,
135  ulint fork_type,
136  mem_heap_t* heap)
137 {
138  que_fork_t* fork;
139 
140  ut_ad(heap);
141 
142  fork = static_cast<que_fork_t*>(mem_heap_zalloc(heap, sizeof(*fork)));
143 
144  fork->heap = heap;
145 
146  fork->fork_type = fork_type;
147 
148  fork->common.parent = parent;
149 
150  fork->common.type = QUE_NODE_FORK;
151 
152  fork->state = QUE_FORK_COMMAND_WAIT;
153 
154  fork->graph = (graph != NULL) ? graph : fork;
155 
156  return(fork);
157 }
158 
159 /***********************************************************************/
162 UNIV_INTERN
163 que_thr_t*
165 /*===========*/
166  que_fork_t* parent,
167  mem_heap_t* heap)
168 {
169  que_thr_t* thr;
170 
171  ut_ad(parent && heap);
172 
173  thr = static_cast<que_thr_t*>(mem_heap_zalloc(heap, sizeof(*thr)));
174 
175  thr->graph = parent->graph;
176 
177  thr->common.parent = parent;
178 
179  thr->magic_n = QUE_THR_MAGIC_N;
180 
181  thr->common.type = QUE_NODE_THR;
182 
183  thr->state = QUE_THR_COMMAND_WAIT;
184 
185  thr->lock_state = QUE_THR_LOCK_NOLOCK;
186 
187  UT_LIST_ADD_LAST(thrs, parent->thrs, thr);
188 
189  return(thr);
190 }
191 
192 /**********************************************************************/
198 UNIV_INTERN
199 que_thr_t*
201 /*==================*/
202  trx_t* trx)
204 {
205  que_thr_t* thr;
206  ibool was_active;
207 
209  ut_ad(trx_mutex_own(trx));
210 
211  thr = trx->lock.wait_thr;
212 
213  ut_ad(thr != NULL);
214 
216  /* In MySQL this is the only possible state here */
217  ut_a(thr->state == QUE_THR_LOCK_WAIT);
218 
219  was_active = thr->is_active;
220 
221  que_thr_move_to_run_state(thr);
222 
224 
225  trx->lock.wait_thr = NULL;
226 
227  /* In MySQL we let the OS thread (not just the query thread) to wait
228  for the lock to be released: */
229 
230  return((!was_active && thr != NULL) ? thr : NULL);
231 }
232 
233 /**********************************************************************/
235 UNIV_INLINE
236 void
238 /*=================*/
239  que_thr_t* thr)
240 {
241  thr->run_node = thr;
242  thr->prev_node = thr->common.parent;
243 
244  que_thr_move_to_run_state(thr);
245 }
246 
247 /**********************************************************************/
252 UNIV_INTERN
253 que_thr_t*
255 /*===========================*/
256  que_fork_t* fork,
257  que_thr_t* thr)
258 {
259  trx_mutex_enter(fork->trx);
260 
261  /* If no current, start first available. */
262  if (thr == NULL) {
263  thr = UT_LIST_GET_FIRST(fork->thrs);
264  } else {
265  thr = UT_LIST_GET_NEXT(thrs, thr);
266  }
267 
268  if (thr) {
269 
270  fork->state = QUE_FORK_ACTIVE;
271 
272  fork->last_sel_node = NULL;
273 
274  switch (thr->state) {
275  case QUE_THR_COMMAND_WAIT:
276  case QUE_THR_COMPLETED:
277  ut_a(!thr->is_active);
279  break;
280 
281  case QUE_THR_SUSPENDED:
282  case QUE_THR_LOCK_WAIT:
283  default:
284  ut_error;
285 
286  }
287  }
288 
289  trx_mutex_exit(fork->trx);
290 
291  return(thr);
292 }
293 
294 /**********************************************************************/
302 UNIV_INTERN
303 que_thr_t*
305 /*===================*/
306  que_fork_t* fork)
307 {
308  que_thr_t* thr;
309  que_thr_t* suspended_thr = NULL;
310  que_thr_t* completed_thr = NULL;
311 
312  fork->state = QUE_FORK_ACTIVE;
313 
314  fork->last_sel_node = NULL;
315 
316  suspended_thr = NULL;
317  completed_thr = NULL;
318 
319  /* Choose the query thread to run: usually there is just one thread,
320  but in a parallelized select, which necessarily is non-scrollable,
321  there may be several to choose from */
322 
323  /* First we try to find a query thread in the QUE_THR_COMMAND_WAIT
324  state. Then we try to find a query thread in the QUE_THR_SUSPENDED
325  state, finally we try to find a query thread in the QUE_THR_COMPLETED
326  state */
327 
328  /* We make a single pass over the thr list within which we note which
329  threads are ready to run. */
330  for (thr = UT_LIST_GET_FIRST(fork->thrs);
331  thr != NULL;
332  thr = UT_LIST_GET_NEXT(thrs, thr)) {
333 
334  switch (thr->state) {
335  case QUE_THR_COMMAND_WAIT:
336 
337  /* We have to send the initial message to query thread
338  to start it */
339 
341 
342  return(thr);
343 
344  case QUE_THR_SUSPENDED:
345  /* In this case the execution of the thread was
346  suspended: no initial message is needed because
347  execution can continue from where it was left */
348  if (!suspended_thr) {
349  suspended_thr = thr;
350  }
351 
352  break;
353 
354  case QUE_THR_COMPLETED:
355  if (!completed_thr) {
356  completed_thr = thr;
357  }
358 
359  break;
360 
361  case QUE_THR_LOCK_WAIT:
362  ut_error;
363 
364  }
365  }
366 
367  if (suspended_thr) {
368 
369  thr = suspended_thr;
370  que_thr_move_to_run_state(thr);
371 
372  } else if (completed_thr) {
373 
374  thr = completed_thr;
376  } else {
377  ut_error;
378  }
379 
380  return(thr);
381 }
382 
383 /****************************************************************/
387 UNIV_INLINE
388 ibool
390 /*=======================*/
391  que_fork_t* fork,
392  ulint state)
393 {
394  que_thr_t* thr_node;
395 
396  for (thr_node = UT_LIST_GET_FIRST(fork->thrs);
397  thr_node != NULL;
398  thr_node = UT_LIST_GET_NEXT(thrs, thr_node)) {
399 
400  if (thr_node->state != state) {
401 
402  return(FALSE);
403  }
404  }
405 
406  return(TRUE);
407 }
408 
409 /**********************************************************************/
411 static
412 void
413 que_graph_free_stat_list(
414 /*=====================*/
415  que_node_t* node)
416 {
417  while (node) {
419 
420  node = que_node_get_next(node);
421  }
422 }
423 
424 /**********************************************************************/
427 UNIV_INTERN
428 void
430 /*=====================*/
431  que_node_t* node)
432 {
433  que_fork_t* fork;
434  que_thr_t* thr;
435  undo_node_t* undo;
436  sel_node_t* sel;
437  ins_node_t* ins;
438  upd_node_t* upd;
439  tab_node_t* cre_tab;
440  ind_node_t* cre_ind;
441  purge_node_t* purge;
442 
443  if (node == NULL) {
444 
445  return;
446  }
447 
448  switch (que_node_get_type(node)) {
449 
450  case QUE_NODE_FORK:
451  fork = static_cast<que_fork_t*>(node);
452 
453  thr = UT_LIST_GET_FIRST(fork->thrs);
454 
455  while (thr) {
457 
458  thr = UT_LIST_GET_NEXT(thrs, thr);
459  }
460 
461  break;
462  case QUE_NODE_THR:
463 
464  thr = static_cast<que_thr_t*>(node);
465 
466  if (thr->magic_n != QUE_THR_MAGIC_N) {
467  fprintf(stderr,
468  "que_thr struct appears corrupt;"
469  " magic n %lu\n",
470  (unsigned long) thr->magic_n);
472  ut_error;
473  }
474 
475  thr->magic_n = QUE_THR_MAGIC_FREED;
476 
478 
479  break;
480  case QUE_NODE_UNDO:
481 
482  undo = static_cast<undo_node_t*>(node);
483 
484  mem_heap_free(undo->heap);
485 
486  break;
487  case QUE_NODE_SELECT:
488 
489  sel = static_cast<sel_node_t*>(node);
490 
492 
493  break;
494  case QUE_NODE_INSERT:
495 
496  ins = static_cast<ins_node_t*>(node);
497 
499 
500  mem_heap_free(ins->entry_sys_heap);
501 
502  break;
503  case QUE_NODE_PURGE:
504  purge = static_cast<purge_node_t*>(node);
505 
506  mem_heap_free(purge->heap);
507 
508  break;
509 
510  case QUE_NODE_UPDATE:
511 
512  upd = static_cast<upd_node_t*>(node);
513 
514  if (upd->in_mysql_interface) {
515 
517  }
518 
519  que_graph_free_recursive(upd->cascade_node);
520 
521  if (upd->cascade_heap) {
522  mem_heap_free(upd->cascade_heap);
523  }
524 
526 
527  mem_heap_free(upd->heap);
528 
529  break;
530  case QUE_NODE_CREATE_TABLE:
531  cre_tab = static_cast<tab_node_t*>(node);
532 
533  que_graph_free_recursive(cre_tab->tab_def);
534  que_graph_free_recursive(cre_tab->col_def);
535  que_graph_free_recursive(cre_tab->commit_node);
536 
537  mem_heap_free(cre_tab->heap);
538 
539  break;
540  case QUE_NODE_CREATE_INDEX:
541  cre_ind = static_cast<ind_node_t*>(node);
542 
543  que_graph_free_recursive(cre_ind->ind_def);
544  que_graph_free_recursive(cre_ind->field_def);
545  que_graph_free_recursive(cre_ind->commit_node);
546 
547  mem_heap_free(cre_ind->heap);
548 
549  break;
550  case QUE_NODE_PROC:
551  que_graph_free_stat_list(((proc_node_t*) node)->stat_list);
552 
553  break;
554  case QUE_NODE_IF:
555  que_graph_free_stat_list(((if_node_t*) node)->stat_list);
556  que_graph_free_stat_list(((if_node_t*) node)->else_part);
557  que_graph_free_stat_list(((if_node_t*) node)->elsif_list);
558 
559  break;
560  case QUE_NODE_ELSIF:
561  que_graph_free_stat_list(((elsif_node_t*) node)->stat_list);
562 
563  break;
564  case QUE_NODE_WHILE:
565  que_graph_free_stat_list(((while_node_t*) node)->stat_list);
566 
567  break;
568  case QUE_NODE_FOR:
569  que_graph_free_stat_list(((for_node_t*) node)->stat_list);
570 
571  break;
572 
573  case QUE_NODE_ASSIGNMENT:
574  case QUE_NODE_EXIT:
575  case QUE_NODE_RETURN:
576  case QUE_NODE_COMMIT:
577  case QUE_NODE_ROLLBACK:
578  case QUE_NODE_LOCK:
579  case QUE_NODE_FUNC:
580  case QUE_NODE_ORDER:
581  case QUE_NODE_ROW_PRINTF:
582  case QUE_NODE_OPEN:
583  case QUE_NODE_FETCH:
584  /* No need to do anything */
585 
586  break;
587  default:
588  fprintf(stderr,
589  "que_node struct appears corrupt; type %lu\n",
590  (unsigned long) que_node_get_type(node));
592  ut_error;
593  }
594 }
595 
596 /**********************************************************************/
598 UNIV_INTERN
599 void
601 /*===========*/
602  que_t* graph)
607 {
608  ut_ad(graph);
609 
610  if (graph->sym_tab) {
611  /* The following call frees dynamic memory allocated
612  for variables etc. during execution. Frees also explicit
613  cursor definitions. */
614 
616  }
617 
618  if (graph->info && graph->info->graph_owns_us) {
619  pars_info_free(graph->info);
620  }
621 
623 
624  mem_heap_free(graph->heap);
625 }
626 
627 /****************************************************************/
630 static
631 que_thr_t*
632 que_thr_node_step(
633 /*==============*/
634  que_thr_t* thr)
636 {
637  ut_ad(thr->run_node == thr);
638 
639  if (thr->prev_node == thr->common.parent) {
640  /* If control to the node came from above, it is just passed
641  on */
642 
643  thr->run_node = thr->child;
644 
645  return(thr);
646  }
647 
649 
650  if (que_thr_peek_stop(thr)) {
651 
653 
654  return(thr);
655  }
656 
657  /* Thread execution completed */
658 
659  thr->state = QUE_THR_COMPLETED;
660 
662 
663  return(NULL);
664 }
665 
666 /**********************************************************************/
672 static
673 void
674 que_thr_move_to_run_state(
675 /*======================*/
676  que_thr_t* thr)
677 {
678  ut_ad(thr->state != QUE_THR_RUNNING);
679 
680  if (!thr->is_active) {
681  trx_t* trx;
682 
683  trx = thr_get_trx(thr);
684 
685  thr->graph->n_active_thrs++;
686 
687  trx->lock.n_active_thrs++;
688 
689  thr->is_active = TRUE;
690  }
691 
692  thr->state = QUE_THR_RUNNING;
693 }
694 
695 /**********************************************************************/
699 UNIV_INTERN
700 ibool
702 /*=========*/
703  que_thr_t* thr)
704 {
705  que_t* graph;
706  trx_t* trx = thr_get_trx(thr);
707 
708  graph = thr->graph;
709 
710  ut_ad(trx_mutex_own(trx));
711 
712  if (graph->state == QUE_FORK_COMMAND_WAIT) {
713 
714  thr->state = QUE_THR_SUSPENDED;
715 
716  } else if (trx->lock.que_state == TRX_QUE_LOCK_WAIT) {
717 
718  trx->lock.wait_thr = thr;
719  thr->state = QUE_THR_LOCK_WAIT;
720 
721  } else if (trx->error_state != DB_SUCCESS
722  && trx->error_state != DB_LOCK_WAIT) {
723 
724  /* Error handling built for the MySQL interface */
725  thr->state = QUE_THR_COMPLETED;
726 
727  } else if (graph->fork_type == QUE_FORK_ROLLBACK) {
728 
729  thr->state = QUE_THR_SUSPENDED;
730  } else {
731  ut_ad(graph->state == QUE_FORK_ACTIVE);
732 
733  return(FALSE);
734  }
735 
736  return(TRUE);
737 }
738 
739 /**********************************************************************/
747 static
748 void
749 que_thr_dec_refer_count(
750 /*====================*/
751  que_thr_t* thr,
752  que_thr_t** next_thr)
757 {
758  trx_t* trx;
759  que_fork_t* fork;
760 
761  trx = thr_get_trx(thr);
762 
763  ut_a(thr->is_active);
764  ut_ad(trx_mutex_own(trx));
765 
766  if (thr->state == QUE_THR_RUNNING) {
767 
768  if (!que_thr_stop(thr)) {
769 
770  ut_a(next_thr != NULL && *next_thr == NULL);
771 
772  /* The reason for the thr suspension or wait was
773  already canceled before we came here: continue
774  running the thread.
775 
776  This is also possible because in trx_commit_step() we
777  assume a single query thread. We set the query thread
778  state to QUE_THR_RUNNING. */
779 
780  /* fprintf(stderr,
781  "Wait already ended: trx: %p\n", trx); */
782 
783  /* Normally srv_suspend_mysql_thread resets
784  the state to DB_SUCCESS before waiting, but
785  in this case we have to do it here,
786  otherwise nobody does it. */
787 
788  trx->error_state = DB_SUCCESS;
789 
790  *next_thr = thr;
791 
792  return;
793  }
794  }
795 
796  fork = static_cast<que_fork_t*>(thr->common.parent);
797 
798  --trx->lock.n_active_thrs;
799 
800  --fork->n_active_thrs;
801 
802  thr->is_active = FALSE;
803 }
804 
805 /**********************************************************************/
810 UNIV_INTERN
811 void
813 /*===================*/
814  que_thr_t* thr)
815 {
816  trx_t* trx;
817 
818  trx = thr_get_trx(thr);
819 
820  /* Can't be the purge transaction. */
821  ut_a(trx->id != 0);
822 
823  trx_mutex_enter(trx);
824 
825  if (thr->state == QUE_THR_RUNNING) {
826 
827  if (trx->error_state != DB_SUCCESS
828  && trx->error_state != DB_LOCK_WAIT) {
829 
830  /* Error handling built for the MySQL interface */
831  thr->state = QUE_THR_COMPLETED;
832  } else {
833  /* It must have been a lock wait but the lock was
834  already released, or this transaction was chosen
835  as a victim in selective deadlock resolution */
836 
837  trx_mutex_exit(trx);
838 
839  return;
840  }
841  }
842 
843  ut_ad(thr->is_active == TRUE);
844  ut_ad(trx->lock.n_active_thrs == 1);
845  ut_ad(thr->graph->n_active_thrs == 1);
846 
847  thr->is_active = FALSE;
848  thr->graph->n_active_thrs--;
849 
850  trx->lock.n_active_thrs--;
851 
852  trx_mutex_exit(trx);
853 }
854 
855 /**********************************************************************/
859 UNIV_INTERN
860 void
862 /*================================*/
863  que_thr_t* thr,
864  trx_t* trx)
865 {
866  if (thr->magic_n != QUE_THR_MAGIC_N) {
867  fprintf(stderr,
868  "que_thr struct appears corrupt; magic n %lu\n",
869  (unsigned long) thr->magic_n);
870 
872 
873  ut_error;
874  }
875 
876  if (!thr->is_active) {
877 
878  thr->graph->n_active_thrs++;
879 
880  trx->lock.n_active_thrs++;
881 
882  thr->is_active = TRUE;
883  }
884 
885  thr->state = QUE_THR_RUNNING;
886 }
887 
888 /**********************************************************************/
891 UNIV_INTERN
892 void
894 /*============================*/
895  que_thr_t* thr,
896  trx_t* trx)
897 {
898  ut_ad(thr->state == QUE_THR_RUNNING);
899  ut_ad(thr_get_trx(thr)->id != 0);
900  ut_ad(thr->is_active == TRUE);
901  ut_ad(trx->lock.n_active_thrs == 1);
902  ut_ad(thr->graph->n_active_thrs == 1);
903 
904  if (thr->magic_n != QUE_THR_MAGIC_N) {
905  fprintf(stderr,
906  "que_thr struct appears corrupt; magic n %lu\n",
907  (unsigned long) thr->magic_n);
908 
910 
911  ut_error;
912  }
913 
914  thr->state = QUE_THR_COMPLETED;
915 
916  thr->is_active = FALSE;
917  thr->graph->n_active_thrs--;
918 
919  trx->lock.n_active_thrs--;
920 }
921 
922 /****************************************************************/
926 UNIV_INTERN
927 que_node_t*
929 /*==============================*/
930  que_node_t* node)
931 {
932  ut_ad(node);
933 
934  for (;;) {
935  ulint type;
936 
937  node = que_node_get_parent(node);
938 
939  if (!node) {
940  break;
941  }
942 
943  type = que_node_get_type(node);
944 
945  if ((type == QUE_NODE_FOR) || (type == QUE_NODE_WHILE)) {
946  break;
947  }
948  }
949 
950  return(node);
951 }
952 
953 /**********************************************************************/
955 UNIV_INTERN
956 void
958 /*================*/
959  que_node_t* node)
960 {
961  ulint type;
962  const char* str;
963 
964  type = que_node_get_type(node);
965 
966  if (type == QUE_NODE_SELECT) {
967  str = "SELECT";
968  } else if (type == QUE_NODE_INSERT) {
969  str = "INSERT";
970  } else if (type == QUE_NODE_UPDATE) {
971  str = "UPDATE";
972  } else if (type == QUE_NODE_WHILE) {
973  str = "WHILE";
974  } else if (type == QUE_NODE_ASSIGNMENT) {
975  str = "ASSIGNMENT";
976  } else if (type == QUE_NODE_IF) {
977  str = "IF";
978  } else if (type == QUE_NODE_FETCH) {
979  str = "FETCH";
980  } else if (type == QUE_NODE_OPEN) {
981  str = "OPEN";
982  } else if (type == QUE_NODE_PROC) {
983  str = "STORED PROCEDURE";
984  } else if (type == QUE_NODE_FUNC) {
985  str = "FUNCTION";
986  } else if (type == QUE_NODE_LOCK) {
987  str = "LOCK";
988  } else if (type == QUE_NODE_THR) {
989  str = "QUERY THREAD";
990  } else if (type == QUE_NODE_COMMIT) {
991  str = "COMMIT";
992  } else if (type == QUE_NODE_UNDO) {
993  str = "UNDO ROW";
994  } else if (type == QUE_NODE_PURGE) {
995  str = "PURGE ROW";
996  } else if (type == QUE_NODE_ROLLBACK) {
997  str = "ROLLBACK";
998  } else if (type == QUE_NODE_CREATE_TABLE) {
999  str = "CREATE TABLE";
1000  } else if (type == QUE_NODE_CREATE_INDEX) {
1001  str = "CREATE INDEX";
1002  } else if (type == QUE_NODE_FOR) {
1003  str = "FOR LOOP";
1004  } else if (type == QUE_NODE_RETURN) {
1005  str = "RETURN";
1006  } else if (type == QUE_NODE_EXIT) {
1007  str = "EXIT";
1008  } else {
1009  str = "UNKNOWN NODE TYPE";
1010  }
1011 
1012  fprintf(stderr, "Node type %lu: %s, address %p\n",
1013  (ulong) type, str, (void*) node);
1014 }
1015 
1016 /**********************************************************************/
1020 UNIV_INLINE
1021 que_thr_t*
1023 /*=========*/
1024  que_thr_t* thr)
1025 {
1026  que_node_t* node;
1027  que_thr_t* old_thr;
1028  trx_t* trx;
1029  ulint type;
1030 
1031  trx = thr_get_trx(thr);
1032 
1033  ut_ad(thr->state == QUE_THR_RUNNING);
1034  ut_a(trx->error_state == DB_SUCCESS);
1035 
1036  thr->resource++;
1037 
1038  node = thr->run_node;
1039  type = que_node_get_type(node);
1040 
1041  old_thr = thr;
1042 
1043 #ifdef UNIV_DEBUG
1044  if (que_trace_on) {
1045  fputs("To execute: ", stderr);
1046  que_node_print_info(node);
1047  }
1048 #endif
1049  if (type & QUE_NODE_CONTROL_STAT) {
1050  if ((thr->prev_node != que_node_get_parent(node))
1051  && que_node_get_next(thr->prev_node)) {
1052 
1053  /* The control statements, like WHILE, always pass the
1054  control to the next child statement if there is any
1055  child left */
1056 
1057  thr->run_node = que_node_get_next(thr->prev_node);
1058 
1059  } else if (type == QUE_NODE_IF) {
1060  if_step(thr);
1061  } else if (type == QUE_NODE_FOR) {
1062  for_step(thr);
1063  } else if (type == QUE_NODE_PROC) {
1064 
1065  /* We can access trx->undo_no without reserving
1066  trx->undo_mutex, because there cannot be active query
1067  threads doing updating or inserting at the moment! */
1068 
1069  if (thr->prev_node == que_node_get_parent(node)) {
1071  = trx->undo_no;
1072  }
1073 
1074  proc_step(thr);
1075  } else if (type == QUE_NODE_WHILE) {
1076  while_step(thr);
1077  } else {
1078  ut_error;
1079  }
1080  } else if (type == QUE_NODE_ASSIGNMENT) {
1081  assign_step(thr);
1082  } else if (type == QUE_NODE_SELECT) {
1083  thr = row_sel_step(thr);
1084  } else if (type == QUE_NODE_INSERT) {
1085  thr = row_ins_step(thr);
1086  } else if (type == QUE_NODE_UPDATE) {
1087  thr = row_upd_step(thr);
1088  } else if (type == QUE_NODE_FETCH) {
1089  thr = fetch_step(thr);
1090  } else if (type == QUE_NODE_OPEN) {
1091  thr = open_step(thr);
1092  } else if (type == QUE_NODE_FUNC) {
1093  proc_eval_step(thr);
1094 
1095  } else if (type == QUE_NODE_LOCK) {
1096 
1097  ut_error;
1098  } else if (type == QUE_NODE_THR) {
1099  thr = que_thr_node_step(thr);
1100  } else if (type == QUE_NODE_COMMIT) {
1101  thr = trx_commit_step(thr);
1102  } else if (type == QUE_NODE_UNDO) {
1103  thr = row_undo_step(thr);
1104  } else if (type == QUE_NODE_PURGE) {
1105  thr = row_purge_step(thr);
1106  } else if (type == QUE_NODE_RETURN) {
1107  thr = return_step(thr);
1108  } else if (type == QUE_NODE_EXIT) {
1109  thr = exit_step(thr);
1110  } else if (type == QUE_NODE_ROLLBACK) {
1111  thr = trx_rollback_step(thr);
1112  } else if (type == QUE_NODE_CREATE_TABLE) {
1113  thr = dict_create_table_step(thr);
1114  } else if (type == QUE_NODE_CREATE_INDEX) {
1115  thr = dict_create_index_step(thr);
1116  } else if (type == QUE_NODE_ROW_PRINTF) {
1117  thr = row_printf_step(thr);
1118  } else {
1119  ut_error;
1120  }
1121 
1122  if (type == QUE_NODE_EXIT) {
1124  } else {
1125  old_thr->prev_node = node;
1126  }
1127 
1128  if (thr) {
1129  ut_a(thr_get_trx(thr)->error_state == DB_SUCCESS);
1130  }
1131 
1132  return(thr);
1133 }
1134 
1135 /**********************************************************************/
1137 static
1138 void
1139 que_run_threads_low(
1140 /*================*/
1141  que_thr_t* thr)
1142 {
1143  trx_t* trx;
1144  que_thr_t* next_thr;
1145 
1146  ut_ad(thr->state == QUE_THR_RUNNING);
1147  ut_a(thr_get_trx(thr)->error_state == DB_SUCCESS);
1149 
1150  /* cumul_resource counts how much resources the OS thread (NOT the
1151  query thread) has spent in this function */
1152 
1153  trx = thr_get_trx(thr);
1154 
1155  do {
1156  /* Check that there is enough space in the log to accommodate
1157  possible log entries by this query step; if the operation can
1158  touch more than about 4 pages, checks must be made also within
1159  the query step! */
1160 
1161  log_free_check();
1162 
1163  /* Perform the actual query step: note that the query thread
1164  may change if, e.g., a subprocedure call is made */
1165 
1166  /*-------------------------*/
1167  next_thr = que_thr_step(thr);
1168  /*-------------------------*/
1169 
1170  trx_mutex_enter(trx);
1171 
1172  ut_a(next_thr == NULL || trx->error_state == DB_SUCCESS);
1173 
1174  if (next_thr != thr) {
1175  ut_a(next_thr == NULL);
1176 
1177  /* This can change next_thr to a non-NULL value
1178  if there was a lock wait that already completed. */
1179 
1180  que_thr_dec_refer_count(thr, &next_thr);
1181 
1182  if (next_thr != NULL) {
1183 
1184  thr = next_thr;
1185  }
1186  }
1187 
1188  ut_ad(trx == thr_get_trx(thr));
1189 
1190  trx_mutex_exit(trx);
1191 
1192  } while (next_thr != NULL);
1193 }
1194 
1195 /**********************************************************************/
1197 UNIV_INTERN
1198 void
1200 /*============*/
1201  que_thr_t* thr)
1202 {
1204 
1205 loop:
1206  ut_a(thr_get_trx(thr)->error_state == DB_SUCCESS);
1207 
1208  que_run_threads_low(thr);
1209 
1210  switch (thr->state) {
1211 
1212  case QUE_THR_RUNNING:
1213  /* There probably was a lock wait, but it already ended
1214  before we came here: continue running thr */
1215 
1216  goto loop;
1217 
1218  case QUE_THR_LOCK_WAIT:
1220 
1222 
1223  ut_a(thr_get_trx(thr)->id != 0);
1224 
1225  if (thr_get_trx(thr)->error_state != DB_SUCCESS) {
1226  /* thr was chosen as a deadlock victim or there was
1227  a lock wait timeout */
1228 
1229  que_thr_dec_refer_count(thr, NULL);
1231  break;
1232  }
1233 
1235  goto loop;
1236 
1237  case QUE_THR_COMPLETED:
1238  case QUE_THR_COMMAND_WAIT:
1239  /* Do nothing */
1240  break;
1241 
1242  default:
1243  ut_error;
1244  }
1245 }
1246 
1247 /*********************************************************************/
1250 UNIV_INTERN
1251 dberr_t
1253 /*=========*/
1254  pars_info_t* info,
1255  const char* sql,
1256  ibool reserve_dict_mutex,
1259  trx_t* trx)
1260 {
1261  que_thr_t* thr;
1262  que_t* graph;
1263 
1264  ut_a(trx->error_state == DB_SUCCESS);
1265 
1266  if (reserve_dict_mutex) {
1267  mutex_enter(&dict_sys->mutex);
1268  }
1269 
1270  graph = pars_sql(info, sql);
1271 
1272  if (reserve_dict_mutex) {
1273  mutex_exit(&dict_sys->mutex);
1274  }
1275 
1276  ut_a(graph);
1277 
1278  graph->trx = trx;
1279  trx->graph = NULL;
1280 
1281  graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
1282 
1283  ut_a(thr = que_fork_start_command(graph));
1284 
1285  que_run_threads(thr);
1286 
1287  if (reserve_dict_mutex) {
1288  mutex_enter(&dict_sys->mutex);
1289  }
1290 
1291  que_graph_free(graph);
1292 
1293  if (reserve_dict_mutex) {
1294  mutex_exit(&dict_sys->mutex);
1295  }
1296 
1297  return(trx->error_state);
1298 }
1299 
1300 /*********************************************************************/
1302 UNIV_INTERN
1303 void
1305 /*==========*/
1306 {
1307  /* No op */
1308 }
1309 
1310 /*********************************************************************/
1312 UNIV_INTERN
1313 void
1315 /*===========*/
1316 {
1317  /* No op */
1318 }