sql_lex.cc 79.7 KB
Newer Older
1
/* Copyright (C) 2000-2006 MySQL 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
   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
5
   the Free Software Foundation; version 2 of the License.
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
6

bk@work.mysql.com's avatar
bk@work.mysql.com committed
7 8 9 10
   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
11

bk@work.mysql.com's avatar
bk@work.mysql.com committed
12 13 14 15 16 17 18
   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 */

19
#define MYSQL_LEX 1
bk@work.mysql.com's avatar
bk@work.mysql.com committed
20 21 22 23
#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
/*
  We are using pointer to this variable for distinguishing between assignment
  to NEW row field (when parsing trigger definition) and structured variable.
*/
31 32

sys_var *trg_new_row_fake_var= (sys_var*) 0x01;
33

34
/* Longest standard keyword name */
bk@work.mysql.com's avatar
bk@work.mysql.com committed
35 36
#define TOCK_NAME_LENGTH 24

37 38
/*
  The following data is based on the latin1 character set, and is only
bk@work.mysql.com's avatar
bk@work.mysql.com committed
39 40 41
  used when comparing keywords
*/

monty@mysql.com's avatar
monty@mysql.com committed
42 43
static uchar to_upper_lex[]=
{
bk@work.mysql.com's avatar
bk@work.mysql.com committed
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
    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
};

62 63 64 65 66 67 68 69 70 71 72
/* 
  Names of the index hints (for error messages). Keep in sync with 
  index_hint_type 
*/

const char * index_hint_type_name[] =
{
  "IGNORE INDEX", 
  "USE INDEX", 
  "FORCE INDEX"
};
73

bk@work.mysql.com's avatar
bk@work.mysql.com committed
74 75 76 77 78 79 80
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;
}

serg@serg.mylan's avatar
serg@serg.mylan committed
81
#include <lex_hash.h>
bk@work.mysql.com's avatar
bk@work.mysql.com committed
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103


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

  DBUG_VOID_RETURN;
}


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


104 105 106 107 108 109 110 111 112
void
st_parsing_options::reset()
{
  allows_variable= TRUE;
  allows_select_into= TRUE;
  allows_select_procedure= TRUE;
  allows_derived= TRUE;
}

113 114 115 116 117 118 119
Lex_input_stream::Lex_input_stream(THD *thd,
                                   const char* buffer,
                                   unsigned int length)
: m_thd(thd),
  yylineno(1),
  yytoklen(0),
  yylval(NULL),
120 121 122 123 124 125
  m_ptr(buffer),
  m_tok_start(NULL),
  m_tok_end(NULL),
  m_end_of_query(buffer + length),
  m_tok_start_prev(NULL),
  m_buf(buffer),
126
  m_buf_length(length),
kostja@bodhi.(none)'s avatar
kostja@bodhi.(none) committed
127
  m_echo(TRUE),
128 129 130
  m_cpp_tok_start(NULL),
  m_cpp_tok_start_prev(NULL),
  m_cpp_tok_end(NULL),
131 132
  m_body_utf8(NULL),
  m_cpp_utf8_processed_ptr(NULL),
133 134
  next_state(MY_LEX_START),
  found_semicolon(NULL),
135
  ignore_space(test(thd->variables.sql_mode & MODE_IGNORE_SPACE)),
136
  stmt_prepare_mode(FALSE),
137 138
  in_comment(NO_COMMENT),
  m_underscore_cs(NULL)
139
{
140 141
  m_cpp_buf= (char*) thd->alloc(length + 1);
  m_cpp_ptr= m_cpp_buf;
142 143 144 145 146
}

Lex_input_stream::~Lex_input_stream()
{}

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
/**
  The operation is called from the parser in order to
  1) designate the intention to have utf8 body;
  1) Indicate to the lexer that we will need a utf8 representation of this
     statement;
  2) Determine the beginning of the body.

  @param thd        Thread context.
  @param begin_ptr  Pointer to the start of the body in the pre-processed
                    buffer.
*/

void Lex_input_stream::body_utf8_start(THD *thd, const char *begin_ptr)
{
  DBUG_ASSERT(begin_ptr);
  DBUG_ASSERT(m_cpp_buf <= begin_ptr && begin_ptr <= m_cpp_buf + m_buf_length);

  uint body_utf8_length=
    (m_buf_length / thd->variables.character_set_client->mbminlen) *
    my_charset_utf8_bin.mbmaxlen;

  m_body_utf8= (char *) thd->alloc(body_utf8_length + 1);
  m_body_utf8_ptr= m_body_utf8;
  *m_body_utf8_ptr= 0;

  m_cpp_utf8_processed_ptr= begin_ptr;
}

/**
kostja@bodhi.(none)'s avatar
kostja@bodhi.(none) committed
176
  @brief The operation appends unprocessed part of pre-processed buffer till
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 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
  the given pointer (ptr) and sets m_cpp_utf8_processed_ptr to end_ptr.

  The idea is that some tokens in the pre-processed buffer (like character
  set introducers) should be skipped.

  Example:
    CPP buffer: SELECT 'str1', _latin1 'str2';
    m_cpp_utf8_processed_ptr -- points at the "SELECT ...";
    In order to skip "_latin1", the following call should be made:
      body_utf8_append(<pointer to "_latin1 ...">, <pointer to " 'str2'...">)

  @param ptr      Pointer in the pre-processed buffer, which specifies the
                  end of the chunk, which should be appended to the utf8
                  body.
  @param end_ptr  Pointer in the pre-processed buffer, to which
                  m_cpp_utf8_processed_ptr will be set in the end of the
                  operation.
*/

void Lex_input_stream::body_utf8_append(const char *ptr,
                                        const char *end_ptr)
{
  DBUG_ASSERT(m_cpp_buf <= ptr && ptr <= m_cpp_buf + m_buf_length);
  DBUG_ASSERT(m_cpp_buf <= end_ptr && end_ptr <= m_cpp_buf + m_buf_length);

  if (!m_body_utf8)
    return;

  if (m_cpp_utf8_processed_ptr >= ptr)
    return;

  int bytes_to_copy= ptr - m_cpp_utf8_processed_ptr;

  memcpy(m_body_utf8_ptr, m_cpp_utf8_processed_ptr, bytes_to_copy);
  m_body_utf8_ptr += bytes_to_copy;
  *m_body_utf8_ptr= 0;

  m_cpp_utf8_processed_ptr= end_ptr;
}

/**
  The operation appends unprocessed part of the pre-processed buffer till
  the given pointer (ptr) and sets m_cpp_utf8_processed_ptr to ptr.

  @param ptr  Pointer in the pre-processed buffer, which specifies the end
              of the chunk, which should be appended to the utf8 body.
*/

void Lex_input_stream::body_utf8_append(const char *ptr)
{
  body_utf8_append(ptr, ptr);
}

/**
  The operation converts the specified text literal to the utf8 and appends
  the result to the utf8-body.

  @param thd      Thread context.
  @param txt      Text literal.
  @param txt_cs   Character set of the text literal.
  @param end_ptr  Pointer in the pre-processed buffer, to which
                  m_cpp_utf8_processed_ptr will be set in the end of the
                  operation.
*/

void Lex_input_stream::body_utf8_append_literal(THD *thd,
                                                const LEX_STRING *txt,
                                                CHARSET_INFO *txt_cs,
                                                const char *end_ptr)
{
  if (!m_cpp_utf8_processed_ptr)
    return;

  LEX_STRING utf_txt;

anozdrin/alik@ibm's avatar
anozdrin/alik@ibm committed
252
  if (!my_charset_same(txt_cs, &my_charset_utf8_general_ci))
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
  {
    thd->convert_string(&utf_txt,
                        &my_charset_utf8_general_ci,
                        txt->str, txt->length,
                        txt_cs);
  }
  else
  {
    utf_txt.str= txt->str;
    utf_txt.length= txt->length;
  }

  /* NOTE: utf_txt.length is in bytes, not in symbols. */

  memcpy(m_body_utf8_ptr, utf_txt.str, utf_txt.length);
  m_body_utf8_ptr += utf_txt.length;
  *m_body_utf8_ptr= 0;

  m_cpp_utf8_processed_ptr= end_ptr;
}

274

275 276 277 278 279 280
/*
  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)
*/

281
void lex_start(THD *thd)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
282
{
283
  LEX *lex= thd->lex;
284 285 286 287
  DBUG_ENTER("lex_start");

  lex->thd= lex->unit.thd= thd;

288
  lex->context_stack.empty();
289 290
  lex->unit.init_query();
  lex->unit.init_select();
291 292
  /* 'parent_lex' is used in init_query() so it must be before it. */
  lex->select_lex.parent_lex= lex;
293 294
  lex->select_lex.init_query();
  lex->value_list.empty();
295
  lex->update_list.empty();
296
  lex->set_var_list.empty();
297
  lex->param_list.empty();
monty@mysql.com's avatar
monty@mysql.com committed
298
  lex->view_list.empty();
299
  lex->prepared_stmt_params.empty();
300
  lex->auxiliary_table_list.empty();
301 302 303 304 305 306 307 308 309 310
  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;
311
  lex->select_lex.sql_cache= SELECT_LEX::SQL_CACHE_UNSPECIFIED;
monty@mysql.com's avatar
monty@mysql.com committed
312 313
  lex->select_lex.init_order();
  lex->select_lex.group_list.empty();
314
  lex->describe= 0;
monty@mysql.com's avatar
monty@mysql.com committed
315
  lex->subqueries= FALSE;
monty@mysql.com's avatar
monty@mysql.com committed
316
  lex->view_prepare_mode= FALSE;
monty@mysql.com's avatar
monty@mysql.com committed
317
  lex->derived_tables= 0;
318 319
  lex->lock_option= TL_READ;
  lex->safe_to_cache_query= 1;
320
  lex->leaf_tables_insert= 0;
321
  lex->parsing_options.reset();
monty@mysql.com's avatar
monty@mysql.com committed
322
  lex->empty_field_list_on_rset= 0;
323
  lex->select_lex.select_number= 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
324
  lex->length=0;
325
  lex->part_info= 0;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
326
  lex->select_lex.in_sum_expr=0;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
327
  lex->select_lex.ftfunc_list_alloc.empty();
328
  lex->select_lex.ftfunc_list= &lex->select_lex.ftfunc_list_alloc;
329 330
  lex->select_lex.group_list.empty();
  lex->select_lex.order_list.empty();
331
  lex->sql_command= SQLCOM_END;
332
  lex->duplicates= DUP_ERROR;
333
  lex->ignore= 0;
334
  lex->spname= NULL;
335 336
  lex->sphead= NULL;
  lex->spcont= NULL;
337
  lex->proc_list.first= 0;
338
  lex->escape_used= FALSE;
antony@ppcg5.local's avatar
antony@ppcg5.local committed
339
  lex->query_tables= 0;
340
  lex->reset_query_tables_list(FALSE);
341
  lex->expr_allows_subselect= TRUE;
342
  lex->use_only_table_context= FALSE;
343

344 345
  lex->name.str= 0;
  lex->name.length= 0;
346
  lex->event_parse_data= NULL;
347
  lex->profile_options= PROFILE_NONE;
igor@rurik.mysql.com's avatar
igor@rurik.mysql.com committed
348 349 350
  lex->nest_level=0 ;
  lex->allow_sum_func= 0;
  lex->in_sum_func= NULL;
patg@radha.tangent.org's avatar
patg@radha.tangent.org committed
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
  /*
    ok, there must be a better solution for this, long-term
    I tried "bzero" in the sql_yacc.yy code, but that for
    some reason made the values zero, even if they were set
  */
  lex->server_options.server_name= 0;
  lex->server_options.server_name_length= 0;
  lex->server_options.host= 0;
  lex->server_options.db= 0;
  lex->server_options.username= 0;
  lex->server_options.password= 0;
  lex->server_options.scheme= 0;
  lex->server_options.socket= 0;
  lex->server_options.owner= 0;
  lex->server_options.port= -1;
366

367
  lex->is_lex_started= TRUE;
368
  DBUG_VOID_RETURN;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
369 370 371 372
}

