sql_prepare.cc 84.6 KB
Newer Older
unknown's avatar
unknown committed
1 2 3 4
/* Copyright (C) 1995-2002 MySQL AB

   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
unknown's avatar
unknown committed
5
   the Free Software Foundation; version 2 of the License.
unknown's avatar
unknown committed
6 7 8 9 10 11 12 13

   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.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA */
unknown's avatar
unknown committed
15 16

/**********************************************************************
17
This file contains the implementation of prepared statements.
unknown's avatar
unknown committed
18

19
When one prepares a statement:
unknown's avatar
unknown committed
20

21
  - Server gets the query from client with command 'COM_STMT_PREPARE';
unknown's avatar
unknown committed
22
    in the following format:
23
    [COM_STMT_PREPARE:1] [query]
unknown's avatar
unknown committed
24
  - Parse the query and recognize any parameter markers '?' and
unknown's avatar
unknown committed
25
    store its information list in lex->param_list
unknown's avatar
unknown committed
26
  - Allocate a new statement for this prepare; and keep this in
27
    'thd->stmt_map'.
unknown's avatar
unknown committed
28
  - Without executing the query, return back to client the total
unknown's avatar
unknown committed
29
    number of parameters along with result-set metadata information
unknown's avatar
unknown committed
30
    (if any) in the following format:
31 32 33
    [STMT_ID:4]
    [Column_count:2]
    [Param_count:2]
34
    [Params meta info (stubs only for now)]  (if Param_count > 0)
35
    [Columns meta info] (if Column_count > 0)
unknown's avatar
unknown committed
36

37
When one executes a statement:
unknown's avatar
unknown committed
38

39
  - Server gets the command 'COM_STMT_EXECUTE' to execute the
40 41
    previously prepared query. If there are any parameter markers, then the
    client will send the data in the following format:
42
    [COM_STMT_EXECUTE:1]
unknown's avatar
unknown committed
43 44 45 46
    [STMT_ID:4]
    [NULL_BITS:(param_count+7)/8)]
    [TYPES_SUPPLIED_BY_CLIENT(0/1):1]
    [[length]data]
unknown's avatar
unknown committed
47 48
    [[length]data] .. [[length]data].
    (Note: Except for string/binary types; all other types will not be
unknown's avatar
unknown committed
49
    supplied with length field)
50 51 52
  - If it is a first execute or types of parameters were altered by client,
    then setup the conversion routines.
  - Assign parameter items from the supplied data.
unknown's avatar
unknown committed
53
  - Execute the query without re-parsing and send back the results
unknown's avatar
unknown committed
54 55
    to client

56
When one supplies long data for a placeholder:
unknown's avatar
unknown committed
57

58 59
  - Server gets the long data in pieces with command type
    'COM_STMT_SEND_LONG_DATA'.
unknown's avatar
unknown committed
60
  - The packet recieved will have the format as:
61
    [COM_STMT_SEND_LONG_DATA:1][STMT_ID:4][parameter_number:2][data]
62
  - data from the packet is appended to the long data value buffer for this
63
    placeholder.
64 65 66 67
  - It's up to the client to stop supplying data chunks at any point. The
    server doesn't care; also, the server doesn't notify the client whether
    it got the data or not; if there is any error, then it will be returned
    at statement execute.
68

unknown's avatar
unknown committed
69 70 71
***********************************************************************/

#include "mysql_priv.h"
unknown's avatar
unknown committed
72
#include "sql_select.h" // for JOIN
73
#include "sql_cursor.h"
74
#include "sp_head.h"
75
#include "sp.h"
unknown's avatar
unknown committed
76
#include "sp_cache.h"
77 78 79
#ifdef EMBEDDED_LIBRARY
/* include MYSQL_BIND headers */
#include <mysql.h>
80 81
#else
#include <mysql_com.h>
82
#endif
unknown's avatar
unknown committed
83

84 85 86 87 88 89 90 91 92 93
/* A result class used to send cursor rows using the binary protocol. */

class Select_fetch_protocol_prep: public select_send
{
  Protocol_prep protocol;
public:
  Select_fetch_protocol_prep(THD *thd);
  virtual bool send_fields(List<Item> &list, uint flags);
  virtual bool send_data(List<Item> &items);
  virtual bool send_eof();
94 95 96 97 98 99
#ifdef EMBEDDED_LIBRARY
  void begin_dataset()
  {
    protocol.begin_dataset();
  }
#endif
100 101
};

102 103 104 105 106 107
/****************************************************************************/

/**
  @class Prepared_statement
  @brief Prepared_statement: a statement that can contain placeholders
*/
108

109 110 111
class Prepared_statement: public Statement
{
public:
112 113 114 115 116
  enum flag_values
  {
    IS_IN_USE= 1
  };

117
  THD *thd;
118
  Select_fetch_protocol_prep result;
119
  Protocol *protocol;
120
  Item_param **param_array;
121 122
  uint param_count;
  uint last_errno;
123
  uint flags;
124 125
  char last_error[MYSQL_ERRMSG_SIZE];
#ifndef EMBEDDED_LIBRARY
126
  bool (*set_params)(Prepared_statement *st, uchar *data, uchar *data_end,
127
                     uchar *read_pos, String *expanded_query);
unknown's avatar
unknown committed
128
#else
129
  bool (*set_params_data)(Prepared_statement *st, String *expanded_query);
unknown's avatar
unknown committed
130
#endif
unknown's avatar
unknown committed
131
  bool (*set_params_from_vars)(Prepared_statement *stmt,
132 133
                               List<LEX_STRING>& varnames,
                               String *expanded_query);
134
public:
135
  Prepared_statement(THD *thd_arg, Protocol *protocol_arg);
136
  virtual ~Prepared_statement();
137
  void setup_set_params();
unknown's avatar
unknown committed
138
  virtual Query_arena::Type type() const;
139
  virtual void cleanup_stmt();
140
  bool set_name(LEX_STRING *name);
141
  inline void close_cursor() { delete cursor; cursor= 0; }
142 143 144 145 146

  bool prepare(const char *packet, uint packet_length);
  bool execute(String *expanded_query, bool open_cursor);
  /* Destroy this statement */
  bool deallocate();
147 148 149 150 151 152 153 154 155 156
private:
  /**
    Store the parsed tree of a prepared statement here.
  */
  LEX main_lex;
  /**
    The memory root to allocate parsed tree elements (instances of Item,
    SELECT_LEX and other classes).
  */
  MEM_ROOT main_mem_root;
157
};
158

unknown's avatar
unknown committed
159

160 161 162
/******************************************************************************
  Implementation
******************************************************************************/
163 164


165
inline bool is_param_null(const uchar *pos, ulong param_no)
166
{
167
  return pos[param_no/8] & (1 << (param_no & 7));
168 169 170
}

/*
171 172 173 174 175 176 177 178 179 180 181 182 183 184
  Find a prepared statement in the statement map by id.

  SYNOPSIS
    find_prepared_statement()
      thd                thread handle
      id                 statement id
      where              the place from which this function is called (for
                         error reporting).

  DESCRIPTION
    Try to find a prepared statement and set THD error if it's not found.

  RETURN VALUE
    0 if the statement was not found, a pointer otherwise.
185 186
*/

187
static Prepared_statement *
unknown's avatar
unknown committed
188
find_prepared_statement(THD *thd, ulong id, const char *where)
189
{
190 191 192 193 194
  /*
    To strictly separate namespaces of SQL prepared statements and C API
    prepared statements find() will return 0 if there is a named prepared
    statement with such id.
  */
195 196
  Statement *stmt= thd->stmt_map.find(id);

unknown's avatar
unknown committed
197
  if (stmt == 0 || stmt->type() != Query_arena::PREPARED_STATEMENT)
198
  {
199
    char llbuf[22];
200 201
    my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), sizeof(llbuf), llstr(id, llbuf),
             where);
202 203 204
    return 0;
  }
  return (Prepared_statement *) stmt;
205 206
}

207

208
/*
209 210 211 212 213 214 215
  Send prepared statement id and metadata to the client after prepare.

  SYNOPSIS
    send_prep_stmt()

  RETURN VALUE
    0 in case of success, 1 otherwise
216 217
*/

unknown's avatar
unknown committed
218
#ifndef EMBEDDED_LIBRARY
219
static bool send_prep_stmt(Prepared_statement *stmt, uint columns)
220
{
221
  NET *net= &stmt->thd->net;
unknown's avatar
unknown committed
222 223
  char buff[12];
  uint tmp;
unknown's avatar
unknown committed
224 225
  DBUG_ENTER("send_prep_stmt");

226
  buff[0]= 0;                                   /* OK packet indicator */
227
  int4store(buff+1, stmt->id);
228 229
  int2store(buff+5, columns);
  int2store(buff+7, stmt->param_count);
unknown's avatar
unknown committed
230 231 232 233
  buff[9]= 0;                                   // Guard against a 4.1 client
  tmp= min(stmt->thd->total_warn_count, 65535);
  int2store(buff+10, tmp);

234 235 236 237
  /*
    Send types and names of placeholders to the client
    XXX: fix this nasty upcast from List<Item_param> to List<Item>
  */
unknown's avatar
unknown committed
238
  DBUG_RETURN(my_net_write(net, buff, sizeof(buff)) ||
unknown's avatar
unknown committed
239 240 241
              (stmt->param_count &&
               stmt->thd->protocol_simple.send_fields((List<Item> *)
                                                      &stmt->lex->param_list,
242
                                                      Protocol::SEND_EOF)));
unknown's avatar
unknown committed
243
}
244
#else
245 246
static bool send_prep_stmt(Prepared_statement *stmt,
                           uint columns __attribute__((unused)))
unknown's avatar
unknown committed
247
{
unknown's avatar
SCRUM  
unknown committed
248 249
  THD *thd= stmt->thd;

250
  thd->client_stmt_id= stmt->id;
unknown's avatar
SCRUM  
unknown committed
251
  thd->client_param_count= stmt->param_count;
unknown's avatar
unknown committed
252
  thd->clear_error();
unknown's avatar
unknown committed
253

unknown's avatar
SCRUM  
unknown committed
254
  return 0;
255
}
unknown's avatar
unknown committed
256
#endif /*!EMBEDDED_LIBRARY*/
257

unknown's avatar
unknown committed
258 259

/*
260 261 262 263 264 265 266 267 268 269 270 271 272 273
  Read the length of the parameter data and return it back to
  the caller.

  SYNOPSIS
    get_param_length()
      packet             a pointer to the data
      len                remaining packet length

  DESCRIPTION
    Read data length, position the packet to the first byte after it,
    and return the length to the caller.

  RETURN VALUE
    Length of data piece.
unknown's avatar
unknown committed
274 275
*/

unknown's avatar
unknown committed
276
#ifndef EMBEDDED_LIBRARY
277
static ulong get_param_length(uchar **packet, ulong len)
unknown's avatar
unknown committed
278 279
{
  reg1 uchar *pos= *packet;
280 281
  if (len < 1)
    return 0;
unknown's avatar
unknown committed
282 283 284 285 286
  if (*pos < 251)
  {
    (*packet)++;
    return (ulong) *pos;
  }
287 288
  if (len < 3)
    return 0;
unknown's avatar
unknown committed
289 290 291 292 293
  if (*pos == 252)
  {
    (*packet)+=3;
    return (ulong) uint2korr(pos+1);
  }
294 295
  if (len < 4)
    return 0;
unknown's avatar
unknown committed
296 297 298 299 300
  if (*pos == 253)
  {
    (*packet)+=4;
    return (ulong) uint3korr(pos+1);
  }
301 302
  if (len < 5)
    return 0;
unknown's avatar
unknown committed
303
  (*packet)+=9; // Must be 254 when here
304 305 306 307 308 309 310
  /*
    In our client-server protocol all numbers bigger than 2^24
    stored as 8 bytes with uint8korr. Here we always know that
    parameter length is less than 2^4 so don't look at the second
    4 bytes. But still we need to obey the protocol hence 9 in the
    assignment above.
  */
unknown's avatar
unknown committed
311 312
  return (ulong) uint4korr(pos+1);
}
unknown's avatar
unknown committed
313
#else
314
#define get_param_length(packet, len) len
unknown's avatar
unknown committed
315 316
#endif /*!EMBEDDED_LIBRARY*/

unknown's avatar
unknown committed
317
 /*
318 319
   Data conversion routines.

320
   SYNOPSIS
321 322 323 324
     set_param_xx()
       param             parameter item
       pos               input data buffer
       len               length of data in the buffer
unknown's avatar
unknown committed
325

326 327 328
  DESCRIPTION
    All these functions read the data from pos, convert it to requested
    type and assign to param; pos is advanced to predefined length.
unknown's avatar
unknown committed
329

330 331 332
    Make a note that the NULL handling is examined at first execution
    (i.e. when input types altered) and for all subsequent executions
    we don't read any values for this.
unknown's avatar
unknown committed
333

334 335
  RETURN VALUE
    none
unknown's avatar
unknown committed
336 337
*/

338
static void set_param_tiny(Item_param *param, uchar **pos, ulong len)
unknown's avatar
unknown committed
339
{
340 341 342 343
#ifndef EMBEDDED_LIBRARY
  if (len < 1)
    return;
#endif
344
  int8 value= (int8) **pos;
unknown's avatar
unknown committed
345
  param->set_int(param->unsigned_flag ? (longlong) ((uint8) value) :
346
                                        (longlong) value, 4);
unknown's avatar
unknown committed
347 348 349
  *pos+= 1;
}

350
static void set_param_short(Item_param *param, uchar **pos, ulong len)
unknown's avatar
unknown committed
351
{
352
  int16 value;
353 354 355
#ifndef EMBEDDED_LIBRARY
  if (len < 2)
    return;
356
  value= sint2korr(*pos);
357 358
#else
  shortget(value, *pos);
359
#endif
360
  param->set_int(param->unsigned_flag ? (longlong) ((uint16) value) :
361
                                        (longlong) value, 6);
unknown's avatar
unknown committed
362 363 364
  *pos+= 2;
}

365
static void set_param_int32(Item_param *param, uchar **pos, ulong len)
unknown's avatar
unknown committed
366
{
367
  int32 value;
368 369 370
#ifndef EMBEDDED_LIBRARY
  if (len < 4)
    return;
371
  value= sint4korr(*pos);
372 373
#else
  longget(value, *pos);
374
#endif
375
  param->set_int(param->unsigned_flag ? (longlong) ((uint32) value) :
376
                                        (longlong) value, 11);
unknown's avatar
unknown committed
377 378 379
  *pos+= 4;
}

380
static void set_param_int64(Item_param *param, uchar **pos, ulong len)
unknown's avatar
unknown committed
381
{
382
  longlong value;
383 384 385
#ifndef EMBEDDED_LIBRARY
  if (len < 8)
    return;
386
  value= (longlong) sint8korr(*pos);
387 388
#else
  longlongget(value, *pos);
389
#endif
390
  param->set_int(value, 21);
unknown's avatar
unknown committed
391 392 393
  *pos+= 8;
}

394
static void set_param_float(Item_param *param, uchar **pos, ulong len)
unknown's avatar
unknown committed
395
{
unknown's avatar
unknown committed
396
  float data;
397 398 399
#ifndef EMBEDDED_LIBRARY
  if (len < 4)
    return;
unknown's avatar
unknown committed
400
  float4get(data,*pos);
unknown's avatar
unknown committed
401
#else
402
  floatget(data, *pos);
unknown's avatar
unknown committed
403
#endif
unknown's avatar
unknown committed
404 405 406 407
  param->set_double((double) data);
  *pos+= 4;
}

408
static void set_param_double(Item_param *param, uchar **pos, ulong len)
unknown's avatar
unknown committed
409
{
unknown's avatar
unknown committed
410
  double data;
411 412 413
#ifndef EMBEDDED_LIBRARY
  if (len < 8)
    return;
unknown's avatar
unknown committed
414
  float8get(data,*pos);
unknown's avatar
unknown committed
415
#else
416
  doubleget(data, *pos);
unknown's avatar
unknown committed
417
#endif
unknown's avatar
unknown committed
418 419 420 421
  param->set_double((double) data);
  *pos+= 8;
}

unknown's avatar
unknown committed
422 423 424 425
static void set_param_decimal(Item_param *param, uchar **pos, ulong len)
{
  ulong length= get_param_length(pos, len);
  param->set_decimal((char*)*pos, length);
426
  *pos+= length;
unknown's avatar
unknown committed
427 428
}

429
#ifndef EMBEDDED_LIBRARY
430 431 432 433 434 435 436

/*
  Read date/time/datetime parameter values from network (binary
  protocol). See writing counterparts of these functions in
  libmysql.c (store_param_{time,date,datetime}).
*/

