sql_lex.cc 37.4 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 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 97 98 99 100
   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>

LEX_STRING tmp_table_alias= {(char*) "tmp-table",8};

/* 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)

#if MYSQL_VERSION_ID < 32300
#define FLOAT_NUM	REAL_NUM
#endif

pthread_key(LEX*,THR_LEX);

#define TOCK_NAME_LENGTH 24

/*
  The following is based on the latin1 character set, and is only
  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
};

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;
}


101 102 103 104 105 106
/*
  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)
*/

bk@work.mysql.com's avatar
bk@work.mysql.com committed
107 108 109
LEX *lex_start(THD *thd, uchar *buf,uint length)
{
  LEX *lex= &thd->lex;
110
  lex->thd= thd;
111
  lex->next_state=MY_LEX_START;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
112 113
  lex->end_of_query=(lex->ptr=buf)+length;
  lex->yylineno = 1;
114 115
  lex->select_lex.parsing_place= SELECT_LEX_NODE::NO_MATTER;
  lex->in_comment=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
116
  lex->length=0;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
117 118
  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
119
  lex->select_lex.ftfunc_list_alloc.empty();
120
  lex->select_lex.ftfunc_list= &lex->select_lex.ftfunc_list_alloc;
121
  lex->current_select= &lex->select_lex;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
122
  lex->yacc_yyss=lex->yacc_yyvs=0;
123
  lex->ignore_space=test(thd->variables.sql_mode & MODE_IGNORE_SPACE);
124
  lex->sql_command=SQLCOM_END;
125
  lex->duplicates= DUP_ERROR;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
126 127 128 129 130
  return lex;
}

void lex_end(LEX *lex)
{
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
131
  lex->select_lex.expr_list.delete_elements();	// If error when parsing sql-varargs
bk@work.mysql.com's avatar
bk@work.mysql.com committed
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
  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;
    return symbol->tok;
  }
#ifdef HAVE_DLOPEN
  udf_func *udf;
  if (function && using_udf_functions && (udf=find_udf((char*) tok, len)))
  {
153
    lex->safe_to_cache_query=0;
154
    lex->yylval->udf=udf;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
155 156 157 158 159 160 161
    switch (udf->returns) {
    case STRING_RESULT:
      return (udf->type == UDFTYPE_FUNCTION) ? UDF_CHAR_FUNC : UDA_CHAR_SUM;
    case REAL_RESULT:
      return (udf->type == UDFTYPE_FUNCTION) ? UDF_FLOAT_FUNC : UDA_FLOAT_SUM;
    case INT_RESULT:
      return (udf->type == UDFTYPE_FUNCTION) ? UDF_INT_FUNC : UDA_INT_SUM;
162
    case ROW_RESULT:
163
    default:
164 165 166
      // This case should never be choosen
      DBUG_ASSERT(0);
      return 0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
167 168 169 170 171 172 173 174 175
    }
  }
#endif
  return 0;
}


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

176
static LEX_STRING get_token(LEX *lex,uint length)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
177 178 179 180
{
  LEX_STRING tmp;
  yyUnget();			// ptr points now after last token char
  tmp.length=lex->yytoklen=length;
181
  tmp.str=(char*) lex->thd->strmake((char*) lex->tok_start,tmp.length);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
182 183 184
  return tmp;
}

185 186 187 188 189 190 191
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);
192 193 194
  for (from= (byte*) lex->tok_start, to= (byte*) tmp.str, end= to+length ;
       to != end ;
       )
195 196 197 198 199 200 201 202 203 204 205 206 207
  {
    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
208 209 210 211 212

static char *get_text(LEX *lex)
{
  reg1 uchar c,sep;
  uint found_escape=0;
213
  CHARSET_INFO *cs= lex->thd->charset();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
214 215 216 217 218 219 220 221

  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
222 223
    if (use_mb(cs) &&
        (l = my_ismbchar(cs,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
                         (const char *)lex->ptr-1,
                         (const char *)lex->end_of_query))) {
	lex->ptr += l-1;
	continue;
    }
#endif
    if (c == '\\')
    {					// Escaped character
      found_escape=1;
      if (lex->ptr == lex->end_of_query)
	return 0;
      yySkip();
    }
    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;
252
      if (!(start=(uchar*) lex->thd->alloc((uint) (end-str)+1)))
253
	return (char*) "";		// Sql_alloc has set error flag
bk@work.mysql.com's avatar
bk@work.mysql.com committed
254 255 256 257 258 259 260 261 262 263 264 265 266
      if (!found_escape)
      {
	lex->yytoklen=(uint) (end-str);
	memcpy(start,str,lex->yytoklen);
	start[lex->yytoklen]=0;
      }
      else
      {
	uchar *to;
	for (to=start ; str != end ; str++)
	{
#ifdef USE_MB
	  int l;
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
267 268
	  if (use_mb(cs) &&
              (l = my_ismbchar(cs,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
                               (const char *)str, (const char *)end))) {
	      while (l--)
		  *to++ = *str++;
	      str--;
	      continue;
	  }
#endif
	  if (*str == '\\' && str+1 != end)
	  {
	    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:
	      *to++ = *str;
	      break;
	    }
	  }
	  else if (*str == sep)
	    *to++= *str++;		// Two ' or "
	  else
	    *to++ = *str;

	}
	*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;
337 338
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
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 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 382 383 384 385 386 387 388 389 390 391 392 393

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)
      return REAL_NUM;
    else
    {
      cmp=signed_longlong_str+1;
      smaller=LONG_NUM;				// If <= signed_longlong_str
      bigger=REAL_NUM;
    }
  }
  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)