void lex_end(LEX *lex)
{
monty@mysql.com's avatar
monty@mysql.com committed
373
  DBUG_ENTER("lex_end");
374
  DBUG_PRINT("enter", ("lex: 0x%lx", (long) lex));
antony@ppcg5.local's avatar
antony@ppcg5.local committed
375 376 377 378 379 380

  /* release used plugins */
  plugin_unlock_list(0, (plugin_ref*)lex->plugins.buffer, 
                     lex->plugins.elements);
  reset_dynamic(&lex->plugins);

monty@mysql.com's avatar
monty@mysql.com committed
381
  DBUG_VOID_RETURN;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
382 383
}

384 385 386 387
Yacc_state::~Yacc_state()
{
  if (yacc_yyss)
  {
388 389
    my_free(yacc_yyss, MYF(0));
    my_free(yacc_yyvs, MYF(0));
390
  }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
391 392
}

393
static int find_keyword(Lex_input_stream *lip, uint len, bool function)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
394
{
395
  const char *tok= lip->get_tok_start();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
396

397
  SYMBOL *symbol= get_hash_symbol(tok, len, function);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
398 399
  if (symbol)
  {
400 401 402 403
    lip->yylval->symbol.symbol=symbol;
    lip->yylval->symbol.str= (char*) tok;
    lip->yylval->symbol.length=len;

404
    if ((symbol->tok == NOT_SYM) &&
405
        (lip->m_thd->variables.sql_mode & MODE_HIGH_NOT_PRECEDENCE))
406 407
      return NOT2_SYM;
    if ((symbol->tok == OR_OR_SYM) &&
408
	!(lip->m_thd->variables.sql_mode & MODE_PIPES_AS_CONCAT))
409
      return OR2_SYM;
410

bk@work.mysql.com's avatar
bk@work.mysql.com committed
411 412 413 414 415
    return symbol->tok;
  }
  return 0;
}

416 417 418 419 420
/*
  Check if name is a keyword

  SYNOPSIS
    is_keyword()
421
    name      checked name (must not be empty)
422 423 424 425 426 427 428 429 430
    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)
{
431
  DBUG_ASSERT(len != 0);
432 433
  return get_hash_symbol(name,len,0)!=0;
}
bk@work.mysql.com's avatar
bk@work.mysql.com committed
434

435 436 437 438 439 440
bool is_lex_native_function(const LEX_STRING *name)
{
  DBUG_ASSERT(name != NULL);
  return (get_hash_symbol(name->str, name->length, 1) != 0);
}

bk@work.mysql.com's avatar
bk@work.mysql.com committed
441 442
/* make a copy of token before ptr and set yytoklen */

443
static LEX_STRING get_token(Lex_input_stream *lip, uint skip, uint length)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
444 445
{
  LEX_STRING tmp;
446
  lip->yyUnget();                       // ptr points now after last token char
447
  tmp.length=lip->yytoklen=length;
448
  tmp.str= lip->m_thd->strmake(lip->get_tok_start() + skip, tmp.length);
449 450 451 452

  lip->m_cpp_text_start= lip->get_cpp_tok_start() + skip;
  lip->m_cpp_text_end= lip->m_cpp_text_start + tmp.length;

bk@work.mysql.com's avatar
bk@work.mysql.com committed
453 454 455
  return tmp;
}

456 457 458 459 460 461 462
/* 
 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)
*/

463
static LEX_STRING get_quoted_token(Lex_input_stream *lip,
464
                                   uint skip,
465
                                   uint length, char quote)
466 467
{
  LEX_STRING tmp;
468 469
  const char *from, *end;
  char *to;
470
  lip->yyUnget();                       // ptr points now after last token char
471 472
  tmp.length= lip->yytoklen=length;
  tmp.str=(char*) lip->m_thd->alloc(tmp.length+1);
473
  from= lip->get_tok_start() + skip;
474
  to= tmp.str;
475
  end= to+length;
476 477 478 479

  lip->m_cpp_text_start= lip->get_cpp_tok_start() + skip;
  lip->m_cpp_text_end= lip->m_cpp_text_start + length;

480
  for ( ; to != end; )
481
  {
482
    if ((*to++= *from++) == quote)
483
    {
484
      from++;					// Skip double quotes
485 486
      lip->m_cpp_text_start++;
    }
487 488 489 490 491 492 493 494 495 496
  }
  *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
497

498
static char *get_text(Lex_input_stream *lip, int pre_skip, int post_skip)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
499 500 501
{
  reg1 uchar c,sep;
  uint found_escape=0;
502
  CHARSET_INFO *cs= lip->m_thd->charset();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
503

504
  lip->tok_bitmap= 0;
505 506
  sep= lip->yyGetLast();                        // String should end with this
  while (! lip->eof())
bk@work.mysql.com's avatar
bk@work.mysql.com committed
507
  {
508
    c= lip->yyGet();
509
    lip->tok_bitmap|= c;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
510
#ifdef USE_MB
511 512 513
    {
      int l;
      if (use_mb(cs) &&
514 515 516 517 518
          (l = my_ismbchar(cs,
                           lip->get_ptr() -1,
                           lip->get_end_of_query()))) {
        lip->skip_binary(l-1);
        continue;
519
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
520 521
    }
#endif
522
    if (c == '\\' &&
523
        !(lip->m_thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
524 525
    {					// Escaped character
      found_escape=1;
526
      if (lip->eof())
bk@work.mysql.com's avatar
bk@work.mysql.com committed
527
	return 0;
528
      lip->yySkip();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
529 530 531
    }
    else if (c == sep)
    {
532
      if (c == lip->yyGet())            // Check if two separators in a row
bk@work.mysql.com's avatar
bk@work.mysql.com committed
533
      {
534
        found_escape=1;                 // duplicate. Remember for delete
bk@work.mysql.com's avatar
bk@work.mysql.com committed
535 536 537
	continue;
      }
      else
538
        lip->yyUnget();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
539 540

      /* Found end. Unescape and return string */
541 542
      const char *str, *end;
      char *start;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
543

544 545 546 547 548 549 550
      str= lip->get_tok_start();
      end= lip->get_ptr();
      /* Extract the text from the token */
      str += pre_skip;
      end -= post_skip;
      DBUG_ASSERT(end >= str);

551
      if (!(start= (char*) lip->m_thd->alloc((uint) (end-str)+1)))
552
	return (char*) "";		// Sql_alloc has set error flag
553 554 555 556

      lip->m_cpp_text_start= lip->get_cpp_tok_start() + pre_skip;
      lip->m_cpp_text_end= lip->get_cpp_ptr() - post_skip;

bk@work.mysql.com's avatar
bk@work.mysql.com committed
557 558
      if (!found_escape)
      {
559 560 561
	lip->yytoklen=(uint) (end-str);
	memcpy(start,str,lip->yytoklen);
	start[lip->yytoklen]=0;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
562 563 564
      }
      else
      {
565
        char *to;
566

bk@work.mysql.com's avatar
bk@work.mysql.com committed
567 568 569 570
	for (to=start ; str != end ; str++)
	{
#ifdef USE_MB
	  int l;
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
571
	  if (use_mb(cs) &&
572
              (l = my_ismbchar(cs, str, end))) {
bk@work.mysql.com's avatar
bk@work.mysql.com committed
573 574 575 576 577 578
	      while (l--)
		  *to++ = *str++;
	      str--;
	      continue;
	  }
#endif
579
	  if (!(lip->m_thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) &&
580
              *str == '\\' && str+1 != end)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605
	  {
	    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:
606
              *to++= *str;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
607 608 609
	      break;
	    }
	  }
610 611
	  else if (*str == sep)
	    *to++= *str++;		// Two ' or "
bk@work.mysql.com's avatar
bk@work.mysql.com committed
612 613 614 615
	  else
	    *to++ = *str;
	}
	*to=0;
616
	lip->yytoklen=(uint) (to-start);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
617
      }
618
      return start;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639
    }
  }
  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;
640 641
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
642

monty@mysql.com's avatar
monty@mysql.com committed
643
static inline uint int_token(const char *str,uint length)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677
{
  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)
678
      return DECIMAL_NUM;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
679 680 681 682
    else
    {
      cmp=signed_longlong_str+1;
      smaller=LONG_NUM;				// If <= signed_longlong_str
683
      bigger=DECIMAL_NUM;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
684 685 686 687 688 689 690 691 692 693 694 695 696
    }
  }
  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)
697 698
    {
      if (length > unsigned_longlong_len)
699
        return DECIMAL_NUM;
700 701
      cmp=unsigned_longlong_str;
      smaller=ULONGLONG_NUM;
702
      bigger=DECIMAL_NUM;
703
    }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
704 705 706 707
    else
    {
      cmp=longlong_str;
      smaller=LONG_NUM;
708
      bigger= ULONGLONG_NUM;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
709 710 711 712 713 714
    }
  }
  while (*cmp && *cmp++ == *str++) ;
  return ((uchar) str[-1] <= (uchar) cmp[-1]) ? smaller : bigger;
}

715
/*
716
  MYSQLlex remember the following states from the following MYSQLlex()
717 718 719 720 721

  - 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
722

723
int MYSQLlex(void *arg, void *yythd)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
724 725
{
  reg1	uchar c;
726
  bool comment_closed;
727
  int	tokval, result_state;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
728
  uint length;
729
  enum my_lex_states state;
730
  THD *thd= (THD *)yythd;
731
  Lex_input_stream *lip= & thd->m_parser_state->m_lip;
732
  LEX *lex= thd->lex;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
733
  YYSTYPE *yylval=(YYSTYPE*) arg;
734
  CHARSET_INFO *cs= thd->charset();
735 736
  uchar *state_map= cs->state_map;
  uchar *ident_map= cs->ident_map;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
737

738
  lip->yylval=yylval;			// The global state
739

740
  lip->start_token();
741 742
  state=lip->next_state;
  lip->next_state=MY_LEX_OPERATOR_OR_IDENT;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
743 744 745
  LINT_INIT(c);
  for (;;)
  {
746
    switch (state) {
747 748
    case MY_LEX_OPERATOR_OR_IDENT:	// Next is operator or keyword
    case MY_LEX_START:			// Start of token
749 750
      // Skip starting whitespace
      while(state_map[c= lip->yyPeek()] == MY_LEX_SKIP)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
751 752
      {
	if (c == '\n')
753
	  lip->yylineno++;
754 755

        lip->yySkip();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
756
      }
757 758 759 760

      /* Start of real token */
      lip->restart_token();
      c= lip->yyGet();
761
      state= (enum my_lex_states) state_map[c];
bk@work.mysql.com's avatar
bk@work.mysql.com committed
762
      break;
763
    case MY_LEX_ESCAPE:
764
      if (lip->yyGet() == 'N')
bk@work.mysql.com's avatar
bk@work.mysql.com committed
765 766 767 768 769
      {					// Allow \N as shortcut for NULL
	yylval->lex_str.str=(char*) "\\N";
	yylval->lex_str.length=2;
	return NULL_SYM;
      }
770 771
    case MY_LEX_CHAR:			// Unknown or single char token
    case MY_LEX_SKIP:			// This should not happen
772 773 774
      if (c == '-' && lip->yyPeek() == '-' &&
          (my_isspace(cs,lip->yyPeekn(1)) ||
           my_iscntrl(cs,lip->yyPeekn(1))))
775 776 777 778
      {
        state=MY_LEX_COMMENT;
        break;
      }
779

bk@work.mysql.com's avatar
bk@work.mysql.com committed
780
      if (c != ')')
781
	lip->next_state= MY_LEX_START;	// Allow signed numbers
782

bk@work.mysql.com's avatar
bk@work.mysql.com committed
783
      if (c == ',')