437
static void set_param_time(Item_param *param, uchar **pos, ulong len)
438
{
439 440
  MYSQL_TIME tm;
  ulong length= get_param_length(pos, len);
441

442
  if (length >= 8)
443 444
  {
    uchar *to= *pos;
445
    uint day;
446

447 448
    tm.neg= (bool) to[0];
    day= (uint) sint4korr(to+1);
449
    tm.hour=   (uint) to[5] + day * 24;
450 451
    tm.minute= (uint) to[6];
    tm.second= (uint) to[7];
452
    tm.second_part= (length > 8) ? (ulong) sint4korr(to+8) : 0;
453 454 455 456 457 458 459 460
    if (tm.hour > 838)
    {
      /* TODO: add warning 'Data truncated' here */
      tm.hour= 838;
      tm.minute= 59;
      tm.second= 59;
    }
    tm.day= tm.year= tm.month= 0;
461
  }
462
  else
463
    set_zero_time(&tm, MYSQL_TIMESTAMP_TIME);
464 465
  param->set_time(&tm, MYSQL_TIMESTAMP_TIME,
                  MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
466 467 468
  *pos+= length;
}

469
static void set_param_datetime(Item_param *param, uchar **pos, ulong len)
470
{
471 472
  MYSQL_TIME tm;
  ulong length= get_param_length(pos, len);
473

474
  if (length >= 4)
475 476
  {
    uchar *to= *pos;
477 478 479 480 481

    tm.neg=    0;
    tm.year=   (uint) sint2korr(to);
    tm.month=  (uint) to[2];
    tm.day=    (uint) to[3];
482 483 484 485 486 487 488 489 490
    if (length > 4)
    {
      tm.hour=   (uint) to[4];
      tm.minute= (uint) to[5];
      tm.second= (uint) to[6];
    }
    else
      tm.hour= tm.minute= tm.second= 0;

491
    tm.second_part= (length > 7) ? (ulong) sint4korr(to+7) : 0;
492
  }
493
  else
494
    set_zero_time(&tm, MYSQL_TIMESTAMP_DATETIME);
495 496
  param->set_time(&tm, MYSQL_TIMESTAMP_DATETIME,
                  MAX_DATETIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
497 498 499
  *pos+= length;
}

500

501
static void set_param_date(Item_param *param, uchar **pos, ulong len)
502
{
503 504 505 506
  MYSQL_TIME tm;
  ulong length= get_param_length(pos, len);

  if (length >= 4)
507 508
  {
    uchar *to= *pos;
509

510
    tm.year=  (uint) sint2korr(to);
511 512 513 514 515 516 517
    tm.month=  (uint) to[2];
    tm.day= (uint) to[3];

    tm.hour= tm.minute= tm.second= 0;
    tm.second_part= 0;
    tm.neg= 0;
  }
518
  else
519
    set_zero_time(&tm, MYSQL_TIMESTAMP_DATE);
520 521
  param->set_time(&tm, MYSQL_TIMESTAMP_DATE,
                  MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
522 523 524
  *pos+= length;
}

525 526 527
#else/*!EMBEDDED_LIBRARY*/
void set_param_time(Item_param *param, uchar **pos, ulong len)
{
528 529 530 531 532 533 534 535 536 537 538
  MYSQL_TIME tm= *((MYSQL_TIME*)*pos);
  tm.hour+= tm.day * 24;
  tm.day= tm.year= tm.month= 0;
  if (tm.hour > 838)
  {
    /* TODO: add warning 'Data truncated' here */
    tm.hour= 838;
    tm.minute= 59;
    tm.second= 59;
  }
  param->set_time(&tm, MYSQL_TIMESTAMP_TIME,
539
                  MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
540 541 542 543 544

}

void set_param_datetime(Item_param *param, uchar **pos, ulong len)
{
545 546
  MYSQL_TIME tm= *((MYSQL_TIME*)*pos);
  tm.neg= 0;
547

548
  param->set_time(&tm, MYSQL_TIMESTAMP_DATETIME,
549
                  MAX_DATETIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
550 551 552 553 554 555
}

void set_param_date(Item_param *param, uchar **pos, ulong len)
{
  MYSQL_TIME *to= (MYSQL_TIME*)*pos;

556
  param->set_time(to, MYSQL_TIMESTAMP_DATE,
557
                  MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
558 559 560
}
#endif /*!EMBEDDED_LIBRARY*/

561 562

static void set_param_str(Item_param *param, uchar **pos, ulong len)
unknown's avatar
unknown committed
563
{
564
  ulong length= get_param_length(pos, len);
565
  param->set_str((const char *)*pos, length);
566
  *pos+= length;
unknown's avatar
unknown committed
567 568
}

569

unknown's avatar
unknown committed
570
#undef get_param_length
571 572 573

static void setup_one_conversion_function(THD *thd, Item_param *param,
                                          uchar param_type)
unknown's avatar
unknown committed
574
{
unknown's avatar
unknown committed
575
  switch (param_type) {
576
  case MYSQL_TYPE_TINY:
577
    param->set_param_func= set_param_tiny;
578
    param->item_type= Item::INT_ITEM;
579
    param->item_result_type= INT_RESULT;
unknown's avatar
unknown committed
580
    break;
581
  case MYSQL_TYPE_SHORT:
582
    param->set_param_func= set_param_short;
583
    param->item_type= Item::INT_ITEM;
584
    param->item_result_type= INT_RESULT;
unknown's avatar
unknown committed
585
    break;
586
  case MYSQL_TYPE_LONG:
587
    param->set_param_func= set_param_int32;
588
    param->item_type= Item::INT_ITEM;
589
    param->item_result_type= INT_RESULT;
unknown's avatar
unknown committed
590
    break;
591
  case MYSQL_TYPE_LONGLONG:
592
    param->set_param_func= set_param_int64;
593
    param->item_type= Item::INT_ITEM;
594
    param->item_result_type= INT_RESULT;
unknown's avatar
unknown committed
595
    break;
596
  case MYSQL_TYPE_FLOAT:
597
    param->set_param_func= set_param_float;
598
    param->item_type= Item::REAL_ITEM;
599
    param->item_result_type= REAL_RESULT;
unknown's avatar
unknown committed
600
    break;
601
  case MYSQL_TYPE_DOUBLE:
602
    param->set_param_func= set_param_double;
603
    param->item_type= Item::REAL_ITEM;
604
    param->item_result_type= REAL_RESULT;
unknown's avatar
unknown committed
605
    break;
unknown's avatar
unknown committed
606 607 608 609 610 611
  case MYSQL_TYPE_DECIMAL:
  case MYSQL_TYPE_NEWDECIMAL:
    param->set_param_func= set_param_decimal;
    param->item_type= Item::DECIMAL_ITEM;
    param->item_result_type= DECIMAL_RESULT;
    break;
612
  case MYSQL_TYPE_TIME:
613
    param->set_param_func= set_param_time;
614
    param->item_type= Item::STRING_ITEM;
615
    param->item_result_type= STRING_RESULT;
616
    break;
617
  case MYSQL_TYPE_DATE:
618
    param->set_param_func= set_param_date;
619
    param->item_type= Item::STRING_ITEM;
620
    param->item_result_type= STRING_RESULT;
621
    break;
622 623
  case MYSQL_TYPE_DATETIME:
  case MYSQL_TYPE_TIMESTAMP:
624
    param->set_param_func= set_param_datetime;
625
    param->item_type= Item::STRING_ITEM;
626
    param->item_result_type= STRING_RESULT;
627
    break;
628 629 630 631
  case MYSQL_TYPE_TINY_BLOB:
  case MYSQL_TYPE_MEDIUM_BLOB:
  case MYSQL_TYPE_LONG_BLOB:
  case MYSQL_TYPE_BLOB:
632
    param->set_param_func= set_param_str;
633 634 635
    param->value.cs_info.character_set_of_placeholder= &my_charset_bin;
    param->value.cs_info.character_set_client=
      thd->variables.character_set_client;
636 637
    param->value.cs_info.final_character_set_of_str_value= &my_charset_bin;
    param->item_type= Item::STRING_ITEM;
638
    param->item_result_type= STRING_RESULT;
639 640 641 642 643 644 645 646 647 648 649 650
    break;
  default:
    /*
      The client library ensures that we won't get any other typecodes
      except typecodes above and typecodes for string types. Marking
      label as 'default' lets us to handle malformed packets as well.
    */
    {
      CHARSET_INFO *fromcs= thd->variables.character_set_client;
      CHARSET_INFO *tocs= thd->variables.collation_connection;
      uint32 dummy_offset;

651
      param->value.cs_info.character_set_of_placeholder= fromcs;
652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669
      param->value.cs_info.character_set_client= fromcs;

      /*
        Setup source and destination character sets so that they
        are different only if conversion is necessary: this will
        make later checks easier.
      */
      param->value.cs_info.final_character_set_of_str_value=
        String::needs_conversion(0, fromcs, tocs, &dummy_offset) ?
        tocs : fromcs;
      param->set_param_func= set_param_str;
      /*
        Exact value of max_length is not known unless data is converted to
        charset of connection, so we have to set it later.
      */
      param->item_type= Item::STRING_ITEM;
      param->item_result_type= STRING_RESULT;
    }
unknown's avatar
unknown committed
670
  }
671
  param->param_type= (enum enum_field_types) param_type;
unknown's avatar
unknown committed
672 673
}

unknown's avatar
unknown committed
674
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
675
/*
676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704
  Routines to assign parameters from data supplied by the client.

  DESCRIPTION
    Update the parameter markers by reading data from the packet and
    and generate a valid query for logging.

  NOTES
    This function, along with other _withlog functions is called when one of
    binary, slow or general logs is open. Logging of prepared statements in
    all cases is performed by means of conventional queries: if parameter
    data was supplied from C API, each placeholder in the query is
    replaced with its actual value; if we're logging a [Dynamic] SQL
    prepared statement, parameter markers are replaced with variable names.
    Example:
     mysql_stmt_prepare("UPDATE t1 SET a=a*1.25 WHERE a=?")
       --> general logs gets [Prepare] UPDATE t1 SET a*1.25 WHERE a=?"
     mysql_stmt_execute(stmt);
       --> general and binary logs get
                             [Execute] UPDATE t1 SET a*1.25 WHERE a=1"
     If a statement has been prepared using SQL syntax:
     PREPARE stmt FROM "UPDATE t1 SET a=a*1.25 WHERE a=?"
       --> general log gets
                                 [Query]   PREPARE stmt FROM "UPDATE ..."
     EXECUTE stmt USING @a
       --> general log gets
                                 [Query]   EXECUTE stmt USING @a;

  RETURN VALUE
   0 if success, 1 otherwise
unknown's avatar
unknown committed
705 706
*/

707
static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array,
unknown's avatar
unknown committed
708
                                  uchar *read_pos, uchar *data_end,
709
                                  String *query)
710
{
711 712 713 714
  THD  *thd= stmt->thd;
  Item_param **begin= stmt->param_array;
  Item_param **end= begin + stmt->param_count;
  uint32 length= 0;
unknown's avatar
unknown committed
715
  String str;
716
  const String *res;
unknown's avatar
unknown committed
717
  DBUG_ENTER("insert_params_withlog");
718

719
  if (query->copy(stmt->query, stmt->query_length, default_charset_info))
720
    DBUG_RETURN(1);
unknown's avatar
unknown committed
721

722
  for (Item_param **it= begin; it < end; ++it)
723
  {
724
    Item_param *param= *it;
725
    if (param->state != Item_param::LONG_DATA_VALUE)
726
    {
727
      if (is_param_null(null_array, it - begin))
728
        param->set_null();
729 730
      else
      {
731 732 733
        if (read_pos >= data_end)
          DBUG_RETURN(1);
        param->set_param_func(param, &read_pos, data_end - read_pos);
734 735
      }
    }
736 737 738 739
    res= param->query_val_str(&str);
    if (param->convert_str_value(thd))
      DBUG_RETURN(1);                           /* out of memory */

740
    if (query->replace(param->pos_in_query+length, 1, *res))
741
      DBUG_RETURN(1);
unknown's avatar
unknown committed
742

743 744 745 746 747
    length+= res->length()-1;
  }
  DBUG_RETURN(0);
}

748

749
static bool insert_params(Prepared_statement *stmt, uchar *null_array,
unknown's avatar
unknown committed
750
                          uchar *read_pos, uchar *data_end,
751
                          String *expanded_query)
752
{
753 754
  Item_param **begin= stmt->param_array;
  Item_param **end= begin + stmt->param_count;
755

unknown's avatar
unknown committed
756
  DBUG_ENTER("insert_params");
757

758
  for (Item_param **it= begin; it < end; ++it)
759
  {
760
    Item_param *param= *it;
761
    if (param->state != Item_param::LONG_DATA_VALUE)
762
    {
763
      if (is_param_null(null_array, it - begin))
764
        param->set_null();
765 766
      else
      {
767 768 769
        if (read_pos >= data_end)
          DBUG_RETURN(1);
        param->set_param_func(param, &read_pos, data_end - read_pos);
770 771
      }
    }
772 773
    if (param->convert_str_value(stmt->thd))
      DBUG_RETURN(1);                           /* out of memory */
774 775 776 777
  }
  DBUG_RETURN(0);
}

778

779
static bool setup_conversion_functions(Prepared_statement *stmt,
780
                                       uchar **data, uchar *data_end)
781 782 783
{
  /* skip null bits */
  uchar *read_pos= *data + (stmt->param_count+7) / 8;
unknown's avatar
unknown committed
784

785
  DBUG_ENTER("setup_conversion_functions");
786

unknown's avatar
unknown committed
787
  if (*read_pos++) //types supplied / first execute
788
  {
unknown's avatar
unknown committed
789
    /*
unknown's avatar
unknown committed
790
      First execute or types altered by the client, setup the
unknown's avatar
unknown committed
791 792
      conversion routines for all parameters (one time)
    */
793 794
    Item_param **it= stmt->param_array;
    Item_param **end= it + stmt->param_count;
795
    THD *thd= stmt->thd;
796 797
    for (; it < end; ++it)
    {
798 799 800
      ushort typecode;
      const uint signed_bit= 1 << 15;

801 802
      if (read_pos >= data_end)
        DBUG_RETURN(1);
803 804

      typecode= sint2korr(read_pos);
unknown's avatar
unknown committed
805
      read_pos+= 2;
806
      (**it).unsigned_flag= test(typecode & signed_bit);
807
      setup_one_conversion_function(thd, *it, (uchar) (typecode & ~signed_bit));
unknown's avatar
unknown committed
808
    }
809 810
  }
  *data= read_pos;
unknown's avatar
unknown committed
811 812 813
  DBUG_RETURN(0);
}

814 815
#else

816 817 818 819 820 821 822 823 824 825 826
/*
  Embedded counterparts of parameter assignment routines.

  DESCRIPTION
    The main difference between the embedded library and the server is
    that in embedded case we don't serialize/deserialize parameters data.
    Additionally, for unknown reason, the client-side flag raised for
    changed types of placeholders is ignored and we simply setup conversion
    functions at each execute (TODO: fix).
*/

827
static bool emb_insert_params(Prepared_statement *stmt, String *expanded_query)
828
{
829
  THD *thd= stmt->thd;
830 831
  Item_param **it= stmt->param_array;
  Item_param **end= it + stmt->param_count;
832 833
  MYSQL_BIND *client_param= stmt->thd->client_params;

834
  DBUG_ENTER("emb_insert_params");
835

836 837 838
  for (; it < end; ++it, ++client_param)
  {
    Item_param *param= *it;
839 840
    setup_one_conversion_function(thd, param, client_param->buffer_type);
    if (param->state != Item_param::LONG_DATA_VALUE)
841 842
    {
      if (*client_param->is_null)
843
        param->set_null();
844 845
      else
      {
846
        uchar *buff= (uchar*) client_param->buffer;
unknown's avatar
unknown committed
847
        param->unsigned_flag= client_param->is_unsigned;
848
        param->set_param_func(param, &buff,
unknown's avatar
unknown committed
849 850
                              client_param->length ?
                              *client_param->length :
851
                              client_param->buffer_length);
852 853
      }
    }
854 855
    if (param->convert_str_value(thd))
      DBUG_RETURN(1);                           /* out of memory */
856 857 858 859
  }
  DBUG_RETURN(0);
}

860

861
static bool emb_insert_params_withlog(Prepared_statement *stmt, String *query)
862
{
863
  THD *thd= stmt->thd;
864 865
  Item_param **it= stmt->param_array;
  Item_param **end= it + stmt->param_count;
866 867
  MYSQL_BIND *client_param= thd->client_params;

868
  String str;
869
  const String *res;
870
  uint32 length= 0;
871

872
  DBUG_ENTER("emb_insert_params_withlog");
873

874
  if (query->copy(stmt->query, stmt->query_length, default_charset_info))
875
    DBUG_RETURN(1);
unknown's avatar
unknown committed
876

877 878 879
  for (; it < end; ++it, ++client_param)
  {
    Item_param *param= *it;
880 881
    setup_one_conversion_function(thd, param, client_param->buffer_type);
    if (param->state != Item_param::LONG_DATA_VALUE)
882 883
    {
      if (*client_param->is_null)
884
        param->set_null();
885 886
      else
      {
887
        uchar *buff= (uchar*)client_param->buffer;
unknown's avatar
unknown committed
888
        param->unsigned_flag= client_param->is_unsigned;
889
        param->set_param_func(param, &buff,
unknown's avatar
unknown committed
890 891
                              client_param->length ?
                              *client_param->length :
892
                              client_param->buffer_length);
893 894
      }
    }
895 896 897 898
    res= param->query_val_str(&str);
    if (param->convert_str_value(thd))
      DBUG_RETURN(1);                           /* out of memory */

899
    if (query->replace(param->pos_in_query+length, 1, *res))
900
      DBUG_RETURN(1);
901

902 903 904 905 906
    length+= res->length()-1;
  }
  DBUG_RETURN(0);
}

unknown's avatar
unknown committed
907 908
#endif /*!EMBEDDED_LIBRARY*/

unknown's avatar
unknown committed
909

910
/*
911 912
  Assign prepared statement parameters from user variables.

unknown's avatar
unknown committed
913 914 915 916 917
  SYNOPSIS
    insert_params_from_vars()
      stmt      Statement
      varnames  List of variables. Caller must ensure that number of variables
                in the list is equal to number of statement parameters
918
      query     Ignored
unknown's avatar
unknown committed
919 920
*/

921 922
static bool insert_params_from_vars(Prepared_statement *stmt,
                                    List<LEX_STRING>& varnames,
923
                                    String *query __attribute__((unused)))
unknown's avatar
unknown committed
924 925 926 927 928 929
{
  Item_param **begin= stmt->param_array;
  Item_param **end= begin + stmt->param_count;
  user_var_entry *entry;
  LEX_STRING *varname;
  List_iterator<LEX_STRING> var_it(varnames);
930 931
  DBUG_ENTER("insert_params_from_vars");

unknown's avatar
unknown committed
932 933 934 935
  for (Item_param **it= begin; it < end; ++it)
  {
    Item_param *param= *it;
    varname= var_it++;
936 937 938 939 940 941
    entry= (user_var_entry*)hash_search(&stmt->thd->user_vars,
                                        (byte*) varname->str,
                                         varname->length);
    if (param->set_from_user_var(stmt->thd, entry) ||
        param->convert_str_value(stmt->thd))
      DBUG_RETURN(1);
unknown's avatar
unknown committed
942 943 944 945
  }
  DBUG_RETURN(0);
}

946

947
/*
948 949
  Do the same as insert_params_from_vars but also construct query text for
  binary log.
950

951 952
  SYNOPSIS
    insert_params_from_vars()
953
      stmt      Prepared statement
954 955
      varnames  List of variables. Caller must ensure that number of variables
                in the list is equal to number of statement parameters
956 957
      query     The query with parameter markers replaced with corresponding
                user variables that were used to execute the query.
958 959
*/

unknown's avatar
unknown committed
960
static bool insert_params_from_vars_with_log(Prepared_statement *stmt,
961
                                             List<LEX_STRING>& varnames,
962
                                             String *query)
unknown's avatar
unknown committed
963 964 965 966 967 968
{
  Item_param **begin= stmt->param_array;
  Item_param **end= begin + stmt->param_count;
  user_var_entry *entry;
  LEX_STRING *varname;
  List_iterator<LEX_STRING> var_it(varnames);
969 970
  String buf;
  const String *val;
unknown's avatar
unknown committed
971
  uint32 length= 0;
972 973 974

  DBUG_ENTER("insert_params_from_vars");

975
  if (query->copy(stmt->query, stmt->query_length, default_charset_info))
976
    DBUG_RETURN(1);
unknown's avatar
unknown committed
977 978 979 980 981

  for (Item_param **it= begin; it < end; ++it)
  {
    Item_param *param= *it;
    varname= var_it++;
982 983
    if (get_var_with_binlog(stmt->thd, stmt->lex->sql_command,
                            *varname, &entry))
984
        DBUG_RETURN(1);
unknown's avatar
unknown committed
985

986 987 988
    if (param->set_from_user_var(stmt->thd, entry))
      DBUG_RETURN(1);
    /* Insert @'escaped-varname' instead of parameter in the query */
989 990
    if (entry)
    {
991
      char *start, *ptr;
992 993 994
      buf.length(0);
      if (buf.reserve(entry->name.length*2+3))
        DBUG_RETURN(1);
995

996
      start= ptr= buf.c_ptr_quick();
997 998 999
      *ptr++= '@';
      *ptr++= '\'';
      ptr+= escape_string_for_mysql(&my_charset_utf8_general_ci,
unknown's avatar
unknown committed
1000 1001
                                    ptr, 0, entry->name.str,
                                    entry->name.length);
1002
      *ptr++= '\'';
1003
      buf.length(ptr - start);
1004 1005 1006 1007
      val= &buf;
    }
    else
      val= &my_null_string;
1008 1009 1010

    if (param->convert_str_value(stmt->thd))
      DBUG_RETURN(1);                           /* out of memory */
1011

1012
    if (query->replace(param->pos_in_query+length, 1, *val))
1013
      DBUG_RETURN(1);
1014
    length+= val->length()-1;
unknown's avatar
unknown committed
1015 1016 1017 1018
  }
  DBUG_RETURN(0);
}

unknown's avatar
unknown committed
1019
/*
1020
  Validate INSERT statement.
unknown's avatar
unknown committed
1021

1022
  SYNOPSIS
unknown's avatar
unknown committed
1023
    mysql_test_insert()
1024 1025
      stmt               prepared statement
      tables             global/local table list
unknown's avatar
unknown committed
1026

1027
  RETURN VALUE
1028 1029
    FALSE                success
    TRUE                 error, error message is set in THD
unknown's avatar
unknown committed
1030
*/
unknown's avatar
unknown committed
1031

unknown's avatar
unknown committed
1032 1033
static bool mysql_test_insert(Prepared_statement *stmt,
                              TABLE_LIST *table_list,
unknown's avatar
unknown committed
1034
                              List<Item> &fields,
unknown's avatar
unknown committed
1035 1036 1037 1038
                              List<List_item> &values_list,
                              List<Item> &update_fields,
                              List<Item> &update_values,
                              enum_duplicates duplic)
unknown's avatar
unknown committed
1039
{
1040
  THD *thd= stmt->thd;
unknown's avatar
unknown committed
1041 1042
  List_iterator_fast<List_item> its(values_list);
  List_item *values;
1043
  DBUG_ENTER("mysql_test_insert");
unknown's avatar
unknown committed
1044

unknown's avatar
unknown committed
1045 1046
  if (insert_precheck(thd, table_list))
    goto error;
unknown's avatar
unknown committed
1047

1048
  /*
unknown's avatar
unknown committed
1049 1050 1051 1052 1053 1054
    open temporary memory pool for temporary data allocated by derived
    tables & preparation procedure
    Note that this is done without locks (should not be needed as we will not
    access any data here)
    If we would use locks, then we have to ensure we are not using
    TL_WRITE_DELAYED as having two such locks can cause table corruption.
unknown's avatar
unknown committed
1055
  */
1056
  if (open_normal_and_derived_tables(thd, table_list, 0))
unknown's avatar
unknown committed
1057
    goto error;
unknown's avatar
unknown committed
1058

unknown's avatar
unknown committed
1059 1060 1061
  if ((values= its++))
  {
    uint value_count;
1062
    ulong counter= 0;
unknown's avatar
unknown committed
1063
    Item *unused_conds= 0;
unknown's avatar
unknown committed
1064

unknown's avatar
unknown committed
1065
    if (table_list->table)
1066 1067 1068 1069 1070
    {
      // don't allocate insert_values
      table_list->table->insert_values=(byte *)1;
    }

unknown's avatar
unknown committed
1071 1072
    if (mysql_prepare_insert(thd, table_list, table_list->table,
                             fields, values, update_fields, update_values,
unknown's avatar
unknown committed
1073
                             duplic, &unused_conds, FALSE, FALSE, FALSE))
unknown's avatar
unknown committed
1074
      goto error;
1075

unknown's avatar
unknown committed
1076 1077
    value_count= values->elements;
    its.rewind();
1078

unknown's avatar
unknown committed
1079 1080 1081 1082 1083
    if (table_list->lock_type == TL_WRITE_DELAYED &&
        !(table_list->table->file->table_flags() & HA_CAN_INSERT_DELAYED))
    {
      my_error(ER_ILLEGAL_HA, MYF(0), (table_list->view ?
                                       table_list->view_name.str :
1084
                                       table_list->table_name));
unknown's avatar
unknown committed
1085 1086
      goto error;
    }
1087
    while ((values= its++))
unknown's avatar
unknown committed
1088 1089 1090 1091
    {
      counter++;
      if (values->elements != value_count)
      {
1092
        my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter);
1093
        goto error;
unknown's avatar
unknown committed
1094
      }
1095
      if (setup_fields(thd, 0, *values, 0, 0, 0))
unknown's avatar
unknown committed
1096
        goto error;
unknown's avatar
unknown committed
1097 1098
    }
  }
unknown's avatar
unknown committed
1099
  DBUG_RETURN(FALSE);
1100 1101

error:
1102
  /* insert_values is cleared in open_table */
unknown's avatar
unknown committed
1103
  DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
1104 1105 1106 1107
}


/*
unknown's avatar
unknown committed
1108 1109
  Validate UPDATE statement

1110
  SYNOPSIS
1111
    mysql_test_update()
1112 1113
      stmt               prepared statement
      tables             list of tables used in this query
unknown's avatar
unknown committed
1114

1115
  RETURN VALUE
1116 1117 1118
    0                    success
    1                    error, error message is set in THD
    2                    convert to multi_update
unknown's avatar
unknown committed
1119
*/
unknown's avatar
unknown committed
1120

unknown's avatar
unknown committed
1121
static int mysql_test_update(Prepared_statement *stmt,
unknown's avatar
unknown committed
1122
                              TABLE_LIST *table_list)
unknown's avatar
unknown committed
1123
{
unknown's avatar
unknown committed
1124
  int res;
1125
  THD *thd= stmt->thd;
unknown's avatar
unknown committed
1126
  uint table_count= 0;
unknown's avatar
unknown committed
1127
  SELECT_LEX *select= &stmt->lex->select_lex;
1128
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
1129
  uint          want_privilege;
1130
#endif
1131
  bool need_reopen;
unknown's avatar
unknown committed
1132 1133
  DBUG_ENTER("mysql_test_update");

unknown's avatar
merge  
unknown committed
1134
  if (update_precheck(thd, table_list))
unknown's avatar
unknown committed
1135 1136
    goto error;

1137
  for ( ; ; )
1138
  {
1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155
    if (open_tables(thd, &table_list, &table_count, 0))
      goto error;

    if (table_list->multitable_view)
    {
      DBUG_ASSERT(table_list->view != 0);
      DBUG_PRINT("info", ("Switch to multi-update"));
      /* pass counter value */
      thd->lex->table_count= table_count;
      /* convert to multiupdate */
      DBUG_RETURN(2);
    }

    if (!lock_tables(thd, table_list, table_count, &need_reopen))
      break;
    if (!need_reopen)
      goto error;
1156
    close_tables_for_reopen(thd, &table_list);
unknown's avatar
unknown committed
1157
  }
unknown's avatar
unknown committed
1158

unknown's avatar
unknown committed
1159 1160 1161 1162
  /*
    thd->fill_derived_tables() is false here for sure (because it is
    preparation of PS, so we even do not check it).
  */
1163
  if (mysql_handle_derived(thd->lex, &mysql_derived_prepare))
unknown's avatar
unknown committed
1164
    goto error;
unknown's avatar
unknown committed
1165

1166 1167 1168 1169 1170
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  /* TABLE_LIST contain right privilages request */
  want_privilege= table_list->grant.want_privilege;
#endif

unknown's avatar
unknown committed
1171 1172 1173 1174 1175
  if (mysql_prepare_update(thd, table_list, &select->where,
                           select->order_list.elements,
                           (ORDER *) select->order_list.first))
    goto error;

1176
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
1177 1178
  table_list->grant.want_privilege= want_privilege;
  table_list->table->grant.want_privilege= want_privilege;
1179
  table_list->register_want_access(want_privilege);
1180
#endif
1181 1182 1183
  thd->lex->select_lex.no_wrap_view_item= TRUE;
  res= setup_fields(thd, 0, select->item_list, 1, 0, 0);
  thd->lex->select_lex.no_wrap_view_item= FALSE;
unknown's avatar
unknown committed
1184 1185
  if (res)
    goto error;
1186
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
1187 1188 1189 1190
  /* Check values */
  table_list->grant.want_privilege=
  table_list->table->grant.want_privilege=
    (SELECT_ACL & ~table_list->table->grant.privilege);
1191
  table_list->register_want_access(SELECT_ACL);
1192
#endif
1193
  if (setup_fields(thd, 0, stmt->lex->value_list, 0, 0, 0))
unknown's avatar
unknown committed
1194
    goto error;
unknown's avatar
unknown committed
1195
  /* TODO: here we should send types of placeholders to the client. */
unknown's avatar
unknown committed
1196 1197 1198
  DBUG_RETURN(0);
error:
  DBUG_RETURN(1);
unknown's avatar
unknown committed
1199 1200 1201 1202
}


/*
1203
  Validate DELETE statement.
unknown's avatar
unknown committed
1204

1205
  SYNOPSIS
unknown's avatar
unknown committed
1206
    mysql_test_delete()
1207 1208
      stmt               prepared statement
      tables             list of tables used in this query
unknown's avatar
unknown committed
1209

1210
  RETURN VALUE
1211 1212
    FALSE                success
    TRUE                 error, error message is set in THD
unknown's avatar
unknown committed
1213
*/
unknown's avatar
unknown committed
1214 1215 1216

static bool mysql_test_delete(Prepared_statement *stmt,
                              TABLE_LIST *table_list)
unknown's avatar
unknown committed
1217
{
1218
  THD *thd= stmt->thd;
unknown's avatar
unknown committed
1219 1220
  LEX *lex= stmt->lex;
  DBUG_ENTER("mysql_test_delete");
unknown's avatar
unknown committed
1221

unknown's avatar
unknown committed
1222 1223 1224
  if (delete_precheck(thd, table_list) ||
      open_and_lock_tables(thd, table_list))
    goto error;
unknown's avatar
unknown committed
1225

unknown's avatar
unknown committed
1226
  if (!table_list->table)
unknown's avatar
unknown committed
1227
  {
unknown's avatar
unknown committed
1228 1229 1230
    my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
             table_list->view_db.str, table_list->view_name.str);
    goto error;
unknown's avatar
unknown committed
1231
  }
unknown's avatar
unknown committed
1232 1233 1234

  DBUG_RETURN(mysql_prepare_delete(thd, table_list, &lex->select_lex.where));
error:
unknown's avatar
unknown committed
1235
  DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
1236 1237
}

unknown's avatar
unknown committed
1238

unknown's avatar
unknown committed
1239
/*
unknown's avatar
unknown committed
1240 1241
  Validate SELECT statement.

1242
  SYNOPSIS
unknown's avatar
unknown committed
1243
    mysql_test_select()
1244 1245 1246 1247 1248 1249
      stmt               prepared statement
      tables             list of tables used in the query

  DESCRIPTION
    In case of success, if this query is not EXPLAIN, send column list info
    back to the client.
unknown's avatar
unknown committed
1250

1251
  RETURN VALUE
1252 1253 1254
    0                    success
    1                    error, error message is set in THD
    2                    success, and statement metadata has been sent
unknown's avatar
unknown committed
1255
*/
1256

1257 1258
static int mysql_test_select(Prepared_statement *stmt,
                             TABLE_LIST *tables, bool text_protocol)
unknown's avatar
unknown committed
1259
{
1260
  THD *thd= stmt->thd;
1261
  LEX *lex= stmt->lex;
1262
  SELECT_LEX_UNIT *unit= &lex->unit;
unknown's avatar
unknown committed
1263
  DBUG_ENTER("mysql_test_select");
unknown's avatar
unknown committed
1264

1265 1266
  lex->select_lex.context.resolve_in_select_list= TRUE;

1267 1268 1269
  ulong privilege= lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL;
  if (tables)
  {
unknown's avatar
unknown committed
1270
    if (check_table_access(thd, privilege, tables,0))
unknown's avatar
unknown committed
1271
      goto error;
1272
  }
1273
  else if (check_access(thd, privilege, any_db,0,0,0,0))
unknown's avatar
unknown committed
1274
    goto error;
unknown's avatar
unknown committed
1275

unknown's avatar
unknown committed
1276
  if (!lex->result && !(lex->result= new (stmt->mem_root) select_send))
unknown's avatar
unknown committed
1277 1278 1279 1280
  {
    my_error(ER_OUTOFMEMORY, MYF(0), sizeof(select_send));
    goto error;
  }
1281

1282
  if (open_and_lock_tables(thd, tables))
unknown's avatar
unknown committed
1283
    goto error;
unknown's avatar
unknown committed
1284

1285 1286
  thd->used_tables= 0;                        // Updated by setup_fields

1287 1288 1289 1290 1291
  /*
    JOIN::prepare calls
    It is not SELECT COMMAND for sure, so setup_tables will be called as
    usual, and we pass 0 as setup_tables_done_option
  */
1292
  if (unit->prepare(thd, 0, 0))
unknown's avatar
unknown committed
1293
    goto error;
1294
  if (!lex->describe && !text_protocol)
1295
  {
1296 1297
    /* Make copy of item list, as change_columns may change it */
    List<Item> fields(lex->select_lex.item_list);
1298

1299 1300 1301
    /* Change columns if a procedure like analyse() */
    if (unit->last_procedure && unit->last_procedure->change_columns(fields))
      goto error;
1302

1303 1304 1305 1306 1307 1308 1309 1310 1311
    /*
      We can use lex->result as it should've been prepared in
      unit->prepare call above.
    */
    if (send_prep_stmt(stmt, lex->result->field_count(fields)) ||
        lex->result->send_fields(fields, Protocol::SEND_EOF) ||
        thd->protocol->flush())
      goto error;
    DBUG_RETURN(2);
1312
  }
1313
  DBUG_RETURN(0);
unknown's avatar
unknown committed
1314
error:
1315
  DBUG_RETURN(1);
unknown's avatar
unknown committed
1316 1317
}

1318

1319
/*
1320
  Validate and prepare for execution DO statement expressions.
1321 1322 1323

  SYNOPSIS
    mysql_test_do_fields()
1324 1325 1326
      stmt               prepared statement
      tables             list of tables used in this query
      values             list of expressions
1327 1328

  RETURN VALUE
1329 1330
    FALSE                success
    TRUE                 error, error message is set in THD
1331 1332
*/

unknown's avatar
unknown committed
1333
static bool mysql_test_do_fields(Prepared_statement *stmt,
unknown's avatar
unknown committed
1334 1335
                                TABLE_LIST *tables,
                                List<Item> *values)
1336 1337
{
  THD *thd= stmt->thd;
unknown's avatar
unknown committed
1338 1339

  DBUG_ENTER("mysql_test_do_fields");
unknown's avatar
unknown committed
1340 1341
  if (tables && check_table_access(thd, SELECT_ACL, tables, 0))
    DBUG_RETURN(TRUE);
1342

1343
  if (open_and_lock_tables(thd, tables))
unknown's avatar
unknown committed
1344
    DBUG_RETURN(TRUE);
1345
  DBUG_RETURN(setup_fields(thd, 0, *values, 0, 0, 0));
1346 1347 1348 1349 1350 1351 1352 1353
}


/*
  Validate and prepare for execution SET statement expressions

  SYNOPSIS
    mysql_test_set_fields()
1354 1355 1356
      stmt               prepared statement
      tables             list of tables used in this query
      values             list of expressions
1357 1358

  RETURN VALUE
1359 1360
    FALSE                success
    TRUE                 error, error message is set in THD
1361
*/
unknown's avatar
unknown committed
1362

unknown's avatar
unknown committed
1363 1364 1365
static bool mysql_test_set_fields(Prepared_statement *stmt,
                                  TABLE_LIST *tables,
                                  List<set_var_base> *var_list)
1366 1367 1368 1369 1370
{
  DBUG_ENTER("mysql_test_set_fields");
  List_iterator_fast<set_var_base> it(*var_list);
  THD *thd= stmt->thd;
  set_var_base *var;
1371

unknown's avatar
unknown committed
1372 1373
  if (tables && check_table_access(thd, SELECT_ACL, tables, 0) ||
      open_and_lock_tables(thd, tables))
1374
    goto error;
unknown's avatar
unknown committed
1375

1376 1377 1378 1379 1380
  while ((var= it++))
  {
    if (var->light_check(thd))
      goto error;
  }
unknown's avatar
unknown committed
1381
  DBUG_RETURN(FALSE);
1382
error:
unknown's avatar
unknown committed
1383
  DBUG_RETURN(TRUE);
1384 1385 1386 1387 1388 1389 1390
}


/*
  Check internal SELECT of the prepared command

  SYNOPSIS
1391
    select_like_stmt_test()
1392 1393 1394
      stmt                      prepared statement
      specific_prepare          function of command specific prepare
      setup_tables_done_option  options to be passed to LEX::unit.prepare()
1395 1396 1397 1398 1399 1400

  NOTE
    This function won't directly open tables used in select. They should
    be opened either by calling function (and in this case you probably
    should use select_like_stmt_test_with_open_n_lock()) or by
    "specific_prepare" call (like this happens in case of multi-update).
1401

unknown's avatar
unknown committed
1402
  RETURN VALUE
1403 1404
    FALSE                success
    TRUE                 error, error message is set in THD
1405
*/
1406 1407 1408 1409

static bool select_like_stmt_test(Prepared_statement *stmt,
                                  bool (*specific_prepare)(THD *thd),
                                  ulong setup_tables_done_option)
1410
{
1411
  DBUG_ENTER("select_like_stmt_test");
1412 1413 1414
  THD *thd= stmt->thd;
  LEX *lex= stmt->lex;

1415 1416
  lex->select_lex.context.resolve_in_select_list= TRUE;

unknown's avatar
unknown committed
1417 1418
  if (specific_prepare && (*specific_prepare)(thd))
    DBUG_RETURN(TRUE);
unknown's avatar
VIEW  
unknown committed
1419

1420 1421
  thd->used_tables= 0;                        // Updated by setup_fields

unknown's avatar
unknown committed
1422
  /* Calls JOIN::prepare */
1423
  DBUG_RETURN(lex->unit.prepare(thd, 0, setup_tables_done_option));
1424 1425
}

1426 1427
/*
  Check internal SELECT of the prepared command (with opening and
1428
  locking of used tables).
1429 1430 1431

  SYNOPSIS
    select_like_stmt_test_with_open_n_lock()
1432 1433 1434 1435 1436
      stmt                      prepared statement
      tables                    list of tables to be opened and locked
                                before calling specific_prepare function
      specific_prepare          function of command specific prepare
      setup_tables_done_option  options to be passed to LEX::unit.prepare()
1437 1438

  RETURN VALUE
1439 1440
    FALSE                success
    TRUE                 error
1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463
*/

static bool
select_like_stmt_test_with_open_n_lock(Prepared_statement *stmt,
                                       TABLE_LIST *tables,
                                       bool (*specific_prepare)(THD *thd),
                                       ulong setup_tables_done_option)
{
  DBUG_ENTER("select_like_stmt_test_with_open_n_lock");

  /*
    We should not call LEX::unit.cleanup() after this open_and_lock_tables()
    call because we don't allow prepared EXPLAIN yet so derived tables will
    clean up after themself.
  */
  if (open_and_lock_tables(stmt->thd, tables))
    DBUG_RETURN(TRUE);

  DBUG_RETURN(select_like_stmt_test(stmt, specific_prepare,
                                    setup_tables_done_option));
}


1464
/*
1465
  Validate and prepare for execution CREATE TABLE statement
1466 1467 1468

  SYNOPSIS
    mysql_test_create_table()
1469 1470
      stmt               prepared statement
      tables             list of tables used in this query
1471 1472

  RETURN VALUE
1473 1474
    FALSE                success
    TRUE                 error, error message is set in THD
1475
*/
unknown's avatar
unknown committed
1476

unknown's avatar
unknown committed
1477
static bool mysql_test_create_table(Prepared_statement *stmt)
1478 1479 1480 1481
{
  DBUG_ENTER("mysql_test_create_table");
  THD *thd= stmt->thd;
  LEX *lex= stmt->lex;
1482
  SELECT_LEX *select_lex= &lex->select_lex;
unknown's avatar
unknown committed
1483
  bool res= FALSE;
1484
  /* Skip first table, which is the table we are creating */
unknown's avatar
VIEW  
unknown committed
1485 1486 1487
  bool link_to_local;
  TABLE_LIST *create_table= lex->unlink_first_table(&link_to_local);
  TABLE_LIST *tables= lex->query_tables;
1488

unknown's avatar
unknown committed
1489 1490 1491 1492
  if (create_table_precheck(thd, tables, create_table))
    DBUG_RETURN(TRUE);

  if (select_lex->item_list.elements)
1493
  {
unknown's avatar
unknown committed
1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505
    if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
    {
      lex->link_first_table_back(create_table, link_to_local);
      create_table->create= TRUE;
    }

    if (open_and_lock_tables(stmt->thd, lex->query_tables))
      DBUG_RETURN(TRUE);

    if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
      create_table= lex->unlink_first_table(&link_to_local);

1506
    select_lex->context.resolve_in_select_list= TRUE;
unknown's avatar
unknown committed
1507 1508

    res= select_like_stmt_test(stmt, 0, 0);
1509
  }
1510

unknown's avatar
unknown committed
1511
  /* put tables back for PS rexecuting */
unknown's avatar
VIEW  
unknown committed
1512
  lex->link_first_table_back(create_table, link_to_local);
1513 1514 1515
  DBUG_RETURN(res);
}

unknown's avatar
unknown committed
1516

1517
/*
1518
  Validate and prepare for execution a multi update statement.
1519 1520 1521

  SYNOPSIS
    mysql_test_multiupdate()
1522 1523 1524
      stmt               prepared statement
      tables             list of tables used in this query
      converted          converted to multi-update from usual update
1525 1526

  RETURN VALUE
1527 1528
    FALSE                success
    TRUE                 error, error message is set in THD
1529
*/
unknown's avatar
unknown committed
1530 1531

static bool mysql_test_multiupdate(Prepared_statement *stmt,
unknown's avatar
unknown committed
1532
                                  TABLE_LIST *tables,
1533
                                  bool converted)
1534
{
1535
  /* if we switched from normal update, rights are checked */
unknown's avatar
merge  
unknown committed
1536
  if (!converted && multi_update_precheck(stmt->thd, tables))
unknown's avatar
unknown committed
1537
    return TRUE;
1538 1539 1540

  return select_like_stmt_test(stmt, &mysql_multi_update_prepare,
                               OPTION_SETUP_TABLES_DONE);
1541 1542 1543 1544
}


/*
1545
  Validate and prepare for execution a multi delete statement.
1546 1547 1548

  SYNOPSIS
    mysql_test_multidelete()
1549 1550
      stmt               prepared statement
      tables             list of tables used in this query
1551 1552

  RETURN VALUE
1553 1554
    FALSE                success
    TRUE                 error, error message in THD is set.
1555
*/
unknown's avatar
unknown committed
1556 1557

static bool mysql_test_multidelete(Prepared_statement *stmt,
unknown's avatar
unknown committed
1558
                                  TABLE_LIST *tables)
1559 1560 1561
{
  stmt->thd->lex->current_select= &stmt->thd->lex->select_lex;
  if (add_item_to_list(stmt->thd, new Item_null()))
unknown's avatar
unknown committed
1562 1563 1564 1565
  {
    my_error(ER_OUTOFMEMORY, MYF(0), 0);
    goto error;
  }
1566

unknown's avatar
unknown committed
1567
  if (multi_delete_precheck(stmt->thd, tables) ||
unknown's avatar
unknown committed
1568 1569 1570 1571
      select_like_stmt_test_with_open_n_lock(stmt, tables,
                                             &mysql_multi_delete_prepare,
                                             OPTION_SETUP_TABLES_DONE))
    goto error;
1572 1573 1574
  if (!tables->table)
  {
    my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
unknown's avatar
unknown committed
1575
             tables->view_db.str, tables->view_name.str);
unknown's avatar
unknown committed
1576
    goto error;
1577
  }
unknown's avatar
unknown committed
1578 1579 1580
  return FALSE;
error:
  return TRUE;
1581 1582 1583
}


1584 1585 1586 1587 1588 1589
/*
  Wrapper for mysql_insert_select_prepare, to make change of local tables
  after open_and_lock_tables() call.

  SYNOPSIS
    mysql_insert_select_prepare_tester()
1590
      thd                thread handle
1591

1592 1593 1594
  NOTE
    We need to remove the first local table after open_and_lock_tables,
    because mysql_handle_derived uses local tables lists.
1595 1596 1597 1598 1599
*/

static bool mysql_insert_select_prepare_tester(THD *thd)
{
  SELECT_LEX *first_select= &thd->lex->select_lex;
1600 1601 1602
  TABLE_LIST *second_table= ((TABLE_LIST*)first_select->table_list.first)->
    next_local;

1603
  /* Skip first table, which is the table we are inserting in */
1604 1605 1606 1607 1608
  first_select->table_list.first= (byte *) second_table;
  thd->lex->select_lex.context.table_list=
    thd->lex->select_lex.context.first_name_resolution_table= second_table;

  return mysql_insert_select_prepare(thd);
1609 1610 1611
}


1612
/*
1613
  Validate and prepare for execution INSERT ... SELECT statement.
1614 1615 1616

  SYNOPSIS
    mysql_test_insert_select()
1617 1618
      stmt               prepared statement
      tables             list of tables used in this query
1619 1620

  RETURN VALUE
1621 1622
    FALSE                success
    TRUE                 error, error message is set in THD
1623
*/
unknown's avatar
unknown committed
1624

1625 1626
static bool mysql_test_insert_select(Prepared_statement *stmt,
                                     TABLE_LIST *tables)
1627 1628 1629
{
  int res;
  LEX *lex= stmt->lex;
unknown's avatar
unknown committed
1630 1631
  TABLE_LIST *first_local_table;

1632 1633 1634 1635 1636
  if (tables->table)
  {
    // don't allocate insert_values
    tables->table->insert_values=(byte *)1;
  }
unknown's avatar
unknown committed
1637

unknown's avatar
unknown committed
1638 1639
  if (insert_precheck(stmt->thd, tables))
    return 1;
1640 1641 1642 1643 1644

  /* store it, because mysql_insert_select_prepare_tester change it */
  first_local_table= (TABLE_LIST *)lex->select_lex.table_list.first;
  DBUG_ASSERT(first_local_table != 0);

1645 1646 1647 1648
  res=
    select_like_stmt_test_with_open_n_lock(stmt, tables,
                                           &mysql_insert_select_prepare_tester,
                                           OPTION_SETUP_TABLES_DONE);
1649
  /* revert changes  made by mysql_insert_select_prepare_tester */
unknown's avatar
unknown committed
1650
  lex->select_lex.table_list.first= (byte*) first_local_table;
1651 1652 1653 1654
  return res;
}


unknown's avatar
unknown committed
1655
/*
1656 1657 1658
  Perform semantic analysis of the parsed tree and send a response packet
  to the client.

1659
  SYNOPSIS
1660
    check_prepared_statement()
1661
      stmt               prepared statement
1662 1663 1664 1665 1666 1667 1668

  DESCRIPTION
    This function
    - opens all tables and checks access rights
    - validates semantics of statement columns and SQL functions
      by calling fix_fields.

1669
  RETURN VALUE
1670 1671
    FALSE                success, statement metadata is sent to client
    TRUE                 error, error message is set in THD (but not sent)
unknown's avatar
unknown committed
1672
*/
1673

unknown's avatar
unknown committed
1674 1675
static bool check_prepared_statement(Prepared_statement *stmt,
                                     bool text_protocol)
1676
{
1677
  THD *thd= stmt->thd;
1678
  LEX *lex= stmt->lex;
1679
  SELECT_LEX *select_lex= &lex->select_lex;
unknown's avatar
VIEW  
unknown committed
1680
  TABLE_LIST *tables;
1681
  enum enum_sql_command sql_command= lex->sql_command;
unknown's avatar
unknown committed
1682
  int res= 0;
1683
  DBUG_ENTER("check_prepared_statement");
unknown's avatar
unknown committed
1684
  DBUG_PRINT("enter",("command: %d  param_count: %u",
1685
                      sql_command, stmt->param_count));
1686

unknown's avatar
VIEW  
unknown committed
1687 1688
  lex->first_lists_tables_same();
  tables= lex->query_tables;
1689

1690 1691 1692 1693
  /* set context for commands which do not use setup_tables */
  lex->select_lex.context.resolve_in_table_list_only(select_lex->
                                                     get_table_list());

1694
  switch (sql_command) {
1695
  case SQLCOM_REPLACE:
unknown's avatar
unknown committed
1696
  case SQLCOM_INSERT:
unknown's avatar
unknown committed
1697
    res= mysql_test_insert(stmt, tables, lex->field_list,
unknown's avatar
unknown committed
1698
                           lex->many_values,
unknown's avatar
unknown committed
1699
                           lex->update_list, lex->value_list,
unknown's avatar
unknown committed
1700
                           lex->duplicates);
unknown's avatar
unknown committed
1701 1702 1703
    break;

  case SQLCOM_UPDATE:
unknown's avatar
unknown committed
1704
    res= mysql_test_update(stmt, tables);
unknown's avatar
unknown committed
1705
    /* mysql_test_update returns 2 if we need to switch to multi-update */
1706 1707 1708 1709 1710
    if (res != 2)
      break;

  case SQLCOM_UPDATE_MULTI:
    res= mysql_test_multiupdate(stmt, tables, res == 2);
unknown's avatar
unknown committed
1711 1712
    break;

unknown's avatar
unknown committed
1713
  case SQLCOM_DELETE:
unknown's avatar
unknown committed
1714
    res= mysql_test_delete(stmt, tables);
unknown's avatar
unknown committed
1715 1716 1717
    break;

  case SQLCOM_SELECT:
1718 1719 1720 1721 1722 1723 1724
    res= mysql_test_select(stmt, tables, text_protocol);
    if (res == 2)
    {
      /* Statement and field info has already been sent */
      DBUG_RETURN(FALSE);
    }
    break;
1725
  case SQLCOM_CREATE_TABLE:
unknown's avatar
VIEW  
unknown committed
1726
    res= mysql_test_create_table(stmt);
1727
    break;
unknown's avatar
unknown committed
1728

1729
  case SQLCOM_DO:
unknown's avatar
unknown committed
1730 1731
    res= mysql_test_do_fields(stmt, tables, lex->insert_list);
    break;
1732 1733

  case SQLCOM_SET_OPTION:
unknown's avatar
unknown committed
1734
    res= mysql_test_set_fields(stmt, tables, &lex->var_list);
1735 1736 1737
    break;

  case SQLCOM_DELETE_MULTI:
unknown's avatar
unknown committed
1738
    res= mysql_test_multidelete(stmt, tables);
1739 1740 1741
    break;

  case SQLCOM_INSERT_SELECT:
1742
  case SQLCOM_REPLACE_SELECT:
unknown's avatar
unknown committed
1743
    res= mysql_test_insert_select(stmt, tables);
1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763
    break;

  case SQLCOM_SHOW_DATABASES:
  case SQLCOM_SHOW_PROCESSLIST:
  case SQLCOM_SHOW_STORAGE_ENGINES:
  case SQLCOM_SHOW_PRIVILEGES:
  case SQLCOM_SHOW_COLUMN_TYPES:
  case SQLCOM_SHOW_STATUS:
  case SQLCOM_SHOW_VARIABLES:
  case SQLCOM_SHOW_LOGS:
  case SQLCOM_SHOW_TABLES:
  case SQLCOM_SHOW_OPEN_TABLES:
  case SQLCOM_SHOW_CHARSETS:
  case SQLCOM_SHOW_COLLATIONS:
  case SQLCOM_SHOW_FIELDS:
  case SQLCOM_SHOW_KEYS:
  case SQLCOM_SHOW_CREATE_DB:
  case SQLCOM_SHOW_GRANTS:
  case SQLCOM_DROP_TABLE:
  case SQLCOM_RENAME_TABLE:
1764 1765 1766 1767 1768 1769
  case SQLCOM_ALTER_TABLE:
  case SQLCOM_COMMIT:
  case SQLCOM_CREATE_INDEX:
  case SQLCOM_DROP_INDEX:
  case SQLCOM_ROLLBACK:
  case SQLCOM_TRUNCATE:
1770
  case SQLCOM_CALL:
1771 1772
  case SQLCOM_CREATE_VIEW:
  case SQLCOM_DROP_VIEW:
1773 1774 1775
  case SQLCOM_REPAIR:
  case SQLCOM_ANALYZE:
  case SQLCOM_OPTIMIZE:
1776 1777
    break;

1778 1779 1780
  case SQLCOM_PREPARE:
  case SQLCOM_EXECUTE:
  case SQLCOM_DEALLOCATE_PREPARE:
unknown's avatar
unknown committed
1781
  default:
unknown's avatar
unknown committed
1782
    /* All other statements are not supported yet. */
unknown's avatar
unknown committed
1783
    my_message(ER_UNSUPPORTED_PS, ER(ER_UNSUPPORTED_PS), MYF(0));
1784
    goto error;
unknown's avatar
unknown committed
1785
  }
unknown's avatar
unknown committed
1786
  if (res == 0)
unknown's avatar
unknown committed
1787 1788
    DBUG_RETURN(text_protocol? FALSE : (send_prep_stmt(stmt, 0) ||
                                        thd->protocol->flush()));
1789
error:
unknown's avatar
unknown committed
1790
  DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
1791 1792
}

unknown's avatar
unknown committed
1793
/*
1794 1795
  Initialize array of parameters in statement from LEX.
  (We need to have quick access to items by number in mysql_stmt_get_longdata).
1796
  This is to avoid using malloc/realloc in the parser.
unknown's avatar
unknown committed
1797
*/
unknown's avatar
unknown committed
1798

1799
static bool init_param_array(Prepared_statement *stmt)
unknown's avatar
unknown committed
1800
{
1801 1802 1803
  LEX *lex= stmt->lex;
  if ((stmt->param_count= lex->param_list.elements))
  {
1804 1805 1806
    if (stmt->param_count > (uint) UINT_MAX16)
    {
      /* Error code to be defined in 5.0 */
1807 1808
      my_message(ER_PS_MANY_PARAM, ER(ER_PS_MANY_PARAM), MYF(0));
      return TRUE;
1809
    }
1810 1811 1812 1813
    Item_param **to;
    List_iterator<Item_param> param_iterator(lex->param_list);
    /* Use thd->mem_root as it points at statement mem_root */
    stmt->param_array= (Item_param **)
unknown's avatar
unknown committed
1814
                       alloc_root(stmt->thd->mem_root,
1815 1816
                                  sizeof(Item_param*) * stmt->param_count);
    if (!stmt->param_array)
1817
      return TRUE;
1818 1819 1820 1821 1822 1823 1824
    for (to= stmt->param_array;
         to < stmt->param_array + stmt->param_count;
         ++to)
    {
      *to= param_iterator++;
    }
  }
1825
  return FALSE;
unknown's avatar
unknown committed
1826
}
1827

1828

unknown's avatar
unknown committed
1829
/*
1830
  COM_STMT_PREPARE handler.
unknown's avatar
unknown committed
1831

1832 1833
  SYNOPSIS
    mysql_stmt_prepare()
1834 1835 1836 1837 1838 1839 1840
      packet             query to be prepared
      packet_length      query string length, including ignored
                         trailing NULL or quote char.

  DESCRIPTION
    Given a query string with parameter markers, create a prepared
    statement from it and send PS info back to the client.
unknown's avatar
unknown committed
1841

1842
  NOTES
unknown's avatar
unknown committed
1843 1844 1845 1846
    This function parses the query and sends the total number of parameters
    and resultset metadata information back to client (if any), without
    executing the query i.e. without any log/disk writes. This allows the
    queries to be re-executed without re-parsing during execute.
1847 1848

    If parameter markers are found in the query, then store the information
unknown's avatar
unknown committed
1849 1850
    using Item_param along with maintaining a list in lex->param_array, so
    that a fast and direct retrieval can be made without going through all
1851
    field items.
unknown's avatar
unknown committed
1852

1853 1854 1855
  RETURN VALUE
    none: in case of success a new statement id and metadata is sent
    to the client, otherwise an error message is set in THD.
unknown's avatar
unknown committed
1856 1857
*/

1858
void mysql_stmt_prepare(THD *thd, const char *packet, uint packet_length)
unknown's avatar
unknown committed
1859
{
unknown's avatar
unknown committed
1860
  Prepared_statement *stmt;
1861
  bool error;
1862
  DBUG_ENTER("mysql_stmt_prepare");
unknown's avatar
unknown committed
1863

unknown's avatar
unknown committed
1864
  DBUG_PRINT("prep_query", ("%s", packet));
unknown's avatar
unknown committed
1865

unknown's avatar
unknown committed
1866 1867 1868 1869
  /* First of all clear possible warnings from the previous command */
  mysql_reset_thd_for_next_command(thd);

  if (! (stmt= new Prepared_statement(thd, &thd->protocol_prep)))
1870
    DBUG_VOID_RETURN; /* out of memory: error is set in Sql_alloc */
1871

1872
  if (thd->stmt_map.insert(thd, stmt))
1873
  {
1874
    /*
1875
      The error is set in the insert. The statement itself
1876 1877
      will be also deleted there (this is how the hash works).
    */
1878
    DBUG_VOID_RETURN;
1879
  }
unknown's avatar
unknown committed
1880

1881
  /* Reset warnings from previous command */
unknown's avatar
unknown committed
1882
  mysql_reset_errors(thd, 0);
1883 1884 1885
  sp_cache_flush_obsolete(&thd->sp_proc_cache);
  sp_cache_flush_obsolete(&thd->sp_func_cache);

1886 1887
  if (!(specialflag & SPECIAL_NO_PRIOR))
    my_pthread_setprio(pthread_self(),QUERY_PRIOR);
1888

1889
  error= stmt->prepare(packet, packet_length);
unknown's avatar
unknown committed
1890 1891

  if (!(specialflag & SPECIAL_NO_PRIOR))
unknown's avatar
unknown committed
1892
    my_pthread_setprio(pthread_self(),WAIT_PRIOR);
unknown's avatar
unknown committed
1893

1894
  if (error)
1895
  {
1896 1897
    /* Statement map deletes statement on erase */
    thd->stmt_map.erase(stmt);
1898 1899
  }
  else
unknown's avatar
unknown committed
1900 1901 1902
  {
    const char *format= "[%lu] %.*b";
    mysql_log.write(thd, COM_STMT_PREPARE, format, stmt->id,
1903
                    stmt->query_length, stmt->query);
1904

unknown's avatar
unknown committed
1905
  }
1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939
  /* check_prepared_statemnt sends the metadata packet in case of success */
  DBUG_VOID_RETURN;
}

/*
  SYNOPSIS
    get_dynamic_sql_string()
      lex       in      main lex
      query_len out     length of the SQL statement (is set only
                        in case of success)

  DESCRIPTION
    Get an SQL statement text from a user variable or from plain
    text. If the statement is plain text, just assign the
    pointers, otherwise allocate memory in thd->mem_root and copy
    the contents of the variable, possibly with character
    set conversion.

  RETURN VALUE
    non-zero success, 0 in case of error (out of memory)
*/

static const char *get_dynamic_sql_string(LEX *lex, uint *query_len)
{
  THD *thd= lex->thd;
  char *query_str= 0;

  if (lex->prepared_stmt_code_is_varref)
  {
    /* This is PREPARE stmt FROM or EXECUTE IMMEDIATE @var. */
    String str;
    CHARSET_INFO *to_cs= thd->variables.collation_connection;
    bool needs_conversion;
    user_var_entry *entry;
1940
    String *var_value= &str;
1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953
    uint32 unused, len;
    /*
      Convert @var contents to string in connection character set. Although
      it is known that int/real/NULL value cannot be a valid query we still
      convert it for error messages to be uniform.
    */
    if ((entry=
         (user_var_entry*)hash_search(&thd->user_vars,
                                      (byte*)lex->prepared_stmt_code.str,
                                      lex->prepared_stmt_code.length))
        && entry->value)
    {
      my_bool is_var_null;
1954
      var_value= entry->val_str(&is_var_null, &str, NOT_FIXED_DEC);
1955 1956 1957 1958 1959
      /*
        NULL value of variable checked early as entry->value so here
        we can't get NULL in normal conditions
      */
      DBUG_ASSERT(!is_var_null);
1960
      if (!var_value)
1961 1962 1963 1964 1965 1966 1967 1968
        goto end;
    }
    else
    {
      /*
        variable absent or equal to NULL, so we need to set variable to
        something reasonable to get a readable error message during parsing
      */
1969
      str.set(STRING_WITH_LEN("NULL"), &my_charset_latin1);
1970 1971
    }

1972 1973 1974
    needs_conversion= String::needs_conversion(var_value->length(),
                                               var_value->charset(), to_cs,
                                               &unused);
1975

1976 1977
    len= (needs_conversion ? var_value->length() * to_cs->mbmaxlen :
          var_value->length());
1978 1979 1980 1981 1982 1983
    if (!(query_str= alloc_root(thd->mem_root, len+1)))
      goto end;

    if (needs_conversion)
    {
      uint dummy_errors;
1984 1985 1986
      len= copy_and_convert(query_str, len, to_cs, var_value->ptr(),
                            var_value->length(), var_value->charset(),
                            &dummy_errors);
1987 1988
    }
    else
1989 1990
      memcpy(query_str, var_value->ptr(), var_value->length());
    query_str[len]= '\0';                       // Safety (mostly for debug)
1991
    *query_len= len;
unknown's avatar
unknown committed
1992
  }
1993
  else
unknown's avatar
unknown committed
1994
  {
1995 1996
    query_str= lex->prepared_stmt_code.str;
    *query_len= lex->prepared_stmt_code.length;
unknown's avatar
unknown committed
1997
  }
1998 1999
end:
  return query_str;
unknown's avatar
unknown committed
2000 2001
}

unknown's avatar
unknown committed
2002

2003
/* Init PS/SP specific parse tree members.  */
2004

2005
static void init_stmt_after_parse(LEX *lex)
2006 2007
{
  SELECT_LEX *sl= lex->all_selects_list;
2008 2009 2010 2011
  /*
    Switch off a temporary flag that prevents evaluation of
    subqueries in statement prepare.
  */
2012 2013
  for (; sl; sl= sl->next_select_in_list())
   sl->uncacheable&= ~UNCACHEABLE_PREPARE;
2014 2015
}

2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041
/*
  SQLCOM_PREPARE implementation.

  SYNOPSIS
    mysql_sql_stmt_prepare()
      thd     thread handle

  DESCRIPTION
    Prepare an SQL prepared statement. This is called from
    mysql_execute_command and should therefore behave like an
    ordinary query (e.g. should not reset any global THD data).

  RETURN VALUE
    none: in case of success, OK packet is sent to the client,
    otherwise an error message is set in THD
*/

void mysql_sql_stmt_prepare(THD *thd)
{
  LEX *lex= thd->lex;
  LEX_STRING *name= &lex->prepared_stmt_name;
  Prepared_statement *stmt;
  const char *query;
  uint query_len;
  DBUG_ENTER("mysql_sql_stmt_prepare");
  DBUG_ASSERT(thd->protocol == &thd->protocol_simple);
2042
  LINT_INIT(query_len);
2043

2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059
  if ((stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name)))
  {
    /*
      If there is a statement with the same name, remove it. It is ok to
      remove old and fail to insert a new one at the same time.
    */
    if (stmt->deallocate())
      DBUG_VOID_RETURN;
  }

  if (! (query= get_dynamic_sql_string(lex, &query_len)) ||
      ! (stmt= new Prepared_statement(thd, &thd->protocol_simple)))
  {
    DBUG_VOID_RETURN;                           /* out of memory */
  }

2060 2061
  /* Set the name first, insert should know that this statement has a name */
  if (stmt->set_name(name))
2062
  {
2063
    delete stmt;
2064 2065
    DBUG_VOID_RETURN;
  }
2066

2067
  if (thd->stmt_map.insert(thd, stmt))
2068
  {
2069
    /* The statement is deleted and an error is set if insert fails */
2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082
    DBUG_VOID_RETURN;
  }

  if (stmt->prepare(query, query_len+1))
  {
    /* Statement map deletes the statement on erase */
    thd->stmt_map.erase(stmt);
  }
  else
    send_ok(thd, 0L, 0L, "Statement prepared");

  DBUG_VOID_RETURN;
}
2083 2084

/* Reinit prepared statement/stored procedure before execution */
unknown's avatar
unknown committed
2085

2086
void reinit_stmt_before_use(THD *thd, LEX *lex)
2087
{
2088
  SELECT_LEX *sl= lex->all_selects_list;
2089
  DBUG_ENTER("reinit_stmt_before_use");
unknown's avatar
unknown committed
2090

2091 2092 2093 2094 2095 2096 2097
  /*
    We have to update "thd" pointer in LEX, all its units and in LEX::result,
    since statements which belong to trigger body are associated with TABLE
    object and because of this can be used in different threads.
  */
  lex->thd= thd;

unknown's avatar
VIEW  
unknown committed
2098 2099 2100
  if (lex->empty_field_list_on_rset)
  {
    lex->empty_field_list_on_rset= 0;
2101
    lex->field_list.empty();
unknown's avatar
VIEW  
unknown committed
2102
  }
2103
  for (; sl; sl= sl->next_select_in_list())
2104
  {
2105 2106
    if (!sl->first_execution)
    {
unknown's avatar
unknown committed
2107 2108 2109
      /* remove option which was put by mysql_explain_union() */
      sl->options&= ~SELECT_DESCRIBE;

2110 2111 2112
      /* see unique_table() */
      sl->exclude_from_table_unique_test= FALSE;

2113
      /*
unknown's avatar
unknown committed
2114 2115
        Copy WHERE, HAVING clause pointers to avoid damaging them
        by optimisation
2116
      */
unknown's avatar
unknown committed
2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127
      if (sl->prep_where)
      {
        sl->where= sl->prep_where->copy_andor_structure(thd);
        sl->where->cleanup();
      }
      if (sl->prep_having)
      {
        sl->having= sl->prep_having->copy_andor_structure(thd);
        sl->having->cleanup();
      }
      DBUG_ASSERT(sl->join == 0);
2128 2129 2130 2131 2132 2133 2134
      ORDER *order;
      /* Fix GROUP list */
      for (order= (ORDER *)sl->group_list.first; order; order= order->next)
        order->item= &order->item_ptr;
      /* Fix ORDER list */
      for (order= (ORDER *)sl->order_list.first; order; order= order->next)
        order->item= &order->item_ptr;
unknown's avatar
unknown committed
2135
    }
2136 2137 2138 2139
    {
      SELECT_LEX_UNIT *unit= sl->master_unit();
      unit->unclean();
      unit->types.empty();
2140
      /* for derived tables & PS (which can't be reset by Item_subquery) */
2141
      unit->reinit_exec_mechanism();
2142
      unit->set_thd(thd);
2143
    }
2144
  }
unknown's avatar
VIEW  
unknown committed
2145 2146

  /*
unknown's avatar
unknown committed
2147 2148
    TODO: When the new table structure is ready, then have a status bit
    to indicate the table is altered, and re-do the setup_*
unknown's avatar
VIEW  
unknown committed
2149 2150
    and open the tables back.
  */
2151 2152 2153 2154 2155
  /*
    NOTE: We should reset whole table list here including all tables added
    by prelocking algorithm (it is not a problem for substatements since
    they have their own table list).
  */
unknown's avatar
VIEW  
unknown committed
2156
  for (TABLE_LIST *tables= lex->query_tables;
2157 2158
       tables;
       tables= tables->next_global)
unknown's avatar
VIEW  
unknown committed
2159
  {
2160 2161
    tables->reinit_before_use(thd);
  }
2162 2163 2164 2165 2166
  /*
    Cleanup of the special case of DELETE t1, t2 FROM t1, t2, t3 ...
    (multi-delete).  We do a full clean up, although at the moment all we
    need to clean in the tables of MULTI-DELETE list is 'table' member.
  */
2167
  for (TABLE_LIST *tables= (TABLE_LIST*) lex->auxiliary_table_list.first;
2168
       tables;
2169
       tables= tables->next_global)
unknown's avatar
VIEW  
unknown committed
2170
  {
2171
    tables->reinit_before_use(thd);
unknown's avatar
VIEW  
unknown committed
2172
  }
2173
  lex->current_select= &lex->select_lex;
2174 2175 2176 2177 2178

  /* restore original list used in INSERT ... SELECT */
  if (lex->leaf_tables_insert)
    lex->select_lex.leaf_tables= lex->leaf_tables_insert;

2179
  if (lex->result)
2180
  {
2181
    lex->result->cleanup();
2182 2183
    lex->result->set_thd(thd);
  }
unknown's avatar
unknown committed
2184 2185
  lex->allow_sum_func= 0;
  lex->in_sum_func= NULL;
2186
  DBUG_VOID_RETURN;
2187 2188
}

2189

2190 2191
/*
  Clears parameters from data left from previous execution or long data
unknown's avatar
unknown committed
2192

2193 2194
  SYNOPSIS
    reset_stmt_params()
2195 2196
      stmt               prepared statement for which parameters should
                         be reset
2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207
*/

static void reset_stmt_params(Prepared_statement *stmt)
{
  Item_param **item= stmt->param_array;
  Item_param **end= item + stmt->param_count;
  for (;item < end ; ++item)
    (**item).reset();
}


2208
/*
2209
  COM_STMT_EXECUTE handler: execute a previously prepared statement.
2210

2211
  SYNOPSIS
2212
    mysql_stmt_execute()
2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225
      thd                current thread
      packet             parameter types and data, if any
      packet_length      packet length, including the terminator character.

  DESCRIPTION
    If there are any parameters, then replace parameter markers with the
    data supplied from the client, and then execute the statement.
    This function uses binary protocol to send a possible result set
    to the client.

  RETURN VALUE
    none: in case of success OK packet or a result set is sent to the
    client, otherwise an error message is set in THD.
unknown's avatar
unknown committed
2226 2227
*/

2228
void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length)
unknown's avatar
unknown committed
2229
{
2230
  uchar *packet= (uchar*)packet_arg; // GCC 4.0.1 workaround
unknown's avatar
unknown committed
2231
  ulong stmt_id= uint4korr(packet);
unknown's avatar
unknown committed
2232
  ulong flags= (ulong) packet[4];
2233
  /* Query text for binary, general or slow log, if any of them is open */
2234
  String expanded_query;
unknown's avatar
unknown committed
2235
#ifndef EMBEDDED_LIBRARY
2236
  uchar *packet_end= packet + packet_length - 1;
unknown's avatar
unknown committed
2237
#endif
2238
  Prepared_statement *stmt;
2239
  bool error;
2240
  DBUG_ENTER("mysql_stmt_execute");
2241 2242

  packet+= 9;                               /* stmt_id + 5 bytes of flags */
2243

unknown's avatar
unknown committed
2244 2245 2246
  /* First of all clear possible warnings from the previous command */
  mysql_reset_thd_for_next_command(thd);

unknown's avatar
unknown committed
2247
  if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_execute")))
2248 2249
    DBUG_VOID_RETURN;

2250 2251
  DBUG_PRINT("exec_query", ("%s", stmt->query));
  DBUG_PRINT("info",("stmt: %p", stmt));
unknown's avatar
unknown committed
2252

2253 2254 2255
  sp_cache_flush_obsolete(&thd->sp_proc_cache);
  sp_cache_flush_obsolete(&thd->sp_func_cache);

unknown's avatar
unknown committed
2256
#ifndef EMBEDDED_LIBRARY
2257
  if (stmt->param_count)
2258
  {
2259 2260 2261
    uchar *null_array= packet;
    if (setup_conversion_functions(stmt, &packet, packet_end) ||
        stmt->set_params(stmt, null_array, packet, packet_end,
2262
                         &expanded_query))
2263
      goto set_params_data_err;
2264
  }
unknown's avatar
unknown committed
2265
#else
2266
  /*
unknown's avatar
unknown committed
2267 2268
    In embedded library we re-install conversion routines each time
    we set params, and also we don't need to parse packet.
2269
    So we do it in one function.
2270
  */
2271
  if (stmt->param_count && stmt->set_params_data(stmt, &expanded_query))
2272
    goto set_params_data_err;
unknown's avatar
unknown committed
2273
#endif
2274 2275
  if (!(specialflag & SPECIAL_NO_PRIOR))
    my_pthread_setprio(pthread_self(),QUERY_PRIOR);
2276 2277 2278 2279 2280 2281 2282 2283

  /*
    If the free_list is not empty, we'll wrongly free some externally
    allocated items when cleaning up after validation of the prepared
    statement.
  */
  DBUG_ASSERT(thd->free_list == NULL);

2284
  error= stmt->execute(&expanded_query,
2285
                       test(flags & (ulong) CURSOR_TYPE_READ_ONLY));
2286 2287
  if (!(specialflag & SPECIAL_NO_PRIOR))
    my_pthread_setprio(pthread_self(), WAIT_PRIOR);
2288
  if (error == 0)
unknown's avatar
unknown committed
2289 2290 2291
  {
    const char *format= "[%lu] %.*b";
    mysql_log.write(thd, COM_STMT_EXECUTE, format, stmt->id,
2292
                    thd->query_length, thd->query);
unknown's avatar
unknown committed
2293
  }
2294

2295
  DBUG_VOID_RETURN;
unknown's avatar
unknown committed
2296

2297
set_params_data_err:
2298
  my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_stmt_execute");
2299
  reset_stmt_params(stmt);
unknown's avatar
unknown committed
2300 2301 2302
  DBUG_VOID_RETURN;
}

