Commit 57341d44 authored by osku's avatar osku

Port r371 and r372 from branches/fts:

Add support for the EXIT keyword in InnoDB's SQL parser.

Add short introduction to query graphs.
parent dd352910
...@@ -212,6 +212,38 @@ for_step( ...@@ -212,6 +212,38 @@ for_step(
return(thr); return(thr);
} }
/**************************************************************************
Performs an execution step of an exit statement node. */
que_thr_t*
exit_step(
/*======*/
/* out: query thread to run next or NULL */
que_thr_t* thr) /* in: query thread */
{
exit_node_t* node;
que_node_t* loop_node;
ut_ad(thr);
node = thr->run_node;
ut_ad(que_node_get_type(node) == QUE_NODE_EXIT);
/* Loops exit by setting thr->run_node as the loop node's parent, so
find our containing loop node and get its parent. */
loop_node = que_node_get_containing_loop_node(node);
/* If someone uses an EXIT statement outside of a loop, this will
trigger. */
ut_a(loop_node);
thr->run_node = que_node_get_parent(loop_node);
return(thr);
}
/************************************************************************** /**************************************************************************
Performs an execution step of a return-statement node. */ Performs an execution step of a return-statement node. */
......
...@@ -63,6 +63,14 @@ proc_eval_step( ...@@ -63,6 +63,14 @@ proc_eval_step(
/* out: query thread to run next or NULL */ /* out: query thread to run next or NULL */
que_thr_t* thr); /* in: query thread */ que_thr_t* thr); /* in: query thread */
/************************************************************************** /**************************************************************************
Performs an execution step of an exit statement node. */
que_thr_t*
exit_step(
/*======*/
/* out: query thread to run next or NULL */
que_thr_t* thr); /* in: query thread */
/**************************************************************************
Performs an execution step of a return-statement node. */ Performs an execution step of a return-statement node. */
que_thr_t* que_thr_t*
......
...@@ -115,7 +115,8 @@ ...@@ -115,7 +115,8 @@
PARS_ROLLBACK_TOKEN = 341, PARS_ROLLBACK_TOKEN = 341,
PARS_WORK_TOKEN = 342, PARS_WORK_TOKEN = 342,
PARS_UNSIGNED_TOKEN = 343, PARS_UNSIGNED_TOKEN = 343,
NEG = 344 PARS_EXIT_TOKEN = 344,
NEG = 345
}; };
#endif #endif
#define PARS_INT_LIT 258 #define PARS_INT_LIT 258
...@@ -204,7 +205,8 @@ ...@@ -204,7 +205,8 @@
#define PARS_ROLLBACK_TOKEN 341 #define PARS_ROLLBACK_TOKEN 341
#define PARS_WORK_TOKEN 342 #define PARS_WORK_TOKEN 342
#define PARS_UNSIGNED_TOKEN 343 #define PARS_UNSIGNED_TOKEN 343
#define NEG 344 #define PARS_EXIT_TOKEN 344
#define NEG 345
......
...@@ -269,6 +269,13 @@ pars_while_statement( ...@@ -269,6 +269,13 @@ pars_while_statement(
que_node_t* cond, /* in: while-condition */ que_node_t* cond, /* in: while-condition */
que_node_t* stat_list); /* in: statement list */ que_node_t* stat_list); /* in: statement list */
/************************************************************************* /*************************************************************************
Parses an exit statement. */
exit_node_t*
pars_exit_statement(void);
/*=====================*/
/* out: exit statement node */
/*************************************************************************
Parses a return-statement. */ Parses a return-statement. */
return_node_t* return_node_t*
...@@ -500,6 +507,11 @@ struct for_node_struct{ ...@@ -500,6 +507,11 @@ struct for_node_struct{
que_node_t* stat_list; /* statement list */ que_node_t* stat_list; /* statement list */
}; };
/* exit statement node */
struct exit_node_struct{
que_common_t common; /* type: QUE_NODE_EXIT */
};
/* return-statement node */ /* return-statement node */
struct return_node_struct{ struct return_node_struct{
que_common_t common; /* type: QUE_NODE_RETURN */ que_common_t common; /* type: QUE_NODE_RETURN */
......
...@@ -19,6 +19,7 @@ typedef struct elsif_node_struct elsif_node_t; ...@@ -19,6 +19,7 @@ typedef struct elsif_node_struct elsif_node_t;
typedef struct if_node_struct if_node_t; typedef struct if_node_struct if_node_t;
typedef struct while_node_struct while_node_t; typedef struct while_node_struct while_node_t;
typedef struct for_node_struct for_node_t; typedef struct for_node_struct for_node_t;
typedef struct exit_node_struct exit_node_t;
typedef struct return_node_struct return_node_t; typedef struct return_node_struct return_node_t;
typedef struct assign_node_struct assign_node_t; typedef struct assign_node_struct assign_node_t;
typedef struct col_assign_node_struct col_assign_node_t; typedef struct col_assign_node_struct col_assign_node_t;
......
...@@ -277,6 +277,15 @@ que_node_get_parent( ...@@ -277,6 +277,15 @@ que_node_get_parent(
/*================*/ /*================*/
/* out: parent node or NULL */ /* out: parent node or NULL */
que_node_t* node); /* in: node */ que_node_t* node); /* in: node */
/********************************************************************
Get the first containing loop node (e.g. while_node_t or for_node_t) for the
given node, or NULL if the node is not within a loop. */
que_node_t*
que_node_get_containing_loop_node(
/*==============================*/
/* out: containing loop node, or NULL. */
que_node_t* node); /* in: node */
/************************************************************************* /*************************************************************************
Catenates a query graph node to a list of them, possible empty list. */ Catenates a query graph node to a list of them, possible empty list. */
UNIV_INLINE UNIV_INLINE
...@@ -469,6 +478,7 @@ struct que_fork_struct{ ...@@ -469,6 +478,7 @@ struct que_fork_struct{
#define QUE_NODE_ROW_PRINTF 29 #define QUE_NODE_ROW_PRINTF 29
#define QUE_NODE_ELSIF 30 #define QUE_NODE_ELSIF 30
#define QUE_NODE_CALL 31 #define QUE_NODE_CALL 31
#define QUE_NODE_EXIT 32
/* Query thread states */ /* Query thread states */
#define QUE_THR_RUNNING 1 #define QUE_THR_RUNNING 1
......
This diff is collapsed.
This diff is collapsed.
...@@ -115,7 +115,8 @@ ...@@ -115,7 +115,8 @@
PARS_ROLLBACK_TOKEN = 341, PARS_ROLLBACK_TOKEN = 341,
PARS_WORK_TOKEN = 342, PARS_WORK_TOKEN = 342,
PARS_UNSIGNED_TOKEN = 343, PARS_UNSIGNED_TOKEN = 343,
NEG = 344 PARS_EXIT_TOKEN = 344,
NEG = 345
}; };
#endif #endif
#define PARS_INT_LIT 258 #define PARS_INT_LIT 258
...@@ -204,7 +205,8 @@ ...@@ -204,7 +205,8 @@
#define PARS_ROLLBACK_TOKEN 341 #define PARS_ROLLBACK_TOKEN 341
#define PARS_WORK_TOKEN 342 #define PARS_WORK_TOKEN 342
#define PARS_UNSIGNED_TOKEN 343 #define PARS_UNSIGNED_TOKEN 343
#define NEG 344 #define PARS_EXIT_TOKEN 344
#define NEG 345
......
...@@ -116,6 +116,7 @@ yylex(void); ...@@ -116,6 +116,7 @@ yylex(void);
%token PARS_ROLLBACK_TOKEN %token PARS_ROLLBACK_TOKEN
%token PARS_WORK_TOKEN %token PARS_WORK_TOKEN
%token PARS_UNSIGNED_TOKEN %token PARS_UNSIGNED_TOKEN
%token PARS_EXIT_TOKEN
%left PARS_AND_TOKEN PARS_OR_TOKEN %left PARS_AND_TOKEN PARS_OR_TOKEN
%left PARS_NOT_TOKEN %left PARS_NOT_TOKEN
...@@ -134,6 +135,7 @@ statement: ...@@ -134,6 +135,7 @@ statement:
| predefined_procedure_call ';' | predefined_procedure_call ';'
| while_statement ';' | while_statement ';'
| for_statement ';' | for_statement ';'
| exit_statement ';'
| if_statement ';' | if_statement ';'
| return_statement ';' | return_statement ';'
| assignment_statement ';' | assignment_statement ';'
...@@ -429,6 +431,10 @@ for_statement: ...@@ -429,6 +431,10 @@ for_statement:
{ $$ = pars_for_statement($2, $4, $6, $8); } { $$ = pars_for_statement($2, $4, $6, $8); }
; ;
exit_statement:
PARS_EXIT_TOKEN { $$ = pars_exit_statement(); }
;
return_statement: return_statement:
PARS_RETURN_TOKEN { $$ = pars_return_statement(); } PARS_RETURN_TOKEN { $$ = pars_return_statement(); }
; ;
......
...@@ -466,6 +466,10 @@ In the state 'quoted', only two actions are possible (defined below). */ ...@@ -466,6 +466,10 @@ In the state 'quoted', only two actions are possible (defined below). */
return(PARS_UNSIGNED_TOKEN); return(PARS_UNSIGNED_TOKEN);
} }
"EXIT" {
return(PARS_EXIT_TOKEN);
}
{ID} { {ID} {
yylval = sym_tab_add_id(pars_sym_tab_global, yylval = sym_tab_add_id(pars_sym_tab_global,
(byte*)yytext, (byte*)yytext,
......
...@@ -1352,6 +1352,22 @@ pars_for_statement( ...@@ -1352,6 +1352,22 @@ pars_for_statement(
return(node); return(node);
} }
/*************************************************************************
Parses an exit statement. */
exit_node_t*
pars_exit_statement(void)
/*=====================*/
/* out: exit statement node */
{
exit_node_t* node;
node = mem_heap_alloc(pars_sym_tab_global->heap, sizeof(exit_node_t));
node->common.type = QUE_NODE_EXIT;
return(node);
}
/************************************************************************* /*************************************************************************
Parses a return-statement. */ Parses a return-statement. */
......
...@@ -36,6 +36,50 @@ ibool que_trace_on = FALSE; ...@@ -36,6 +36,50 @@ ibool que_trace_on = FALSE;
ibool que_always_false = FALSE; ibool que_always_false = FALSE;
/* Short introduction to query graphs
==================================
A query graph consists of nodes linked to each other in various ways. The
execution starts at que_run_threads() which takes a que_thr_t parameter.
que_thr_t contains two fields that control query graph execution: run_node
and prev_node. run_node is the next node to execute and prev_node is the
last node executed.
Each node has a pointer to a 'next' statement, i.e., its brother, and a
pointer to its parent node. The next pointer is NULL in the last statement
of a block.
Loop nodes contain a link to the first statement of the enclosed statement
list. While the loop runs, que_thr_step() checks if execution to the loop
node came from its parent or from one of the statement nodes in the loop. If
it came from the parent of the loop node it starts executing the first
statement node in the loop. If it came from one of the statement nodes in
the loop, then it checks if the statement node has another statement node
following it, and runs it if so.
To signify loop ending, the loop statements (see e.g. while_step()) set
que_thr_t->run_node to the loop node's parent node. This is noticed on the
next call of que_thr_step() and execution proceeds to the node pointed to by
the loop node's 'next' pointer.
For example, the code:
X := 1;
WHILE X < 5 LOOP
X := X + 1;
X := X + 1;
X := 5
will result in the following node hierarchy, with the X-axis indicating
'next' links and the Y-axis indicating parent/child links:
A - W - A
|
|
A - A
A = assign_node_t, W = while_node_t. */
/* How a stored procedure containing COMMIT or ROLLBACK commands /* How a stored procedure containing COMMIT or ROLLBACK commands
is executed? is executed?
...@@ -583,6 +627,7 @@ que_graph_free_recursive( ...@@ -583,6 +627,7 @@ que_graph_free_recursive(
break; break;
case QUE_NODE_ASSIGNMENT: case QUE_NODE_ASSIGNMENT:
case QUE_NODE_EXIT:
case QUE_NODE_RETURN: case QUE_NODE_RETURN:
case QUE_NODE_COMMIT: case QUE_NODE_COMMIT:
case QUE_NODE_ROLLBACK: case QUE_NODE_ROLLBACK:
...@@ -1040,6 +1085,37 @@ que_thr_stop_for_mysql_no_error( ...@@ -1040,6 +1085,37 @@ que_thr_stop_for_mysql_no_error(
trx->n_active_thrs--; trx->n_active_thrs--;
} }
/********************************************************************
Get the first containing loop node (e.g. while_node_t or for_node_t) for the
given node, or NULL if the node is not within a loop. */
que_node_t*
que_node_get_containing_loop_node(
/*==============================*/
/* out: containing loop node, or NULL. */
que_node_t* node) /* in: node */
{
ut_ad(node);
for (;;) {
ulint type;
node = que_node_get_parent(node);
if (!node) {
break;
}
type = que_node_get_type(node);
if ((type == QUE_NODE_FOR) || (type == QUE_NODE_WHILE)) {
break;
}
}
return(node);
}
/************************************************************************** /**************************************************************************
Prints info of an SQL query graph node. */ Prints info of an SQL query graph node. */
...@@ -1093,6 +1169,8 @@ que_node_print_info( ...@@ -1093,6 +1169,8 @@ que_node_print_info(
str = "FOR LOOP"; str = "FOR LOOP";
} else if (type == QUE_NODE_RETURN) { } else if (type == QUE_NODE_RETURN) {
str = "RETURN"; str = "RETURN";
} else if (type == QUE_NODE_EXIT) {
str = "EXIT";
} else { } else {
str = "UNKNOWN NODE TYPE"; str = "UNKNOWN NODE TYPE";
} }
...@@ -1120,8 +1198,8 @@ que_thr_step( ...@@ -1120,8 +1198,8 @@ que_thr_step(
thr->resource++; thr->resource++;
type = que_node_get_type(thr->run_node);
node = thr->run_node; node = thr->run_node;
type = que_node_get_type(node);
old_thr = thr; old_thr = thr;
...@@ -1160,6 +1238,8 @@ que_thr_step( ...@@ -1160,6 +1238,8 @@ que_thr_step(
proc_step(thr); proc_step(thr);
} else if (type == QUE_NODE_WHILE) { } else if (type == QUE_NODE_WHILE) {
while_step(thr); while_step(thr);
} else {
ut_error;
} }
} else if (type == QUE_NODE_ASSIGNMENT) { } else if (type == QUE_NODE_ASSIGNMENT) {
assign_step(thr); assign_step(thr);
...@@ -1192,6 +1272,8 @@ que_thr_step( ...@@ -1192,6 +1272,8 @@ que_thr_step(
thr = row_purge_step(thr); thr = row_purge_step(thr);
} else if (type == QUE_NODE_RETURN) { } else if (type == QUE_NODE_RETURN) {
thr = return_step(thr); thr = return_step(thr);
} else if (type == QUE_NODE_EXIT) {
thr = exit_step(thr);
} else if (type == QUE_NODE_ROLLBACK) { } else if (type == QUE_NODE_ROLLBACK) {
thr = trx_rollback_step(thr); thr = trx_rollback_step(thr);
} else if (type == QUE_NODE_CREATE_TABLE) { } else if (type == QUE_NODE_CREATE_TABLE) {
...@@ -1204,7 +1286,11 @@ que_thr_step( ...@@ -1204,7 +1286,11 @@ que_thr_step(
ut_error; ut_error;
} }
if (type == QUE_NODE_EXIT) {
old_thr->prev_node = que_node_get_containing_loop_node(node);
} else {
old_thr->prev_node = node; old_thr->prev_node = node;
}
return(thr); return(thr);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment