The world's most popular open source database
#include "mysql_priv.h"#include "item_create.h"#include <m_ctype.h>#include <hash.h>#include "sp.h"#include "sp_head.h"#include <lex_hash.h>Include dependency graph for sql_lex.cc:

Go to the source code of this file.
Defines | |
| #define | MYSQL_LEX 1 |
| #define | yyGet() *(lex->ptr++) |
| #define | yyGetLast() lex->ptr[-1] |
| #define | yyPeek() lex->ptr[0] |
| #define | yyPeek2() lex->ptr[1] |
| #define | yyUnget() lex->ptr-- |
| #define | yySkip() lex->ptr++ |
| #define | yyLength() ((uint) (lex->ptr - lex->tok_start)-1) |
| #define | TOCK_NAME_LENGTH 24 |
Functions | |
| int | lex_casecmp (const char *s, const char *t, uint len) |
| void | lex_init (void) |
| void | lex_free (void) |
| void | lex_start (THD *thd, const uchar *buf, uint length) |
| void | lex_end (LEX *lex) |
| static int | find_keyword (LEX *lex, uint len, bool function) |
| bool | is_keyword (const char *name, uint len) |
| static LEX_STRING | get_token (LEX *lex, uint length) |
| static LEX_STRING | get_quoted_token (LEX *lex, uint length, char quote) |
| static char * | get_text (LEX *lex) |
| static uint | int_token (const char *str, uint length) |
| int | MYSQLlex (void *arg, void *yythd) |
| const uchar * | skip_rear_comments (const uchar *begin, const uchar *end) |
| static void | fix_prepare_info_in_table_list (THD *thd, TABLE_LIST *tbl) |
Variables | |
| sys_var * | trg_new_row_fake_var = (sys_var*) 0x01 |
| static uchar | to_upper_lex [] |
| static const char * | long_str = "2147483647" |
| static const uint | long_len = 10 |
| static const char * | signed_long_str = "-2147483648" |
| static const char * | longlong_str = "9223372036854775807" |
| static const uint | longlong_len = 19 |
| static const char * | signed_longlong_str = "-9223372036854775808" |
| static const uint | signed_longlong_len = 19 |
| static const char * | unsigned_longlong_str = "18446744073709551615" |
| static const uint | unsigned_longlong_len = 20 |
| #define MYSQL_LEX 1 |
Definition at line 20 of file sql_lex.cc.
| #define TOCK_NAME_LENGTH 24 |
Definition at line 46 of file sql_lex.cc.
| #define yyGet | ( | ) | *(lex->ptr++) |
| #define yyGetLast | ( | ) | lex->ptr[-1] |
| #define yyLength | ( | ) | ((uint) (lex->ptr - lex->tok_start)-1) |
| #define yyPeek | ( | ) | lex->ptr[0] |
| #define yyPeek2 | ( | ) | lex->ptr[1] |
| #define yySkip | ( | ) | lex->ptr++ |
| #define yyUnget | ( | ) | lex->ptr-- |
Definition at line 41 of file sql_lex.cc.
Referenced by get_quoted_token(), get_text(), get_token(), and MYSQLlex().
Definition at line 202 of file sql_lex.cc.
References get_hash_symbol(), st_symbol::length, MODE_HIGH_NOT_PRECEDENCE, MODE_PIPES_AS_CONCAT, NOT2_SYM, NOT_SYM, OR2_SYM, OR_OR_SYM, and st_symbol::tok.
Referenced by MYSQLlex().
00203 { 00204 const uchar *tok=lex->tok_start; 00205 00206 SYMBOL *symbol= get_hash_symbol((const char *)tok,len,function); 00207 if (symbol) 00208 { 00209 lex->yylval->symbol.symbol=symbol; 00210 lex->yylval->symbol.str= (char*) tok; 00211 lex->yylval->symbol.length=len; 00212 00213 if ((symbol->tok == NOT_SYM) && 00214 (lex->thd->variables.sql_mode & MODE_HIGH_NOT_PRECEDENCE)) 00215 return NOT2_SYM; 00216 if ((symbol->tok == OR_OR_SYM) && 00217 !(lex->thd->variables.sql_mode & MODE_PIPES_AS_CONCAT)) 00218 return OR2_SYM; 00219 00220 return symbol->tok; 00221 } 00222 return 0; 00223 }
Here is the call graph for this function:

Here is the caller graph for this function:

| static void fix_prepare_info_in_table_list | ( | THD * | thd, | |
| TABLE_LIST * | tbl | |||
| ) | [static] |
Definition at line 2153 of file sql_lex.cc.
References Item::copy_andor_structure(), st_table_list::merge_underlying_list, st_table_list::next_local, st_table_list::on_expr, and st_table_list::prep_on_expr.
02154 { 02155 for (; tbl; tbl= tbl->next_local) 02156 { 02157 if (tbl->on_expr) 02158 { 02159 tbl->prep_on_expr= tbl->on_expr; 02160 tbl->on_expr= tbl->on_expr->copy_andor_structure(thd); 02161 } 02162 fix_prepare_info_in_table_list(thd, tbl->merge_underlying_list); 02163 } 02164 }
Here is the call graph for this function:

| static LEX_STRING get_quoted_token | ( | LEX * | lex, | |
| uint | length, | |||
| char | quote | |||
| ) | [static] |
Definition at line 262 of file sql_lex.cc.
References from, LEX_STRING::length, LEX_STRING::str, to, and yyUnget.
Referenced by MYSQLlex().
00263 { 00264 LEX_STRING tmp; 00265 const uchar *from, *end; 00266 uchar *to; 00267 yyUnget(); // ptr points now after last token char 00268 tmp.length=lex->yytoklen=length; 00269 tmp.str=(char*) lex->thd->alloc(tmp.length+1); 00270 for (from= lex->tok_start, to= (uchar*) tmp.str, end= to+length ; 00271 to != end ; 00272 ) 00273 { 00274 if ((*to++= *from++) == (uchar) quote) 00275 from++; // Skip double quotes 00276 } 00277 *to= 0; // End null for safety 00278 return tmp; 00279 }
Here is the caller graph for this function:

| static char* get_text | ( | LEX * | lex | ) | [static] |
Definition at line 287 of file sql_lex.cc.
References memcpy, MODE_NO_BACKSLASH_ESCAPES, my_ismbchar, reg1, start(), to, USE_MB, use_mb, yyGet, yyGetLast, yySkip, and yyUnget.
Referenced by MYSQLlex().
00288 { 00289 reg1 uchar c,sep; 00290 uint found_escape=0; 00291 CHARSET_INFO *cs= lex->thd->charset(); 00292 00293 sep= yyGetLast(); // String should end with this 00294 while (lex->ptr != lex->end_of_query) 00295 { 00296 c = yyGet(); 00297 #ifdef USE_MB 00298 int l; 00299 if (use_mb(cs) && 00300 (l = my_ismbchar(cs, 00301 (const char *)lex->ptr-1, 00302 (const char *)lex->end_of_query))) { 00303 lex->ptr += l-1; 00304 continue; 00305 } 00306 #endif 00307 if (c == '\\' && 00308 !(lex->thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES)) 00309 { // Escaped character 00310 found_escape=1; 00311 if (lex->ptr == lex->end_of_query) 00312 return 0; 00313 yySkip(); 00314 } 00315 else if (c == sep) 00316 { 00317 if (c == yyGet()) // Check if two separators in a row 00318 { 00319 found_escape=1; // dupplicate. Remember for delete 00320 continue; 00321 } 00322 else 00323 yyUnget(); 00324 00325 /* Found end. Unescape and return string */ 00326 const uchar *str, *end; 00327 uchar *start; 00328 00329 str=lex->tok_start+1; 00330 end=lex->ptr-1; 00331 if (!(start=(uchar*) lex->thd->alloc((uint) (end-str)+1))) 00332 return (char*) ""; // Sql_alloc has set error flag 00333 if (!found_escape) 00334 { 00335 lex->yytoklen=(uint) (end-str); 00336 memcpy(start,str,lex->yytoklen); 00337 start[lex->yytoklen]=0; 00338 } 00339 else 00340 { 00341 uchar *to; 00342 00343 for (to=start ; str != end ; str++) 00344 { 00345 #ifdef USE_MB 00346 int l; 00347 if (use_mb(cs) && 00348 (l = my_ismbchar(cs, 00349 (const char *)str, (const char *)end))) { 00350 while (l--) 00351 *to++ = *str++; 00352 str--; 00353 continue; 00354 } 00355 #endif 00356 if (!(lex->thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) && 00357 *str == '\\' && str+1 != end) 00358 { 00359 switch(*++str) { 00360 case 'n': 00361 *to++='\n'; 00362 break; 00363 case 't': 00364 *to++= '\t'; 00365 break; 00366 case 'r': 00367 *to++ = '\r'; 00368 break; 00369 case 'b': 00370 *to++ = '\b'; 00371 break; 00372 case '0': 00373 *to++= 0; // Ascii null 00374 break; 00375 case 'Z': // ^Z must be escaped on Win32 00376 *to++='\032'; 00377 break; 00378 case '_': 00379 case '%': 00380 *to++= '\\'; // remember prefix for wildcard 00381 /* Fall through */ 00382 default: 00383 *to++= *str; 00384 break; 00385 } 00386 } 00387 else if (*str == sep) 00388 *to++= *str++; // Two ' or " 00389 else 00390 *to++ = *str; 00391 } 00392 *to=0; 00393 lex->yytoklen=(uint) (to-start); 00394 } 00395 return (char*) start; 00396 } 00397 } 00398 return 0; // unexpected end of query 00399 }
Here is the call graph for this function:

Here is the caller graph for this function:

| static LEX_STRING get_token | ( | LEX * | lex, | |
| uint | length | |||
| ) | [static] |
Definition at line 246 of file sql_lex.cc.
References LEX_STRING::length, LEX_STRING::str, and yyUnget.
00247 { 00248 LEX_STRING tmp; 00249 yyUnget(); // ptr points now after last token char 00250 tmp.length=lex->yytoklen=length; 00251 tmp.str=(char*) lex->thd->strmake((char*) lex->tok_start,tmp.length); 00252 return tmp; 00253 }
Definition at line 420 of file sql_lex.cc.
References cmp, DECIMAL_NUM, long_len, LONG_NUM, long_str, longlong_len, longlong_str, NUM, signed_long_str, signed_longlong_len, signed_longlong_str, smaller, ULONGLONG_NUM, unsigned_longlong_len, and unsigned_longlong_str.
Referenced by MYSQLlex().
00421 { 00422 if (length < long_len) // quick normal case 00423 return NUM; 00424 bool neg=0; 00425 00426 if (*str == '+') // Remove sign and pre-zeros 00427 { 00428 str++; length--; 00429 } 00430 else if (*str == '-') 00431 { 00432 str++; length--; 00433 neg=1; 00434 } 00435 while (*str == '0' && length) 00436 { 00437 str++; length --; 00438 } 00439 if (length < long_len) 00440 return NUM; 00441 00442 uint smaller,bigger; 00443 const char *cmp; 00444 if (neg) 00445 { 00446 if (length == long_len) 00447 { 00448 cmp= signed_long_str+1; 00449 smaller=NUM; // If <= signed_long_str 00450 bigger=LONG_NUM; // If >= signed_long_str 00451 } 00452 else if (length < signed_longlong_len) 00453 return LONG_NUM; 00454 else if (length > signed_longlong_len) 00455 return DECIMAL_NUM; 00456 else 00457 { 00458 cmp=signed_longlong_str+1; 00459 smaller=LONG_NUM; // If <= signed_longlong_str 00460 bigger=DECIMAL_NUM; 00461 } 00462 } 00463 else 00464 { 00465 if (length == long_len) 00466 { 00467 cmp= long_str; 00468 smaller=NUM; 00469 bigger=LONG_NUM; 00470 } 00471 else if (length < longlong_len) 00472 return LONG_NUM; 00473 else if (length > longlong_len) 00474 { 00475 if (length > unsigned_longlong_len) 00476 return DECIMAL_NUM; 00477 cmp=unsigned_longlong_str; 00478 smaller=ULONGLONG_NUM; 00479 bigger=DECIMAL_NUM; 00480 } 00481 else 00482 { 00483 cmp=longlong_str; 00484 smaller=LONG_NUM; 00485 bigger= ULONGLONG_NUM; 00486 } 00487 } 00488 while (*cmp && *cmp++ == *str++) ; 00489 return ((uchar) str[-1] <= (uchar) cmp[-1]) ? smaller : bigger; 00490 }
Here is the caller graph for this function:

Definition at line 238 of file sql_lex.cc.
References DBUG_ASSERT, and get_hash_symbol().
Referenced by get_quote_char_for_identifier().
00239 { 00240 DBUG_ASSERT(len != 0); 00241 return get_hash_symbol(name,len,0)!=0; 00242 }
Here is the call graph for this function:

Here is the caller graph for this function:

| int lex_casecmp | ( | const char * | s, | |
| const char * | t, | |||
| uint | len | |||
| ) | [inline] |
Definition at line 74 of file sql_lex.cc.
References to_upper_lex.
Referenced by get_hash_symbol().
00075 { 00076 while (len-- != 0 && 00077 to_upper_lex[(uchar) *s++] == to_upper_lex[(uchar) *t++]) ; 00078 return (int) len+1; 00079 }
Here is the caller graph for this function:

| void lex_end | ( | LEX * | lex | ) |
Definition at line 187 of file sql_lex.cc.
References DBUG_ENTER, DBUG_PRINT, DBUG_VOID_RETURN, my_free, and MYF.
Referenced by Table_triggers_list::check_n_load(), Event_timed::compile(), db_load_routine(), sp_head::destroy(), Prepared_statement::prepare(), sp_head::restore_lex(), and sp_lex_keeper::~sp_lex_keeper().
00188 { 00189 DBUG_ENTER("lex_end"); 00190 DBUG_PRINT("enter", ("lex: 0x%lx", (long) lex)); 00191 if (lex->yacc_yyss) 00192 { 00193 my_free(lex->yacc_yyss, MYF(0)); 00194 my_free(lex->yacc_yyvs, MYF(0)); 00195 lex->yacc_yyss= 0; 00196 lex->yacc_yyvs= 0; 00197 } 00198 DBUG_VOID_RETURN; 00199 }
Here is the caller graph for this function:

| void lex_free | ( | void | ) |
Definition at line 97 of file sql_lex.cc.
References DBUG_ENTER, and DBUG_VOID_RETURN.
Referenced by clean_up().
00098 { // Call this when daemon ends 00099 DBUG_ENTER("lex_free"); 00100 DBUG_VOID_RETURN; 00101 }
Here is the caller graph for this function:

| void lex_init | ( | void | ) |
Definition at line 84 of file sql_lex.cc.
References array_elements, DBUG_ENTER, DBUG_VOID_RETURN, name, sql_functions, strlen(), and symbols.
Referenced by init_common_variables().
00085 { 00086 uint i; 00087 DBUG_ENTER("lex_init"); 00088 for (i=0 ; i < array_elements(symbols) ; i++) 00089 symbols[i].length=(uchar) strlen(symbols[i].name); 00090 for (i=0 ; i < array_elements(sql_functions) ; i++) 00091 sql_functions[i].length=(uchar) strlen(sql_functions[i].name); 00092 00093 DBUG_VOID_RETURN; 00094 }
Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 110 of file sql_lex.cc.
References DBUG_ENTER, DBUG_VOID_RETURN, DUP_ERROR, FALSE, MODE_IGNORE_SPACE, MY_LEX_START, NULL, SQLCOM_END, test, and TL_READ.
Referenced by Table_triggers_list::check_n_load(), Event_timed::compile(), db_load_routine(), dispatch_command(), get_var_with_binlog(), mysql_init_query(), mysql_make_view(), Prepared_statement::prepare(), and sp_head::reset_lex().
00111 { 00112 LEX *lex= thd->lex; 00113 DBUG_ENTER("lex_start"); 00114 00115 lex->thd= lex->unit.thd= thd; 00116 lex->buf= lex->ptr= buf; 00117 lex->end_of_query= buf+length; 00118 00119 lex->context_stack.empty(); 00120 lex->unit.init_query(); 00121 lex->unit.init_select(); 00122 /* 'parent_lex' is used in init_query() so it must be before it. */ 00123 lex->select_lex.parent_lex= lex; 00124 lex->select_lex.init_query(); 00125 lex->value_list.empty(); 00126 lex->update_list.empty(); 00127 lex->param_list.empty(); 00128 lex->view_list.empty(); 00129 lex->prepared_stmt_params.empty(); 00130 lex->auxiliary_table_list.empty(); 00131 lex->unit.next= lex->unit.master= 00132 lex->unit.link_next= lex->unit.return_to= 0; 00133 lex->unit.prev= lex->unit.link_prev= 0; 00134 lex->unit.slave= lex->unit.global_parameters= lex->current_select= 00135 lex->all_selects_list= &lex->select_lex; 00136 lex->select_lex.master= &lex->unit; 00137 lex->select_lex.prev= &lex->unit.slave; 00138 lex->select_lex.link_next= lex->select_lex.slave= lex->select_lex.next= 0; 00139 lex->select_lex.link_prev= (st_select_lex_node**)&(lex->all_selects_list); 00140 lex->select_lex.options= 0; 00141 lex->select_lex.sql_cache= SELECT_LEX::SQL_CACHE_UNSPECIFIED; 00142 lex->select_lex.init_order(); 00143 lex->select_lex.group_list.empty(); 00144 lex->describe= 0; 00145 lex->subqueries= FALSE; 00146 lex->view_prepare_mode= FALSE; 00147 lex->stmt_prepare_mode= FALSE; 00148 lex->derived_tables= 0; 00149 lex->lock_option= TL_READ; 00150 lex->found_semicolon= 0; 00151 lex->safe_to_cache_query= 1; 00152 lex->time_zone_tables_used= 0; 00153 lex->leaf_tables_insert= 0; 00154 lex->variables_used= 0; 00155 lex->empty_field_list_on_rset= 0; 00156 lex->select_lex.select_number= 1; 00157 lex->next_state=MY_LEX_START; 00158 lex->yylineno = 1; 00159 lex->in_comment=0; 00160 lex->length=0; 00161 lex->part_info= 0; 00162 lex->select_lex.in_sum_expr=0; 00163 lex->select_lex.expr_list.empty(); 00164 lex->select_lex.ftfunc_list_alloc.empty(); 00165 lex->select_lex.ftfunc_list= &lex->select_lex.ftfunc_list_alloc; 00166 lex->select_lex.group_list.empty(); 00167 lex->select_lex.order_list.empty(); 00168 lex->ignore_space=test(thd->variables.sql_mode & MODE_IGNORE_SPACE); 00169 lex->sql_command= SQLCOM_END; 00170 lex->duplicates= DUP_ERROR; 00171 lex->ignore= 0; 00172 lex->sphead= NULL; 00173 lex->spcont= NULL; 00174 lex->proc_list.first= 0; 00175 lex->escape_used= lex->et_compile_phase= FALSE; 00176 lex->reset_query_tables_list(FALSE); 00177 00178 lex->name= 0; 00179 lex->et= NULL; 00180 00181 lex->nest_level=0 ; 00182 lex->allow_sum_func= 0; 00183 lex->in_sum_func= NULL; 00184 DBUG_VOID_RETURN; 00185 }
Here is the caller graph for this function:

| int MYSQLlex | ( | void * | arg, | |
| void * | yythd | |||
| ) |
Definition at line 500 of file sql_lex.cc.
References ABORT_SYM, BIN_NUM, CLIENT_MULTI_STATEMENTS, DECIMAL_NUM, END_OF_INPUT, find_keyword(), FLOAT_NUM, get_charset_by_csname(), get_quoted_token(), get_text(), get_token(), HEX_NUM, IDENT, charset_info_st::ident_map, IDENT_QUOTED, int_token(), LEX_HOSTNAME, LINT_INIT, MODE_ANSI_QUOTES, MY_CS_PRIMARY, my_isalnum, my_iscntrl, my_isdigit, my_ismbchar, my_isspace, my_isxdigit, MY_LEX_BIN_NUMBER, MY_LEX_BOOL, MY_LEX_CHAR, MY_LEX_CMP_OP, MY_LEX_COMMENT, MY_LEX_END, MY_LEX_END_LONG_COMMENT, MY_LEX_EOL, MY_LEX_ESCAPE, MY_LEX_HEX_NUMBER, MY_LEX_HOSTNAME, MY_LEX_IDENT, MY_LEX_IDENT_OR_BIN, MY_LEX_IDENT_OR_HEX, MY_LEX_IDENT_OR_KEYWORD, MY_LEX_IDENT_OR_NCHAR, MY_LEX_IDENT_SEP, MY_LEX_IDENT_START, MY_LEX_INT_OR_REAL, MY_LEX_LONG_CMP_OP, MY_LEX_LONG_COMMENT, MY_LEX_NUMBER_IDENT, MY_LEX_OPERATOR_OR_IDENT, MY_LEX_REAL, MY_LEX_REAL_OR_POINT, MY_LEX_SEMICOLON, MY_LEX_SET_VAR, MY_LEX_SKIP, MY_LEX_START, MY_LEX_STRING, MY_LEX_STRING_OR_DELIMITER, MY_LEX_SYSTEM_VAR, MY_LEX_USER_END, MY_LEX_USER_VARIABLE_DELIMITER, my_mbcharlen, MYF, MYSQL_VERSION_ID, NCHAR_STRING, NULL_SYM, OPTION_FOUND_COMMENT, PARAM_MARKER, reg1, SERVER_MORE_RESULTS_EXISTS, SET_VAR, start(), charset_info_st::state_map, strtol(), TEXT_STRING, UNDERSCORE_CHARSET, use_mb, version(), yyGet, yyGetLast, yyLength, yylval, yyPeek, yyPeek2, yySkip, and yyUnget.
00501 { 00502 reg1 uchar c; 00503 int tokval, result_state; 00504 uint length; 00505 enum my_lex_states state; 00506 LEX *lex= ((THD *)yythd)->lex; 00507 YYSTYPE *yylval=(YYSTYPE*) arg; 00508 CHARSET_INFO *cs= ((THD *) yythd)->charset(); 00509 uchar *state_map= cs->state_map; 00510 uchar *ident_map= cs->ident_map; 00511 00512 lex->yylval=yylval; // The global state 00513 00514 lex->tok_end_prev= lex->tok_end; 00515 lex->tok_start_prev= lex->tok_start; 00516 00517 lex->tok_start=lex->tok_end=lex->ptr; 00518 state=lex->next_state; 00519 lex->next_state=MY_LEX_OPERATOR_OR_IDENT; 00520 LINT_INIT(c); 00521 for (;;) 00522 { 00523 switch (state) { 00524 case MY_LEX_OPERATOR_OR_IDENT: // Next is operator or keyword 00525 case MY_LEX_START: // Start of token 00526 // Skip startspace 00527 for (c=yyGet() ; (state_map[c] == MY_LEX_SKIP) ; c= yyGet()) 00528 { 00529 if (c == '\n') 00530 lex->yylineno++; 00531 } 00532 lex->tok_start=lex->ptr-1; // Start of real token 00533 state= (enum my_lex_states) state_map[c]; 00534 break; 00535 case MY_LEX_ESCAPE: 00536 if (yyGet() == 'N') 00537 { // Allow \N as shortcut for NULL 00538 yylval->lex_str.str=(char*) "\\N"; 00539 yylval->lex_str.length=2; 00540 return NULL_SYM; 00541 } 00542 case MY_LEX_CHAR: // Unknown or single char token 00543 case MY_LEX_SKIP: // This should not happen 00544 if (c == '-' && yyPeek() == '-' && 00545 (my_isspace(cs,yyPeek2()) || 00546 my_iscntrl(cs,yyPeek2()))) 00547 { 00548 state=MY_LEX_COMMENT; 00549 break; 00550 } 00551 yylval->lex_str.str=(char*) (lex->ptr=lex->tok_start);// Set to first chr 00552 yylval->lex_str.length=1; 00553 c=yyGet(); 00554 if (c != ')') 00555 lex->next_state= MY_LEX_START; // Allow signed numbers 00556 if (c == ',') 00557 lex->tok_start=lex->ptr; // Let tok_start point at next item 00558 /* 00559 Check for a placeholder: it should not precede a possible identifier 00560 because of binlogging: when a placeholder is replaced with 00561 its value in a query for the binlog, the query must stay 00562 grammatically correct. 00563 */ 00564 else if (c == '?' && lex->stmt_prepare_mode && !ident_map[yyPeek()]) 00565 return(PARAM_MARKER); 00566 return((int) c); 00567 00568 case MY_LEX_IDENT_OR_NCHAR: 00569 if (yyPeek() != '\'') 00570 { 00571 state= MY_LEX_IDENT; 00572 break; 00573 } 00574 /* Found N'string' */ 00575 lex->tok_start++; // Skip N 00576 yySkip(); // Skip ' 00577 if (!(yylval->lex_str.str = get_text(lex))) 00578 { 00579 state= MY_LEX_CHAR; // Read char by char 00580 break; 00581 } 00582 yylval->lex_str.length= lex->yytoklen; 00583 return(NCHAR_STRING); 00584 00585 case MY_LEX_IDENT_OR_HEX: 00586 if (yyPeek() == '\'') 00587 { // Found x'hex-number' 00588 state= MY_LEX_HEX_NUMBER; 00589 break; 00590 } 00591 case MY_LEX_IDENT_OR_BIN: 00592 if (yyPeek() == '\'') 00593 { // Found b'bin-number' 00594 state= MY_LEX_BIN_NUMBER; 00595 break; 00596 } 00597 case MY_LEX_IDENT: 00598 const uchar *start; 00599 #if defined(USE_MB) && defined(USE_MB_IDENT) 00600 if (use_mb(cs)) 00601 { 00602 result_state= IDENT_QUOTED; 00603 if (my_mbcharlen(cs, yyGetLast()) > 1) 00604 { 00605 int l = my_ismbchar(cs, 00606 (const char *)lex->ptr-1, 00607 (const char *)lex->end_of_query); 00608 if (l == 0) { 00609 state = MY_LEX_CHAR; 00610 continue; 00611 } 00612 lex->ptr += l - 1; 00613 } 00614 while (ident_map[c=yyGet()]) 00615 { 00616 if (my_mbcharlen(cs, c) > 1) 00617 { 00618 int l; 00619 if ((l = my_ismbchar(cs, 00620 (const char *)lex->ptr-1, 00621 (const char *)lex->end_of_query)) == 0) 00622 break; 00623 lex->ptr += l-1; 00624 } 00625 } 00626 } 00627 else 00628 #endif 00629 { 00630 for (result_state= c; ident_map[c= yyGet()]; result_state|= c); 00631 /* If there were non-ASCII characters, mark that we must convert */ 00632 result_state= result_state & 0x80 ? IDENT_QUOTED : IDENT; 00633 } 00634 length= (uint) (lex->ptr - lex->tok_start)-1; 00635 start= lex->ptr; 00636 if (lex->ignore_space) 00637 { 00638 /* 00639 If we find a space then this can't be an identifier. We notice this 00640 below by checking start != lex->ptr. 00641 */ 00642 for (; state_map[c] == MY_LEX_SKIP ; c= yyGet()); 00643 } 00644 if (start == lex->ptr && c == '.' && ident_map[yyPeek()]) 00645 lex->next_state=MY_LEX_IDENT_SEP; 00646 else 00647 { // '(' must follow directly if function 00648 yyUnget(); 00649 if ((tokval = find_keyword(lex,length,c == '('))) 00650 { 00651 lex->next_state= MY_LEX_START; // Allow signed numbers 00652 return(tokval); // Was keyword 00653 } 00654 yySkip(); // next state does a unget 00655 } 00656 yylval->lex_str=get_token(lex,length); 00657 00658 /* 00659 Note: "SELECT _bla AS 'alias'" 00660 _bla should be considered as a IDENT if charset haven't been found. 00661 So we don't use MYF(MY_WME) with get_charset_by_csname to avoid 00662 producing an error. 00663 */ 00664 00665 if ((yylval->lex_str.str[0]=='_') && 00666 (lex->charset=get_charset_by_csname(yylval->lex_str.str+1, 00667 MY_CS_PRIMARY,MYF(0)))) 00668 return(UNDERSCORE_CHARSET); 00669 return(result_state); // IDENT or IDENT_QUOTED 00670 00671 case MY_LEX_IDENT_SEP: // Found ident and now '.' 00672 yylval->lex_str.str=(char*) lex->ptr; 00673 yylval->lex_str.length=1; 00674 c=yyGet(); // should be '.' 00675 lex->next_state= MY_LEX_IDENT_START;// Next is an ident (not a keyword) 00676 if (!ident_map[yyPeek()]) // Probably ` or " 00677 lex->next_state= MY_LEX_START; 00678 return((int) c); 00679 00680 case MY_LEX_NUMBER_IDENT: // number or ident which num-start 00681 while (my_isdigit(cs,(c = yyGet()))) ; 00682 if (!ident_map[c]) 00683 { // Can't be identifier 00684 state=MY_LEX_INT_OR_REAL; 00685 break; 00686 } 00687 if (c == 'e' || c == 'E') 00688 { 00689 // The following test is written this way to allow numbers of type 1e1 00690 if (my_isdigit(cs,