394 395 396 397 398 399 400
    {
      if (length > unsigned_longlong_len)
	return REAL_NUM;
      cmp=unsigned_longlong_str;
      smaller=ULONGLONG_NUM;
      bigger=REAL_NUM;
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
401 402 403 404
    else
    {
      cmp=longlong_str;
      smaller=LONG_NUM;
405
      bigger= ULONGLONG_NUM;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
406 407 408 409 410 411 412 413
    }
  }
  while (*cmp && *cmp++ == *str++) ;
  return ((uchar) str[-1] <= (uchar) cmp[-1]) ? smaller : bigger;
}


// yylex remember the following states from the following yylex()
414 415
// MY_LEX_EOQ ; found end of query
// MY_LEX_OPERATOR_OR_IDENT ; last state was an ident, text or number
bk@work.mysql.com's avatar
bk@work.mysql.com committed
416 417
// 			     (which can't be followed by a signed number)

418
int yylex(void *arg, void *yythd)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
419 420 421 422
{
  reg1	uchar c;
  int	tokval;
  uint length;
423
  enum my_lex_states state,prev_state;
424
  LEX	*lex= &(((THD *)yythd)->lex);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
425
  YYSTYPE *yylval=(YYSTYPE*) arg;
426
  CHARSET_INFO *cs= ((THD *) yythd)->charset();
427 428
  uchar *state_map= cs->state_map;
  uchar *ident_map= cs->ident_map;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
429 430 431 432

  lex->yylval=yylval;			// The global state
  lex->tok_start=lex->tok_end=lex->ptr;
  prev_state=state=lex->next_state;
433
  lex->next_state=MY_LEX_OPERATOR_OR_IDENT;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
434 435 436
  LINT_INIT(c);
  for (;;)
  {
437
    switch (state) {
438 439
    case MY_LEX_OPERATOR_OR_IDENT:	// Next is operator or keyword
    case MY_LEX_START:			// Start of token
440
      // Skip startspace
441
      for (c=yyGet() ; (state_map[c] == MY_LEX_SKIP) ; c= yyGet())
bk@work.mysql.com's avatar
bk@work.mysql.com committed
442 443 444 445 446
      {
	if (c == '\n')
	  lex->yylineno++;
      }
      lex->tok_start=lex->ptr-1;	// Start of real token
447
      state= (enum my_lex_states) state_map[c];
bk@work.mysql.com's avatar
bk@work.mysql.com committed
448
      break;
449
    case MY_LEX_ESCAPE:
bk@work.mysql.com's avatar
bk@work.mysql.com committed
450 451 452 453 454 455
      if (yyGet() == 'N')
      {					// Allow \N as shortcut for NULL
	yylval->lex_str.str=(char*) "\\N";
	yylval->lex_str.length=2;
	return NULL_SYM;
      }
456 457
    case MY_LEX_CHAR:			// Unknown or single char token
    case MY_LEX_SKIP:			// This should not happen
458 459 460 461 462 463 464
      if (c == '-' && yyPeek() == '-' &&
          (my_isspace(cs,yyPeek2()) || 
           my_iscntrl(cs,yyPeek2())))
      {
        state=MY_LEX_COMMENT;
        break;
      }
465
      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
466 467 468
      yylval->lex_str.length=1;
      c=yyGet();
      if (c != ')')
469
	lex->next_state= MY_LEX_START;	// Allow signed numbers
bk@work.mysql.com's avatar
bk@work.mysql.com committed
470 471 472 473
      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
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
    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);

494
    case MY_LEX_IDENT_OR_HEX:
495
      if (yyPeek() == '\'')
496
      {					// Found x'hex-number'
497
	state= MY_LEX_HEX_NUMBER;
498 499
	break;
      }
500
      /* Fall through */
501 502
    case MY_LEX_IDENT_OR_BIN:		// TODO: Add binary string handling
    case MY_LEX_IDENT:
bk@work.mysql.com's avatar
bk@work.mysql.com committed
503
#if defined(USE_MB) && defined(USE_MB_IDENT)
504
      if (use_mb(cs))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
505
      {
506
        if (my_mbcharlen(cs, yyGetLast()) > 1)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
507
        {
508
          int l = my_ismbchar(cs,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
509 510 511
                              (const char *)lex->ptr-1,
                              (const char *)lex->end_of_query);
          if (l == 0) {
512
            state = MY_LEX_CHAR;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
513 514 515 516
            continue;
          }
          lex->ptr += l - 1;
        }
517
        while (ident_map[c=yyGet()])
bk@work.mysql.com's avatar
bk@work.mysql.com committed
518
        {
519
          if (my_mbcharlen(cs, c) > 1)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
520 521
          {
            int l;
522
            if ((l = my_ismbchar(cs,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
523 524 525 526 527 528 529 530 531
                              (const char *)lex->ptr-1,
                              (const char *)lex->end_of_query)) == 0)
              break;
            lex->ptr += l-1;
          }
        }
      }
      else
#endif
532
        while (ident_map[c=yyGet()]) ;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
533 534 535
      length= (uint) (lex->ptr - lex->tok_start)-1;
      if (lex->ignore_space)
      {
536
	for (; state_map[c] == MY_LEX_SKIP ; c= yyGet());
bk@work.mysql.com's avatar
bk@work.mysql.com committed
537
      }
538
      if (c == '.' && ident_map[yyPeek()])
539
	lex->next_state=MY_LEX_IDENT_SEP;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
540 541 542 543 544
      else
      {					// '(' must follow directly if function
	yyUnget();
	if ((tokval = find_keyword(lex,length,c == '(')))
	{
545
	  lex->next_state= MY_LEX_START;	// Allow signed numbers
bk@work.mysql.com's avatar
bk@work.mysql.com committed
546 547 548 549 550
	  return(tokval);		// Was keyword
	}
	yySkip();			// next state does a unget
      }
      yylval->lex_str=get_token(lex,length);
551 552 553 554

      /* 
         Note: "SELECT _bla AS 'alias'"
         _bla should be considered as a IDENT if charset haven't been found.
555
         So we don't use MYF(MY_WME) with get_charset_by_csname to avoid 
556 557 558 559
         producing an error.
      */

      if ((yylval->lex_str.str[0]=='_') && 
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
560 561
          (lex->charset=get_charset_by_csname(yylval->lex_str.str+1,
					      MY_CS_PRIMARY,MYF(0))))
562 563 564
        return(UNDERSCORE_CHARSET);
      else
        return(IDENT);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
565

566
    case MY_LEX_IDENT_SEP:		// Found ident and now '.'
bk@work.mysql.com's avatar
bk@work.mysql.com committed
567 568 569
      yylval->lex_str.str=(char*) lex->ptr;
      yylval->lex_str.length=1;
      c=yyGet();			// should be '.'
570 571 572
      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
573 574
      return((int) c);

575 576
    case MY_LEX_NUMBER_IDENT:		// number or ident which num-start
      while (my_isdigit(cs,(c = yyGet()))) ;
577
      if (!ident_map[c])
bk@work.mysql.com's avatar
bk@work.mysql.com committed
578
      {					// Can't be identifier
579
	state=MY_LEX_INT_OR_REAL;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
580 581 582 583
	break;
      }
      if (c == 'e' || c == 'E')
      {
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
584
	// The following test is written this way to allow numbers of type 1e1
585
	if (my_isdigit(cs,yyPeek()) || 
586
            (c=(yyGet())) == '+' || c == '-')
bk@work.mysql.com's avatar
bk@work.mysql.com committed
587
	{				// Allow 1E+10
588
	  if (my_isdigit(cs,yyPeek()))	// Number must have digit after sign
bk@work.mysql.com's avatar
bk@work.mysql.com committed
589 590
	  {
	    yySkip();
591
	    while (my_isdigit(cs,yyGet())) ;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
592 593 594 595 596 597 598 599 600
	    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
601
	while (my_isxdigit(cs,(c = yyGet()))) ;
602
	if ((lex->ptr - lex->tok_start) >= 4 && !ident_map[c])
bk@work.mysql.com's avatar
bk@work.mysql.com committed
603 604
	{
	  yylval->lex_str=get_token(lex,yyLength());
605
	  yylval->lex_str.str+=2;		// Skip 0x
bk@work.mysql.com's avatar
bk@work.mysql.com committed
606 607 608 609 610 611 612
	  yylval->lex_str.length-=2;
	  lex->yytoklen-=2;
	  return (HEX_NUM);
	}
	yyUnget();
      }
      // fall through
613
    case MY_LEX_IDENT_START:			// We come here after '.'
bk@work.mysql.com's avatar
bk@work.mysql.com committed
614
#if defined(USE_MB) && defined(USE_MB_IDENT)
615
      if (use_mb(cs))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
616
      {
617
        if (my_mbcharlen(cs, yyGetLast()) > 1)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
618
        {
619
          int l = my_ismbchar(cs,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
620 621 622 623
                              (const char *)lex->ptr-1,
                              (const char *)lex->end_of_query);
          if (l == 0)
          {
624
            state = MY_LEX_CHAR;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
625 626 627 628
            continue;
          }
          lex->ptr += l - 1;
        }
629
        while (ident_map[c=yyGet()])
bk@work.mysql.com's avatar
bk@work.mysql.com committed
630
        {
631
          if (my_mbcharlen(cs, c) > 1)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
632 633
          {
            int l;
634
            if ((l = my_ismbchar(cs,
bk@work.mysql.com's avatar
bk@work.mysql.com committed
635 636 637 638 639 640 641 642 643
                                 (const char *)lex->ptr-1,
                                 (const char *)lex->end_of_query)) == 0)
              break;
            lex->ptr += l-1;
          }
        }
      }
      else
#endif
644
        while (ident_map[c = yyGet()]) ;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
645

646
      if (c == '.' && ident_map[yyPeek()])
647
	lex->next_state=MY_LEX_IDENT_SEP;// Next is '.'
bk@work.mysql.com's avatar
bk@work.mysql.com committed
648 649
      // fall through

650
    case MY_LEX_FOUND_IDENT:		// Complete ident
bk@work.mysql.com's avatar
bk@work.mysql.com committed
651 652 653
      yylval->lex_str=get_token(lex,yyLength());
      return(IDENT);

654
    case MY_LEX_USER_VARIABLE_DELIMITER:
655 656
    {
      char delim= c;				// Used char
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
657
      lex->tok_start=lex->ptr;			// Skip first `
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
658
#ifdef USE_MB
659
      if (use_mb(cs))
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
660
      {
661
	while ((c=yyGet()) && c != delim && c != (uchar) NAMES_SEP_CHAR)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
662
	{
663
          if (my_mbcharlen(cs, c) > 1)
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
664 665
          {
            int l;
666
            if ((l = my_ismbchar(cs,
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
667 668 669 670 671 672
                                 (const char *)lex->ptr-1,
                                 (const char *)lex->end_of_query)) == 0)
              break;
            lex->ptr += l-1;
          }
        }
673
	yylval->lex_str=get_token(lex,yyLength());
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
674 675 676 677
      }
      else
#endif
      {
678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697
	uint double_quotes= 0;
	char quote_char= c;
	while ((c=yyGet()))
	{
	  if (c == quote_char)
	  {
	    if (yyPeek() != quote_char)
	      break;
	    c=yyGet();
	    double_quotes++;
	    continue;
	  }
	  if (c == (uchar) NAMES_SEP_CHAR)
	    break;
	}
	if (double_quotes)
	  yylval->lex_str=get_quoted_token(lex,yyLength() - double_quotes,
					   quote_char);
	else
	  yylval->lex_str=get_token(lex,yyLength());
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
698
      }
699
      if (c == delim)
700
	yySkip();			// Skip end `
701
      lex->next_state= MY_LEX_START;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
702
      return(IDENT);
703
    }
704
    case MY_LEX_INT_OR_REAL:		// Compleat int or incompleat real
bk@work.mysql.com's avatar
bk@work.mysql.com committed
705 706 707 708 709 710
      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
711 712
    case MY_LEX_REAL:			// Incomplete real number
      while (my_isdigit(cs,c = yyGet())) ;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
713 714 715 716

      if (c == 'e' || c == 'E')
      {
	c = yyGet();
717
	if (c == '-' || c == '+')
718
	  c = yyGet();			// Skip sign
719
	if (!my_isdigit(cs,c))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
720
	{				// No digit after sign
721
	  state= MY_LEX_CHAR;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
722 723
	  break;
	}
724
	while (my_isdigit(cs,yyGet())) ;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
725 726 727 728 729 730
	yylval->lex_str=get_token(lex,yyLength());
	return(FLOAT_NUM);
      }
      yylval->lex_str=get_token(lex,yyLength());
      return(REAL_NUM);

731
    case MY_LEX_HEX_NUMBER:		// Found x'hexstring'
732
      yyGet();				// Skip '
733
      while (my_isxdigit(cs,(c = yyGet()))) ;
734 735 736 737 738 739 740 741 742 743 744 745
      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);

746 747 748
    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
749 750 751
	yySkip();
      if ((tokval = find_keyword(lex,(uint) (lex->ptr - lex->tok_start),0)))
      {
752
	lex->next_state= MY_LEX_START;	// Allow signed numbers
bk@work.mysql.com's avatar
bk@work.mysql.com committed
753 754
	return(tokval);
      }
755
      state = MY_LEX_CHAR;		// Something fishy found
bk@work.mysql.com's avatar
bk@work.mysql.com committed
756 757
      break;

758 759 760
    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
761 762
      {
	yySkip();
763
	if (state_map[yyPeek()] == MY_LEX_CMP_OP)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
764 765 766 767
	  yySkip();
      }
      if ((tokval = find_keyword(lex,(uint) (lex->ptr - lex->tok_start),0)))
      {
768
	lex->next_state= MY_LEX_START;	// Found long op
bk@work.mysql.com's avatar
bk@work.mysql.com committed
769 770
	return(tokval);
      }
771
      state = MY_LEX_CHAR;		// Something fishy found
bk@work.mysql.com's avatar
bk@work.mysql.com committed
772 773
      break;

774
    case MY_LEX_BOOL:
bk@work.mysql.com's avatar
bk@work.mysql.com committed
775 776
      if (c != yyPeek())
      {
777
	state=MY_LEX_CHAR;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
778 779 780 781
	break;
      }
      yySkip();
      tokval = find_keyword(lex,2,0);	// Is a bool operator
782
      lex->next_state= MY_LEX_START;	// Allow signed numbers
bk@work.mysql.com's avatar
bk@work.mysql.com committed
783 784
      return(tokval);

785
    case MY_LEX_STRING_OR_DELIMITER:
786 787
      if (((THD *) yythd)->variables.sql_mode & MODE_ANSI_QUOTES)
      {
788
	state= MY_LEX_USER_VARIABLE_DELIMITER;
789 790 791
	break;
      }
      /* " used for strings */
792
    case MY_LEX_STRING:			// Incomplete text string
bk@work.mysql.com's avatar
bk@work.mysql.com committed
793 794
      if (!(yylval->lex_str.str = get_text(lex)))
      {
795
	state= MY_LEX_CHAR;		// Read char by char
bk@work.mysql.com's avatar
bk@work.mysql.com committed
796 797 798 799 800
	break;
      }
      yylval->lex_str.length=lex->yytoklen;
      return(TEXT_STRING);

801
    case MY_LEX_COMMENT:			//  Comment
802
      lex->select_lex.options|= OPTION_FOUND_COMMENT;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
803 804
      while ((c = yyGet()) != '\n' && c) ;
      yyUnget();			// Safety against eof
805
      state = MY_LEX_START;		// Try again
bk@work.mysql.com's avatar
bk@work.mysql.com committed
806
      break;
807
    case MY_LEX_LONG_COMMENT:		/* Long C comment? */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
808 809
      if (yyPeek() != '*')
      {
810
	state=MY_LEX_CHAR;		// Probable division
bk@work.mysql.com's avatar
bk@work.mysql.com committed
811 812 813
	break;
      }
      yySkip();				// Skip '*'
814
      lex->select_lex.options|= OPTION_FOUND_COMMENT;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
815 816 817 818
      if (yyPeek() == '!')		// MySQL command in comment
      {
	ulong version=MYSQL_VERSION_ID;
	yySkip();
819 820
	state=MY_LEX_START;
	if (my_isdigit(cs,yyPeek()))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837
	{				// 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 '/'
838
      state = MY_LEX_START;		// Try again
bk@work.mysql.com's avatar
bk@work.mysql.com committed
839
      break;
840
    case MY_LEX_END_LONG_COMMENT:
bk@work.mysql.com's avatar
bk@work.mysql.com committed
841 842 843 844
      if (lex->in_comment && yyPeek() == '/')
      {
	yySkip();
	lex->in_comment=0;
845
	state=MY_LEX_START;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
846 847
      }
      else
848
	state=MY_LEX_CHAR;		// Return '*'
bk@work.mysql.com's avatar
bk@work.mysql.com committed
849
      break;
850
    case MY_LEX_SET_VAR:		// Check if ':='
bk@work.mysql.com's avatar
bk@work.mysql.com committed
851 852
      if (yyPeek() != '=')
      {
853
	state=MY_LEX_CHAR;		// Return ':'
bk@work.mysql.com's avatar
bk@work.mysql.com committed
854 855 856 857
	break;
      }
      yySkip();
      return (SET_VAR);
858
    case MY_LEX_COLON:			// optional line terminator
bk@work.mysql.com's avatar
bk@work.mysql.com committed
859 860
      if (yyPeek())
      {
861 862 863 864
        if (((THD *)yythd)->client_capabilities & CLIENT_MULTI_QUERIES)
        {
          lex->found_colon=(char*)lex->ptr;
          ((THD *)yythd)->server_status |= SERVER_MORE_RESULTS_EXISTS;
865
          lex->next_state=MY_LEX_END;
866 867 868
          return(END_OF_INPUT);
        }
        else
869
 	  state=MY_LEX_CHAR;		// Return ';'
bk@work.mysql.com's avatar
bk@work.mysql.com committed
870 871 872
	break;
      }
      /* fall true */
873 874
    case MY_LEX_EOL:
      lex->next_state=MY_LEX_END;	// Mark for next loop
bk@work.mysql.com's avatar
bk@work.mysql.com committed
875
      return(END_OF_INPUT);
876 877
    case MY_LEX_END:
      lex->next_state=MY_LEX_END;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
878
      return(0);			// We found end of input last time
879 880
      
      /* Actually real shouldn't start with . but allow them anyhow */
881 882 883
    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
884 885
      else
      {
886 887
	state= MY_LEX_IDENT_SEP;	// return '.'
	yyUnget();			// Put back '.'
bk@work.mysql.com's avatar
bk@work.mysql.com committed
888 889
      }
      break;
890
    case MY_LEX_USER_END:		// end '@' of user@hostname
891
      switch (state_map[yyPeek()]) {
892 893 894
      case MY_LEX_STRING:
      case MY_LEX_USER_VARIABLE_DELIMITER:
      case MY_LEX_STRING_OR_DELIMITER:
895
	break;
896 897
      case MY_LEX_USER_END:
	lex->next_state=MY_LEX_SYSTEM_VAR;
898 899
	break;
      default:
900
	lex->next_state=MY_LEX_HOSTNAME;
901 902
	break;
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
903 904 905
      yylval->lex_str.str=(char*) lex->ptr;
      yylval->lex_str.length=1;
      return((int) '@');
906 907 908
    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
909 910 911
	   c= yyGet()) ;
      yylval->lex_str=get_token(lex,yyLength());
      return(LEX_HOSTNAME);
912
    case MY_LEX_SYSTEM_VAR:
913 914 915
      yylval->lex_str.str=(char*) lex->ptr;
      yylval->lex_str.length=1;
      yySkip();					// Skip '@'
916 917 918 919
      lex->next_state= (state_map[yyPeek()] ==
			MY_LEX_USER_VARIABLE_DELIMITER ?
			MY_LEX_OPERATOR_OR_IDENT :
			MY_LEX_IDENT_OR_KEYWORD);
920
      return((int) '@');
921
    case MY_LEX_IDENT_OR_KEYWORD:
922 923 924 925 926
      /*
	We come here when we have found two '@' in a row.
	We should now be able to handle:
	[(global | local | session) .]variable_name
      */
927
      while (ident_map[c=yyGet()]) ;
928
      if (c == '.')
929
	lex->next_state=MY_LEX_IDENT_SEP;
930 931 932 933 934 935 936 937
      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);
      return(IDENT);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
938 939 940
    }
  }
}
941 942 943 944 945 946 947

/*
  st_select_lex structures initialisations
*/

void st_select_lex_node::init_query()
{
948 949
  options= 0;
  linkage= UNSPECIFIED_TYPE;
950
  no_error= no_table_names_allowed= uncacheable= dependent= 0;
951 952 953 954 955 956 957 958 959
}

void st_select_lex_node::init_select()
{
}

void st_select_lex_unit::init_query()
{
  st_select_lex_node::init_query();
960
  linkage= GLOBAL_OPTIONS_TYPE;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
961
  global_parameters= first_select();
962 963
  select_limit_cnt= HA_POS_ERROR;
  offset_limit_cnt= 0;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
964
  union_option= 0;
965
  prepared= optimized= executed= 0;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
966
  item= 0;
967 968
  union_result= 0;
  table= 0;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
969
  fake_select_lex= 0;
970 971 972 973 974
}

void st_select_lex::init_query()
{
  st_select_lex_node::init_query();
975
  table_list.empty();
976
  item_list.empty();
977
  join= 0;
978
  where= 0;
979
  olap= UNSPECIFIED_OLAP_TYPE;
980 981
  having_fix_field= 0;
  resolve_mode= NOMATTER_MODE;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
982 983
  cond_count= with_wild= 0;
  ref_pointer_array= 0;
bell@laptop.sanja.is.com.ua's avatar
bell@laptop.sanja.is.com.ua committed
984
  select_n_having_items= 0;
985
  prep_where= 0;
986 987 988 989 990
}

void st_select_lex::init_select()
{
  st_select_lex_node::init_select();
991 992 993 994 995 996
  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;
997
  options= 0;
998
  braces= 0;
999 1000 1001 1002
  when_list.empty(); 
  expr_list.empty();
  interval_list.empty(); 
  use_index.empty();
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1003 1004
  ftfunc_list_alloc.empty();
  ftfunc_list= &ftfunc_list_alloc;
1005
  linkage= UNSPECIFIED_TYPE;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1006 1007 1008 1009 1010 1011 1012
  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;
  parsing_place= SELECT_LEX_NODE::NO_MATTER;
1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026
}

/*
  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;
1027
  slave= 0;
1028 1029
}

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046
/*
  include on level down (but do not link)
  
  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;
}

1047 1048 1049 1050 1051 1052 1053 1054
/* 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;
1055
  slave= 0;
1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069
}

/* 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()
{
1070
  if (link_prev)
1071 1072 1073 1074
  {
    if ((*link_prev= link_next))
      link_next->link_prev= link_prev;
  }
1075 1076 1077 1078
  // Remove slave structure
  for (; slave; slave= slave->next)
    slave->fast_exclude();
  
1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098
}

/*
  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;
  */
}
1099

1100 1101 1102 1103 1104 1105 1106 1107 1108 1109

/*
  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 
*/
1110 1111 1112
void st_select_lex_unit::exclude_level()
{
  SELECT_LEX_UNIT *units= 0, **units_last= &units;
1113
  for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
1114
  {
1115
    // unlink current level from global SELECTs list
1116 1117
    if (sl->link_prev && (*sl->link_prev= sl->link_next))
      sl->link_next->link_prev= sl->link_prev;
1118 1119

    // bring up underlay levels
1120 1121
    SELECT_LEX_UNIT **last= 0;
    for (SELECT_LEX_UNIT *u= sl->first_inner_unit(); u; u= u->next_unit())
1122 1123
    {
      u->master= master;
1124
      last= (SELECT_LEX_UNIT**)&(u->next);
1125
    }
1126 1127 1128 1129 1130 1131 1132 1133
    if (last)
    {
      (*units_last)= sl->first_inner_unit();
      units_last= last;
    }
  }
  if (units)
  {
1134
    // include brought up levels in place of current
1135 1136
    (*prev)= units;
    (*units_last)= (SELECT_LEX_UNIT*)next;
1137 1138 1139
    if (next)
      next->prev= (SELECT_LEX_NODE**)units_last;
    units->prev= prev;
1140 1141
  }
  else
1142 1143
  {
    // exclude currect unit from list of nodes
1144
    (*prev)= next;
1145 1146 1147
    if (next)
      next->prev= prev;
  }
1148 1149
}

