Mysql源码学习――打造专属语法(二)

2014-11-24 10:35:16 · 作者: · 浏览: 2
MYSQL_YYABORT;

if (add_item_to_list(thd, item))

MYSQL_YYABORT;

(thd->lex->current_select->with_wild)++;

}

;

select_item:

remember_name select_item2 remember_end select_alias

{

THD *thd= YYTHD;

DBUG_ASSERT($1 < $3);

if (add_item_to_list(thd, $2))

MYSQL_YYABORT;

if ($4.str)

{

if (Lex->sql_command == SQLCOM_CREATE_VIEW &&

check_column_name($4.str))

{

my_error(ER_WRONG_COLUMN_NAME, MYF(0), $4.str);

MYSQL_YYABORT;

}

$2->is_autogenerated_name= FALSE;

$2->set_name($4.str, $4.length, system_charset_info);

}

else if (!$2->name)

{

$2->set_name($1, (uint) ($3 - $1), thd->charset());

}

}

;

variable:

'@'

{

if (! Lex->parsing_options.allows_variable)

{

my_error(ER_VIEW_SELECT_VARIABLE, MYF(0));

MYSQL_YYABORT;

}

}

variable_aux

{

$$= $3;

}

;

variable_aux:

ident_or_text SET_VAR expr

{

Item_func_set_user_var *item;

$$= item= new (YYTHD->mem_root) Item_func_set_user_var($1, $3);

if ($$ == NULL)

MYSQL_YYABORT;

LEX *lex= Lex;

lex->uncacheable(UNCACHEABLE_RAND);

lex->set_var_list.push_back(item);

}

| ident_or_text

{

$$= new (YYTHD->mem_root) Item_func_get_user_var($1);

if ($$ == NULL)

MYSQL_YYABORT;

LEX *lex= Lex;

lex->uncacheable(UNCACHEABLE_RAND);

}

| '@' opt_var_ident_type ident_or_text opt_component

{

/* disallow "SELECT @@global.global.variable" */

if ($3.str && $4.str && check_reserved_words(&$3))

{

my_parse_error(ER(ER_SYNTAX_ERROR));

MYSQL_YYABORT;

}

if (!($$= get_system_var(YYTHD, $2, $3, $4)))

MYSQL_YYABORT;

if (!((Item_func_get_system_var*) $$)->is_written_to_binlog())

Lex->set_stmt_unsafe();

}

;

下面我们仔细的来看一下整个SELECT语法节点的执行流程:

query->verb_clause->statement->select->select_init->select_init2->select_part2->select_item_list->select_item…->variable

语法是自上而下的,实际的解析过程是自下而上的匹配过程。词法分析首先yacc送来SELECT关键字,上一节说过为什么SELECT是关键字呢?

我们看下sql_yacc.yy,可以找到如下一个定义:

%token SELECT_SYM /* SQL-2003-R */

这里其实是定义了一个宏SELECT_SYM,代表一个关键字,宏定义如下:

#define SELECT_SYM 687

那么字符串"SELECT"和SELECT_SYM是如何联系在一起的呢?我们回头看下MYSQLlex中的find_keyword这个函数:

static int find_keyword(Lex_input_stream *lip, uint len, bool function)

{

const char *tok= lip->get_tok_start();

SYMBOL *symbol= get_hash_symbol(tok, len, function);

if (symbol)

{

lip->yylval->symbol.symbol=symbol;

lip->yylval->symbol.str= (char*) tok;

lip->yylval->symbol.length=len;

if ((symbol->tok == NOT_SYM) &&