2303

unknown's avatar
unknown committed
2304
/*
2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321
  SQLCOM_EXECUTE implementation.

  SYNOPSIS
    mysql_sql_stmt_execute()
      thd                thread handle

  DESCRIPTION
    Execute prepared statement using parameter values from
    lex->prepared_stmt_params and send result to the client using
    text protocol. This is called from mysql_execute_command and
    therefore should behave like an ordinary query (e.g. not change
    global THD data, such as warning count, server status, etc).
    This function uses text protocol to send a possible result set.

  RETURN
    none: in case of success, OK (or result set) packet is sent to the
    client, otherwise an error is set in THD
unknown's avatar
unknown committed
2322 2323
*/

2324
void mysql_sql_stmt_execute(THD *thd)
unknown's avatar
unknown committed
2325
{
2326
  LEX *lex= thd->lex;
2327
  Prepared_statement *stmt;
2328 2329
  LEX_STRING *name= &lex->prepared_stmt_name;
  /* Query text for binary, general or slow log, if any of them is open */
2330
  String expanded_query;
2331
  DBUG_ENTER("mysql_sql_stmt_execute");
2332
  DBUG_PRINT("info", ("EXECUTE: %.*s\n", name->length, name->str));
2333

2334
  if (!(stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name)))
2335
  {
2336 2337
    my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0),
             name->length, name->str, "EXECUTE");