784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804
      {
        /*
          Warning:
          This is a work around, to make the "remember_name" rule in
          sql/sql_yacc.yy work properly.
          The problem is that, when parsing "select expr1, expr2",
          the code generated by bison executes the *pre* action
          remember_name (see select_item) *before* actually parsing the
          first token of expr2.
        */
        lip->restart_token();
      }
      else
      {
        /*
          Check for a placeholder: it should not precede a possible identifier
          because of binlogging: when a placeholder is replaced with
          its value in a query for the binlog, the query must stay
          grammatically correct.
        */
        if (c == '?' && lip->stmt_prepare_mode && !ident_map[lip->yyPeek()])
805
        return(PARAM_MARKER);
806 807
      }

bk@work.mysql.com's avatar
bk@work.mysql.com committed
808 809
      return((int) c);

bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
810
    case MY_LEX_IDENT_OR_NCHAR:
811 812
      if (lip->yyPeek() != '\'')
      {
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
813 814 815
	state= MY_LEX_IDENT;
	break;
      }
816
      /* Found N'string' */
817 818
      lip->yySkip();                         // Skip '
      if (!(yylval->lex_str.str = get_text(lip, 2, 1)))
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
819
      {
820 821
	state= MY_LEX_CHAR;             // Read char by char
	break;
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
822
      }
823
      yylval->lex_str.length= lip->yytoklen;
824
      lex->text_string_is_7bit= (lip->tok_bitmap & 0x80) ? 0 : 1;
825
      return(NCHAR_STRING);
bar@bar.mysql.r18.ru's avatar
bar@bar.mysql.r18.ru committed
826

827
    case MY_LEX_IDENT_OR_HEX:
828
      if (lip->yyPeek() == '\'')
829
      {					// Found x'hex-number'
830
	state= MY_LEX_HEX_NUMBER;
831 832
	break;
      }
ram@gw.mysql.r18.ru's avatar
ram@gw.mysql.r18.ru committed
833
    case MY_LEX_IDENT_OR_BIN:
834
      if (lip->yyPeek() == '\'')
ram@gw.mysql.r18.ru's avatar
ram@gw.mysql.r18.ru committed
835 836 837 838
      {                                 // Found b'bin-number'
        state= MY_LEX_BIN_NUMBER;
        break;
      }
839
    case MY_LEX_IDENT:
840
      const char *start;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
841
#if defined(USE_MB) && defined(USE_MB_IDENT)
842
      if (use_mb(cs))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