1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161

/*
  Exclude subtree of current unit from tree of SELECTs

  SYNOPSYS
    st_select_lex_unit::exclude_tree()
*/
void st_select_lex_unit::exclude_tree()
{
  SELECT_LEX_UNIT *units= 0, **units_last= &units;
  for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
  {
1162
    // unlink current level from global SELECTs list
1163 1164 1165
    if (sl->link_prev && (*sl->link_prev= sl->link_next))
      sl->link_next->link_prev= sl->link_prev;

1166
    // unlink underlay levels
1167 1168 1169 1170 1171
    for (SELECT_LEX_UNIT *u= sl->first_inner_unit(); u; u= u->next_unit())
    {
      u->exclude_level();
    }
  }
1172
  // exclude currect unit from list of nodes
1173
  (*prev)= next;
1174 1175
  if (next)
    next->prev= prev;
1176 1177 1178
}


1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190
/*
  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
1191
void st_select_lex::mark_as_dependent(SELECT_LEX *last)
1192 1193 1194 1195 1196
{
  /*
    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
1197
  for (SELECT_LEX *s= this;
1198 1199
       s &&s != last;
       s= s->outer_select())
1200
    if ( !s->dependent )
1201 1202 1203
    {
      // Select is dependent of outer select
      s->dependent= 1;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1204 1205 1206 1207 1208 1209 1210
      s->master_unit()->dependent= 1;
      //Tables will be reopened many times
      for (TABLE_LIST *tbl=
	     s->get_table_list();
	   tbl;
	   tbl= tbl->next)
	tbl->shared= 1;
1211 1212 1213
    }
}

1214 1215 1216 1217 1218 1219 1220 1221
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; }

1222 1223 1224 1225 1226 1227 1228 1229
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
1230
bool st_select_lex::test_limit()
1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243
{
  if (select_limit != HA_POS_ERROR)
  {
    my_error(ER_NOT_SUPPORTED_YET, MYF(0),
         "LIMIT & IN/ALL/ANY/SOME subquery");
    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);
}
1244

1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263
/*  
  Interface method of table list creation for query
  
  SYNOPSIS
    st_select_lex_unit::create_total_list()
    thd            THD pointer
    result         pointer on result list of tables pointer
    check_derived  force derived table chacking (used for creating 
                   table list for derived query)
  DESCRIPTION
    This is used for UNION & subselect to create a new table list of all used 
    tables.
    The table_list->table entry in all used tables are set to point
    to the entries in this list.

  RETURN
    0 - OK
    !0 - error
*/
1264
bool st_select_lex_unit::create_total_list(THD *thd, st_lex *lex,
1265 1266
					   TABLE_LIST **result,
					   bool check_derived)