2338
    DBUG_VOID_RETURN;
2339 2340
  }

2341
  if (stmt->param_count != lex->prepared_stmt_params.elements)
unknown's avatar
unknown committed
2342
  {
2343
    my_error(ER_WRONG_ARGUMENTS, MYF(0), "EXECUTE");
unknown's avatar
unknown committed
2344 2345 2346
    DBUG_VOID_RETURN;
  }

2347 2348
  DBUG_PRINT("info",("stmt: %p", stmt));

2349 2350 2351 2352 2353 2354 2355
  /*
    If the free_list is not empty, we'll wrongly free some externally
    allocated items when cleaning up after validation of the prepared
    statement.
  */
  DBUG_ASSERT(thd->free_list == NULL);

2356
  if (stmt->set_params_from_vars(stmt, lex->prepared_stmt_params,
2357
                                 &expanded_query))
2358
    goto set_params_data_err;
2359

2360
  (void) stmt->execute(&expanded_query, FALSE);
2361

unknown's avatar
unknown committed
2362
  DBUG_VOID_RETURN;
2363 2364 2365 2366 2367

set_params_data_err:
  my_error(ER_WRONG_ARGUMENTS, MYF(0), "EXECUTE");
  reset_stmt_params(stmt);
  DBUG_VOID_RETURN;