843
      {
844
	result_state= IDENT_QUOTED;
845
        if (my_mbcharlen(cs, lip->yyGetLast()) > 1)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
846
        {
847 848 849
          int l = my_ismbchar(cs,
                              lip->get_ptr() -1,
                              lip->get_end_of_query());
bk@work.mysql.com's avatar
bk@work.mysql.com committed
850
          if (l == 0) {
851
            state = MY_LEX_CHAR;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
852 853
            continue;
          }
854
          lip->skip_binary(l - 1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
855
        }
856
        while (ident_map[c=lip->yyGet()])
bk@work.mysql.com's avatar
bk@work.mysql.com committed
857
        {
858
          if (my_mbcharlen(cs, c) > 1)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
859 860
          {
            int l;
861 862 863
            if ((l = my_ismbchar(cs,
                                 lip->get_ptr() -1,
                                 lip->get_end_of_query())) == 0)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
864
              break;
865
            lip->skip_binary(l-1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
866 867 868 869 870
          }
        }
      }
      else
#endif
871
      {
872
        for (result_state= c; ident_map[c= lip->yyGet()]; result_state|= c);
873 874
        /* If there were non-ASCII characters, mark that we must convert */
        result_state= result_state & 0x80 ? IDENT_QUOTED : IDENT;
875
      }
876 877
      length= lip->yyLength();
      start= lip->get_ptr();
878
      if (lip->ignore_space)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
879
      {
880 881 882 883
        /*
          If we find a space then this can't be an identifier. We notice this
          below by checking start != lex->ptr.
        */
884
        for (; state_map[c] == MY_LEX_SKIP ; c= lip->yyGet());
bk@work.mysql.com's avatar
bk@work.mysql.com committed
885
      }
886
      if (start == lip->get_ptr() && c == '.' && ident_map[lip->yyPeek()])
887
	lip->next_state=MY_LEX_IDENT_SEP;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
888 889
      else
      {					// '(' must follow directly if function
890 891
        lip->yyUnget();
	if ((tokval = find_keyword(lip, length, c == '(')))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
892
	{
893
	  lip->next_state= MY_LEX_START;	// Allow signed numbers
bk@work.mysql.com's avatar
bk@work.mysql.com committed
894 895
	  return(tokval);		// Was keyword
	}
896
        lip->yySkip();                  // next state does a unget
bk@work.mysql.com's avatar
bk@work.mysql.com committed
897
      }
898
      yylval->lex_str=get_token(lip, 0, length);
899

900
      /*
901 902
         Note: "SELECT _bla AS 'alias'"
         _bla should be considered as a IDENT if charset haven't been found.
903
         So we don't use MYF(MY_WME) with get_charset_by_csname to avoid
904 905 906
         producing an error.
      */

907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926
      if (yylval->lex_str.str[0] == '_')
      {
        CHARSET_INFO *cs= get_charset_by_csname(yylval->lex_str.str + 1,
                                                MY_CS_PRIMARY, MYF(0));
        if (cs)
        {
          yylval->charset= cs;
          lip->m_underscore_cs= cs;

          lip->body_utf8_append(lip->m_cpp_text_start,
                                lip->get_cpp_tok_start() + length);
          return(UNDERSCORE_CHARSET);
        }
      }

      lip->body_utf8_append(lip->m_cpp_text_start);

      lip->body_utf8_append_literal(thd, &yylval->lex_str, cs,
                                    lip->m_cpp_text_end);

927
      return(result_state);			// IDENT or IDENT_QUOTED
bk@work.mysql.com's avatar
bk@work.mysql.com committed
928

929
    case MY_LEX_IDENT_SEP:		// Found ident and now '.'
930 931 932
      yylval->lex_str.str= (char*) lip->get_ptr();
      yylval->lex_str.length= 1;
      c= lip->yyGet();                  // should be '.'
933
      lip->next_state= MY_LEX_IDENT_START;// Next is an ident (not a keyword)
934
      if (!ident_map[lip->yyPeek()])            // Probably ` or "
935
	lip->next_state= MY_LEX_START;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
936 937
      return((int) c);

938
    case MY_LEX_NUMBER_IDENT:		// number or ident which num-start
939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971
      if (lip->yyGetLast() == '0')
      {
        c= lip->yyGet();
        if (c == 'x')
        {
          while (my_isxdigit(cs,(c = lip->yyGet()))) ;
          if ((lip->yyLength() >= 3) && !ident_map[c])
          {
            /* skip '0x' */
            yylval->lex_str=get_token(lip, 2, lip->yyLength()-2);
            return (HEX_NUM);
          }
          lip->yyUnget();
          state= MY_LEX_IDENT_START;
          break;
        }
        else if (c == 'b')
        {
          while ((c= lip->yyGet()) == '0' || c == '1');
          if ((lip->yyLength() >= 3) && !ident_map[c])
          {
            /* Skip '0b' */
            yylval->lex_str= get_token(lip, 2, lip->yyLength()-2);
            return (BIN_NUM);
          }
          lip->yyUnget();
          state= MY_LEX_IDENT_START;
          break;
        }
        lip->yyUnget();
      }

      while (my_isdigit(cs, (c = lip->yyGet()))) ;
972
      if (!ident_map[c])
bk@work.mysql.com's avatar
bk@work.mysql.com committed
973
      {					// Can't be identifier
974
	state=MY_LEX_INT_OR_REAL;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
975 976 977 978
	break;
      }
      if (c == 'e' || c == 'E')
      {
monty@narttu.mysql.fi's avatar
monty@narttu.mysql.fi committed
979
	// The following test is written this way to allow numbers of type 1e1
980 981
        if (my_isdigit(cs,lip->yyPeek()) ||
            (c=(lip->yyGet())) == '+' || c == '-')
bk@work.mysql.com's avatar
bk@work.mysql.com committed
982
	{				// Allow 1E+10
983
          if (my_isdigit(cs,lip->yyPeek()))     // Number must have digit after sign
bk@work.mysql.com's avatar
bk@work.mysql.com committed
984
	  {
985 986 987
            lip->yySkip();
            while (my_isdigit(cs,lip->yyGet())) ;
            yylval->lex_str=get_token(lip, 0, lip->yyLength());
bk@work.mysql.com's avatar
bk@work.mysql.com committed
988 989 990
	    return(FLOAT_NUM);
	  }
	}
991
        lip->yyUnget();
ram@gw.mysql.r18.ru's avatar
ram@gw.mysql.r18.ru committed
992
      }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
993
      // fall through
994
    case MY_LEX_IDENT_START:			// We come here after '.'
995
      result_state= IDENT;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
996
#if defined(USE_MB) && defined(USE_MB_IDENT)
997
      if (use_mb(cs))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
998
      {
999
	result_state= IDENT_QUOTED;
1000
        while (ident_map[c=lip->yyGet()])
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1001
        {
1002
          if (my_mbcharlen(cs, c) > 1)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1003 1004
          {
            int l;
1005 1006 1007
            if ((l = my_ismbchar(cs,
                                 lip->get_ptr() -1,
                                 lip->get_end_of_query())) == 0)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1008
              break;
1009
            lip->skip_binary(l-1);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1010 1011 1012 1013 1014
          }
        }
      }
      else
#endif
1015
      {
1016
        for (result_state=0; ident_map[c= lip->yyGet()]; result_state|= c);
1017 1018 1019
        /* If there were non-ASCII characters, mark that we must convert */
        result_state= result_state & 0x80 ? IDENT_QUOTED : IDENT;
      }
1020
      if (c == '.' && ident_map[lip->yyPeek()])
1021
	lip->next_state=MY_LEX_IDENT_SEP;// Next is '.'
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1022

1023
      yylval->lex_str= get_token(lip, 0, lip->yyLength());
1024 1025 1026 1027 1028

      lip->body_utf8_append(lip->m_cpp_text_start);

      lip->body_utf8_append_literal(thd, &yylval->lex_str, cs,
                                    lip->m_cpp_text_end);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1029

1030
      return(result_state);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1031

1032
    case MY_LEX_USER_VARIABLE_DELIMITER:	// Found quote char
1033
    {
1034 1035
      uint double_quotes= 0;
      char quote_char= c;                       // Used char
1036
      while ((c=lip->yyGet()))
1037
      {
1038 1039
	int var_length;
	if ((var_length= my_mbcharlen(cs, c)) == 1)
1040 1041 1042
	{
	  if (c == quote_char)
	  {
1043
            if (lip->yyPeek() != quote_char)
1044
	      break;
1045
            c=lip->yyGet();
1046 1047 1048
	    double_quotes++;
	    continue;
	  }
1049 1050
	}
#ifdef USE_MB
1051
	else if (var_length < 1)
1052
	  break;				// Error
1053
        lip->skip_binary(var_length-1);
1054
#endif
monty@hundin.mysql.fi's avatar
monty@hundin.mysql.fi committed
1055
      }
1056
      if (double_quotes)
1057
	yylval->lex_str=get_quoted_token(lip, 1,
1058
                                         lip->yyLength() - double_quotes -1,
1059 1060
					 quote_char);
      else
1061
        yylval->lex_str=get_token(lip, 1, lip->yyLength() -1);
1062
      if (c == quote_char)
1063
        lip->yySkip();                  // Skip end `
1064
      lip->next_state= MY_LEX_START;
1065 1066 1067 1068 1069 1070

      lip->body_utf8_append(lip->m_cpp_text_start);

      lip->body_utf8_append_literal(thd, &yylval->lex_str, cs,
                                    lip->m_cpp_text_end);

1071
      return(IDENT_QUOTED);
1072
    }
1073
    case MY_LEX_INT_OR_REAL:		// Complete int or incomplete real
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1074 1075
      if (c != '.')
      {					// Found complete integer number.
1076
        yylval->lex_str=get_token(lip, 0, lip->yyLength());
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1077 1078 1079
	return int_token(yylval->lex_str.str,yylval->lex_str.length);
      }
      // fall through
1080
    case MY_LEX_REAL:			// Incomplete real number
1081
      while (my_isdigit(cs,c = lip->yyGet())) ;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1082 1083 1084

      if (c == 'e' || c == 'E')
      {
1085
        c = lip->yyGet();
1086
	if (c == '-' || c == '+')
1087
          c = lip->yyGet();                     // Skip sign
1088
	if (!my_isdigit(cs,c))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1089
	{				// No digit after sign
1090
	  state= MY_LEX_CHAR;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1091 1092
	  break;
	}
1093 1094
        while (my_isdigit(cs,lip->yyGet())) ;
        yylval->lex_str=get_token(lip, 0, lip->yyLength());
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1095 1096
	return(FLOAT_NUM);
      }
1097
      yylval->lex_str=get_token(lip, 0, lip->yyLength());
1098
      return(DECIMAL_NUM);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1099

1100
    case MY_LEX_HEX_NUMBER:		// Found x'hexstring'
1101 1102 1103 1104 1105 1106 1107 1108
      lip->yySkip();                    // Accept opening '
      while (my_isxdigit(cs, (c= lip->yyGet()))) ;
      if (c != '\'')
        return(ABORT_SYM);              // Illegal hex constant
      lip->yySkip();                    // Accept closing '
      length= lip->yyLength();          // Length of hexnum+3
      if ((length % 2) == 0)
        return(ABORT_SYM);              // odd number of hex digits
1109 1110 1111
      yylval->lex_str=get_token(lip,
                                2,          // skip x'
                                length-3);  // don't count x' and last '
1112 1113
      return (HEX_NUM);

ram@gw.mysql.r18.ru's avatar
ram@gw.mysql.r18.ru committed
1114
    case MY_LEX_BIN_NUMBER:           // Found b'bin-string'
1115 1116
      lip->yySkip();                  // Accept opening '
      while ((c= lip->yyGet()) == '0' || c == '1');
ram@gw.mysql.r18.ru's avatar
ram@gw.mysql.r18.ru committed
1117
      if (c != '\'')
1118 1119 1120
        return(ABORT_SYM);            // Illegal hex constant
      lip->yySkip();                  // Accept closing '
      length= lip->yyLength();        // Length of bin-num + 3
1121 1122 1123 1124
      yylval->lex_str= get_token(lip,
                                 2,         // skip b'
                                 length-3); // don't count b' and last '
      return (BIN_NUM);
ram@gw.mysql.r18.ru's avatar
ram@gw.mysql.r18.ru committed
1125

1126
    case MY_LEX_CMP_OP:			// Incomplete comparison operator
1127 1128 1129 1130
      if (state_map[lip->yyPeek()] == MY_LEX_CMP_OP ||
          state_map[lip->yyPeek()] == MY_LEX_LONG_CMP_OP)
        lip->yySkip();
      if ((tokval = find_keyword(lip, lip->yyLength() + 1, 0)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1131
      {
1132
	lip->next_state= MY_LEX_START;	// Allow signed numbers
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1133 1134
	return(tokval);
      }
1135
      state = MY_LEX_CHAR;		// Something fishy found
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1136 1137
      break;

1138
    case MY_LEX_LONG_CMP_OP:		// Incomplete comparison operator
1139 1140
      if (state_map[lip->yyPeek()] == MY_LEX_CMP_OP ||
          state_map[lip->yyPeek()] == MY_LEX_LONG_CMP_OP)
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1141
      {
1142 1143 1144
        lip->yySkip();
        if (state_map[lip->yyPeek()] == MY_LEX_CMP_OP)
          lip->yySkip();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1145
      }
1146
      if ((tokval = find_keyword(lip, lip->yyLength() + 1, 0)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1147
      {
1148
	lip->next_state= MY_LEX_START;	// Found long op
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1149 1150
	return(tokval);
      }
1151
      state = MY_LEX_CHAR;		// Something fishy found
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1152 1153
      break;

1154
    case MY_LEX_BOOL:
1155
      if (c != lip->yyPeek())
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1156
      {
1157
	state=MY_LEX_CHAR;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1158 1159
	break;
      }
1160
      lip->yySkip();
1161 1162
      tokval = find_keyword(lip,2,0);	// Is a bool operator
      lip->next_state= MY_LEX_START;	// Allow signed numbers
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1163 1164
      return(tokval);

1165
    case MY_LEX_STRING_OR_DELIMITER:
1166
      if (thd->variables.sql_mode & MODE_ANSI_QUOTES)
1167
      {
1168
	state= MY_LEX_USER_VARIABLE_DELIMITER;
1169 1170 1171
	break;
      }
      /* " used for strings */
1172
    case MY_LEX_STRING:			// Incomplete text string
1173
      if (!(yylval->lex_str.str = get_text(lip, 1, 1)))
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1174
      {
1175
	state= MY_LEX_CHAR;		// Read char by char
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1176 1177
	break;
      }
1178
      yylval->lex_str.length=lip->yytoklen;
1179 1180 1181 1182 1183 1184 1185 1186 1187

      lip->body_utf8_append(lip->m_cpp_text_start);

      lip->body_utf8_append_literal(thd, &yylval->lex_str,
        lip->m_underscore_cs ? lip->m_underscore_cs : cs,
        lip->m_cpp_text_end);

      lip->m_underscore_cs= NULL;

1188
      lex->text_string_is_7bit= (lip->tok_bitmap & 0x80) ? 0 : 1;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1189 1190
      return(TEXT_STRING);

1191
    case MY_LEX_COMMENT:			//  Comment
1192
      lex->select_lex.options|= OPTION_FOUND_COMMENT;
1193 1194
      while ((c = lip->yyGet()) != '\n' && c) ;
      lip->yyUnget();                   // Safety against eof
1195
      state = MY_LEX_START;		// Try again
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1196
      break;
1197
    case MY_LEX_LONG_COMMENT:		/* Long C comment? */
1198
      if (lip->yyPeek() != '*')
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1199
      {
1200
	state=MY_LEX_CHAR;		// Probable division
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1201 1202
	break;
      }
1203
      lex->select_lex.options|= OPTION_FOUND_COMMENT;
1204 1205 1206 1207
      /* Reject '/' '*', since we might need to turn off the echo */
      lip->yyUnget();

      if (lip->yyPeekn(2) == '!')
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1208
      {
1209 1210
        lip->in_comment= DISCARD_COMMENT;
        /* Accept '/' '*' '!', but do not keep this marker. */
kostja@bodhi.(none)'s avatar
kostja@bodhi.(none) committed
1211
        lip->set_echo(FALSE);
1212 1213 1214 1215 1216 1217 1218
        lip->yySkip();
        lip->yySkip();
        lip->yySkip();

        /*
          The special comment format is very strict:
          '/' '*' '!', followed by exactly
1219 1220 1221 1222
          1 digit (major), 2 digits (minor), then 2 digits (dot).
          32302 -> 3.23.02
          50032 -> 5.0.32
          50114 -> 5.1.14
1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240
        */
        char version_str[6];
        version_str[0]= lip->yyPeekn(0);
        version_str[1]= lip->yyPeekn(1);
        version_str[2]= lip->yyPeekn(2);
        version_str[3]= lip->yyPeekn(3);
        version_str[4]= lip->yyPeekn(4);
        version_str[5]= 0;
        if (  my_isdigit(cs, version_str[0])
           && my_isdigit(cs, version_str[1])
           && my_isdigit(cs, version_str[2])
           && my_isdigit(cs, version_str[3])
           && my_isdigit(cs, version_str[4])
           )
        {
          ulong version;
          version=strtol(version_str, NULL, 10);

1241
          /* Accept 'M' 'm' 'm' 'd' 'd' */
1242 1243 1244 1245 1246
          lip->yySkipn(5);

          if (version <= MYSQL_VERSION_ID)
          {
            /* Expand the content of the special comment as real code */
kostja@bodhi.(none)'s avatar
kostja@bodhi.(none) committed
1247
            lip->set_echo(TRUE);
1248 1249 1250 1251 1252 1253 1254
            state=MY_LEX_START;
            break;
          }
        }
        else
        {
          state=MY_LEX_START;
kostja@bodhi.(none)'s avatar
kostja@bodhi.(none) committed
1255
          lip->set_echo(TRUE);
1256 1257
          break;
        }
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1258
      }
1259
      else
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1260
      {
1261 1262 1263
        lip->in_comment= PRESERVE_COMMENT;
        lip->yySkip();                  // Accept /
        lip->yySkip();                  // Accept *
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1264
      }
1265 1266 1267 1268 1269 1270 1271 1272 1273 1274
      /*
        Discard:
        - regular '/' '*' comments,
        - special comments '/' '*' '!' for a future version,
        by scanning until we find a closing '*' '/' marker.
        Note: There is no such thing as nesting comments,
        the first '*' '/' sequence seen will mark the end.
      */
      comment_closed= FALSE;
      while (! lip->eof())
1275
      {
1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287
        c= lip->yyGet();
        if (c == '*')
        {
          if (lip->yyPeek() == '/')
          {
            lip->yySkip();
            comment_closed= TRUE;
            state = MY_LEX_START;
            break;
          }
        }
        else if (c == '\n')
1288 1289
          lip->yylineno++;
      }
1290 1291 1292
      /* Unbalanced comments with a missing '*' '/' are a syntax error */
      if (! comment_closed)
        return (ABORT_SYM);
1293
      state = MY_LEX_START;             // Try again
1294
      lip->in_comment= NO_COMMENT;
kostja@bodhi.(none)'s avatar
kostja@bodhi.(none) committed
1295
      lip->set_echo(TRUE);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1296
      break;
1297
    case MY_LEX_END_LONG_COMMENT:
1298
      if ((lip->in_comment != NO_COMMENT) && lip->yyPeek() == '/')
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1299
      {
1300 1301 1302 1303 1304 1305
        /* Reject '*' '/' */
        lip->yyUnget();
        /* Accept '*' '/', with the proper echo */
        lip->set_echo(lip->in_comment == PRESERVE_COMMENT);
        lip->yySkipn(2);
        /* And start recording the tokens again */
kostja@bodhi.(none)'s avatar
kostja@bodhi.(none) committed
1306
        lip->set_echo(TRUE);
1307 1308
        lip->in_comment=NO_COMMENT;
        state=MY_LEX_START;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1309 1310
      }
      else
1311
	state=MY_LEX_CHAR;		// Return '*'
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1312
      break;
1313
    case MY_LEX_SET_VAR:		// Check if ':='
1314
      if (lip->yyPeek() != '=')
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1315
      {
1316
	state=MY_LEX_CHAR;		// Return ':'
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1317 1318
	break;
      }
1319
      lip->yySkip();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1320
      return (SET_VAR);
1321
    case MY_LEX_SEMICOLON:			// optional line terminator
1322 1323
      state= MY_LEX_CHAR;               // Return ';'
      break;
1324
    case MY_LEX_EOL:
1325
      if (lip->eof())
1326
      {
1327
        lip->yyUnget();                 // Reject the last '\0'
kostja@bodhi.(none)'s avatar
kostja@bodhi.(none) committed
1328
        lip->set_echo(FALSE);
1329
        lip->yySkip();
kostja@bodhi.(none)'s avatar
kostja@bodhi.(none) committed
1330
        lip->set_echo(TRUE);
1331 1332 1333
        /* Unbalanced comments with a missing '*' '/' are a syntax error */
        if (lip->in_comment != NO_COMMENT)
          return (ABORT_SYM);
1334 1335
        lip->next_state=MY_LEX_END;     // Mark for next loop
        return(END_OF_INPUT);
1336 1337 1338
      }
      state=MY_LEX_CHAR;
      break;
1339
    case MY_LEX_END:
1340
      lip->next_state=MY_LEX_END;
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1341
      return(0);			// We found end of input last time
1342

1343
      /* Actually real shouldn't start with . but allow them anyhow */
1344
    case MY_LEX_REAL_OR_POINT:
1345
      if (my_isdigit(cs,lip->yyPeek()))
1346
	state = MY_LEX_REAL;		// Real
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1347 1348
      else
      {
1349
	state= MY_LEX_IDENT_SEP;	// return '.'
1350
        lip->yyUnget();                 // Put back '.'
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1351 1352
      }
      break;
1353
    case MY_LEX_USER_END:		// end '@' of user@hostname
1354
      switch (state_map[lip->yyPeek()]) {
1355 1356 1357
      case MY_LEX_STRING:
      case MY_LEX_USER_VARIABLE_DELIMITER:
      case MY_LEX_STRING_OR_DELIMITER:
1358
	break;
1359
      case MY_LEX_USER_END:
1360
	lip->next_state=MY_LEX_SYSTEM_VAR;
1361 1362
	break;
      default:
1363
	lip->next_state=MY_LEX_HOSTNAME;
1364 1365
	break;
      }
1366
      yylval->lex_str.str=(char*) lip->get_ptr();
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1367 1368
      yylval->lex_str.length=1;
      return((int) '@');
1369
    case MY_LEX_HOSTNAME:		// end '@' of user@hostname
1370
      for (c=lip->yyGet() ;
1371
	   my_isalnum(cs,c) || c == '.' || c == '_' ||  c == '$';
1372 1373
           c= lip->yyGet()) ;
      yylval->lex_str=get_token(lip, 0, lip->yyLength());
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1374
      return(LEX_HOSTNAME);
1375
    case MY_LEX_SYSTEM_VAR:
1376
      yylval->lex_str.str=(char*) lip->get_ptr();
1377
      yylval->lex_str.length=1;
1378 1379
      lip->yySkip();                                    // Skip '@'
      lip->next_state= (state_map[lip->yyPeek()] ==
1380 1381 1382
			MY_LEX_USER_VARIABLE_DELIMITER ?
			MY_LEX_OPERATOR_OR_IDENT :
			MY_LEX_IDENT_OR_KEYWORD);
1383
      return((int) '@');
1384
    case MY_LEX_IDENT_OR_KEYWORD:
1385 1386 1387 1388 1389
      /*
	We come here when we have found two '@' in a row.
	We should now be able to handle:
	[(global | local | session) .]variable_name
      */
1390 1391

      for (result_state= 0; ident_map[c= lip->yyGet()]; result_state|= c);
1392 1393
      /* If there were non-ASCII characters, mark that we must convert */
      result_state= result_state & 0x80 ? IDENT_QUOTED : IDENT;
1394

1395
      if (c == '.')
1396
	lip->next_state=MY_LEX_IDENT_SEP;
1397 1398
      length= lip->yyLength();
      if (length == 0)
1399
        return(ABORT_SYM);              // Names must be nonempty.
1400
      if ((tokval= find_keyword(lip, length,0)))
1401
      {
1402
        lip->yyUnget();                         // Put back 'c'
1403 1404
	return(tokval);				// Was keyword
      }
1405
      yylval->lex_str=get_token(lip, 0, length);
1406 1407 1408 1409 1410 1411

      lip->body_utf8_append(lip->m_cpp_text_start);

      lip->body_utf8_append_literal(thd, &yylval->lex_str, cs,
                                    lip->m_cpp_text_end);

1412
      return(result_state);
bk@work.mysql.com's avatar
bk@work.mysql.com committed
1413 1414 1415
    }
  }
}
1416

1417

kostja@bodhi.(none)'s avatar
kostja@bodhi.(none) committed
1418 1419 1420
/**
  Construct a copy of this object to be used for mysql_alter_table
  and mysql_create_table.
1421

kostja@bodhi.(none)'s avatar
kostja@bodhi.(none) committed
1422 1423 1424 1425
  Historically, these two functions modify their Alter_info
  arguments. This behaviour breaks re-execution of prepared
  statements and stored procedures and is compensated by always
  supplying a copy of Alter_info to these functions.
1426

kostja@bodhi.(none)'s avatar
kostja@bodhi.(none) committed
1427 1428
  @return You need to use check the error in THD for out
  of memory condition after calling this function.
1429 1430
*/

1431 1432 1433 1434 1435 1436 1437 1438 1439
Alter_info::Alter_info(const Alter_info &rhs, MEM_ROOT *mem_root)
  :drop_list(rhs.drop_list, mem_root),
  alter_list(rhs.alter_list, mem_root),
  key_list(rhs.key_list, mem_root),
  create_list(rhs.create_list, mem_root),
  flags(rhs.flags),
  keys_onoff(rhs.keys_onoff),
  tablespace_op(rhs.tablespace_op),
  partition_names(rhs.partition_names, mem_root),
igor@olga.mysql.com's avatar
igor@olga.mysql.com committed
1440 1441 1442 1443
  no_parts(rhs.no_parts),
  change_level(rhs.change_level),
  datetime_field(rhs.datetime_field),
  error_if_not_empty(rhs.error_if_not_empty)
1444
{
1445 1446 1447
  /*
    Make deep copies of used objects.
    This is not a fully deep copy - clone() implementations
1448
    of Alter_drop, Alter_column, Key, foreign_key, Key_part_spec
1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461
    do not copy string constants. At the same length the only
    reason we make a copy currently is that ALTER/CREATE TABLE
    code changes input Alter_info definitions, but string
    constants never change.
  */
  list_copy_and_replace_each_value(drop_list, mem_root);
  list_copy_and_replace_each_value(alter_list, mem_root);
  list_copy_and_replace_each_value(key_list, mem_root);
  list_copy_and_replace_each_value(create_list, mem_root);
  /* partition_names are not deeply copied currently */
}


1462 1463 1464 1465 1466 1467 1468
void trim_whitespace(CHARSET_INFO *cs, LEX_STRING *str)
{
  /*
    TODO:
    This code assumes that there are no multi-bytes characters
    that can be considered white-space.
  */
1469

1470 1471 1472 1473 1474
  while ((str->length > 0) && (my_isspace(cs, str->str[0])))
  {
    str->length --;
    str->str ++;
  }
1475

1476 1477 1478 1479 1480 1481 1482 1483
  /*
    FIXME:
    Also, parsing backward is not safe with multi bytes characters
  */
  while ((str->length > 0) && (my_isspace(cs, str->str[str->length-1])))
  {
    str->length --;
  }
1484 1485
}

1486

1487 1488 1489 1490 1491 1492
/*
  st_select_lex structures initialisations
*/

void st_select_lex_node::init_query()
{
1493
  options= 0;
1494
  sql_cache= SQL_CACHE_UNSPECIFIED;
1495
  linkage= UNSPECIFIED_TYPE;
1496 1497
  no_error= no_table_names_allowed= 0;
  uncacheable= 0;
1498 1499 1500 1501 1502 1503 1504 1505 1506
}

void st_select_lex_node::init_select()
{
}

void st_select_lex_unit::init_query()
{
  st_select_lex_node::init_query();
1507
  linkage= GLOBAL_OPTIONS_TYPE;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1508
  global_parameters= first_select();
1509 1510
  select_limit_cnt= HA_POS_ERROR;
  offset_limit_cnt= 0;
1511
  union_distinct= 0;
1512
  prepared= optimized= executed= 0;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1513
  item= 0;
1514 1515
  union_result= 0;
  table= 0;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1516
  fake_select_lex= 0;
1517
  cleaned= 0;
1518
  item_list.empty();
1519
  describe= 0;
1520
  found_rows_for_union= 0;
1521 1522 1523 1524 1525
}

void st_select_lex::init_query()
{
  st_select_lex_node::init_query();
1526
  table_list.empty();
1527 1528
  top_join_list.empty();
  join_list= &top_join_list;
1529
  embedding= leaf_tables= 0;
1530
  item_list.empty();
1531
  join= 0;
1532
  having= prep_having= where= prep_where= 0;
1533
  olap= UNSPECIFIED_OLAP_TYPE;
1534
  having_fix_field= 0;
1535 1536
  context.select_lex= this;
  context.init();
1537 1538 1539
  /*
    Add the name resolution context of the current (sub)query to the
    stack of contexts for the whole query.
1540 1541 1542 1543 1544
    TODO:
    push_context may return an error if there is no memory for a new
    element in the stack, however this method has no return value,
    thus push_context should be moved to a place where query
    initialization is checked for failure.
1545 1546
  */
  parent_lex->push_context(&context);
1547
  cond_count= between_count= with_wild= 0;
igor@olga.mysql.com's avatar
igor@olga.mysql.com committed
1548
  max_equal_elems= 0;
1549
  conds_processed_with_permanent_arena= 0;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1550
  ref_pointer_array= 0;
evgen@moonbone.local's avatar
evgen@moonbone.local committed
1551
  select_n_where_fields= 0;
bell@laptop.sanja.is.com.ua's avatar
bell@laptop.sanja.is.com.ua committed
1552
  select_n_having_items= 0;
1553
  subquery_in_having= explicit_limit= 0;
1554
  is_item_list_lookup= 0;
1555
  first_execution= 1;
1556
  first_natural_join_processing= 1;
1557
  first_cond_optimization= 1;
1558
  parsing_place= NO_MATTER;
1559
  exclude_from_table_unique_test= no_wrap_view_item= FALSE;
igor@rurik.mysql.com's avatar
igor@rurik.mysql.com committed
1560
  nest_level= 0;
1561
  link_next= 0;
1562 1563 1564 1565 1566
}

void st_select_lex::init_select()
{
  st_select_lex_node::init_select();
1567
  group_list.empty();
1568
  type= db= 0;
1569 1570 1571
  having= 0;
  table_join_options= 0;
  in_sum_expr= with_wild= 0;
1572
  options= 0;
1573
  sql_cache= SQL_CACHE_UNSPECIFIED;
1574
  braces= 0;
1575
  interval_list.empty();
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1576
  ftfunc_list_alloc.empty();
igor@rurik.mysql.com's avatar
igor@rurik.mysql.com committed
1577
  inner_sum_func_list= 0;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1578
  ftfunc_list= &ftfunc_list_alloc;
1579
  linkage= UNSPECIFIED_TYPE;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1580 1581
  order_list.elements= 0;
  order_list.first= 0;
1582
  order_list.next= (uchar**) &order_list.first;
1583 1584 1585
  /* Set limit and offset to default values */
  select_limit= 0;      /* denotes the default limit = HA_POS_ERROR */
  offset_limit= 0;      /* denotes the default offset = 0 */
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1586
  with_sum_func= 0;
1587
  is_correlated= 0;
1588 1589
  cur_pos_in_select_list= UNDEF_POS;
  non_agg_fields.empty();
1590
  cond_value= having_value= Item::COND_UNDEF;
1591
  inner_refs_list.empty();
1592
  full_group_by_flag= 0;
1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606
}

/*
  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;
1607
  slave= 0;
1608 1609
}

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1610 1611
/*
  include on level down (but do not link)
1612

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626
  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;
}

1627 1628 1629 1630 1631 1632 1633 1634
/* 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;
1635
  slave= 0;
1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649
}

/* 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()
{
1650
  if (link_prev)
1651 1652 1653 1654
  {
    if ((*link_prev= link_next))
      link_next->link_prev= link_prev;
  }
1655 1656 1657 1658
  // Remove slave structure
  for (; slave; slave= slave->next)
    slave->fast_exclude();
  
1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678
}

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

1680 1681 1682 1683 1684 1685 1686 1687 1688 1689

/*
  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 
*/
1690 1691 1692
void st_select_lex_unit::exclude_level()
{
  SELECT_LEX_UNIT *units= 0, **units_last= &units;
1693
  for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
1694
  {
1695
    // unlink current level from global SELECTs list
1696 1697
    if (sl->link_prev && (*sl->link_prev= sl->link_next))
      sl->link_next->link_prev= sl->link_prev;
1698 1699

    // bring up underlay levels
1700 1701
    SELECT_LEX_UNIT **last= 0;
    for (SELECT_LEX_UNIT *u= sl->first_inner_unit(); u; u= u->next_unit())
1702 1703
    {
      u->master= master;
1704
      last= (SELECT_LEX_UNIT**)&(u->next);
1705
    }
1706 1707 1708 1709 1710 1711 1712 1713
    if (last)
    {
      (*units_last)= sl->first_inner_unit();
      units_last= last;
    }
  }
  if (units)
  {
1714
    // include brought up levels in place of current
1715 1716
    (*prev)= units;
    (*units_last)= (SELECT_LEX_UNIT*)next;
1717 1718 1719
    if (next)
      next->prev= (SELECT_LEX_NODE**)units_last;
    units->prev= prev;
1720 1721
  }
  else
1722 1723
  {
    // exclude currect unit from list of nodes
1724
    (*prev)= next;
1725 1726 1727
    if (next)
      next->prev= prev;
  }
1728 1729
}

1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740

/*
  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())
  {
1741
    // unlink current level from global SELECTs list
1742 1743 1744
    if (sl->link_prev && (*sl->link_prev= sl->link_next))
      sl->link_next->link_prev= sl->link_prev;

1745
    // unlink underlay levels
1746 1747 1748 1749 1750
    for (SELECT_LEX_UNIT *u= sl->first_inner_unit(); u; u= u->next_unit())
    {
      u->exclude_level();
    }
  }
1751
  // exclude currect unit from list of nodes
1752
  (*prev)= next;
1753 1754
  if (next)
    next->prev= prev;
1755 1756 1757
}


1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769
/*
  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
*/

kostja@bodhi.(none)'s avatar
kostja@bodhi.(none) committed
1770
void st_select_lex::mark_as_dependent(st_select_lex *last)
1771 1772 1773 1774 1775
{
  /*
    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
1776
  for (SELECT_LEX *s= this;
1777
       s && s != last;
1778
       s= s->outer_select())
1779
    if (!(s->uncacheable & UNCACHEABLE_DEPENDENT))
1780 1781
    {
      // Select is dependent of outer select
1782 1783
      s->uncacheable= (s->uncacheable & ~UNCACHEABLE_UNITED) |
                       UNCACHEABLE_DEPENDENT;
1784
      SELECT_LEX_UNIT *munit= s->master_unit();
1785 1786 1787 1788 1789 1790 1791 1792
      munit->uncacheable= (munit->uncacheable & ~UNCACHEABLE_UNITED) |
                       UNCACHEABLE_DEPENDENT;
      for (SELECT_LEX *sl= munit->first_select(); sl ; sl= sl->next_select())
      {
        if (sl != s &&
            !(sl->uncacheable & (UNCACHEABLE_DEPENDENT | UNCACHEABLE_UNITED)))
          sl->uncacheable|= UNCACHEABLE_UNITED;
      }
1793
    }
1794 1795
  is_correlated= TRUE;
  this->master_unit()->item->is_correlated= TRUE;
1796 1797
}

1798 1799 1800 1801 1802
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; }
1803
TABLE_LIST *st_select_lex_node::add_table_to_list (THD *thd, Table_ident *table,
1804
						  LEX_STRING *alias,
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1805
						  ulong table_join_options,
1806
						  thr_lock_type flags,
1807
						  List<Index_hint> *hints,
igor@rurik.mysql.com's avatar
igor@rurik.mysql.com committed
1808
                                                  LEX_STRING *option)
1809 1810 1811
{
  return 0;
}
1812 1813 1814 1815 1816 1817 1818 1819
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
1820
bool st_select_lex::test_limit()
1821
{
1822
  if (select_limit != 0)
1823 1824
  {
    my_error(ER_NOT_SUPPORTED_YET, MYF(0),
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1825
             "LIMIT & IN/ALL/ANY/SOME subquery");
1826 1827 1828 1829
    return(1);
  }
  return(0);
}
1830

1831

1832 1833 1834 1835 1836
st_select_lex_unit* st_select_lex_unit::master_unit()
{
    return this;
}

1837

1838 1839 1840 1841 1842
st_select_lex* st_select_lex_unit::outer_select()
{
  return (st_select_lex*) master;
}

1843

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1844
bool st_select_lex::add_order_to_list(THD *thd, Item *item, bool asc)
1845
{
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1846
  return add_to_list(thd, order_list, item, asc);
1847
}
1848

1849

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1850
bool st_select_lex::add_item_to_list(THD *thd, Item *item)
1851
{
1852
  DBUG_ENTER("st_select_lex::add_item_to_list");
1853
  DBUG_PRINT("info", ("Item: 0x%lx", (long) item));
1854
  DBUG_RETURN(item_list.push_back(item));
1855 1856
}

1857

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1858
bool st_select_lex::add_group_to_list(THD *thd, Item *item, bool asc)
1859
{
monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1860
  return add_to_list(thd, group_list, item, asc);
1861 1862
}

1863

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

1869

1870 1871 1872 1873 1874
st_select_lex_unit* st_select_lex::master_unit()
{
  return (st_select_lex_unit*) master;
}

1875

1876 1877 1878 1879 1880
st_select_lex* st_select_lex::outer_select()
{
  return (st_select_lex*) master->get_master();
}

1881

1882 1883 1884 1885 1886 1887
bool st_select_lex::set_braces(bool value)
{
  braces= value;
  return 0; 
}

1888

1889 1890 1891 1892 1893 1894
bool st_select_lex::inc_in_sum_expr()
{
  in_sum_expr++;
  return 0;
}

1895

1896 1897 1898 1899 1900
uint st_select_lex::get_in_sum_expr()
{
  return in_sum_expr;
}

1901

1902 1903 1904 1905 1906 1907 1908 1909 1910 1911
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;
}

monty@mashka.mysql.fi's avatar
monty@mashka.mysql.fi committed
1912 1913 1914 1915 1916
ulong st_select_lex::get_table_join_options()
{
  return table_join_options;
}

1917

bell@laptop.sanja.is.com.ua's avatar
bell@laptop.sanja.is.com.ua committed
1918 1919 1920 1921
bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num)
{
  if (ref_pointer_array)
    return 0;
1922 1923 1924 1925 1926

  /*
    We have to create array in prepared statement memory if it is
    prepared statement
  */
konstantin@mysql.com's avatar
konstantin@mysql.com committed
1927
  Query_arena *arena= thd->stmt_arena;
serg@serg.mylan's avatar
serg@serg.mylan committed
1928
  return (ref_pointer_array=
1929 1930 1931
          (Item **)arena->alloc(sizeof(Item*) * (n_child_sum_items +
                                                 item_list.elements +
                                                 select_n_having_items +
evgen@moonbone.local's avatar
evgen@moonbone.local committed
1932
                                                 select_n_where_fields +
1933
                                                 order_group_num)*5)) == 0;
bell@laptop.sanja.is.com.ua's avatar
bell@laptop.sanja.is.com.ua committed
1934 1935
}

1936

1937
void st_select_lex_unit::print(String *str, enum_query_type query_type)
1938
{
1939
  bool union_all= !union_distinct;
1940 1941 1942 1943
  for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
  {
    if (sl != first_select())
    {
1944
      str->append(STRING_WITH_LEN(" union "));
1945
      if (union_all)
1946
	str->append(STRING_WITH_LEN("all "));
1947
      else if (union_distinct == sl)
1948
        union_all= TRUE;
1949 1950 1951
    }
    if (sl->braces)
      str->append('(');
1952
    sl->print(thd, str, query_type);
1953 1954 1955 1956 1957 1958 1959
    if (sl->braces)
      str->append(')');
  }
  if (fake_select_lex == global_parameters)
  {
    if (fake_select_lex->order_list.elements)
    {
1960
      str->append(STRING_WITH_LEN(" order by "));
1961 1962 1963 1964
      fake_select_lex->print_order(
        str,
        (ORDER *) fake_select_lex->order_list.first,
        query_type);
1965
    }
1966
    fake_select_lex->print_limit(thd, str, query_type);
1967 1968 1969 1970
  }
}


1971 1972 1973
void st_select_lex::print_order(String *str,
                                ORDER *order,
                                enum_query_type query_type)
1974 1975 1976
{
  for (; order; order= order->next)
  {
1977 1978 1979
    if (order->counter_used)
    {
      char buffer[20];
monty@mysql.com's avatar
monty@mysql.com committed
1980 1981
      uint length= my_snprintf(buffer, 20, "%d", order->counter);
      str->append(buffer, length);
1982 1983
    }
    else
1984
      (*order->item)->print(str, query_type);
1985
    if (!order->asc)
1986
      str->append(STRING_WITH_LEN(" desc"));
1987 1988 1989 1990 1991
    if (order->next)
      str->append(',');
  }
}
 
1992

1993 1994 1995
void st_select_lex::print_limit(THD *thd,
                                String *str,
                                enum_query_type query_type)
1996
{
1997 1998 1999
  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
2000 2001 2002 2003
      (item->substype() == Item_subselect::EXISTS_SUBS ||
       item->substype() == Item_subselect::IN_SUBS ||
       item->substype() == Item_subselect::ALL_SUBS))
  {
2004 2005
    DBUG_ASSERT(!item->fixed ||
                select_limit->val_int() == LL(1) && offset_limit == 0);
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
2006 2007 2008
    return;
  }

2009
  if (explicit_limit)
2010
  {
2011
    str->append(STRING_WITH_LEN(" limit "));
2012 2013
    if (offset_limit)
    {
2014
      offset_limit->print(str, query_type);
2015 2016
      str->append(',');
    }
2017
    select_limit->print(str, query_type);
2018 2019 2020
  }
}

2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044
/**
  @brief Restore the LEX and THD in case of a parse error.

  This is a clean up call that is invoked by the Bison generated
  parser before returning an error from MYSQLparse. If your
  semantic actions manipulate with the global thread state (which
  is a very bad practice and should not normally be employed) and
  need a clean-up in case of error, and you can not use %destructor
  rule in the grammar file itself, this function should be used
  to implement the clean up.
*/

void st_lex::cleanup_lex_after_parse_error(THD *thd)
{
  /*
    Delete sphead for the side effect of restoring of the original
    LEX state, thd->lex, thd->mem_root and thd->free_list if they
    were replaced when parsing stored procedure statements.  We
    will never use sphead object after a parse error, so it's okay
    to delete it only for the sake of the side effect.
    TODO: make this functionality explicit in sp_head class.
    Sic: we must nullify the member of the main lex, not the
    current one that will be thrown away
  */
2045
  if (thd->lex->sphead)
2046 2047 2048 2049 2050
  {
    delete thd->lex->sphead;
    thd->lex->sphead= NULL;
  }
}
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
2051

2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071
/*
  Initialize (or reset) Query_tables_list object.

  SYNOPSIS
    reset_query_tables_list()
      init  TRUE  - we should perform full initialization of object with
                    allocating needed memory
            FALSE - object is already initialized so we should only reset
                    its state so it can be used for parsing/processing
                    of new statement

  DESCRIPTION
    This method initializes Query_tables_list so it can be used as part
    of LEX object for parsing/processing of statement. One can also use
    this method to reset state of already initialized Query_tables_list
    so it can be used for processing of new statement.
*/

void Query_tables_list::reset_query_tables_list(bool init)
{
antony@ppcg5.local's avatar
antony@ppcg5.local committed
2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082
  if (!init && query_tables)
  {
    TABLE_LIST *table= query_tables;
    for (;;)
    {
      delete table->view;
      if (query_tables_last == &table->next_global ||
          !(table= table->next_global))
        break;
    }
  }
2083 2084 2085 2086
  query_tables= 0;
  query_tables_last= &query_tables;
  query_tables_own_last= 0;
  if (init)
2087 2088 2089 2090 2091 2092 2093
  {
    /*
      We delay real initialization of hash (and therefore related
      memory allocation) until first insertion into this hash.
    */
    hash_clear(&sroutines);
  }
2094
  else if (sroutines.records)
2095 2096
  {
    /* Non-zero sroutines.records means that hash was initialized. */
2097
    my_hash_reset(&sroutines);
2098
  }
2099 2100 2101
  sroutines_list.empty();
  sroutines_list_own_last= sroutines_list.next;
  sroutines_list_own_elements= 0;
2102
  binlog_stmt_flags= 0;
2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118
}


/*
  Destroy Query_tables_list object with freeing all resources used by it.

  SYNOPSIS
    destroy_query_tables_list()
*/

void Query_tables_list::destroy_query_tables_list()
{
  hash_free(&sroutines);
}


2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133
/*
  Initialize LEX object.

  SYNOPSIS
    st_lex::st_lex()

  NOTE
    LEX object initialized with this constructor can be used as part of
    THD object for which one can safely call open_tables(), lock_tables()
    and close_thread_tables() functions. But it is not yet ready for
    statement parsing. On should use lex_start() function to prepare LEX
    for this.
*/

st_lex::st_lex()
2134
  :result(0),
2135
   sql_command(SQLCOM_END), option_type(OPT_DEFAULT), is_lex_started(0)
2136
{
antony@ppcg5.local's avatar
antony@ppcg5.local committed
2137

antony@ppcg5.local's avatar
antony@ppcg5.local committed
2138 2139 2140 2141
  my_init_dynamic_array2(&plugins, sizeof(plugin_ref),
                         plugins_static_buffer,
                         INITIAL_LEX_PLUGIN_LIST_SIZE, 
                         INITIAL_LEX_PLUGIN_LIST_SIZE);
2142
  reset_query_tables_list(TRUE);
2143 2144 2145
}


bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
2146
/*
2147
  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
2148 2149 2150 2151

  SYNOPSIS
    st_lex::can_be_merged()

2152
  DESCRIPTION
2153 2154 2155
    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,
2156 2157 2158
    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
2159 2160 2161 2162 2163 2164 2165 2166 2167 2168
  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 */
2169 2170 2171
  bool selects_allow_merge= select_lex.next_select() == 0;
  if (selects_allow_merge)
  {
2172 2173 2174
    for (SELECT_LEX_UNIT *tmp_unit= select_lex.first_inner_unit();
         tmp_unit;
         tmp_unit= tmp_unit->next_unit())
2175
    {
2176 2177 2178 2179
      if (tmp_unit->first_select()->parent_lex == this &&
          (tmp_unit->item == 0 ||
           (tmp_unit->item->place() != IN_WHERE &&
            tmp_unit->item->place() != IN_ON)))
2180 2181 2182 2183 2184 2185 2186 2187
      {
        selects_allow_merge= 0;
        break;
      }
    }
  }

  return (selects_allow_merge &&
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
2188 2189
	  select_lex.group_list.elements == 0 &&
	  select_lex.having == 0 &&
2190
          select_lex.with_sum_func == 0 &&
2191
	  select_lex.table_list.elements >= 1 &&
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
2192
	  !(select_lex.options & SELECT_DISTINCT) &&
2193
          select_lex.select_limit == 0);
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
2194 2195
}

2196

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
2197
/*
2198
  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
2199 2200 2201 2202

  SYNOPSIS
    st_lex::can_use_merged()

2203 2204 2205 2206 2207
  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
2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226
  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:
2227
  case SQLCOM_LOAD:
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
2228 2229 2230 2231 2232 2233
    return TRUE;
  default:
    return FALSE;
  }
}

2234
/*
2235
  Check if command can't use merged views in any part of command
2236 2237 2238 2239

  SYNOPSIS
    st_lex::can_not_use_merged()

2240 2241 2242 2243
  DESCRIPTION
    Temporary table algorithm will be used on all SELECT levels for queries
    listed here (see also st_lex::can_use_merged()).

2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254
  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:
2255 2256 2257 2258 2259 2260
  /*
    SQLCOM_SHOW_FIELDS is necessary to make 
    information schema tables working correctly with views.
    see get_schema_tables_result function
  */
  case SQLCOM_SHOW_FIELDS:
2261 2262 2263 2264 2265 2266
    return TRUE;
  default:
    return FALSE;
  }
}

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
2267 2268 2269 2270 2271 2272 2273 2274 2275 2276
/*
  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
*/
2277

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
2278 2279
bool st_lex::only_view_structure()
{
2280
  switch (sql_command) {
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294
  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;
  }
}