1267 1268
{
  *result= 0;
1269 1270 1271 1272 1273 1274 1275
  for (SELECT_LEX_UNIT *unit= this; unit; unit= unit->next_unit())
  {
    if ((res= unit->create_total_list_n_last_return(thd, lex, &result,
						    check_derived)))
      return res;
  }
  return 0;
1276 1277
}

1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297
/*  
  Table list creation for query
  
  SYNOPSIS
    st_select_lex_unit::create_total_list()
    thd            THD pointer
    lex            pointer on LEX stricture
    result         pointer on pointer on result list of tables pointer
    check_derived  force derived table chacking (used for creating 
                   table list for derived query)
  DESCRIPTION
    This is used for UNION & subselect to create a new table list of all used 
    tables.
    The table_list->table entry in all used tables are set to point
    to the entries in this list.

  RETURN
    0 - OK
    !0 - error
*/
1298
bool st_select_lex_unit::create_total_list_n_last_return(THD *thd, st_lex *lex,
1299 1300
							 TABLE_LIST ***result,
							 bool check_derived)
1301 1302 1303 1304
{
  TABLE_LIST *slave_list_first=0, **slave_list_last= &slave_list_first;
  TABLE_LIST **new_table_list= *result, *aux;
  SELECT_LEX *sl= (SELECT_LEX*)slave;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316
  
  /*
    iterate all inner selects + fake_select (if exists),
    fake_select->next_select() always is 0
  */
  for (;
       sl;
       sl= (sl->next_select() ?
	    sl->next_select() :
	    (sl == fake_select_lex ?
	     0 :
	     fake_select_lex)))
1317 1318
  {
    // check usage of ORDER BY in union
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1319 1320
    if (sl->order_list.first && sl->next_select() && !sl->braces &&
	sl->linkage != GLOBAL_OPTIONS_TYPE)
1321
    {
1322
      net_printf(thd,ER_WRONG_USAGE,"UNION","ORDER BY");
1323 1324
      return 1;
    }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1325

1326
    if (sl->linkage == DERIVED_TABLE_TYPE && !check_derived)
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1327 1328
      goto end;

1329 1330 1331
    for (SELECT_LEX_UNIT *inner=  sl->first_inner_unit();
	 inner;
	 inner= inner->next_unit())
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1332
    {
1333
      if (inner->create_total_list_n_last_return(thd, lex,
1334
						 &slave_list_last, 0))
1335
	return 1;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1336 1337
    }

1338 1339 1340 1341 1342 1343 1344 1345 1346 1347
    if ((aux= (TABLE_LIST*) sl->table_list.first))
    {
      TABLE_LIST *next;
      for (; aux; aux= next)
      {
	TABLE_LIST *cursor;
	next= aux->next;
	for (cursor= **result; cursor; cursor= cursor->next)
	  if (!strcmp(cursor->db, aux->db) &&
	      !strcmp(cursor->real_name, aux->real_name) &&
1348
	      !strcmp(cursor->alias, aux->alias))
1349 1350 1351 1352 1353 1354 1355
	    break;
	if (!cursor)
	{
	  /* Add not used table to the total table list */
	  if (!(cursor= (TABLE_LIST *) thd->memdup((char*) aux,
						   sizeof(*aux))))
	  {
1356
	    send_error(thd,0);
1357 1358 1359
	    return 1;
	  }
	  *new_table_list= cursor;
1360
	  cursor->table_list= aux; //to be able mark this table as shared
1361 1362 1363 1364
	  new_table_list= &cursor->next;
	  *new_table_list= 0;			// end result list
	}
	else
1365 1366
	  // Mark that it's used twice
	  cursor->table_list->shared= aux->shared= 1;
1367 1368 1369 1370
	aux->table_list= cursor;
      }
    }
  }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1371
end:
1372 1373 1374 1375 1376 1377 1378 1379
  if (slave_list_first)
  {
    *new_table_list= slave_list_first;
    new_table_list= slave_list_last;
  }
  *result= new_table_list;
  return 0;
}
1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390