unknown's avatar
unknown committed
2368 2369
}

2370

2371
/*
2372
  COM_STMT_FETCH handler: fetches requested amount of rows from cursor
unknown's avatar
unknown committed
2373

2374
  SYNOPSIS
unknown's avatar
unknown committed
2375
    mysql_stmt_fetch()
2376 2377 2378
      thd                Thread handle
      packet             Packet from client (with stmt_id & num_rows)
      packet_length      Length of packet
2379 2380 2381 2382 2383 2384
*/

void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length)
{
  /* assume there is always place for 8-16 bytes */
  ulong stmt_id= uint4korr(packet);
2385
  ulong num_rows= uint4korr(packet+4);
2386
  Prepared_statement *stmt;
unknown's avatar
unknown committed
2387
  Statement stmt_backup;
2388
  Server_side_cursor *cursor;
2389 2390
  DBUG_ENTER("mysql_stmt_fetch");

unknown's avatar
unknown committed
2391
  /* First of all clear possible warnings from the previous command */
2392
  mysql_reset_thd_for_next_command(thd);
unknown's avatar
unknown committed
2393
  statistic_increment(thd->status_var.com_stmt_fetch, &LOCK_status);
2394 2395 2396
  if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_fetch")))
    DBUG_VOID_RETURN;

2397
  cursor= stmt->cursor;
2398
  if (!cursor)
2399
  {
2400
    my_error(ER_STMT_HAS_NO_OPEN_CURSOR, MYF(0), stmt_id);
2401 2402
    DBUG_VOID_RETURN;
  }
2403

unknown's avatar
unknown committed
2404
  thd->stmt_arena= stmt;
unknown's avatar
unknown committed
2405
  thd->set_n_backup_statement(stmt, &stmt_backup);
2406 2407 2408 2409

  if (!(specialflag & SPECIAL_NO_PRIOR))
    my_pthread_setprio(pthread_self(), QUERY_PRIOR);

2410
  cursor->fetch(num_rows);
2411 2412 2413 2414

  if (!(specialflag & SPECIAL_NO_PRIOR))
    my_pthread_setprio(pthread_self(), WAIT_PRIOR);

2415
  if (!cursor->is_open())
2416
  {
2417 2418
    stmt->close_cursor();
    thd->cursor= 0;
2419 2420 2421
    reset_stmt_params(stmt);
  }

2422
  thd->restore_backup_statement(stmt, &stmt_backup);
unknown's avatar
unknown committed
2423
  thd->stmt_arena= thd;
2424

2425 2426 2427 2428
  DBUG_VOID_RETURN;
}