2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319
/*
  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;
  }
}

2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336
/*
  Get effective type of CHECK OPTION for given view

  SYNOPSIS
    get_effective_with_check()
    view    given view

  NOTE
    It have not sense to set CHECK OPTION for SELECT satement or subqueries,
    so we do not.

  RETURN
    VIEW_CHECK_NONE      no need CHECK OPTION
    VIEW_CHECK_LOCAL     CHECK OPTION LOCAL
    VIEW_CHECK_CASCADED  CHECK OPTION CASCADED
*/

2337
uint8 st_lex::get_effective_with_check(TABLE_LIST *view)
2338 2339 2340 2341 2342 2343 2344
{
  if (view->select_lex->master_unit() == &unit &&
      which_check_option_applicable())
    return (uint8)view->with_check;
  return VIEW_CHECK_NONE;
}

2345

2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365
/**
  This method should be called only during parsing.
  It is aware of compound statements (stored routine bodies)
  and will initialize the destination with the default
  database of the stored routine, rather than the default
  database of the connection it is parsed in.
  E.g. if one has no current database selected, or current database 
  set to 'bar' and then issues:

  CREATE PROCEDURE foo.p1() BEGIN SELECT * FROM t1 END//

  t1 is meant to refer to foo.t1, not to bar.t1.

  This method is needed to support this rule.

  @return TRUE in case of error (parsing should be aborted, FALSE in
  case of success
*/

