sql_lex.cc 49 KB
Newer Older
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
2

bk@work.mysql.com's avatar
bk@work.mysql.com committed
3 4 5 6
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
7

bk@work.mysql.com's avatar
bk@work.mysql.com committed
8 9 10 11
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
12

bk@work.mysql.com's avatar
bk@work.mysql.com committed
13 14 15 16 17 18 19 20 21 22 23
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */


/* A lexical scanner on a temporary buffer with a yacc interface */

#include "mysql_priv.h"
#include "item_create.h"
#include <m_ctype.h>
#include <hash.h>
24 25
#include "sp.h"
#include "sp_head.h"
bk@work.mysql.com's avatar
bk@work.mysql.com committed
26

27 28 29 30 31
/*
  We are using pointer to this variable for distinguishing between assignment
  to NEW row field (when parsing trigger definition) and structured variable.
*/
sys_var_long_ptr trg_new_row_fake_var(0, 0);
32

bk@work.mysql.com's avatar
bk@work.mysql.com committed
33 34 35 36 37 38 39 40 41 42 43 44
/* Macros to look like lex */

#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)

pthread_key(LEX*,THR_LEX);

45
/* Longest standard keyword name */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
46 47
#define TOCK_NAME_LENGTH 24

48 49
/*
  The following data is based on the latin1 character set, and is only
bk@work.mysql.com's avatar
bk@work.mysql.com committed
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
  used when comparing keywords
*/

uchar to_upper_lex[] = {
    0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
   16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
   32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
   48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
   64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
   80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
   96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
   80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,123,124,125,126,127,
  128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
  144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
  160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
  176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
  192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
  208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
  192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
  208,209,210,211,212,213,214,247,216,217,218,219,220,221,222,255
};

72

bk@work.mysql.com's avatar
bk@work.mysql.com committed
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
inline int lex_casecmp(const char *s, const char *t, uint len)
{
  while (len-- != 0 &&
	 to_upper_lex[(uchar) *s++] == to_upper_lex[(uchar) *t++]) ;
  return (int) len+1;
}

#include "lex_hash.h"


void lex_init(void)
{
  uint i;
  DBUG_ENTER("lex_init");
  for (i=0 ; i < array_elements(symbols) ; i++)
    symbols[i].length=(uchar) strlen(symbols[i].name);
  for (i=0 ; i < array_elements(sql_functions) ; i++)
    sql_functions[i].length=(uchar) strlen(sql_functions[i].name);

  VOID(pthread_key_create(&THR_LEX,NULL));

  DBUG_VOID_RETURN;
}


void lex_free(void)
{					// Call this when daemon ends
  DBUG_ENTER("lex_free");
  DBUG_VOID_RETURN;
}


105 106 107 108 109 110
/*
  This is called before every query that is to be parsed.
  Because of this, it's critical to not do too much things here.
  (We already do too much here)
*/

111
void lex_start(THD *thd, uchar *buf,uint length)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
112
{
113
  LEX *lex= thd->lex;
114 115 116 117 118 119
  DBUG_ENTER("lex_start");

  lex->thd= lex->unit.thd= thd;
  lex->buf= lex->ptr= buf;
  lex->end_of_query= buf+length;

120 121 122 123
  lex->unit.init_query();
  lex->unit.init_select();
  lex->select_lex.init_query();
  lex->value_list.empty();
124
  lex->update_list.empty();
125
  lex->param_list.empty();
monty@mysql.com's avatar
monty@mysql.com committed
126
  lex->view_list.empty();
127 128 129 130 131 132 133 134 135 136
  lex->unit.next= lex->unit.master=
    lex->unit.link_next= lex->unit.return_to= 0;
  lex->unit.prev= lex->unit.link_prev= 0;
  lex->unit.slave= lex->unit.global_parameters= lex->current_select=
    lex->all_selects_list= &lex->select_lex;
  lex->select_lex.master= &lex->unit;
  lex->select_lex.prev= &lex->unit.slave;
  lex->select_lex.link_next= lex->select_lex.slave= lex->select_lex.next= 0;
  lex->select_lex.link_prev= (st_select_lex_node**)&(lex->all_selects_list);
  lex->select_lex.options= 0;
monty@mysql.com's avatar
monty@mysql.com committed
137 138
  lex->select_lex.init_order();
  lex->select_lex.group_list.empty();
139
  lex->describe= 0;
monty@mysql.com's avatar
monty@mysql.com committed
140
  lex->subqueries= FALSE;
monty@mysql.com's avatar
monty@mysql.com committed
141
  lex->view_prepare_mode= FALSE;
monty@mysql.com's avatar
monty@mysql.com committed
142
  lex->derived_tables= 0;
143
  lex->lock_option= TL_READ;
144
  lex->found_semicolon= 0;
145 146
  lex->safe_to_cache_query= 1;
  lex->time_zone_tables_used= 0;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
147
  lex->leaf_tables_insert= lex->proc_table= lex->query_tables= 0;
monty@mysql.com's avatar
monty@mysql.com committed
148 149 150 151
  lex->query_tables_last= &lex->query_tables;
  lex->variables_used= 0;
  lex->select_lex.parent_lex= lex;
  lex->empty_field_list_on_rset= 0;
152
  lex->select_lex.select_number= 1;
153
  lex->next_state=MY_LEX_START;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
154
  lex->yylineno = 1;
155
  lex->in_comment=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
156
  lex->length=0;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
157 158
  lex->select_lex.in_sum_expr=0;
  lex->select_lex.expr_list.empty();
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
159
  lex->select_lex.ftfunc_list_alloc.empty();
160
  lex->select_lex.ftfunc_list= &lex->select_lex.ftfunc_list_alloc;
161 162
  lex->select_lex.group_list.empty();
  lex->select_lex.order_list.empty();
163
  lex->current_select= &lex->select_lex;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
164
  lex->yacc_yyss=lex->yacc_yyvs=0;
165
  lex->ignore_space=test(thd->variables.sql_mode & MODE_IGNORE_SPACE);
166
  lex->sql_command=SQLCOM_END;
167
  lex->duplicates= DUP_ERROR;
168
  lex->ignore= 0;
169 170
  lex->sphead= NULL;
  lex->spcont= NULL;
171
  lex->proc_list.first= 0;
172
  lex->query_tables_own_last= 0;
173

174
  if (lex->spfuns.records)
175
    my_hash_reset(&lex->spfuns);
176 177
  if (lex->spprocs.records)
    my_hash_reset(&lex->spprocs);
178
  DBUG_VOID_RETURN;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
}

void lex_end(LEX *lex)
{
  x_free(lex->yacc_yyss);
  x_free(lex->yacc_yyvs);
}


static int find_keyword(LEX *lex, uint len, bool function)
{
  uchar *tok=lex->tok_start;

  SYMBOL *symbol = get_hash_symbol((const char *)tok,len,function);
  if (symbol)
  {
    lex->yylval->symbol.symbol=symbol;
    lex->yylval->symbol.str= (char*) tok;
    lex->yylval->symbol.length=len;
198 199
    
    if ((symbol->tok == NOT_SYM) &&
200
        (lex->thd->variables.sql_mode & MODE_HIGH_NOT_PRECEDENCE))
201 202 203 204 205
      return NOT2_SYM;
    if ((symbol->tok == OR_OR_SYM) &&
	!(lex->thd->variables.sql_mode & MODE_PIPES_AS_CONCAT))
      return OR2_SYM;
    
bk@work.mysql.com's avatar
bk@work.mysql.com committed
206 207 208 209 210
    return symbol->tok;
  }
  return 0;
}

211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
/*
  Check if name is a keyword

  SYNOPSIS
    is_keyword()
    name      checked name
    len       length of checked name

  RETURN VALUES
    0         name is a keyword
    1         name isn't a keyword
*/

bool is_keyword(const char *name, uint len)
{
  return get_hash_symbol(name,len,0)!=0;
}
bk@work.mysql.com's avatar
bk@work.mysql.com committed
228 229 230

/* make a copy of token before ptr and set yytoklen */

231
static LEX_STRING get_token(LEX *lex,uint length)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
232 233 234 235
{
  LEX_STRING tmp;
  yyUnget();			// ptr points now after last token char
  tmp.length=lex->yytoklen=length;
236
  tmp.str=(char*) lex->thd->strmake((char*) lex->tok_start,tmp.length);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
237 238 239
  return tmp;
}

240 241 242 243 244 245 246
/* 
 todo: 
   There are no dangerous charsets in mysql for function 
   get_quoted_token yet. But it should be fixed in the 
   future to operate multichar strings (like ucs2)
*/