unknown's avatar
unknown committed
2429
/*
2430
  Reset a prepared statement in case there was a recoverable error.
2431 2432
  SYNOPSIS
    mysql_stmt_reset()
2433 2434
      thd                Thread handle
      packet             Packet with stmt id
2435 2436

  DESCRIPTION
2437 2438 2439 2440 2441
    This function resets statement to the state it was right after prepare.
    It can be used to:
     - clear an error happened during mysql_stmt_send_long_data
     - cancel long data stream for all placeholders without
       having to call mysql_stmt_execute.
2442
     - close an open cursor
2443 2444
    Sends 'OK' packet in case of success (statement was reset)
    or 'ERROR' packet (unrecoverable error/statement not found/etc).
unknown's avatar
unknown committed
2445 2446
*/

2447
void mysql_stmt_reset(THD *thd, char *packet)
unknown's avatar
unknown committed
2448
{
2449
  /* There is always space for 4 bytes in buffer */
2450
  ulong stmt_id= uint4korr(packet);
2451
  Prepared_statement *stmt;
2452
  DBUG_ENTER("mysql_stmt_reset");
unknown's avatar
unknown committed
2453

unknown's avatar
unknown committed
2454 2455 2456
  /* First of all clear possible warnings from the previous command */
  mysql_reset_thd_for_next_command(thd);

unknown's avatar
unknown committed
2457
  statistic_increment(thd->status_var.com_stmt_reset, &LOCK_status);
unknown's avatar
unknown committed
2458
  if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_reset")))
2459 2460
    DBUG_VOID_RETURN;

2461 2462 2463 2464 2465 2466 2467
  stmt->close_cursor();

  /*
    Clear parameters from data which could be set by
    mysql_stmt_send_long_data() call.
  */
  reset_stmt_params(stmt);
2468

unknown's avatar
unknown committed
2469
  stmt->state= Query_arena::PREPARED;
2470

2471
  send_ok(thd);
unknown's avatar
unknown committed
2472

2473 2474 2475 2476 2477
  DBUG_VOID_RETURN;
}


/*
2478
  Delete a prepared statement from memory.
2479
  Note: we don't send any reply to this command.
2480 2481
*/

2482
void mysql_stmt_close(THD *thd, char *packet)
2483
{
2484
  /* There is always space for 4 bytes in packet buffer */
2485
  ulong stmt_id= uint4korr(packet);
2486
  Prepared_statement *stmt;
2487
  DBUG_ENTER("mysql_stmt_close");
2488

unknown's avatar
unknown committed
2489
  if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_close")))
2490
    DBUG_VOID_RETURN;
2491

2492 2493 2494 2495
  /*
    The only way currently a statement can be deallocated when it's
    in use is from within Dynamic SQL.
  */
2496
  DBUG_ASSERT(! (stmt->flags & (uint) Prepared_statement::IS_IN_USE));
2497 2498
  (void) stmt->deallocate();

unknown's avatar
unknown committed
2499 2500 2501
  DBUG_VOID_RETURN;
}

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
  SQLCOM_DEALLOCATE implementation.

  DESCRIPTION
    Close an SQL prepared statement. As this can be called from Dynamic
    SQL, we should be careful to not close a statement that is currently
    being executed.

  RETURN VALUE
    none: OK packet is sent in case of success, otherwise an error
    message is set in THD
*/

void mysql_sql_stmt_close(THD *thd)
{
  Prepared_statement* stmt;
  LEX_STRING *name= &thd->lex->prepared_stmt_name;
  DBUG_PRINT("info", ("DEALLOCATE PREPARE: %.*s\n", name->length, name->str));

  if (! (stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name)))
  {
    my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0),
             name->length, name->str, "DEALLOCATE PREPARE");
    return;
  }

  if (stmt->deallocate() == 0)
    send_ok(thd);
}

/*
  Handle long data in pieces from client.
2535 2536 2537

  SYNOPSIS
    mysql_stmt_get_longdata()
2538 2539
      thd                Thread handle
      packet             String to append
2540
      packet_length      Length of string (including end \0)
2541 2542

  DESCRIPTION
2543 2544 2545 2546 2547
    Get a part of a long data. To make the protocol efficient, we are
    not sending any return packets here. If something goes wrong, then
    we will send the error on 'execute' We assume that the client takes
    care of checking that all parts are sent to the server. (No checking
    that we get a 'end of column' in the server is performed).
2548 2549
*/

2550
void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
2551
{
2552 2553
  ulong stmt_id;
  uint param_number;
2554
  Prepared_statement *stmt;
2555
  Item_param *param;
2556
#ifndef EMBEDDED_LIBRARY
2557
  char *packet_end= packet + packet_length - 1;
2558
#endif
2559 2560
  DBUG_ENTER("mysql_stmt_get_longdata");

unknown's avatar
unknown committed
2561
  statistic_increment(thd->status_var.com_stmt_send_long_data, &LOCK_status);
unknown's avatar
unknown committed
2562
#ifndef EMBEDDED_LIBRARY
2563
  /* Minimal size of long data packet is 6 bytes */
2564
  if (packet_length <= MYSQL_LONG_DATA_HEADER)
2565
  {
2566
    my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_stmt_send_long_data");
2567 2568
    DBUG_VOID_RETURN;
  }
unknown's avatar
unknown committed
2569
#endif
2570

2571 2572
  stmt_id= uint4korr(packet);
  packet+= 4;
2573

unknown's avatar
unknown committed
2574 2575
  if (!(stmt=find_prepared_statement(thd, stmt_id,
                                     "mysql_stmt_send_long_data")))
2576 2577
    DBUG_VOID_RETURN;

2578 2579
  param_number= uint2korr(packet);
  packet+= 2;
unknown's avatar
unknown committed
2580
#ifndef EMBEDDED_LIBRARY
2581 2582
  if (param_number >= stmt->param_count)
  {
unknown's avatar
unknown committed
2583
    /* Error will be sent in execute call */
unknown's avatar
unknown committed
2584
    stmt->state= Query_arena::ERROR;
unknown's avatar
unknown committed
2585
    stmt->last_errno= ER_WRONG_ARGUMENTS;
2586 2587
    sprintf(stmt->last_error, ER(ER_WRONG_ARGUMENTS),
            "mysql_stmt_send_long_data");
2588 2589
    DBUG_VOID_RETURN;
  }
unknown's avatar
unknown committed
2590 2591
#endif

2592 2593
  param= stmt->param_array[param_number];

unknown's avatar
unknown committed
2594
#ifndef EMBEDDED_LIBRARY
2595
  if (param->set_longdata(packet, (ulong) (packet_end - packet)))
unknown's avatar
unknown committed
2596
#else
2597
  if (param->set_longdata(thd->extra_data, thd->extra_length))
unknown's avatar
unknown committed
2598
#endif
2599
  {
unknown's avatar
unknown committed
2600
    stmt->state= Query_arena::ERROR;
2601 2602 2603
    stmt->last_errno= ER_OUTOFMEMORY;
    sprintf(stmt->last_error, ER(ER_OUTOFMEMORY), 0);
  }
2604 2605
  DBUG_VOID_RETURN;
}
unknown's avatar
unknown committed
2606