bool
2366
st_lex::copy_db_to(char **p_db, size_t *p_db_length) const
2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382
{
  if (sphead)
  {
    DBUG_ASSERT(sphead->m_db.str && sphead->m_db.length);
    /*
      It is safe to assign the string by-pointer, both sphead and
      its statements reside in the same memory root.
    */
    *p_db= sphead->m_db.str;
    if (p_db_length)
      *p_db_length= sphead->m_db.length;
    return FALSE;
  }
  return thd->copy_db_to(p_db, p_db_length);
}

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2383 2384 2385 2386 2387 2388 2389
/*
  initialize limit counters

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

kostja@bodhi.(none)'s avatar
kostja@bodhi.(none) committed
2391
void st_select_lex_unit::set_limit(st_select_lex *sl)
2392
{
2393
  ha_rows select_limit_val;
2394
  ulonglong val;
2395

konstantin@mysql.com's avatar
konstantin@mysql.com committed
2396
  DBUG_ASSERT(! thd->stmt_arena->is_stmt_prepare());
2397 2398 2399
  val= sl->select_limit ? sl->select_limit->val_uint() : HA_POS_ERROR;
  select_limit_val= (ha_rows)val;
#ifndef BIG_TABLES
2400
  /*
2401 2402 2403 2404 2405 2406
    Check for overflow : ha_rows can be smaller then ulonglong if
    BIG_TABLES is off.
    */
  if (val != (ulonglong)select_limit_val)
    select_limit_val= HA_POS_ERROR;