st_select_lex_unit* st_select_lex_unit::master_unit()
{
    return this;
}

st_select_lex* st_select_lex_unit::outer_select()
{
  return (st_select_lex*) master;
}

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

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1396
bool st_select_lex::add_item_to_list(THD *thd, Item *item)
1397 1398 1399 1400
{
  return item_list.push_back(item);
}

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1401
bool st_select_lex::add_group_to_list(THD *thd, Item *item, bool asc)
1402
{
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1403
  return add_to_list(thd, group_list, item, asc);
1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457
}

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

st_select_lex_unit* st_select_lex::master_unit()
{
  return (st_select_lex_unit*) master;
}

st_select_lex* st_select_lex::outer_select()
{
  return (st_select_lex*) master->get_master();
}

bool st_select_lex::set_braces(bool value)
{
  braces= value;
  return 0; 
}

bool st_select_lex::inc_in_sum_expr()
{
  in_sum_expr++;
  return 0;
}

uint st_select_lex::get_in_sum_expr()
{
  return in_sum_expr;
}

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;
}

List<String>* st_select_lex::get_use_index()
{
  return use_index_ptr;
}

List<String>* st_select_lex::get_ignore_index()
{
  return ignore_index_ptr;
}

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1458 1459 1460 1461 1462
ulong st_select_lex::get_table_join_options()
{
  return table_join_options;
}

bell@laptop.sanja.is.com.ua's avatar
bell@laptop.sanja.is.com.ua committed
1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473
bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num)
{
  if (ref_pointer_array)
    return 0;
  return (ref_pointer_array= 
	  (Item **)thd->alloc(sizeof(Item*) *
			      (item_list.elements +
			       select_n_having_items +
			       order_group_num)* 5)) == 0;
}

1474 1475 1476 1477
/*
  There are st_select_lex::add_table_to_list & 
  st_select_lex::set_lock_for_tables in sql_parse.cc
*/