2607

2608 2609 2610 2611
/***************************************************************************
 Select_fetch_protocol_prep
****************************************************************************/

2612 2613
Select_fetch_protocol_prep::Select_fetch_protocol_prep(THD *thd_arg)
  :protocol(thd_arg)
2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660
{}

bool Select_fetch_protocol_prep::send_fields(List<Item> &list, uint flags)
{
  bool rc;
  Protocol *save_protocol= thd->protocol;

  /*
    Protocol::send_fields caches the information about column types:
    this information is later used to send data. Therefore, the same
    dedicated Protocol object must be used for all operations with
    a cursor.
  */
  thd->protocol= &protocol;
  rc= select_send::send_fields(list, flags);
  thd->protocol= save_protocol;

  return rc;
}

bool Select_fetch_protocol_prep::send_eof()
{
  Protocol *save_protocol= thd->protocol;

  thd->protocol= &protocol;
  ::send_eof(thd);
  thd->protocol= save_protocol;
  return FALSE;
}


bool
Select_fetch_protocol_prep::send_data(List<Item> &fields)
{
  Protocol *save_protocol= thd->protocol;
  bool rc;

  thd->protocol= &protocol;
  rc= select_send::send_data(fields);
  thd->protocol= save_protocol;
  return rc;
}

/***************************************************************************
 Prepared_statement
****************************************************************************/

2661
Prepared_statement::Prepared_statement(THD *thd_arg, Protocol *protocol_arg)
2662 2663
  :Statement(&main_lex, &main_mem_root,
             INITIALIZED, ++thd_arg->statement_id_counter),
2664
  thd(thd_arg),
2665
  result(thd_arg),
2666
  protocol(protocol_arg),
2667
  param_array(0),
2668
  param_count(0),
2669
  last_errno(0),
2670
  flags((uint) IS_IN_USE)
2671
{
2672 2673
  init_alloc_root(&main_mem_root, thd_arg->variables.query_alloc_block_size,
                  thd_arg->variables.query_prealloc_size);
2674 2675 2676
  *last_error= '\0';
}

2677

2678 2679 2680
void Prepared_statement::setup_set_params()
{
  /* Setup binary logging */
2681 2682
  if (mysql_bin_log.is_open() && is_update_query(lex->sql_command) ||
      mysql_log.is_open() || mysql_slow_log.is_open())
2683
  {
2684
    set_params_from_vars= insert_params_from_vars_with_log;
2685
#ifndef EMBEDDED_LIBRARY
2686
    set_params= insert_params_withlog;
2687
#else
2688
    set_params_data= emb_insert_params_withlog;
2689 2690 2691
#endif
  }
  else
2692 2693
  {
    set_params_from_vars= insert_params_from_vars;
2694
#ifndef EMBEDDED_LIBRARY
2695
    set_params= insert_params;
2696
#else
2697
    set_params_data= emb_insert_params;
2698
#endif
2699
  }
2700 2701
}

2702

2703 2704 2705 2706 2707 2708 2709 2710
/*
  DESCRIPTION
    Destroy this prepared statement, cleaning up all used memory
    and resources. This is called from ::deallocate() to
    handle COM_STMT_CLOSE and DEALLOCATE PREPARE or when
    THD ends and all prepared statements are freed.
*/

2711 2712
Prepared_statement::~Prepared_statement()
{
2713 2714
  DBUG_ENTER("Prepared_statement::~Prepared_statement");
  DBUG_PRINT("enter",("stmt: %p  cursor: %p", this, cursor));
2715
  delete cursor;
2716 2717 2718 2719 2720
  /*
    We have to call free on the items even if cleanup is called as some items,
    like Item_param, don't free everything until free_items()
  */
  free_items();
2721
  delete lex->result;
2722
  free_root(&main_mem_root, MYF(0));
2723
  DBUG_VOID_RETURN;
2724 2725 2726
}


unknown's avatar
unknown committed
2727
Query_arena::Type Prepared_statement::type() const
2728 2729 2730
{
  return PREPARED_STATEMENT;
}
2731 2732


2733
void Prepared_statement::cleanup_stmt()
2734
{
2735
  DBUG_ENTER("Prepared_statement::cleanup_stmt");
2736 2737
  DBUG_PRINT("enter",("stmt: %p", this));

2738
  DBUG_ASSERT(lex->sphead == 0);
2739 2740 2741 2742 2743 2744 2745
  /* The order is important */
  lex->unit.cleanup();
  cleanup_items(free_list);
  thd->cleanup_after_query();
  close_thread_tables(thd);
  thd->rollback_item_tree_changes();

2746
  DBUG_VOID_RETURN;
2747
}
2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 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


bool Prepared_statement::set_name(LEX_STRING *name_arg)
{
  name.length= name_arg->length;
  name.str= memdup_root(mem_root, (char*) name_arg->str, name_arg->length);
  return name.str == 0;
}

/**************************************************************************
  Common parts of mysql_[sql]_stmt_prepare, mysql_[sql]_stmt_execute.
  Essentially, these functions do all the magic of preparing/executing
  a statement, leaving network communication, input data handling and
  global THD state management to the caller.
***************************************************************************/

/*
  Parse statement text, validate the statement, and prepare it for execution.

  SYNOPSIS
    Prepared_statement::prepare()
      packet             statement text
      packet_len

  DESCRIPTION
    You should not change global THD state in this function, if at all
    possible: it may be called from any context, e.g. when executing
    a COM_* command, and SQLCOM_* command, or a stored procedure.

  NOTES
      Precondition.
      -------------
    The caller must ensure that thd->change_list and thd->free_list
    is empty: this function will not back them up but will free
    in the end of its execution.

      Postcondition.
      --------------
    thd->mem_root contains unused memory allocated during validation.
*/

bool Prepared_statement::prepare(const char *packet, uint packet_len)
{
2791
  bool error;
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
  Statement stmt_backup;
  Query_arena *old_stmt_arena;
  DBUG_ENTER("Prepared_statement::prepare");
  /*
    If this is an SQLCOM_PREPARE, we also increase Com_prepare_sql.
    However, it seems handy if com_stmt_prepare is increased always,
    no matter what kind of prepare is processed.
  */
  statistic_increment(thd->status_var.com_stmt_prepare, &LOCK_status);

  /*
    alloc_query() uses thd->memroot && thd->query, so we should call
    both of backup_statement() and backup_query_arena() here.
  */
  thd->set_n_backup_statement(this, &stmt_backup);
  thd->set_n_backup_active_arena(this, &stmt_backup);

  if (alloc_query(thd, packet, packet_len))
  {
    thd->restore_backup_statement(this, &stmt_backup);
    thd->restore_active_arena(this, &stmt_backup);
    DBUG_RETURN(TRUE);
  }

  old_stmt_arena= thd->stmt_arena;
  thd->stmt_arena= this;
2818 2819

  Lex_input_stream lip(thd, thd->query, thd->query_length);
2820
  lip.stmt_prepare_mode= TRUE;
2821 2822
  thd->m_lip= &lip;
  lex_start(thd);
2823
  lex->safe_to_cache_query= FALSE;
2824
  int err= MYSQLparse((void *)thd);
2825

2826
  error= err || thd->is_fatal_error ||
2827
      thd->net.report_error || init_param_array(this);
2828

2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843
  /*
    While doing context analysis of the query (in check_prepared_statement)
    we allocate a lot of additional memory: for open tables, JOINs, derived
    tables, etc.  Let's save a snapshot of current parse tree to the
    statement and restore original THD. In cases when some tree
    transformation can be reused on execute, we set again thd->mem_root from
    stmt->mem_root (see setup_wild for one place where we do that).
  */
  thd->restore_active_arena(this, &stmt_backup);

  /*
    If called from a stored procedure, ensure that we won't rollback
    external changes when cleaning up after validation.
  */
  DBUG_ASSERT(thd->change_list.is_empty());
2844 2845 2846 2847 2848

  /* 
   The only case where we should have items in the thd->free_list is
   after stmt->set_params_from_vars(), which may in some cases create
   Item_null objects.
2849 2850
  */

2851 2852
  if (error == 0)
    error= check_prepared_statement(this, name.str != 0);
2853

2854 2855 2856 2857 2858 2859 2860
  /*
    Currently CREATE PROCEDURE/TRIGGER/EVENT are prohibited in prepared
    statements: ensure we have no memory leak here if by someone tries
    to PREPARE stmt FROM "CREATE PROCEDURE ..."
  */
  DBUG_ASSERT(lex->sphead == NULL || error != 0);
  if (lex->sphead)
2861
  {
2862 2863
    delete lex->sphead;
    lex->sphead= NULL;
2864
  }
2865

2866
  lex_end(lex);
2867
  cleanup_stmt();
2868 2869 2870
  thd->restore_backup_statement(this, &stmt_backup);
  thd->stmt_arena= old_stmt_arena;

2871
  if (error == 0)
2872 2873 2874 2875
  {
    setup_set_params();
    init_stmt_after_parse(lex);
    state= Query_arena::PREPARED;
2876
    flags&= ~ (uint) IS_IN_USE;
2877
  }
2878
  DBUG_RETURN(error);
2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899
}

/*
  Execute a prepared statement.

  SYNOPSIS
    Prepared_statement::execute()
      expanded_query     A query for binlogging which has all parameter
                         markers ('?') replaced with their actual values.
      open_cursor        True if an attempt to open a cursor should be made.
                         Currenlty used only in the binary protocol.

  DESCRIPTION
    You should not change global THD state in this function, if at all
    possible: it may be called from any context, e.g. when executing
    a COM_* command, and SQLCOM_* command, or a stored procedure.

  NOTES
      Preconditions, postconditions.
      ------------------------------
      See the comment for Prepared_statement::prepare().
2900 2901 2902 2903

  RETURN
    FALSE		ok
    TRUE		Error
2904 2905 2906 2907 2908 2909
*/

bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
{
  Statement stmt_backup;
  Query_arena *old_stmt_arena;
2910
  bool error= TRUE;
2911 2912 2913 2914 2915 2916 2917

  statistic_increment(thd->status_var.com_stmt_execute, &LOCK_status);

  /* Check if we got an error when sending long data */
  if (state == Query_arena::ERROR)
  {
    my_message(last_errno, last_error, MYF(0));
2918
    return TRUE;
2919
  }
2920
  if (flags & (uint) IS_IN_USE)
2921 2922
  {
    my_error(ER_PS_NO_RECURSION, MYF(0));
2923
    return TRUE;
2924
  }
2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935

  /*
    For SHOW VARIABLES lex->result is NULL, as it's a non-SELECT
    command. For such queries we don't return an error and don't
    open a cursor -- the client library will recognize this case and
    materialize the result set.
    For SELECT statements lex->result is created in
    check_prepared_statement. lex->result->simple_select() is FALSE
    in INSERT ... SELECT and similar commands.
  */

2936
  if (open_cursor && lex->result && lex->result->check_simple_select())
2937 2938 2939 2940 2941
  {
    DBUG_PRINT("info",("Cursor asked for not SELECT stmt"));
    return TRUE;
  }

2942 2943 2944
  /* In case the command has a call to SP which re-uses this statement name */
  flags|= IS_IN_USE;

2945
  close_cursor();
2946 2947 2948 2949 2950 2951

  /*
    If the free_list is not empty, we'll wrongly free some externally
    allocated items when cleaning up after execution of this statement.
  */
  DBUG_ASSERT(thd->change_list.is_empty());
2952 2953 2954 2955 2956 2957 2958

  /* 
   The only case where we should have items in the thd->free_list is
   after stmt->set_params_from_vars(), which may in some cases create
   Item_null objects.
  */

2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974
  thd->set_n_backup_statement(this, &stmt_backup);
  if (expanded_query->length() &&
      alloc_query(thd, (char*) expanded_query->ptr(),
                  expanded_query->length()+1))
  {
    my_error(ER_OUTOFMEMORY, 0, expanded_query->length());
    goto error;
  }
  /*
    Expanded query is needed for slow logging, so we want thd->query
    to point at it even after we restore from backup. This is ok, as
    expanded query was allocated in thd->mem_root.
  */
  stmt_backup.query= thd->query;
  stmt_backup.query_length= thd->query_length;

2975 2976 2977 2978 2979 2980
  /*
    Save orig_sql_command as we use it to disable slow logging for SHOW
    commands (see log_slow_statement()).
  */
  stmt_backup.lex->orig_sql_command= thd->lex->orig_sql_command;

2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992
  /*
    At first execution of prepared statement we may perform logical
    transformations of the query tree. Such changes should be performed
    on the parse tree of current prepared statement and new items should
    be allocated in its memory root. Set the appropriate pointer in THD
    to the arena of the statement.
  */
  old_stmt_arena= thd->stmt_arena;
  thd->stmt_arena= this;
  reinit_stmt_before_use(thd, lex);

  thd->protocol= protocol;                      /* activate stmt protocol */
2993 2994 2995 2996
  error= (open_cursor ?
          mysql_open_cursor(thd, (uint) ALWAYS_MATERIALIZED_CURSOR,
                            &result, &cursor) :
          mysql_execute_command(thd));
2997 2998
  thd->protocol= &thd->protocol_simple;         /* use normal protocol */

2999
  /* Assert that if an error, no cursor is open */
unknown's avatar
unknown committed
3000
  DBUG_ASSERT(! (error && cursor));
3001

3002
  if (! cursor)
3003
  {
3004
    cleanup_stmt();
3005 3006 3007 3008 3009 3010 3011 3012 3013 3014
    reset_stmt_params(this);
  }

  thd->set_statement(&stmt_backup);
  thd->stmt_arena= old_stmt_arena;

  if (state == Query_arena::PREPARED)
    state= Query_arena::EXECUTED;

error:
3015 3016
  flags&= ~ (uint) IS_IN_USE;
  return error;
3017 3018 3019 3020 3021 3022 3023 3024 3025
}


/* Common part of DEALLOCATE PREPARE and mysql_stmt_close */

bool Prepared_statement::deallocate()
{
  /* We account deallocate in the same manner as mysql_stmt_close */
  statistic_increment(thd->status_var.com_stmt_close, &LOCK_status);
3026
  if (flags & (uint) IS_IN_USE)
3027 3028 3029 3030 3031 3032 3033 3034
  {
    my_error(ER_PS_NO_RECURSION, MYF(0));
    return TRUE;
  }
  /* Statement map calls delete stmt on erase */
  thd->stmt_map.erase(this);
  return FALSE;
}