#endif
2407 2408 2409 2410 2411 2412 2413
  val= sl->offset_limit ? sl->offset_limit->val_uint() : ULL(0);
  offset_limit_cnt= (ha_rows)val;
#ifndef BIG_TABLES
  /* Check for truncation. */
  if (val != (ulonglong)offset_limit_cnt)
    offset_limit_cnt= HA_POS_ERROR;
#endif
2414 2415
  select_limit_cnt= select_limit_val + offset_limit_cnt;
  if (select_limit_cnt < select_limit_val)
2416 2417 2418
    select_limit_cnt= HA_POS_ERROR;		// no limit
}

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

2420
/**
2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440
  @brief Set the initial purpose of this TABLE_LIST object in the list of used
    tables.

  We need to track this information on table-by-table basis, since when this
  table becomes an element of the pre-locked list, it's impossible to identify
  which SQL sub-statement it has been originally used in.

  E.g.:

  User request:                 SELECT * FROM t1 WHERE f1();
  FUNCTION f1():                DELETE FROM t2; RETURN 1;
  BEFORE DELETE trigger on t2:  INSERT INTO t3 VALUES (old.a);

  For this user request, the pre-locked list will contain t1, t2, t3
  table elements, each needed for different DML.

  The trigger event map is updated to reflect INSERT, UPDATE, DELETE,
  REPLACE, LOAD DATA, CREATE TABLE .. SELECT, CREATE TABLE ..
  REPLACE SELECT statements, and additionally ON DUPLICATE KEY UPDATE
  clause.
2441 2442 2443 2444
*/

void st_lex::set_trg_event_type_for_tables()
{
2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543
  uint8 new_trg_event_map= 0;

  /*
    Some auxiliary operations
    (e.g. GRANT processing) create TABLE_LIST instances outside
    the parser. Additionally, some commands (e.g. OPTIMIZE) change
    the lock type for a table only after parsing is done. Luckily,
    these do not fire triggers and do not need to pre-load them.
    For these TABLE_LISTs set_trg_event_type is never called, and
    trg_event_map is always empty. That means that the pre-locking
    algorithm will ignore triggers defined on these tables, if
    any, and the execution will either fail with an assert in
    sql_trigger.cc or with an error that a used table was not
    pre-locked, in case of a production build.

    TODO: this usage pattern creates unnecessary module dependencies
    and should be rewritten to go through the parser.
    Table list instances created outside the parser in most cases
    refer to mysql.* system tables. It is not allowed to have
    a trigger on a system table, but keeping track of
    initialization provides extra safety in case this limitation
    is circumvented.
  */

  switch (sql_command) {
  case SQLCOM_LOCK_TABLES:
  /*
    On a LOCK TABLE, all triggers must be pre-loaded for this TABLE_LIST
    when opening an associated TABLE.
  */
    new_trg_event_map= static_cast<uint8>
                        (1 << static_cast<int>(TRG_EVENT_INSERT)) |
                      static_cast<uint8>
                        (1 << static_cast<int>(TRG_EVENT_UPDATE)) |
                      static_cast<uint8>
                        (1 << static_cast<int>(TRG_EVENT_DELETE));
    break;
  /*
    Basic INSERT. If there is an additional ON DUPLIATE KEY UPDATE
    clause, it will be handled later in this method.
  */
  case SQLCOM_INSERT:                           /* fall through */
  case SQLCOM_INSERT_SELECT:
  /*
    LOAD DATA ... INFILE is expected to fire BEFORE/AFTER INSERT
    triggers.
    If the statement also has REPLACE clause, it will be
    handled later in this method.
  */
  case SQLCOM_LOAD:                             /* fall through */
  /*
    REPLACE is semantically equivalent to INSERT. In case
    of a primary or unique key conflict, it deletes the old
    record and inserts a new one. So we also may need to
    fire ON DELETE triggers. This functionality is handled
    later in this method.
  */
  case SQLCOM_REPLACE:                          /* fall through */
  case SQLCOM_REPLACE_SELECT:
  /*
    CREATE TABLE ... SELECT defaults to INSERT if the table or
    view already exists. REPLACE option of CREATE TABLE ...
    REPLACE SELECT is handled later in this method.
  */
  case SQLCOM_CREATE_TABLE:
    new_trg_event_map|= static_cast<uint8>
                          (1 << static_cast<int>(TRG_EVENT_INSERT));
    break;
  /* Basic update and multi-update */
  case SQLCOM_UPDATE:                           /* fall through */
  case SQLCOM_UPDATE_MULTI:
    new_trg_event_map|= static_cast<uint8>
                          (1 << static_cast<int>(TRG_EVENT_UPDATE));
    break;
  /* Basic delete and multi-delete */
  case SQLCOM_DELETE:                           /* fall through */
  case SQLCOM_DELETE_MULTI:
    new_trg_event_map|= static_cast<uint8>
                          (1 << static_cast<int>(TRG_EVENT_DELETE));
    break;
  default:
    break;
  }

  switch (duplicates) {
  case DUP_UPDATE:
    new_trg_event_map|= static_cast<uint8>
                          (1 << static_cast<int>(TRG_EVENT_UPDATE));
    break;
  case DUP_REPLACE:
    new_trg_event_map|= static_cast<uint8>
                          (1 << static_cast<int>(TRG_EVENT_DELETE));
    break;
  case DUP_ERROR:
  default:
    break;
  }


2544 2545 2546 2547 2548 2549 2550 2551
  /*
    Do not iterate over sub-selects, only the tables in the outermost
    SELECT_LEX can be modified, if any.
  */
  TABLE_LIST *tables= select_lex.get_table_list();

  while (tables)
  {
2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562
    /*
      This is a fast check to filter out statements that do
      not change data, or tables  on the right side, in case of
      INSERT .. SELECT, CREATE TABLE .. SELECT and so on.
      Here we also filter out OPTIMIZE statement and non-updateable
      views, for which lock_type is TL_UNLOCK or TL_READ after
      parsing.
    */
    if (static_cast<int>(tables->lock_type) >=
        static_cast<int>(TL_WRITE_ALLOW_WRITE))
      tables->trg_event_map= new_trg_event_map;
2563 2564 2565 2566 2567
    tables= tables->next_local;
  }
}