247 248 249 250 251 252 253
static LEX_STRING get_quoted_token(LEX *lex,uint length, char quote)
{
  LEX_STRING tmp;
  byte *from, *to, *end;
  yyUnget();			// ptr points now after last token char
  tmp.length=lex->yytoklen=length;
  tmp.str=(char*) lex->thd->alloc(tmp.length+1);
254 255 256
  for (from= (byte*) lex->tok_start, to= (byte*) tmp.str, end= to+length ;
       to != end ;
       )
257 258 259 260 261 262 263 264 265 266 267 268 269
  {
    if ((*to++= *from++) == quote)
      from++;					// Skip double quotes
  }
  *to= 0;					// End null for safety
  return tmp;
}


/*
  Return an unescaped text literal without quotes
  Fix sometimes to do only one scan of the string
*/
bk@work.mysql.com's avatar
bk@work.mysql.com committed
270 271 272 273 274

static char *get_text(LEX *lex)
{
  reg1 uchar c,sep;
  uint found_escape=0;
275
  CHARSET_INFO *cs= lex->thd->charset();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
276 277 278 279 280 281 282 283

  sep= yyGetLast();			// String should end with this
  //lex->tok_start=lex->ptr-1;		// Remember '
  while (lex->ptr != lex->end_of_query)
  {
    c = yyGet();
#ifdef USE_MB
    int l;
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
284 285
    if (use_mb(cs) &&
        (l = my_ismbchar(cs,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
286 287 288 289 290 291
                         (const char *)lex->ptr-1,
                         (const char *)lex->end_of_query))) {
	lex->ptr += l-1;
	continue;
    }
#endif
292 293
    if (c == '\\' &&
	!(lex->thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
294 295 296 297
    {					// Escaped character
      found_escape=1;
      if (lex->ptr == lex->end_of_query)
	return 0;
298 299 300 301 302 303 304 305 306 307 308 309
#ifdef USE_MB
      int l;
      if (use_mb(cs) &&
          (l = my_ismbchar(cs,
                           (const char *)lex->ptr,
                           (const char *)lex->end_of_query))) {
          lex->ptr += l;
          continue;
      }
      else
#endif
        yySkip();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
    }
    else if (c == sep)
    {
      if (c == yyGet())			// Check if two separators in a row
      {
	found_escape=1;			// dupplicate. Remember for delete
	continue;
      }
      else
	yyUnget();

      /* Found end. Unescape and return string */
      uchar *str,*end,*start;

      str=lex->tok_start+1;
      end=lex->ptr-1;
326
      if (!(start=(uchar*) lex->thd->alloc((uint) (end-str)+1)))
327
	return (char*) "";		// Sql_alloc has set error flag
bk@work.mysql.com's avatar
bk@work.mysql.com committed
328 329 330 331 332 333 334 335 336
      if (!found_escape)
      {
	lex->yytoklen=(uint) (end-str);
	memcpy(start,str,lex->yytoklen);
	start[lex->yytoklen]=0;
      }
      else
      {
	uchar *to;
337 338 339 340

        /* Re-use found_escape for tracking state of escapes */
        found_escape= 0;

bk@work.mysql.com's avatar
bk@work.mysql.com committed
341 342 343 344
	for (to=start ; str != end ; str++)
	{
#ifdef USE_MB
	  int l;
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
345 346
	  if (use_mb(cs) &&
              (l = my_ismbchar(cs,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
347 348 349 350 351 352 353
                               (const char *)str, (const char *)end))) {
	      while (l--)
		  *to++ = *str++;
	      str--;
	      continue;
	  }
#endif
jimw@mysql.com's avatar
Merge  
jimw@mysql.com committed
354 355
	  if (!found_escape &&
              !(lex->thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) &&
356
              *str == '\\' && str+1 != end)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381
	  {
	    switch(*++str) {
	    case 'n':
	      *to++='\n';
	      break;
	    case 't':
	      *to++= '\t';
	      break;
	    case 'r':
	      *to++ = '\r';
	      break;
	    case 'b':
	      *to++ = '\b';
	      break;
	    case '0':
	      *to++= 0;			// Ascii null
	      break;
	    case 'Z':			// ^Z must be escaped on Win32
	      *to++='\032';
	      break;
	    case '_':
	    case '%':
	      *to++= '\\';		// remember prefix for wildcard
	      /* Fall through */
	    default:
382 383
              found_escape= 1;
              str--;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
384 385 386
	      break;
	    }
	  }
387 388 389 390
	  else if (!found_escape && *str == sep)
          {
            found_escape= 1;
          }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
391
	  else
392
          {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
393
	    *to++ = *str;
394 395
            found_escape= 0;
          }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
	}
	*to=0;
	lex->yytoklen=(uint) (to-start);
      }
      return (char*) start;
    }
  }
  return 0;					// unexpected end of query
}


/*
** Calc type of integer; long integer, longlong integer or real.
** Returns smallest type that match the string.
** When using unsigned long long values the result is converted to a real
** because else they will be unexpected sign changes because all calculation
** is done with longlong or double.
*/

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;
422 423
static const char *unsigned_longlong_str="18446744073709551615";
static const uint unsigned_longlong_len=20;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459

inline static uint int_token(const char *str,uint length)
{
  if (length < long_len)			// quick normal case
    return NUM;
  bool neg=0;

  if (*str == '+')				// Remove sign and pre-zeros
  {
    str++; length--;
  }
  else if (*str == '-')
  {
    str++; length--;
    neg=1;
  }
  while (*str == '0' && length)
  {
    str++; length --;
  }
  if (length < long_len)
    return NUM;

  uint smaller,bigger;
  const char *cmp;
  if (neg)
  {
    if (length == long_len)
    {
      cmp= signed_long_str+1;
      smaller=NUM;				// If <= signed_long_str
      bigger=LONG_NUM;				// If >= signed_long_str
    }
    else if (length < signed_longlong_len)
      return LONG_NUM;
    else if (length > signed_longlong_len)
460
      return DECIMAL_NUM;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
461 462 463 464
    else
    {
      cmp=signed_longlong_str+1;
      smaller=LONG_NUM;				// If <= signed_longlong_str
465
      bigger=DECIMAL_NUM;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
466 467 468 469 470 471 472 473 474 475 476 477 478
    }
  }
  else
  {
    if (length == long_len)
    {
      cmp= long_str;
      smaller=NUM;
      bigger=LONG_NUM;
    }
    else if (length < longlong_len)
      return LONG_NUM;
    else if (length > longlong_len)
479 480
    {
      if (length > unsigned_longlong_len)
481
        return DECIMAL_NUM;
482 483
      cmp=unsigned_longlong_str;
      smaller=ULONGLONG_NUM;
484
      bigger=DECIMAL_NUM;
485
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
486 487 488 489
    else
    {
      cmp=longlong_str;
      smaller=LONG_NUM;
490
      bigger= ULONGLONG_NUM;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
491 492 493 494 495 496
    }
  }
  while (*cmp && *cmp++ == *str++) ;
  return ((uchar) str[-1] <= (uchar) cmp[-1]) ? smaller : bigger;
}

497 498 499 500 501 502 503
/*
  yylex remember the following states from the following yylex()

  - MY_LEX_EOQ			Found end of query
  - MY_LEX_OPERATOR_OR_IDENT	Last state was an ident, text or number
				(which can't be followed by a signed number)
*/
bk@work.mysql.com's avatar
bk@work.mysql.com committed
504

505
int yylex(void *arg, void *yythd)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
506 507
{
  reg1	uchar c;
508
  int	tokval, result_state;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
509
  uint length;
510
  enum my_lex_states state;
511
  LEX	*lex= ((THD *)yythd)->lex;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
512
  YYSTYPE *yylval=(YYSTYPE*) arg;
513
  CHARSET_INFO *cs= ((THD *) yythd)->charset();
514 515
  uchar *state_map= cs->state_map;
  uchar *ident_map= cs->ident_map;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
516 517 518

  lex->yylval=yylval;			// The global state
  lex->tok_start=lex->tok_end=lex->ptr;
519
  state=lex->next_state;
520
  lex->next_state=MY_LEX_OPERATOR_OR_IDENT;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
521 522 523
  LINT_INIT(c);
  for (;;)
  {
524
    switch (state) {
525 526
    case MY_LEX_OPERATOR_OR_IDENT:	// Next is operator or keyword
    case MY_LEX_START:			// Start of token
527
      // Skip startspace
528
      for (c=yyGet() ; (state_map[c] == MY_LEX_SKIP) ; c= yyGet())
bk@work.mysql.com's avatar
bk@work.mysql.com committed
529 530 531 532 533
      {
	if (c == '\n')
	  lex->yylineno++;
      }
      lex->tok_start=lex->ptr-1;	// Start of real token
534
      state= (enum my_lex_states) state_map[c];
bk@work.mysql.com's avatar
bk@work.mysql.com committed
535
      break;
536
    case MY_LEX_ESCAPE:
bk@work.mysql.com's avatar
bk@work.mysql.com committed
537 538 539 540 541 542
      if (yyGet() == 'N')
      {					// Allow \N as shortcut for NULL
	yylval->lex_str.str=(char*) "\\N";
	yylval->lex_str.length=2;
	return NULL_SYM;
      }
543 544
    case MY_LEX_CHAR:			// Unknown or single char token
    case MY_LEX_SKIP:			// This should not happen
545 546 547 548 549 550 551
      if (c == '-' && yyPeek() == '-' &&
          (my_isspace(cs,yyPeek2()) || 
           my_iscntrl(cs,yyPeek2())))
      {
        state=MY_LEX_COMMENT;
        break;
      }
552
      yylval->lex_str.str=(char*) (lex->ptr=lex->tok_start);// Set to first chr
bk@work.mysql.com's avatar
bk@work.mysql.com committed
553 554 555
      yylval->lex_str.length=1;
      c=yyGet();
      if (c != ')')
556
	lex->next_state= MY_LEX_START;	// Allow signed numbers
bk@work.mysql.com's avatar
bk@work.mysql.com committed
557 558 559 560
      if (c == ',')
	lex->tok_start=lex->ptr;	// Let tok_start point at next item
      return((int) c);

bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580
    case MY_LEX_IDENT_OR_NCHAR:
      if (yyPeek() != '\'')
      {					// Found x'hex-number'
	state= MY_LEX_IDENT;
	break;
      }
      yyGet();				// Skip '
      while ((c = yyGet()) && (c !='\'')) ;
      length=(lex->ptr - lex->tok_start);	// Length of hexnum+3
      if (c != '\'')
      {
	return(ABORT_SYM);		// Illegal hex constant
      }
      yyGet();				// get_token makes an unget
      yylval->lex_str=get_token(lex,length);
      yylval->lex_str.str+=2;		// Skip x'
      yylval->lex_str.length-=3;	// Don't count x' and last '
      lex->yytoklen-=3;
      return (NCHAR_STRING);

581
    case MY_LEX_IDENT_OR_HEX:
582
      if (yyPeek() == '\'')
583
      {					// Found x'hex-number'
584
	state= MY_LEX_HEX_NUMBER;
585 586
	break;
      }
ram@gw.mysql.r18.ru's avatar
ram@gw.mysql.r18.ru committed
587 588 589 590 591 592
    case MY_LEX_IDENT_OR_BIN:
      if (yyPeek() == '\'')
      {                                 // Found b'bin-number'
        state= MY_LEX_BIN_NUMBER;
        break;
      }
593
    case MY_LEX_IDENT:
594
      uchar *start;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
595
#if defined(USE_MB) && defined(USE_MB_IDENT)
596
      if (use_mb(cs))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
597
      {
598
	result_state= IDENT_QUOTED;
599
        if (my_mbcharlen(cs, yyGetLast()) > 1)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
600
        {
601
          int l = my_ismbchar(cs,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
602 603 604
                              (const char *)lex->ptr-1,
                              (const char *)lex->end_of_query);
          if (l == 0) {
605
            state = MY_LEX_CHAR;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
606 607 608 609
            continue;
          }
          lex->ptr += l - 1;
        }
610
        while (ident_map[c=yyGet()])
bk@work.mysql.com's avatar
bk@work.mysql.com committed
611
        {
612
          if (my_mbcharlen(cs, c) > 1)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
613 614
          {
            int l;
615
            if ((l = my_ismbchar(cs,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
616 617 618 619 620 621 622 623 624
                              (const char *)lex->ptr-1,
                              (const char *)lex->end_of_query)) == 0)
              break;
            lex->ptr += l-1;
          }
        }
      }
      else
#endif
625
      {
626 627 628
        for (result_state= c; ident_map[c= yyGet()]; result_state|= c);
        /* If there were non-ASCII characters, mark that we must convert */
        result_state= result_state & 0x80 ? IDENT_QUOTED : IDENT;
629
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
630
      length= (uint) (lex->ptr - lex->tok_start)-1;
631
      start= lex->ptr;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
632 633
      if (lex->ignore_space)
      {
634 635 636 637 638
        /*
          If we find a space then this can't be an identifier. We notice this
          below by checking start != lex->ptr.
        */
        for (; state_map[c] == MY_LEX_SKIP ; c= yyGet());
bk@work.mysql.com's avatar
bk@work.mysql.com committed
639
      }
640
      if (start == lex->ptr && c == '.' && ident_map[yyPeek()])
641
	lex->next_state=MY_LEX_IDENT_SEP;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
642 643 644 645 646
      else
      {					// '(' must follow directly if function
	yyUnget();
	if ((tokval = find_keyword(lex,length,c == '(')))
	{
647
	  lex->next_state= MY_LEX_START;	// Allow signed numbers
bk@work.mysql.com's avatar
bk@work.mysql.com committed
648 649 650 651 652
	  return(tokval);		// Was keyword
	}
	yySkip();			// next state does a unget
      }
      yylval->lex_str=get_token(lex,length);
653 654 655 656

      /* 
         Note: "SELECT _bla AS 'alias'"
         _bla should be considered as a IDENT if charset haven't been found.
657
         So we don't use MYF(MY_WME) with get_charset_by_csname to avoid 
658 659 660 661
         producing an error.
      */

      if ((yylval->lex_str.str[0]=='_') && 
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
662 663
          (lex->charset=get_charset_by_csname(yylval->lex_str.str+1,
					      MY_CS_PRIMARY,MYF(0))))
664
        return(UNDERSCORE_CHARSET);
665
      return(result_state);			// IDENT or IDENT_QUOTED
bk@work.mysql.com's avatar
bk@work.mysql.com committed
666

667
    case MY_LEX_IDENT_SEP:		// Found ident and now '.'
bk@work.mysql.com's avatar
bk@work.mysql.com committed
668 669 670
      yylval->lex_str.str=(char*) lex->ptr;
      yylval->lex_str.length=1;
      c=yyGet();			// should be '.'
671 672 673
      lex->next_state= MY_LEX_IDENT_START;// Next is an ident (not a keyword)
      if (!ident_map[yyPeek()])		// Probably ` or "
	lex->next_state= MY_LEX_START;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
674 675
      return((int) c);

676 677
    case MY_LEX_NUMBER_IDENT:		// number or ident which num-start
      while (my_isdigit(cs,(c = yyGet()))) ;
678
      if (!ident_map[c])
bk@work.mysql.com's avatar
bk@work.mysql.com committed
679
      {					// Can't be identifier
680
	state=MY_LEX_INT_OR_REAL;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
681 682 683 684
	break;
      }
      if (c == 'e' || c == 'E')
      {
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
685
	// The following test is written this way to allow numbers of type 1e1
686
	if (my_isdigit(cs,yyPeek()) || 
687
            (c=(yyGet())) == '+' || c == '-')
bk@work.mysql.com's avatar
bk@work.mysql.com committed
688
	{				// Allow 1E+10
689
	  if (my_isdigit(cs,yyPeek()))	// Number must have digit after sign
bk@work.mysql.com's avatar
bk@work.mysql.com committed
690 691
	  {
	    yySkip();
692
	    while (my_isdigit(cs,yyGet())) ;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
693 694 695 696 697 698 699 700 701
	    yylval->lex_str=get_token(lex,yyLength());
	    return(FLOAT_NUM);
	  }
	}
	yyUnget(); /* purecov: inspected */
      }
      else if (c == 'x' && (lex->ptr - lex->tok_start) == 2 &&
	  lex->tok_start[0] == '0' )
      {						// Varbinary
702
	while (my_isxdigit(cs,(c = yyGet()))) ;
703
	if ((lex->ptr - lex->tok_start) >= 4 && !ident_map[c])
bk@work.mysql.com's avatar
bk@work.mysql.com committed
704 705
	{
	  yylval->lex_str=get_token(lex,yyLength());
706
	  yylval->lex_str.str+=2;		// Skip 0x
bk@work.mysql.com's avatar
bk@work.mysql.com committed
707 708 709 710 711 712
	  yylval->lex_str.length-=2;
	  lex->yytoklen-=2;
	  return (HEX_NUM);
	}
	yyUnget();
      }
ram@gw.mysql.r18.ru's avatar
ram@gw.mysql.r18.ru committed
713 714 715 716 717 718 719 720 721 722 723 724 725 726
      else if (c == 'b' && (lex->ptr - lex->tok_start) == 2 &&
               lex->tok_start[0] == '0' )
      {						// b'bin-number'
	while (my_isxdigit(cs,(c = yyGet()))) ;
	if ((lex->ptr - lex->tok_start) >= 4 && !ident_map[c])
	{
	  yylval->lex_str= get_token(lex, yyLength());
	  yylval->lex_str.str+= 2;		// Skip 0x
	  yylval->lex_str.length-= 2;
	  lex->yytoklen-= 2;
	  return (BIN_NUM);
	}
	yyUnget();
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
727
      // fall through
728
    case MY_LEX_IDENT_START:			// We come here after '.'
729
      result_state= IDENT;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
730
#if defined(USE_MB) && defined(USE_MB_IDENT)
731
      if (use_mb(cs))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
732
      {
733
	result_state= IDENT_QUOTED;
734
        while (ident_map[c=yyGet()])
bk@work.mysql.com's avatar
bk@work.mysql.com committed
735
        {
736
          if (my_mbcharlen(cs, c) > 1)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
737 738
          {
            int l;
739
            if ((l = my_ismbchar(cs,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
740 741 742 743 744 745 746 747 748
                                 (const char *)lex->ptr-1,
                                 (const char *)lex->end_of_query)) == 0)
              break;
            lex->ptr += l-1;
          }
        }
      }
      else
#endif
749 750 751 752 753
      {
        for (result_state=0; ident_map[c= yyGet()]; result_state|= c);
        /* If there were non-ASCII characters, mark that we must convert */
        result_state= result_state & 0x80 ? IDENT_QUOTED : IDENT;
      }
754
      if (c == '.' && ident_map[yyPeek()])
755
	lex->next_state=MY_LEX_IDENT_SEP;// Next is '.'
bk@work.mysql.com's avatar
bk@work.mysql.com committed
756

757 758
      yylval->lex_str= get_token(lex,yyLength());
      return(result_state);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
759

760
    case MY_LEX_USER_VARIABLE_DELIMITER:	// Found quote char
761
    {
762 763
      uint double_quotes= 0;
      char quote_char= c;                       // Used char
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
764
      lex->tok_start=lex->ptr;			// Skip first `
765
      while ((c=yyGet()))
766
      {
767 768
	int length;
	if ((length= my_mbcharlen(cs, c)) == 1)
769
	{
770 771
	  if (c == (uchar) NAMES_SEP_CHAR)
	    break; /* Old .frm format can't handle this char */
772 773 774 775 776 777 778 779
	  if (c == quote_char)
	  {
	    if (yyPeek() != quote_char)
	      break;
	    c=yyGet();
	    double_quotes++;
	    continue;
	  }
780 781
	}
#ifdef USE_MB
782 783 784
	else if (length < 1)
	  break;				// Error
	lex->ptr+= length-1;
785
#endif
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
786
      }
787 788 789 790 791 792
      if (double_quotes)
	yylval->lex_str=get_quoted_token(lex,yyLength() - double_quotes,
					 quote_char);
      else
	yylval->lex_str=get_token(lex,yyLength());
      if (c == quote_char)
793
	yySkip();			// Skip end `
794
      lex->next_state= MY_LEX_START;
795
      return(IDENT_QUOTED);
796
    }
797
    case MY_LEX_INT_OR_REAL:		// Compleat int or incompleat real
bk@work.mysql.com's avatar
bk@work.mysql.com committed
798 799 800 801 802 803
      if (c != '.')
      {					// Found complete integer number.
	yylval->lex_str=get_token(lex,yyLength());
	return int_token(yylval->lex_str.str,yylval->lex_str.length);
      }
      // fall through
804 805
    case MY_LEX_REAL:			// Incomplete real number
      while (my_isdigit(cs,c = yyGet())) ;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
806 807 808 809

      if (c == 'e' || c == 'E')
      {
	c = yyGet();
810
	if (c == '-' || c == '+')
811
	  c = yyGet();			// Skip sign
812
	if (!my_isdigit(cs,c))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
813
	{				// No digit after sign
814
	  state= MY_LEX_CHAR;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
815 816
	  break;
	}
817
	while (my_isdigit(cs,yyGet())) ;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
818 819 820 821
	yylval->lex_str=get_token(lex,yyLength());
	return(FLOAT_NUM);
      }
      yylval->lex_str=get_token(lex,yyLength());
822
      return(DECIMAL_NUM);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
823

824
    case MY_LEX_HEX_NUMBER:		// Found x'hexstring'
825
      yyGet();				// Skip '
826
      while (my_isxdigit(cs,(c = yyGet()))) ;
827 828 829 830 831 832 833 834 835 836 837 838
      length=(lex->ptr - lex->tok_start);	// Length of hexnum+3
      if (!(length & 1) || c != '\'')
      {
	return(ABORT_SYM);		// Illegal hex constant
      }
      yyGet();				// get_token makes an unget
      yylval->lex_str=get_token(lex,length);
      yylval->lex_str.str+=2;		// Skip x'
      yylval->lex_str.length-=3;	// Don't count x' and last '
      lex->yytoklen-=3;
      return (HEX_NUM);

ram@gw.mysql.r18.ru's avatar
ram@gw.mysql.r18.ru committed
839 840 841 842 843 844 845 846 847 848 849 850 851
    case MY_LEX_BIN_NUMBER:           // Found b'bin-string'
      yyGet();                                // Skip '
      while ((c= yyGet()) == '0' || c == '1');
      length= (lex->ptr - lex->tok_start);    // Length of bin-num + 3
      if (c != '\'')
      return(ABORT_SYM);              // Illegal hex constant
      yyGet();                        // get_token makes an unget
      yylval->lex_str= get_token(lex, length);
      yylval->lex_str.str+= 2;        // Skip b'
      yylval->lex_str.length-= 3;     // Don't count b' and last '
      lex->yytoklen-= 3;
      return (BIN_NUM); 

852 853 854
    case MY_LEX_CMP_OP:			// Incomplete comparison operator
      if (state_map[yyPeek()] == MY_LEX_CMP_OP ||
	  state_map[yyPeek()] == MY_LEX_LONG_CMP_OP)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
855 856 857
	yySkip();
      if ((tokval = find_keyword(lex,(uint) (lex->ptr - lex->tok_start),0)))
      {
858
	lex->next_state= MY_LEX_START;	// Allow signed numbers
bk@work.mysql.com's avatar
bk@work.mysql.com committed
859 860
	return(tokval);
      }
861
      state = MY_LEX_CHAR;		// Something fishy found
bk@work.mysql.com's avatar
bk@work.mysql.com committed
862 863
      break;

864 865 866
    case MY_LEX_LONG_CMP_OP:		// Incomplete comparison operator
      if (state_map[yyPeek()] == MY_LEX_CMP_OP ||
	  state_map[yyPeek()] == MY_LEX_LONG_CMP_OP)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
867 868
      {
	yySkip();
869
	if (state_map[yyPeek()] == MY_LEX_CMP_OP)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
870 871 872 873
	  yySkip();
      }
      if ((tokval = find_keyword(lex,(uint) (lex->ptr - lex->tok_start),0)))
      {
874
	lex->next_state= MY_LEX_START;	// Found long op
bk@work.mysql.com's avatar
bk@work.mysql.com committed
875 876
	return(tokval);
      }
877
      state = MY_LEX_CHAR;		// Something fishy found
bk@work.mysql.com's avatar
bk@work.mysql.com committed
878 879
      break;

880
    case MY_LEX_BOOL:
bk@work.mysql.com's avatar
bk@work.mysql.com committed
881 882
      if (c != yyPeek())
      {
883
	state=MY_LEX_CHAR;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
884 885 886 887
	break;
      }
      yySkip();
      tokval = find_keyword(lex,2,0);	// Is a bool operator
888
      lex->next_state= MY_LEX_START;	// Allow signed numbers
bk@work.mysql.com's avatar
bk@work.mysql.com committed
889 890
      return(tokval);

891
    case MY_LEX_STRING_OR_DELIMITER:
892 893
      if (((THD *) yythd)->variables.sql_mode & MODE_ANSI_QUOTES)
      {
894
	state= MY_LEX_USER_VARIABLE_DELIMITER;
895 896 897
	break;
      }
      /* " used for strings */
898
    case MY_LEX_STRING:			// Incomplete text string
bk@work.mysql.com's avatar
bk@work.mysql.com committed
899 900
      if (!(yylval->lex_str.str = get_text(lex)))
      {
901
	state= MY_LEX_CHAR;		// Read char by char
bk@work.mysql.com's avatar
bk@work.mysql.com committed
902 903 904 905 906
	break;
      }
      yylval->lex_str.length=lex->yytoklen;
      return(TEXT_STRING);

907
    case MY_LEX_COMMENT:			//  Comment
908
      lex->select_lex.options|= OPTION_FOUND_COMMENT;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
909 910
      while ((c = yyGet()) != '\n' && c) ;
      yyUnget();			// Safety against eof
911
      state = MY_LEX_START;		// Try again
bk@work.mysql.com's avatar
bk@work.mysql.com committed
912
      break;
913
    case MY_LEX_LONG_COMMENT:		/* Long C comment? */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
914 915
      if (yyPeek() != '*')
      {
916
	state=MY_LEX_CHAR;		// Probable division
bk@work.mysql.com's avatar
bk@work.mysql.com committed
917 918 919
	break;
      }
      yySkip();				// Skip '*'
920
      lex->select_lex.options|= OPTION_FOUND_COMMENT;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
921 922 923 924
      if (yyPeek() == '!')		// MySQL command in comment
      {
	ulong version=MYSQL_VERSION_ID;
	yySkip();
925 926
	state=MY_LEX_START;
	if (my_isdigit(cs,yyPeek()))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943
	{				// Version number
	  version=strtol((char*) lex->ptr,(char**) &lex->ptr,10);
	}
	if (version <= MYSQL_VERSION_ID)
	{
	  lex->in_comment=1;
	  break;
	}
      }
      while (lex->ptr != lex->end_of_query &&
	     ((c=yyGet()) != '*' || yyPeek() != '/'))
      {
	if (c == '\n')
	  lex->yylineno++;
      }
      if (lex->ptr != lex->end_of_query)
	yySkip();			// remove last '/'
944
      state = MY_LEX_START;		// Try again
bk@work.mysql.com's avatar
bk@work.mysql.com committed
945
      break;
946
    case MY_LEX_END_LONG_COMMENT:
bk@work.mysql.com's avatar
bk@work.mysql.com committed
947 948 949 950
      if (lex->in_comment && yyPeek() == '/')
      {
	yySkip();
	lex->in_comment=0;
951
	state=MY_LEX_START;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
952 953
      }
      else
954
	state=MY_LEX_CHAR;		// Return '*'
bk@work.mysql.com's avatar
bk@work.mysql.com committed
955
      break;
956
    case MY_LEX_SET_VAR:		// Check if ':='
bk@work.mysql.com's avatar
bk@work.mysql.com committed
957 958
      if (yyPeek() != '=')
      {
959
	state=MY_LEX_CHAR;		// Return ':'
bk@work.mysql.com's avatar
bk@work.mysql.com committed
960 961 962 963
	break;
      }
      yySkip();
      return (SET_VAR);
964
    case MY_LEX_SEMICOLON:			// optional line terminator
bk@work.mysql.com's avatar
bk@work.mysql.com committed
965 966
      if (yyPeek())
      {
967 968 969
        THD* thd= (THD*)yythd;
        if ((thd->client_capabilities & CLIENT_MULTI_STATEMENTS) && 
            (thd->command != COM_PREPARE))
970
        {
monty@mysql.com's avatar
monty@mysql.com committed
971
	  lex->safe_to_cache_query= 0;
serg@serg.mylan's avatar
serg@serg.mylan committed
972
          lex->found_semicolon=(char*) lex->ptr;
monty@mysql.com's avatar
monty@mysql.com committed
973 974 975
          thd->server_status|= SERVER_MORE_RESULTS_EXISTS;
          lex->next_state=     MY_LEX_END;
          return (END_OF_INPUT);
976
        }
monty@mysql.com's avatar
monty@mysql.com committed
977
        state= MY_LEX_CHAR;		// Return ';'
bk@work.mysql.com's avatar
bk@work.mysql.com committed
978 979 980
	break;
      }
      /* fall true */
981
    case MY_LEX_EOL:
982 983 984 985 986 987 988
      if (lex->ptr >= lex->end_of_query)
      {
	lex->next_state=MY_LEX_END;	// Mark for next loop
	return(END_OF_INPUT);
      }
      state=MY_LEX_CHAR;
      break;
989 990
    case MY_LEX_END:
      lex->next_state=MY_LEX_END;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
991
      return(0);			// We found end of input last time
992 993
      
      /* Actually real shouldn't start with . but allow them anyhow */
994 995 996
    case MY_LEX_REAL_OR_POINT:
      if (my_isdigit(cs,yyPeek()))
	state = MY_LEX_REAL;		// Real
bk@work.mysql.com's avatar
bk@work.mysql.com committed
997 998
      else
      {
999 1000
	state= MY_LEX_IDENT_SEP;	// return '.'
	yyUnget();			// Put back '.'
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1001 1002
      }
      break;
1003
    case MY_LEX_USER_END:		// end '@' of user@hostname
1004
      switch (state_map[yyPeek()]) {
1005 1006 1007
      case MY_LEX_STRING:
      case MY_LEX_USER_VARIABLE_DELIMITER:
      case MY_LEX_STRING_OR_DELIMITER:
1008
	break;
1009 1010
      case MY_LEX_USER_END:
	lex->next_state=MY_LEX_SYSTEM_VAR;
1011 1012
	break;
      default:
1013
	lex->next_state=MY_LEX_HOSTNAME;
1014 1015
	break;
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1016 1017 1018
      yylval->lex_str.str=(char*) lex->ptr;
      yylval->lex_str.length=1;
      return((int) '@');
1019 1020 1021
    case MY_LEX_HOSTNAME:		// end '@' of user@hostname
      for (c=yyGet() ; 
	   my_isalnum(cs,c) || c == '.' || c == '_' ||  c == '$';
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1022 1023 1024
	   c= yyGet()) ;
      yylval->lex_str=get_token(lex,yyLength());
      return(LEX_HOSTNAME);
1025
    case MY_LEX_SYSTEM_VAR:
1026 1027 1028
      yylval->lex_str.str=(char*) lex->ptr;
      yylval->lex_str.length=1;
      yySkip();					// Skip '@'
1029 1030 1031 1032
      lex->next_state= (state_map[yyPeek()] ==
			MY_LEX_USER_VARIABLE_DELIMITER ?
			MY_LEX_OPERATOR_OR_IDENT :
			MY_LEX_IDENT_OR_KEYWORD);
1033
      return((int) '@');
1034
    case MY_LEX_IDENT_OR_KEYWORD:
1035 1036 1037 1038 1039
      /*
	We come here when we have found two '@' in a row.
	We should now be able to handle:
	[(global | local | session) .]variable_name
      */
1040 1041 1042 1043 1044
      
      for (result_state= 0; ident_map[c= yyGet()]; result_state|= c);
      /* If there were non-ASCII characters, mark that we must convert */
      result_state= result_state & 0x80 ? IDENT_QUOTED : IDENT;
      
1045
      if (c == '.')
1046
	lex->next_state=MY_LEX_IDENT_SEP;
1047 1048 1049 1050 1051 1052 1053
      length= (uint) (lex->ptr - lex->tok_start)-1;
      if ((tokval= find_keyword(lex,length,0)))
      {
	yyUnget();				// Put back 'c'
	return(tokval);				// Was keyword
      }
      yylval->lex_str=get_token(lex,length);
1054
      return(result_state);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1055 1056 1057
    }
  }
}
1058 1059 1060 1061 1062 1063 1064

/*
  st_select_lex structures initialisations
*/

void st_select_lex_node::init_query()
{
1065 1066
  options= 0;
  linkage= UNSPECIFIED_TYPE;
1067 1068
  no_error= no_table_names_allowed= 0;
  uncacheable= 0;
1069 1070 1071 1072 1073 1074 1075 1076 1077
}

void st_select_lex_node::init_select()
{
}

void st_select_lex_unit::init_query()
{
  st_select_lex_node::init_query();
1078
  linkage= GLOBAL_OPTIONS_TYPE;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1079
  global_parameters= first_select();
1080 1081
  select_limit_cnt= HA_POS_ERROR;
  offset_limit_cnt= 0;
1082
  union_distinct= 0;
1083
  prepared= optimized= executed= 0;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1084
  item= 0;
1085 1086
  union_result= 0;
  table= 0;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1087
  fake_select_lex= 0;
1088
  cleaned= 0;
1089
  item_list.empty();
1090
  describe= 0;
1091
  found_rows_for_union= 0;
1092 1093 1094 1095 1096
}

void st_select_lex::init_query()
{
  st_select_lex_node::init_query();
1097
  table_list.empty();
1098 1099
  top_join_list.empty();
  join_list= &top_join_list;
1100
  embedding= leaf_tables= 0;
1101
  item_list.empty();
1102
  join= 0;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1103
  where= prep_where= 0;
1104
  olap= UNSPECIFIED_OLAP_TYPE;
1105 1106
  having_fix_field= 0;
  resolve_mode= NOMATTER_MODE;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1107
  cond_count= with_wild= 0;
1108
  conds_processed_with_permanent_arena= 0;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1109
  ref_pointer_array= 0;
bell@laptop.sanja.is.com.ua's avatar
bell@laptop.sanja.is.com.ua committed
1110
  select_n_having_items= 0;
1111
  subquery_in_having= explicit_limit= 0;
1112
  first_execution= 1;
1113
  first_cond_optimization= 1;
1114
  parsing_place= NO_MATTER;
1115
  exclude_from_table_unique_test= no_wrap_view_item= FALSE;
1116
  link_next= 0;
1117 1118 1119 1120 1121
}

void st_select_lex::init_select()
{
  st_select_lex_node::init_select();
1122 1123 1124 1125 1126 1127
  group_list.empty();
  type= db= db1= table1= db2= table2= 0;
  having= 0;
  use_index_ptr= ignore_index_ptr= 0;
  table_join_options= 0;
  in_sum_expr= with_wild= 0;
1128
  options= 0;
1129
  braces= 0;
1130
  when_list.empty();
1131
  expr_list.empty();
1132
  interval_list.empty();
1133
  use_index.empty();
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1134 1135
  ftfunc_list_alloc.empty();
  ftfunc_list= &ftfunc_list_alloc;
1136
  linkage= UNSPECIFIED_TYPE;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1137 1138 1139 1140 1141 1142
  order_list.elements= 0;
  order_list.first= 0;
  order_list.next= (byte**) &order_list.first;
  select_limit= HA_POS_ERROR;
  offset_limit= 0;
  with_sum_func= 0;
1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156
}

/*
  st_select_lex structures linking
*/

/* include on level down */
void st_select_lex_node::include_down(st_select_lex_node *upper)
{
  if ((next= upper->slave))
    next->prev= &next;
  prev= &upper->slave;
  upper->slave= this;
  master= upper;
1157
  slave= 0;
1158 1159
}

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1160 1161
/*
  include on level down (but do not link)
1162

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176
  SYNOPSYS
    st_select_lex_node::include_standalone()
    upper - reference on node underr which this node should be included
    ref - references on reference on this node
*/
void st_select_lex_node::include_standalone(st_select_lex_node *upper,
					    st_select_lex_node **ref)
{
  next= 0;
  prev= ref;
  master= upper;
  slave= 0;
}

1177 1178 1179 1180 1181 1182 1183 1184
/* include neighbour (on same level) */
void st_select_lex_node::include_neighbour(st_select_lex_node *before)
{
  if ((next= before->next))
    next->prev= &next;
  prev= &before->next;
  before->next= this;
  master= before->master;
1185
  slave= 0;
1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199
}

/* including in global SELECT_LEX list */
void st_select_lex_node::include_global(st_select_lex_node **plink)
{
  if ((link_next= *plink))
    link_next->link_prev= &link_next;
  link_prev= plink;
  *plink= this;
}

//excluding from global list (internal function)
void st_select_lex_node::fast_exclude()
{
1200
  if (link_prev)
1201 1202 1203 1204
  {
    if ((*link_prev= link_next))
      link_next->link_prev= link_prev;
  }
1205 1206 1207 1208
  // Remove slave structure
  for (; slave; slave= slave->next)
    slave->fast_exclude();
  
1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228
}

/*
  excluding select_lex structure (except first (first select can't be
  deleted, because it is most upper select))
*/
void st_select_lex_node::exclude()
{
  //exclude from global list
  fast_exclude();
  //exclude from other structures
  if ((*prev= next))
    next->prev= prev;
  /* 
     We do not need following statements, because prev pointer of first 
     list element point to master->slave
     if (master->slave == this)
       master->slave= next;
  */
}
1229

1230 1231 1232 1233 1234 1235 1236 1237 1238 1239

/*
  Exclude level of current unit from tree of SELECTs

  SYNOPSYS
    st_select_lex_unit::exclude_level()

  NOTE: units which belong to current will be brought up on level of
  currernt unit 
*/
1240 1241 1242
void st_select_lex_unit::exclude_level()
{
  SELECT_LEX_UNIT *units= 0, **units_last= &units;
1243
  for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
1244
  {
1245
    // unlink current level from global SELECTs list
1246 1247
    if (sl->link_prev && (*sl->link_prev= sl->link_next))
      sl->link_next->link_prev= sl->link_prev;
1248 1249

    // bring up underlay levels
1250 1251
    SELECT_LEX_UNIT **last= 0;
    for (SELECT_LEX_UNIT *u= sl->first_inner_unit(); u; u= u->next_unit())
1252 1253
    {
      u->master= master;
1254
      last= (SELECT_LEX_UNIT**)&(u->next);
1255
    }
1256 1257 1258 1259 1260 1261 1262 1263
    if (last)
    {
      (*units_last)= sl->first_inner_unit();
      units_last= last;
    }
  }
  if (units)
  {
1264
    // include brought up levels in place of current
1265 1266
    (*prev)= units;
    (*units_last)= (SELECT_LEX_UNIT*)next;
1267 1268 1269
    if (next)
      next->prev= (SELECT_LEX_NODE**)units_last;
    units->prev= prev;
1270 1271
  }
  else
1272 1273
  {
    // exclude currect unit from list of nodes
1274
    (*prev)= next;
1275 1276 1277
    if (next)
      next->prev= prev;
  }
1278 1279
}

1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290

/*
  Exclude subtree of current unit from tree of SELECTs

  SYNOPSYS
    st_select_lex_unit::exclude_tree()
*/
void st_select_lex_unit::exclude_tree()
{
  for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
  {
1291
    // unlink current level from global SELECTs list
1292 1293 1294
    if (sl->link_prev && (*sl->link_prev= sl->link_next))
      sl->link_next->link_prev= sl->link_prev;

1295
    // unlink underlay levels
1296 1297 1298 1299 1300
    for (SELECT_LEX_UNIT *u= sl->first_inner_unit(); u; u= u->next_unit())
    {
      u->exclude_level();
    }
  }
1301
  // exclude currect unit from list of nodes
1302
  (*prev)= next;
1303 1304
  if (next)
    next->prev= prev;
1305 1306 1307
}


1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319
/*
  st_select_lex_node::mark_as_dependent mark all st_select_lex struct from 
  this to 'last' as dependent

  SYNOPSIS
    last - pointer to last st_select_lex struct, before wich all 
           st_select_lex have to be marked as dependent

  NOTE
    'last' should be reachable from this st_select_lex_node
*/

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1320
void st_select_lex::mark_as_dependent(SELECT_LEX *last)
1321 1322 1323 1324 1325
{
  /*
    Mark all selects from resolved to 1 before select where was
    found table as depended (of select where was found table)
  */
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1326
  for (SELECT_LEX *s= this;
1327
       s && s != last;
1328
       s= s->outer_select())
1329
    if (!(s->uncacheable & UNCACHEABLE_DEPENDENT))
1330 1331
    {
      // Select is dependent of outer select
1332
      s->uncacheable|= UNCACHEABLE_DEPENDENT;
1333
      SELECT_LEX_UNIT *munit= s->master_unit();
1334
      munit->uncacheable|= UNCACHEABLE_DEPENDENT;
1335 1336 1337
    }
}

1338 1339 1340 1341 1342 1343 1344
bool st_select_lex_node::set_braces(bool value)      { return 1; }
bool st_select_lex_node::inc_in_sum_expr()           { return 1; }
uint st_select_lex_node::get_in_sum_expr()           { return 0; }
TABLE_LIST* st_select_lex_node::get_table_list()     { return 0; }
List<Item>* st_select_lex_node::get_item_list()      { return 0; }
List<String>* st_select_lex_node::get_use_index()    { return 0; }
List<String>* st_select_lex_node::get_ignore_index() { return 0; }
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1345
TABLE_LIST *st_select_lex_node::add_table_to_list(THD *thd, Table_ident *table,
1346
						  LEX_STRING *alias,
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1347
						  ulong table_join_options,
1348 1349
						  thr_lock_type flags,
						  List<String> *use_index,
igor@rurik.mysql.com's avatar
igor@rurik.mysql.com committed
1350 1351
						  List<String> *ignore_index,
                                                  LEX_STRING *option)
1352 1353 1354
{
  return 0;
}
1355 1356 1357 1358 1359 1360 1361 1362
ulong st_select_lex_node::get_table_join_options()
{
  return 0;
}

/*
  prohibit using LIMIT clause
*/
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1363
bool st_select_lex::test_limit()
1364 1365 1366 1367
{
  if (select_limit != HA_POS_ERROR)
  {
    my_error(ER_NOT_SUPPORTED_YET, MYF(0),
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1368
             "LIMIT & IN/ALL/ANY/SOME subquery");
1369 1370 1371 1372 1373 1374 1375 1376
    return(1);
  }
  // We need only 1 row to determinate existence
  select_limit= 1;
  // no sense in ORDER BY without LIMIT
  order_list.empty();
  return(0);
}
1377

1378

1379 1380 1381 1382 1383
st_select_lex_unit* st_select_lex_unit::master_unit()
{
    return this;
}

1384

1385 1386 1387 1388 1389
st_select_lex* st_select_lex_unit::outer_select()
{
  return (st_select_lex*) master;
}

1390

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1391
bool st_select_lex::add_order_to_list(THD *thd, Item *item, bool asc)
1392
{
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1393
  return add_to_list(thd, order_list, item, asc);
1394
}
1395

1396

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1397
bool st_select_lex::add_item_to_list(THD *thd, Item *item)
1398
{
1399 1400 1401
  DBUG_ENTER("st_select_lex::add_item_to_list");
  DBUG_PRINT("info", ("Item: %p", item));
  DBUG_RETURN(item_list.push_back(item));
1402 1403
}

1404

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1405
bool st_select_lex::add_group_to_list(THD *thd, Item *item, bool asc)
1406
{
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1407
  return add_to_list(thd, group_list, item, asc);
1408 1409
}

1410

1411 1412 1413 1414 1415
bool st_select_lex::add_ftfunc_to_list(Item_func_match *func)
{
  return !func || ftfunc_list->push_back(func); // end of memory?
}

1416

1417 1418 1419 1420 1421
st_select_lex_unit* st_select_lex::master_unit()
{
  return (st_select_lex_unit*) master;
}

1422

1423 1424 1425 1426 1427
st_select_lex* st_select_lex::outer_select()
{
  return (st_select_lex*) master->get_master();
}

1428

1429 1430 1431 1432 1433 1434
bool st_select_lex::set_braces(bool value)
{
  braces= value;
  return 0; 
}

1435

1436 1437 1438 1439 1440 1441
bool st_select_lex::inc_in_sum_expr()
{
  in_sum_expr++;
  return 0;
}

1442

1443 1444 1445 1446 1447
uint st_select_lex::get_in_sum_expr()
{
  return in_sum_expr;
}

1448

1449 1450 1451 1452 1453 1454 1455 1456 1457 1458
TABLE_LIST* st_select_lex::get_table_list()
{
  return (TABLE_LIST*) table_list.first;
}

List<Item>* st_select_lex::get_item_list()
{
  return &item_list;
}

1459

1460 1461 1462 1463 1464
List<String>* st_select_lex::get_use_index()
{
  return use_index_ptr;
}

1465

1466 1467 1468 1469 1470
List<String>* st_select_lex::get_ignore_index()
{
  return ignore_index_ptr;
}

1471

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1472 1473 1474 1475 1476
ulong st_select_lex::get_table_join_options()
{
  return table_join_options;
}

1477

bell@laptop.sanja.is.com.ua's avatar
bell@laptop.sanja.is.com.ua committed
1478 1479 1480 1481
bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num)
{
  if (ref_pointer_array)
    return 0;
1482 1483 1484 1485 1486

  /*
    We have to create array in prepared statement memory if it is
    prepared statement
  */
1487
  Item_arena *arena= thd->current_arena;
bell@laptop.sanja.is.com.ua's avatar
bell@laptop.sanja.is.com.ua committed
1488
  return (ref_pointer_array= 
1489 1490 1491 1492
          (Item **)arena->alloc(sizeof(Item*) *
                                (item_list.elements +
                                 select_n_having_items +
                                 order_group_num)* 5)) == 0;
bell@laptop.sanja.is.com.ua's avatar
bell@laptop.sanja.is.com.ua committed
1493 1494
}

1495

1496 1497 1498 1499 1500 1501
void st_select_lex_unit::print(String *str)
{
  for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
  {
    if (sl != first_select())
    {
1502
      str->append(" union ", 7);
1503
      if (!union_distinct)
1504
	str->append("all ", 4);
1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515
    }
    if (sl->braces)
      str->append('(');
    sl->print(thd, str);
    if (sl->braces)
      str->append(')');
  }
  if (fake_select_lex == global_parameters)
  {
    if (fake_select_lex->order_list.elements)
    {
1516
      str->append(" order by ", 10);
1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529
      fake_select_lex->print_order(str,
				   (ORDER *) fake_select_lex->
				   order_list.first);
    }
    fake_select_lex->print_limit(thd, str);
  }
}


void st_select_lex::print_order(String *str, ORDER *order)
{
  for (; order; order= order->next)
  {
1530 1531 1532 1533 1534 1535 1536 1537
    if (order->counter_used)
    {
      char buffer[20];
      my_snprintf(buffer, 20, "%u", order->counter);
      str->append(buffer);
    }
    else
      (*order->item)->print(str);
1538
    if (!order->asc)
1539
      str->append(" desc", 5);
1540 1541 1542 1543 1544
    if (order->next)
      str->append(',');
  }
}
 
1545

1546 1547
void st_select_lex::print_limit(THD *thd, String *str)
{
1548 1549 1550
  SELECT_LEX_UNIT *unit= master_unit();
  Item_subselect *item= unit->item;
  if (item && unit->global_parameters == this &&
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1551 1552 1553 1554 1555 1556 1557 1558
      (item->substype() == Item_subselect::EXISTS_SUBS ||
       item->substype() == Item_subselect::IN_SUBS ||
       item->substype() == Item_subselect::ALL_SUBS))
  {
    DBUG_ASSERT(select_limit == 1L && offset_limit == 0L);
    return;
  }

1559
  if (explicit_limit)
1560
  {
1561 1562 1563 1564 1565 1566
    str->append(" limit ", 7);
    char buff[20];
    // latin1 is good enough for numbers
    String st(buff, sizeof(buff),  &my_charset_latin1);
    st.set((ulonglong)select_limit, &my_charset_latin1);
    str->append(st);
1567 1568 1569
    if (offset_limit)
    {
      str->append(',');
1570 1571
      st.set((ulonglong)select_limit, &my_charset_latin1);
      str->append(st);
1572 1573 1574 1575
    }
  }
}

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1576 1577

/*
1578
  Check whether the merging algorithm can be used on this VIEW
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1579 1580 1581 1582

  SYNOPSIS
    st_lex::can_be_merged()

1583
  DESCRIPTION
1584 1585 1586
    We can apply merge algorithm if it is single SELECT view  with
    subqueries only in WHERE clause (we do not count SELECTs of underlying
    views, and second level subqueries) and we have not grpouping, ordering,
1587 1588 1589
    HAVING clause, aggregate functions, DISTINCT clause, LIMIT clause and
    several underlying tables.

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1590 1591 1592 1593 1594 1595 1596 1597 1598 1599
  RETURN
    FALSE - only temporary table algorithm can be used
    TRUE  - merge algorithm can be used
*/

bool st_lex::can_be_merged()
{
  // TODO: do not forget implement case when select_lex.table_list.elements==0

  /* find non VIEW subqueries/unions */
1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616
  bool selects_allow_merge= select_lex.next_select() == 0;
  if (selects_allow_merge)
  {
    for (SELECT_LEX_UNIT *unit= select_lex.first_inner_unit();
         unit;
         unit= unit->next_unit())
    {
      if (unit->first_select()->parent_lex == this &&
          (unit->item == 0 || unit->item->place() != IN_WHERE))
      {
        selects_allow_merge= 0;
        break;
      }
    }
  }

  return (selects_allow_merge &&
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1617 1618 1619
	  select_lex.order_list.elements == 0 &&
	  select_lex.group_list.elements == 0 &&
	  select_lex.having == 0 &&
1620
          select_lex.with_sum_func == 0 &&
1621
	  select_lex.table_list.elements >= 1 &&
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1622 1623 1624 1625
	  !(select_lex.options & SELECT_DISTINCT) &&
          select_lex.select_limit == HA_POS_ERROR);
}

1626

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1627
/*
1628
  check if command can use VIEW with MERGE algorithm (for top VIEWs)
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1629 1630 1631 1632

  SYNOPSIS
    st_lex::can_use_merged()

1633 1634 1635 1636 1637
  DESCRIPTION
    Only listed here commands can use merge algorithm in top level
    SELECT_LEX (for subqueries will be used merge algorithm if
    st_lex::can_not_use_merged() is not TRUE).

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656
  RETURN
    FALSE - command can't use merged VIEWs
    TRUE  - VIEWs with MERGE algorithms can be used
*/

bool st_lex::can_use_merged()
{
  switch (sql_command)
  {
  case SQLCOM_SELECT:
  case SQLCOM_CREATE_TABLE:
  case SQLCOM_UPDATE:
  case SQLCOM_UPDATE_MULTI:
  case SQLCOM_DELETE:
  case SQLCOM_DELETE_MULTI:
  case SQLCOM_INSERT:
  case SQLCOM_INSERT_SELECT:
  case SQLCOM_REPLACE:
  case SQLCOM_REPLACE_SELECT:
1657
  case SQLCOM_LOAD:
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1658 1659 1660 1661 1662 1663
    return TRUE;
  default:
    return FALSE;
  }
}

1664
/*
1665
  Check if command can't use merged views in any part of command
1666 1667 1668 1669

  SYNOPSIS
    st_lex::can_not_use_merged()

1670 1671 1672 1673
  DESCRIPTION
    Temporary table algorithm will be used on all SELECT levels for queries
    listed here (see also st_lex::can_use_merged()).

1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684
  RETURN
    FALSE - command can't use merged VIEWs
    TRUE  - VIEWs with MERGE algorithms can be used
*/

bool st_lex::can_not_use_merged()
{
  switch (sql_command)
  {
  case SQLCOM_CREATE_VIEW:
  case SQLCOM_SHOW_CREATE:
1685 1686 1687 1688 1689 1690
  /*
    SQLCOM_SHOW_FIELDS is necessary to make 
    information schema tables working correctly with views.
    see get_schema_tables_result function
  */
  case SQLCOM_SHOW_FIELDS:
1691 1692 1693 1694 1695 1696
    return TRUE;
  default:
    return FALSE;
  }
}

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1697 1698 1699 1700 1701 1702 1703 1704 1705 1706
/*
  Detect that we need only table structure of derived table/view

  SYNOPSIS
    only_view_structure()

  RETURN
    TRUE yes, we need only structure
    FALSE no, we need data
*/
1707

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725
bool st_lex::only_view_structure()
{
  switch(sql_command)
  {
  case SQLCOM_SHOW_CREATE:
  case SQLCOM_SHOW_TABLES:
  case SQLCOM_SHOW_FIELDS:
  case SQLCOM_REVOKE_ALL:
  case SQLCOM_REVOKE:
  case SQLCOM_GRANT:
  case SQLCOM_CREATE_VIEW:
    return TRUE;
  default:
    return FALSE;
  }
}


1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751
/*
  Should Items_ident be printed correctly

  SYNOPSIS
    need_correct_ident()

  RETURN
    TRUE yes, we need only structure
    FALSE no, we need data
*/


bool st_lex::need_correct_ident()
{
  switch(sql_command)
  {
  case SQLCOM_SHOW_CREATE:
  case SQLCOM_SHOW_TABLES:
  case SQLCOM_CREATE_VIEW:
    return TRUE;
  default:
    return FALSE;
  }
}


bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1752 1753 1754 1755 1756 1757 1758 1759
/*
  initialize limit counters

  SYNOPSIS
    st_select_lex_unit::set_limit()
    values	- SELECT_LEX with initial values for counters
    sl		- SELECT_LEX for options set
*/
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1760

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1761
void st_select_lex_unit::set_limit(SELECT_LEX *values,
1762 1763
				   SELECT_LEX *sl)
{
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1764 1765 1766
  offset_limit_cnt= values->offset_limit;
  select_limit_cnt= values->select_limit+values->offset_limit;
  if (select_limit_cnt < values->select_limit)
1767 1768 1769
    select_limit_cnt= HA_POS_ERROR;		// no limit
}

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1770

1771
/*
1772 1773
  Unlink the first table from the global table list and the first table from
  outer select (lex->select_lex) local list
1774 1775 1776

  SYNOPSIS
    unlink_first_table()
1777
    link_to_local	Set to 1 if caller should link this table to local list
1778

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1779
  NOTES
1780 1781
    We assume that first tables in both lists is the same table or the local
    list is empty.
1782 1783

  RETURN
1784
    0	If 'query_tables' == 0
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1785
    unlinked table
1786
      In this case link_to_local is set.
1787

1788
*/
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1789
TABLE_LIST *st_lex::unlink_first_table(bool *link_to_local)
1790
{
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1791 1792 1793 1794 1795 1796 1797 1798
  TABLE_LIST *first;
  if ((first= query_tables))
  {
    /*
      Exclude from global table list
    */
    if ((query_tables= query_tables->next_global))
      query_tables->prev_global= &query_tables;
1799 1800
    else
      query_tables_last= &query_tables;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811
    first->next_global= 0;

    /*
      and from local list if it is not empty
    */
    if ((*link_to_local= test(select_lex.table_list.first)))
    {
      select_lex.table_list.first= (byte*) first->next_local;
      select_lex.table_list.elements--;	//safety
      first->next_local= 0;
      /*
1812 1813
        Ensure that the global list has the same first table as the local
        list.
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829
      */
      first_lists_tables_same();
    }
  }
  return first;
}


/*
  Bring first local table of first most outer select to first place in global
  table list

  SYNOPSYS
     st_lex::first_lists_tables_same()

  NOTES
1830 1831 1832 1833 1834 1835
    In many cases (for example, usual INSERT/DELETE/...) the first table of
    main SELECT_LEX have special meaning => check that it is the first table
    in global list and re-link to be first in the global list if it is
    necessary.  We need such re-linking only for queries with sub-queries in
    the select list, as only in this case tables of sub-queries will go to
    the global list first.
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1836 1837 1838 1839 1840 1841 1842
*/

void st_lex::first_lists_tables_same()
{
  TABLE_LIST *first_table= (TABLE_LIST*) select_lex.table_list.first;
  if (query_tables != first_table && first_table != 0)
  {
1843
    TABLE_LIST *next;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1844 1845
    if (query_tables_last == &first_table->next_global)
      query_tables_last= first_table->prev_global;
1846

1847
    if ((next= *first_table->prev_global= first_table->next_global))
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1848 1849 1850 1851
      next->prev_global= first_table->prev_global;
    /* include in new place */
    first_table->next_global= query_tables;
    /*
1852 1853 1854
       We are sure that query_tables is not 0, because first_table was not
       first table in the global list => we can use
       query_tables->prev_global without check of query_tables
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1855 1856 1857 1858 1859
    */
    query_tables->prev_global= &first_table->next_global;
    first_table->prev_global= &query_tables;
    query_tables= first_table;
  }
1860 1861
}

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1862

1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887
/*
  Add implicitly used time zone description tables to global table list
  (if needed).

  SYNOPSYS
    st_lex::add_time_zone_tables_to_query_tables()
      thd - pointer to current thread context

  RETURN VALUE
   TRUE  - error
   FALSE - success
*/

bool st_lex::add_time_zone_tables_to_query_tables(THD *thd)
{
  /* We should not add these tables twice */
  if (!time_zone_tables_used)
  {
    time_zone_tables_used= my_tz_get_table_list(thd, &query_tables_last);
    if (time_zone_tables_used == &fake_time_zone_tables_list)
      return TRUE;
  }
  return FALSE;
}

1888
/*
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1889
  Link table back that was unlinked with unlink_first_table()
1890 1891 1892

  SYNOPSIS
    link_first_table_back()
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1893
    link_to_local	do we need link this table to local
1894 1895 1896 1897

  RETURN
    global list
*/
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1898 1899 1900

void st_lex::link_first_table_back(TABLE_LIST *first,
				   bool link_to_local)
1901
{
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1902
  if (first)
1903
  {
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1904 1905
    if ((first->next_global= query_tables))
      query_tables->prev_global= &first->next_global;
1906 1907
    else
      query_tables_last= &first->next_global;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930
    query_tables= first;

    if (link_to_local)
    {
      first->next_local= (TABLE_LIST*) select_lex.table_list.first;
      select_lex.table_list.first= (byte*) first;
      select_lex.table_list.elements++;	//safety
    }
  }
}


/*
  fix some structures at the end of preparation

  SYNOPSIS
    st_select_lex::fix_prepare_information
    thd   thread handler
    conds pointer on conditions which will be used for execution statement
*/

void st_select_lex::fix_prepare_information(THD *thd, Item **conds)
{
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1931
  if (!thd->current_arena->is_conventional() && first_execution)
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1932 1933
  {
    first_execution= 0;
1934
    prep_where= where;
1935 1936 1937
  }
}

1938
/*
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1939
  There are st_select_lex::add_table_to_list &
1940
  st_select_lex::set_lock_for_tables are in sql_parse.cc
1941

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1942
  st_select_lex::print is in sql_select.cc
1943 1944

  st_select_lex_unit::prepare, st_select_lex_unit::exec,
1945 1946
  st_select_lex_unit::cleanup, st_select_lex_unit::reinit_exec_mechanism,
  st_select_lex_unit::change_result
1947
  are in sql_union.cc
1948
*/