2568
/*
2569 2570
  Unlink the first table from the global table list and the first table from
  outer select (lex->select_lex) local list
2571 2572 2573

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

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
2576
  NOTES
2577 2578
    We assume that first tables in both lists is the same table or the local
    list is empty.
2579 2580

  RETURN
2581
    0	If 'query_tables' == 0
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
2582
    unlinked table
2583
      In this case link_to_local is set.
2584

2585
*/
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
2586
TABLE_LIST *st_lex::unlink_first_table(bool *link_to_local)
2587
{
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
2588 2589 2590 2591 2592 2593 2594 2595
  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;
2596 2597
    else
      query_tables_last= &query_tables;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
2598 2599 2600 2601 2602 2603 2604
    first->next_global= 0;

    /*
      and from local list if it is not empty
    */
    if ((*link_to_local= test(select_lex.table_list.first)))
    {
2605 2606
      select_lex.context.table_list= 
        select_lex.context.first_name_resolution_table= first->next_local;
2607
      select_lex.table_list.first= (uchar*) (first->next_local);
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
2608 2609 2610
      select_lex.table_list.elements--;	//safety
      first->next_local= 0;
      /*
2611 2612
        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
2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628
      */
      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
2629 2630 2631 2632 2633 2634
    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
2635 2636 2637 2638 2639 2640 2641
*/

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)
  {
2642
    TABLE_LIST *next;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
2643 2644
    if (query_tables_last == &first_table->next_global)
      query_tables_last= first_table->prev_global;
2645

2646
    if ((next= *first_table->prev_global= first_table->next_global))
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
2647 2648 2649 2650
      next->prev_global= first_table->prev_global;
    /* include in new place */
    first_table->next_global= query_tables;
    /*
2651 2652 2653
       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
2654 2655 2656 2657 2658
    */
    query_tables->prev_global= &first_table->next_global;
    first_table->prev_global= &query_tables;
    query_tables= first_table;
  }
2659 2660
}

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

2662
/*
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
2663
  Link table back that was unlinked with unlink_first_table()
2664 2665 2666

  SYNOPSIS
    link_first_table_back()
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
2667
    link_to_local	do we need link this table to local
2668 2669 2670 2671

  RETURN
    global list
*/
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
2672 2673 2674

void st_lex::link_first_table_back(TABLE_LIST *first,
				   bool link_to_local)
2675
{
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
2676
  if (first)
2677
  {
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
2678 2679
    if ((first->next_global= query_tables))
      query_tables->prev_global= &first->next_global;
2680 2681
    else
      query_tables_last= &first->next_global;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
2682 2683 2684 2685 2686
    query_tables= first;

    if (link_to_local)
    {
      first->next_local= (TABLE_LIST*) select_lex.table_list.first;
2687
      select_lex.context.table_list= first;
2688
      select_lex.table_list.first= (uchar*) first;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
2689 2690 2691 2692 2693 2694
      select_lex.table_list.elements++;	//safety
    }
  }
}


2695 2696 2697 2698 2699 2700

/*
  cleanup lex for case when we open table by table for processing

  SYNOPSIS
    st_lex::cleanup_after_one_table_open()
2701 2702 2703 2704 2705

  NOTE
    This method is mostly responsible for cleaning up of selects lists and
    derived tables state. To rollback changes in Query_tables_list one has
    to call Query_tables_list::reset_query_tables_list(FALSE).
2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730
*/

void st_lex::cleanup_after_one_table_open()
{
  /*
    thd->lex->derived_tables & additional units may be set if we open
    a view. It is necessary to clear thd->lex->derived_tables flag
    to prevent processing of derived tables during next open_and_lock_tables
    if next table is a real table and cleanup & remove underlying units
    NOTE: all units will be connected to thd->lex->select_lex, because we
    have not UNION on most upper level.
    */
  if (all_selects_list != &select_lex)
  {
    derived_tables= 0;
    /* cleunup underlying units (units of VIEW) */
    for (SELECT_LEX_UNIT *un= select_lex.first_inner_unit();
         un;
         un= un->next_unit())
      un->cleanup();
    /* reduce all selects list to default state */
    all_selects_list= &select_lex;
    /* remove underlying units (units of VIEW) subtree */
    select_lex.cut_subtree();
  }
2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765
}


/*
  Save current state of Query_tables_list for this LEX, and prepare it
  for processing of new statemnt.

  SYNOPSIS
    reset_n_backup_query_tables_list()
      backup  Pointer to Query_tables_list instance to be used for backup
*/

void st_lex::reset_n_backup_query_tables_list(Query_tables_list *backup)
{
  backup->set_query_tables_list(this);
  /*
    We have to perform full initialization here since otherwise we
    will damage backed up state.
  */
  this->reset_query_tables_list(TRUE);
}


/*
  Restore state of Query_tables_list for this LEX from backup.

  SYNOPSIS
    restore_backup_query_tables_list()
      backup  Pointer to Query_tables_list instance used for backup
*/

void st_lex::restore_backup_query_tables_list(Query_tables_list *backup)
{
  this->destroy_query_tables_list();
  this->set_query_tables_list(backup);
2766 2767 2768
}


2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790
/*
  Checks for usage of routines and/or tables in a parsed statement

  SYNOPSIS
    st_lex:table_or_sp_used()

  RETURN
    FALSE  No routines and tables used
    TRUE   Either or both routines and tables are used.
*/

bool st_lex::table_or_sp_used()
{
  DBUG_ENTER("table_or_sp_used");

  if (sroutines.records || query_tables)
    DBUG_RETURN(TRUE);

  DBUG_RETURN(FALSE);
}


2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819
/*
  Do end-of-prepare fixup for list of tables and their merge-VIEWed tables

  SYNOPSIS
    fix_prepare_info_in_table_list()
      thd  Thread handle
      tbl  List of tables to process

  DESCRIPTION
    Perform end-end-of prepare fixup for list of tables, if any of the tables
    is a merge-algorithm VIEW, recursively fix up its underlying tables as
    well.

*/

static void fix_prepare_info_in_table_list(THD *thd, TABLE_LIST *tbl)
{
  for (; tbl; tbl= tbl->next_local)
  {
    if (tbl->on_expr)
    {
      tbl->prep_on_expr= tbl->on_expr;
      tbl->on_expr= tbl->on_expr->copy_andor_structure(thd);
    }
    fix_prepare_info_in_table_list(thd, tbl->merge_underlying_list);
  }
}


bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
2820
/*
2821
  Save WHERE/HAVING/ON clauses and replace them with disposable copies
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
2822 2823 2824

  SYNOPSIS
    st_select_lex::fix_prepare_information
2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835
      thd          thread handler
      conds        in/out pointer to WHERE condition to be met at execution
      having_conds in/out pointer to HAVING condition to be met at execution
  
  DESCRIPTION
    The passed WHERE and HAVING are to be saved for the future executions.
    This function saves it, and returns a copy which can be thrashed during
    this execution of the statement. By saving/thrashing here we mean only
    AND/OR trees.
    The function also calls fix_prepare_info_in_table_list that saves all
    ON expressions.    
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
2836 2837
*/

2838 2839
void st_select_lex::fix_prepare_information(THD *thd, Item **conds, 
                                            Item **having_conds)
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
2840
{
konstantin@mysql.com's avatar
konstantin@mysql.com committed
2841
  if (!thd->stmt_arena->is_conventional() && first_execution)
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
2842 2843
  {
    first_execution= 0;
2844 2845 2846 2847 2848
    if (*conds)
    {
      prep_where= *conds;
      *conds= where= prep_where->copy_andor_structure(thd);
    }
2849 2850 2851 2852 2853
    if (*having_conds)
    {
      prep_having= *having_conds;
      *having_conds= having= prep_having->copy_andor_structure(thd);
    }
2854
    fix_prepare_info_in_table_list(thd, (TABLE_LIST *)table_list.first);
2855 2856 2857
  }
}

2858

2859
/*
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
2860
  There are st_select_lex::add_table_to_list &
2861
  st_select_lex::set_lock_for_tables are in sql_parse.cc
2862

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
2863
  st_select_lex::print is in sql_select.cc
2864 2865

  st_select_lex_unit::prepare, st_select_lex_unit::exec,
2866 2867
  st_select_lex_unit::cleanup, st_select_lex_unit::reinit_exec_mechanism,
  st_select_lex_unit::change_result
2868
  are in sql_union.cc
2869
*/
2870

2871 2872 2873 2874 2875
/*
  Sets the kind of hints to be added by the calls to add_index_hint().

  SYNOPSIS
    set_index_hint_type()
2876 2877
      type_arg     The kind of hints to be added from now on.
      clause       The clause to use for hints to be added from now on.
2878 2879 2880 2881 2882 2883 2884 2885

  DESCRIPTION
    Used in filling up the tagged hints list.
    This list is filled by first setting the kind of the hint as a 
    context variable and then adding hints of the current kind.
    Then the context variable index_hint_type can be reset to the
    next hint type.
*/
2886
void st_select_lex::set_index_hint_type(enum index_hint_type type_arg,
2887 2888
                                        index_clause_map clause)
{ 
2889
  current_index_hint_type= type_arg;
2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903
  current_index_hint_clause= clause;
}


/*
  Makes an array to store index usage hints (ADD/FORCE/IGNORE INDEX).

  SYNOPSIS
    alloc_index_hints()
      thd         current thread.
*/

void st_select_lex::alloc_index_hints (THD *thd)
{ 
2904
  index_hints= new (thd->mem_root) List<Index_hint>(); 
2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924
}



/*
  adds an element to the array storing index usage hints 
  (ADD/FORCE/IGNORE INDEX).

  SYNOPSIS
    add_index_hint()
      thd         current thread.
      str         name of the index.
      length      number of characters in str.

  RETURN VALUE
    0 on success, non-zero otherwise
*/
bool st_select_lex::add_index_hint (THD *thd, char *str, uint length)
{
  return index_hints->push_front (new (thd->mem_root) 
2925
                                 Index_hint(current_index_hint_type,
2926 2927 2928
                                            current_index_hint_clause,
                                            str, length));
}
2929 2930 2931 2932 2933 2934

/**
  A routine used by the parser to decide whether we are specifying a full
  partitioning or if only partitions to add or to split.

  @note  This needs to be outside of WITH_PARTITION_STORAGE_ENGINE since it
kostja@bodhi.(none)'s avatar
kostja@bodhi.(none) committed
2935
  is used from the sql parser that doesn't have any ifdef's
2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947

  @retval  TRUE    Yes, it is part of a management partition command
  @retval  FALSE          No, not a management partition command
*/

bool st_lex::is_partition_management() const
{
  return (sql_command == SQLCOM_ALTER_TABLE &&
          (alter_info.flags == ALTER_ADD_PARTITION ||
           alter_info.flags == ALTER_REORGANIZE_PARTITION));
}