sql_prepare.cc 104 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

unknown's avatar
unknown committed
16 17 18
/**
  @file

19
This file contains the implementation of prepared statements.
unknown's avatar
unknown committed
20

21
When one prepares a statement:
unknown's avatar
unknown committed
22

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

41 42 43 44 45 46
  During prepare the tables used in a statement are opened, but no
  locks are acquired.  Table opening will block any DDL during the
  operation, and we do not need any locks as we neither read nor
  modify any data during prepare.  Tables are closed after prepare
  finishes.

47
When one executes a statement:
unknown's avatar
unknown committed
48

49
  - Server gets the command 'COM_STMT_EXECUTE' to execute the
50 51
    previously prepared query. If there are any parameter markers, then the
    client will send the data in the following format:
unknown's avatar
unknown committed
52
    @verbatim
53
    [COM_STMT_EXECUTE:1]
unknown's avatar
unknown committed
54 55 56 57
    [STMT_ID:4]
    [NULL_BITS:(param_count+7)/8)]
    [TYPES_SUPPLIED_BY_CLIENT(0/1):1]
    [[length]data]
unknown's avatar
unknown committed
58
    [[length]data] .. [[length]data].
unknown's avatar
unknown committed
59
    @endverbatim
unknown's avatar
unknown committed
60
    (Note: Except for string/binary types; all other types will not be
unknown's avatar
unknown committed
61
    supplied with length field)
62 63 64
  - 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
65
  - Execute the query without re-parsing and send back the results
unknown's avatar
unknown committed
66 67
    to client

68 69 70 71
  During execution of prepared statement tables are opened and locked
  the same way they would for normal (non-prepared) statement
  execution.  Tables are unlocked and closed after the execution.

72
When one supplies long data for a placeholder:
unknown's avatar
unknown committed
73

74 75
  - Server gets the long data in pieces with command type
    'COM_STMT_SEND_LONG_DATA'.
unknown's avatar
unknown committed
76
  - The packet recieved will have the format as:
77
    [COM_STMT_SEND_LONG_DATA:1][STMT_ID:4][parameter_number:2][data]
78
  - data from the packet is appended to the long data value buffer for this
79
    placeholder.
80 81 82 83
  - 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.
unknown's avatar
unknown committed
84
*/
unknown's avatar
unknown committed
85 86

#include "mysql_priv.h"
unknown's avatar
unknown committed
87
#include "sql_select.h" // for JOIN
88
#include "sql_cursor.h"
89
#include "sp_head.h"
90
#include "sp.h"
unknown's avatar
unknown committed
91
#include "sp_cache.h"
92
#include "probes_mysql.h"
93 94 95
#ifdef EMBEDDED_LIBRARY
/* include MYSQL_BIND headers */
#include <mysql.h>
96 97
#else
#include <mysql_com.h>
98
#endif
unknown's avatar
unknown committed
99

unknown's avatar
unknown committed
100 101 102
/**
  A result class used to send cursor rows using the binary protocol.
*/
103

unknown's avatar
unknown committed
104
class Select_fetch_protocol_binary: public select_send
105
{
unknown's avatar
unknown committed
106
  Protocol_binary protocol;
107
public:
unknown's avatar
unknown committed
108
  Select_fetch_protocol_binary(THD *thd);
109 110 111
  virtual bool send_fields(List<Item> &list, uint flags);
  virtual bool send_data(List<Item> &items);
  virtual bool send_eof();
112 113 114 115 116 117
#ifdef EMBEDDED_LIBRARY
  void begin_dataset()
  {
    protocol.begin_dataset();
  }
#endif
118 119
};

120 121 122
/****************************************************************************/

/**
unknown's avatar
unknown committed
123
  Prepared_statement: a statement that can contain placeholders.
124
*/
125

126 127 128
class Prepared_statement: public Statement
{
public:
129 130
  enum flag_values
  {
131 132
    IS_IN_USE= 1,
    IS_SQL_PREPARE= 2
133 134
  };

135
  THD *thd;
unknown's avatar
unknown committed
136
  Select_fetch_protocol_binary result;
137
  Item_param **param_array;
138 139
  uint param_count;
  uint last_errno;
140
  uint flags;
141 142
  char last_error[MYSQL_ERRMSG_SIZE];
#ifndef EMBEDDED_LIBRARY
143
  bool (*set_params)(Prepared_statement *st, uchar *data, uchar *data_end,
144
                     uchar *read_pos, String *expanded_query);
unknown's avatar
unknown committed
145
#else
146
  bool (*set_params_data)(Prepared_statement *st, String *expanded_query);
unknown's avatar
unknown committed
147
#endif
unknown's avatar
unknown committed
148
  bool (*set_params_from_vars)(Prepared_statement *stmt,
149 150
                               List<LEX_STRING>& varnames,
                               String *expanded_query);
151
public:
152
  Prepared_statement(THD *thd_arg);
153
  virtual ~Prepared_statement();
154
  void setup_set_params();
unknown's avatar
unknown committed
155
  virtual Query_arena::Type type() const;
156
  virtual void cleanup_stmt();
157
  bool set_name(LEX_STRING *name);
158
  inline void close_cursor() { delete cursor; cursor= 0; }
unknown's avatar
unknown committed
159
  inline bool is_in_use() { return flags & (uint) IS_IN_USE; }
160 161
  inline bool is_sql_prepare() const { return flags & (uint) IS_SQL_PREPARE; }
  void set_sql_prepare() { flags|= (uint) IS_SQL_PREPARE; }
162
  bool prepare(const char *packet, uint packet_length);
unknown's avatar
unknown committed
163 164 165
  bool execute_loop(String *expanded_query,
                    bool open_cursor,
                    uchar *packet_arg, uchar *packet_end_arg);
166
  /* Destroy this statement */
unknown's avatar
unknown committed
167
  void deallocate();
168 169 170 171 172 173
private:
  /**
    The memory root to allocate parsed tree elements (instances of Item,
    SELECT_LEX and other classes).
  */
  MEM_ROOT main_mem_root;
Konstantin Osipov's avatar
Konstantin Osipov committed
174 175
  /* Version of the stored functions cache at the time of prepare. */
  ulong m_sp_cache_version;
unknown's avatar
unknown committed
176 177 178 179 180 181 182 183
private:
  bool set_db(const char *db, uint db_length);
  bool set_parameters(String *expanded_query,
                      uchar *packet, uchar *packet_end);
  bool execute(String *expanded_query, bool open_cursor);
  bool reprepare();
  bool validate_metadata(Prepared_statement  *copy);
  void swap_prepared_statement(Prepared_statement *copy);
184
};
185

unknown's avatar
unknown committed
186

187 188 189
/******************************************************************************
  Implementation
******************************************************************************/
190 191


192
inline bool is_param_null(const uchar *pos, ulong param_no)
193
{
194
  return pos[param_no/8] & (1 << (param_no & 7));
195 196
}

unknown's avatar
unknown committed
197
/**
198 199 200 201
  Find a prepared statement in the statement map by id.

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

unknown's avatar
unknown committed
202 203 204 205 206 207
  @param thd                thread handle
  @param id                 statement id
  @param where              the place from which this function is called (for
                            error reporting).

  @return
208
    0 if the statement was not found, a pointer otherwise.
209 210
*/

211
static Prepared_statement *
unknown's avatar
unknown committed
212
find_prepared_statement(THD *thd, ulong id)
213
{
214 215 216 217 218
  /*
    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.
  */
219 220
  Statement *stmt= thd->stmt_map.find(id);

unknown's avatar
unknown committed
221
  if (stmt == 0 || stmt->type() != Query_arena::PREPARED_STATEMENT)
unknown's avatar
unknown committed
222 223
    return NULL;

224
  return (Prepared_statement *) stmt;
225 226
}

227

unknown's avatar
unknown committed
228
/**
229 230
  Send prepared statement id and metadata to the client after prepare.

unknown's avatar
unknown committed
231 232
  @todo
    Fix this nasty upcast from List<Item_param> to List<Item>
233

unknown's avatar
unknown committed
234
  @return
235
    0 in case of success, 1 otherwise
236 237
*/

unknown's avatar
SCRUM:  
unknown committed
238
#ifndef EMBEDDED_LIBRARY
239
static bool send_prep_stmt(Prepared_statement *stmt, uint columns)
240
{
241
  NET *net= &stmt->thd->net;
242
  uchar buff[12];
unknown's avatar
unknown committed
243
  uint tmp;
244 245
  int error;
  THD *thd= stmt->thd;
unknown's avatar
unknown committed
246 247
  DBUG_ENTER("send_prep_stmt");

248
  buff[0]= 0;                                   /* OK packet indicator */
249
  int4store(buff+1, stmt->id);
250 251
  int2store(buff+5, columns);
  int2store(buff+7, stmt->param_count);
unknown's avatar
unknown committed
252
  buff[9]= 0;                                   // Guard against a 4.1 client
Marc Alff's avatar
Marc Alff committed
253
  tmp= min(stmt->thd->warning_info->statement_warn_count(), 65535);
unknown's avatar
unknown committed
254 255
  int2store(buff+10, tmp);

256 257 258 259
  /*
    Send types and names of placeholders to the client
    XXX: fix this nasty upcast from List<Item_param> to List<Item>
  */
260 261 262 263 264 265 266 267
  error= my_net_write(net, buff, sizeof(buff));
  if (stmt->param_count && ! error)
  {
    error= thd->protocol_text.send_fields((List<Item> *)
                                          &stmt->lex->param_list,
                                          Protocol::SEND_EOF);
  }
  /* Flag that a response has already been sent */
Marc Alff's avatar
Marc Alff committed
268
  thd->stmt_da->disable_status();
269
  DBUG_RETURN(error);
unknown's avatar
SCRUM:  
unknown committed
270
}
271
#else
272 273
static bool send_prep_stmt(Prepared_statement *stmt,
                           uint columns __attribute__((unused)))
unknown's avatar
SCRUM:  
unknown committed
274
{
unknown's avatar
SCRUM  
unknown committed
275 276
  THD *thd= stmt->thd;

277
  thd->client_stmt_id= stmt->id;
unknown's avatar
SCRUM  
unknown committed
278
  thd->client_param_count= stmt->param_count;
unknown's avatar
unknown committed
279
  thd->clear_error();
Marc Alff's avatar
Marc Alff committed
280
  thd->stmt_da->disable_status();
unknown's avatar
SCRUM:  
unknown committed
281

unknown's avatar
SCRUM  
unknown committed
282
  return 0;
283
}
unknown's avatar
unknown committed
284
#endif /*!EMBEDDED_LIBRARY*/
285

unknown's avatar
unknown committed
286

unknown's avatar
unknown committed
287 288 289
#ifndef EMBEDDED_LIBRARY

/**
290 291 292 293 294 295
  Read the length of the parameter data and return it back to
  the caller.

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

unknown's avatar
unknown committed
296 297 298 299
  @param packet             a pointer to the data
  @param len                remaining packet length

  @return
300
    Length of data piece.
unknown's avatar
unknown committed
301 302
*/

303
static ulong get_param_length(uchar **packet, ulong len)
unknown's avatar
unknown committed
304 305
{
  reg1 uchar *pos= *packet;
306 307
  if (len < 1)
    return 0;
unknown's avatar
unknown committed
308 309 310 311 312
  if (*pos < 251)
  {
    (*packet)++;
    return (ulong) *pos;
  }
313 314
  if (len < 3)
    return 0;
unknown's avatar
unknown committed
315 316 317 318 319
  if (*pos == 252)
  {
    (*packet)+=3;
    return (ulong) uint2korr(pos+1);
  }
320 321
  if (len < 4)
    return 0;
unknown's avatar
unknown committed
322 323 324 325 326
  if (*pos == 253)
  {
    (*packet)+=4;
    return (ulong) uint3korr(pos+1);
  }
327 328
  if (len < 5)
    return 0;
unknown's avatar
unknown committed
329
  (*packet)+=9; // Must be 254 when here
330 331 332 333 334 335 336
  /*
    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
337 338
  return (ulong) uint4korr(pos+1);
}
unknown's avatar
unknown committed
339
#else
340
#define get_param_length(packet, len) len
unknown's avatar
unknown committed
341 342
#endif /*!EMBEDDED_LIBRARY*/

unknown's avatar
unknown committed
343 344
/**
  Data conversion routines.
unknown's avatar
unknown committed
345

346 347
    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
348

349 350 351
    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
352

unknown's avatar
unknown committed
353 354 355
  @param  param             parameter item
  @param  pos               input data buffer
  @param  len               length of data in the buffer
unknown's avatar
unknown committed
356 357
*/

358
static void set_param_tiny(Item_param *param, uchar **pos, ulong len)
unknown's avatar
unknown committed
359
{
360 361 362 363
#ifndef EMBEDDED_LIBRARY
  if (len < 1)
    return;
#endif
364
  int8 value= (int8) **pos;
unknown's avatar
unknown committed
365
  param->set_int(param->unsigned_flag ? (longlong) ((uint8) value) :
366
                                        (longlong) value, 4);
unknown's avatar
unknown committed
367 368 369
  *pos+= 1;
}

370
static void set_param_short(Item_param *param, uchar **pos, ulong len)
unknown's avatar
unknown committed
371
{
372
  int16 value;
373 374 375
#ifndef EMBEDDED_LIBRARY
  if (len < 2)
    return;
376
  value= sint2korr(*pos);
377 378
#else
  shortget(value, *pos);
379
#endif
380
  param->set_int(param->unsigned_flag ? (longlong) ((uint16) value) :
381
                                        (longlong) value, 6);
unknown's avatar
unknown committed
382 383 384
  *pos+= 2;
}

385
static void set_param_int32(Item_param *param, uchar **pos, ulong len)
unknown's avatar
unknown committed
386
{
387
  int32 value;
388 389 390
#ifndef EMBEDDED_LIBRARY
  if (len < 4)
    return;
391
  value= sint4korr(*pos);
392 393
#else
  longget(value, *pos);
394
#endif
395
  param->set_int(param->unsigned_flag ? (longlong) ((uint32) value) :
396
                                        (longlong) value, 11);
unknown's avatar
unknown committed
397 398 399
  *pos+= 4;
}

400
static void set_param_int64(Item_param *param, uchar **pos, ulong len)
unknown's avatar
unknown committed
401
{
402
  longlong value;
403 404 405
#ifndef EMBEDDED_LIBRARY
  if (len < 8)
    return;
406
  value= (longlong) sint8korr(*pos);
407 408
#else
  longlongget(value, *pos);
409
#endif
410
  param->set_int(value, 21);
unknown's avatar
unknown committed
411 412 413
  *pos+= 8;
}

414
static void set_param_float(Item_param *param, uchar **pos, ulong len)
unknown's avatar
unknown committed
415
{
unknown's avatar
unknown committed
416
  float data;
417 418 419
#ifndef EMBEDDED_LIBRARY
  if (len < 4)
    return;
unknown's avatar
unknown committed
420
  float4get(data,*pos);
unknown's avatar
unknown committed
421
#else
422
  floatget(data, *pos);
unknown's avatar
unknown committed
423
#endif
unknown's avatar
unknown committed
424 425 426 427
  param->set_double((double) data);
  *pos+= 4;
}

428
static void set_param_double(Item_param *param, uchar **pos, ulong len)
unknown's avatar
unknown committed
429
{
unknown's avatar
unknown committed
430
  double data;
431 432 433
#ifndef EMBEDDED_LIBRARY
  if (len < 8)
    return;
unknown's avatar
unknown committed
434
  float8get(data,*pos);
unknown's avatar
unknown committed
435
#else
436
  doubleget(data, *pos);
unknown's avatar
unknown committed
437
#endif
unknown's avatar
unknown committed
438 439 440 441
  param->set_double((double) data);
  *pos+= 8;
}

unknown's avatar
unknown committed
442 443 444 445
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);
446
  *pos+= length;
unknown's avatar
unknown committed
447 448
}

449
#ifndef EMBEDDED_LIBRARY
450 451 452 453 454 455 456

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

unknown's avatar
unknown committed
457 458 459 460
/**
  @todo
    Add warning 'Data truncated' here
*/
461
static void set_param_time(Item_param *param, uchar **pos, ulong len)
462
{
463 464
  MYSQL_TIME tm;
  ulong length= get_param_length(pos, len);
465

466
  if (length >= 8)
467 468
  {
    uchar *to= *pos;
469
    uint day;
470

471 472
    tm.neg= (bool) to[0];
    day= (uint) sint4korr(to+1);
473
    tm.hour=   (uint) to[5] + day * 24;
474 475
    tm.minute= (uint) to[6];
    tm.second= (uint) to[7];
476
    tm.second_part= (length > 8) ? (ulong) sint4korr(to+8) : 0;
477 478 479 480 481 482 483 484
    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;
485
  }
486
  else
487
    set_zero_time(&tm, MYSQL_TIMESTAMP_TIME);
488 489
  param->set_time(&tm, MYSQL_TIMESTAMP_TIME,
                  MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
490 491 492
  *pos+= length;
}

493
static void set_param_datetime(Item_param *param, uchar **pos, ulong len)
494
{
495 496
  MYSQL_TIME tm;
  ulong length= get_param_length(pos, len);
497

498
  if (length >= 4)
499 500
  {
    uchar *to= *pos;
501 502 503 504 505

    tm.neg=    0;
    tm.year=   (uint) sint2korr(to);
    tm.month=  (uint) to[2];
    tm.day=    (uint) to[3];
506 507 508 509 510 511 512 513 514
    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;

515
    tm.second_part= (length > 7) ? (ulong) sint4korr(to+7) : 0;
516
  }
517
  else
518
    set_zero_time(&tm, MYSQL_TIMESTAMP_DATETIME);
519 520
  param->set_time(&tm, MYSQL_TIMESTAMP_DATETIME,
                  MAX_DATETIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
521 522 523
  *pos+= length;
}

524

525
static void set_param_date(Item_param *param, uchar **pos, ulong len)
526
{
527 528 529 530
  MYSQL_TIME tm;
  ulong length= get_param_length(pos, len);

  if (length >= 4)
531 532
  {
    uchar *to= *pos;
533

534
    tm.year=  (uint) sint2korr(to);
535 536 537 538 539 540 541
    tm.month=  (uint) to[2];
    tm.day= (uint) to[3];

    tm.hour= tm.minute= tm.second= 0;
    tm.second_part= 0;
    tm.neg= 0;
  }
542
  else
543
    set_zero_time(&tm, MYSQL_TIMESTAMP_DATE);
544 545
  param->set_time(&tm, MYSQL_TIMESTAMP_DATE,
                  MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
546 547 548
  *pos+= length;
}

549
#else/*!EMBEDDED_LIBRARY*/
unknown's avatar
unknown committed
550 551 552 553
/**
  @todo
    Add warning 'Data truncated' here
*/
554 555
void set_param_time(Item_param *param, uchar **pos, ulong len)
{
556 557 558 559 560 561 562 563 564 565 566
  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,
567
                  MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
568 569 570 571 572

}

void set_param_datetime(Item_param *param, uchar **pos, ulong len)
{
573 574
  MYSQL_TIME tm= *((MYSQL_TIME*)*pos);
  tm.neg= 0;
575

576
  param->set_time(&tm, MYSQL_TIMESTAMP_DATETIME,
577
                  MAX_DATETIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
578 579 580 581 582 583
}

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

584
  param->set_time(to, MYSQL_TIMESTAMP_DATE,
585
                  MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
586 587 588
}
#endif /*!EMBEDDED_LIBRARY*/

589 590

static void set_param_str(Item_param *param, uchar **pos, ulong len)
unknown's avatar
unknown committed
591
{
592
  ulong length= get_param_length(pos, len);
593 594
  if (length > len)
    length= len;
595
  param->set_str((const char *)*pos, length);
596
  *pos+= length;
unknown's avatar
unknown committed
597 598
}

599

unknown's avatar
unknown committed
600
#undef get_param_length
601 602 603

static void setup_one_conversion_function(THD *thd, Item_param *param,
                                          uchar param_type)
unknown's avatar
unknown committed
604
{
unknown's avatar
unknown committed
605
  switch (param_type) {
606
  case MYSQL_TYPE_TINY:
607
    param->set_param_func= set_param_tiny;
608
    param->item_type= Item::INT_ITEM;
609
    param->item_result_type= INT_RESULT;
unknown's avatar
unknown committed
610
    break;
611
  case MYSQL_TYPE_SHORT:
612
    param->set_param_func= set_param_short;
613
    param->item_type= Item::INT_ITEM;
614
    param->item_result_type= INT_RESULT;
unknown's avatar
unknown committed
615
    break;
616
  case MYSQL_TYPE_LONG:
617
    param->set_param_func= set_param_int32;
618
    param->item_type= Item::INT_ITEM;
619
    param->item_result_type= INT_RESULT;
unknown's avatar
unknown committed
620
    break;
621
  case MYSQL_TYPE_LONGLONG:
622
    param->set_param_func= set_param_int64;
623
    param->item_type= Item::INT_ITEM;
624
    param->item_result_type= INT_RESULT;
unknown's avatar
unknown committed
625
    break;
626
  case MYSQL_TYPE_FLOAT:
627
    param->set_param_func= set_param_float;
628
    param->item_type= Item::REAL_ITEM;
629
    param->item_result_type= REAL_RESULT;
unknown's avatar
unknown committed
630
    break;
631
  case MYSQL_TYPE_DOUBLE:
632
    param->set_param_func= set_param_double;
633
    param->item_type= Item::REAL_ITEM;
634
    param->item_result_type= REAL_RESULT;
unknown's avatar
unknown committed
635
    break;
unknown's avatar
unknown committed
636 637 638 639 640 641
  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;
642
  case MYSQL_TYPE_TIME:
643
    param->set_param_func= set_param_time;
644
    param->item_type= Item::STRING_ITEM;
645
    param->item_result_type= STRING_RESULT;
646
    break;
647
  case MYSQL_TYPE_DATE:
648
    param->set_param_func= set_param_date;
649
    param->item_type= Item::STRING_ITEM;
650
    param->item_result_type= STRING_RESULT;
651
    break;
652 653
  case MYSQL_TYPE_DATETIME:
  case MYSQL_TYPE_TIMESTAMP:
654
    param->set_param_func= set_param_datetime;
655
    param->item_type= Item::STRING_ITEM;
656
    param->item_result_type= STRING_RESULT;
657
    break;
658 659 660 661
  case MYSQL_TYPE_TINY_BLOB:
  case MYSQL_TYPE_MEDIUM_BLOB:
  case MYSQL_TYPE_LONG_BLOB:
  case MYSQL_TYPE_BLOB:
662
    param->set_param_func= set_param_str;
663 664 665
    param->value.cs_info.character_set_of_placeholder= &my_charset_bin;
    param->value.cs_info.character_set_client=
      thd->variables.character_set_client;
666
    DBUG_ASSERT(thd->variables.character_set_client);
667 668
    param->value.cs_info.final_character_set_of_str_value= &my_charset_bin;
    param->item_type= Item::STRING_ITEM;
669
    param->item_result_type= STRING_RESULT;
670 671 672 673 674 675 676 677 678 679 680 681
    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;

682
      param->value.cs_info.character_set_of_placeholder= fromcs;
683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700
      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
701
  }
702
  param->param_type= (enum enum_field_types) param_type;
unknown's avatar
unknown committed
703 704
}

unknown's avatar
SCRUM:  
unknown committed
705
#ifndef EMBEDDED_LIBRARY
unknown's avatar
unknown committed
706
/**
707 708 709 710 711
  Routines to assign parameters from data supplied by the client.

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

unknown's avatar
unknown committed
712
  @note
713
    This function, along with other _with_log functions is called when one of
714 715 716 717 718 719
    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:
unknown's avatar
unknown committed
720
    @verbatim
721
     mysqld_stmt_prepare("UPDATE t1 SET a=a*1.25 WHERE a=?")
722
       --> general logs gets [Prepare] UPDATE t1 SET a*1.25 WHERE a=?"
723
     mysqld_stmt_execute(stmt);
724 725
       --> general and binary logs get
                             [Execute] UPDATE t1 SET a*1.25 WHERE a=1"
unknown's avatar
unknown committed
726 727 728 729
    @endverbatim

    If a statement has been prepared using SQL syntax:
    @verbatim
730 731 732 733 734
     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
unknown's avatar
unknown committed
735 736
                             [Query]   EXECUTE stmt USING @a;
    @endverbatim
737

unknown's avatar
unknown committed
738 739 740 741
  @retval
    0  if success
  @retval
    1  otherwise
unknown's avatar
unknown committed
742 743
*/

744 745 746
static bool insert_params_with_log(Prepared_statement *stmt, uchar *null_array,
                                   uchar *read_pos, uchar *data_end,
                                   String *query)
747
{
748 749 750 751
  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
752
  String str;
753
  const String *res;
754
  DBUG_ENTER("insert_params_with_log");
755

756
  if (query->copy(stmt->query, stmt->query_length, default_charset_info))
757
    DBUG_RETURN(1);
unknown's avatar
unknown committed
758

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

779
    if (query->replace(param->pos_in_query+length, 1, *res))
780
      DBUG_RETURN(1);
unknown's avatar
unknown committed
781

782 783 784 785 786
    length+= res->length()-1;
  }
  DBUG_RETURN(0);
}

787

788
static bool insert_params(Prepared_statement *stmt, uchar *null_array,
unknown's avatar
unknown committed
789
                          uchar *read_pos, uchar *data_end,
790
                          String *expanded_query)
791
{
792 793
  Item_param **begin= stmt->param_array;
  Item_param **end= begin + stmt->param_count;
794

unknown's avatar
unknown committed
795
  DBUG_ENTER("insert_params");
796

797
  for (Item_param **it= begin; it < end; ++it)
798
  {
799
    Item_param *param= *it;
800
    if (param->state != Item_param::LONG_DATA_VALUE)
801
    {
802
      if (is_param_null(null_array, (uint) (it - begin)))
803
        param->set_null();
804 805
      else
      {
806 807
        if (read_pos >= data_end)
          DBUG_RETURN(1);
808
        param->set_param_func(param, &read_pos, (uint) (data_end - read_pos));
809 810
        if (param->state == Item_param::NO_VALUE)
          DBUG_RETURN(1);
811 812
      }
    }
813 814
    if (param->convert_str_value(stmt->thd))
      DBUG_RETURN(1);                           /* out of memory */
815 816 817 818
  }
  DBUG_RETURN(0);
}

819

820
static bool setup_conversion_functions(Prepared_statement *stmt,
821
                                       uchar **data, uchar *data_end)
822 823 824
{
  /* skip null bits */
  uchar *read_pos= *data + (stmt->param_count+7) / 8;
unknown's avatar
unknown committed
825

826
  DBUG_ENTER("setup_conversion_functions");
827

unknown's avatar
unknown committed
828
  if (*read_pos++) //types supplied / first execute
829
  {
unknown's avatar
unknown committed
830
    /*
unknown's avatar
unknown committed
831
      First execute or types altered by the client, setup the
unknown's avatar
unknown committed
832 833
      conversion routines for all parameters (one time)
    */
834 835
    Item_param **it= stmt->param_array;
    Item_param **end= it + stmt->param_count;
836
    THD *thd= stmt->thd;
837 838
    for (; it < end; ++it)
    {
839 840 841
      ushort typecode;
      const uint signed_bit= 1 << 15;

842 843
      if (read_pos >= data_end)
        DBUG_RETURN(1);
844 845

      typecode= sint2korr(read_pos);
unknown's avatar
unknown committed
846
      read_pos+= 2;
847
      (**it).unsigned_flag= test(typecode & signed_bit);
848
      setup_one_conversion_function(thd, *it, (uchar) (typecode & ~signed_bit));
unknown's avatar
unknown committed
849
    }
850 851
  }
  *data= read_pos;
unknown's avatar
unknown committed
852 853 854
  DBUG_RETURN(0);
}

855 856
#else

unknown's avatar
unknown committed
857
/**
858 859 860 861
  Embedded counterparts of parameter assignment routines.

    The main difference between the embedded library and the server is
    that in embedded case we don't serialize/deserialize parameters data.
unknown's avatar
unknown committed
862

863 864 865 866 867
    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).
*/

868
static bool emb_insert_params(Prepared_statement *stmt, String *expanded_query)
869
{
870
  THD *thd= stmt->thd;
871 872
  Item_param **it= stmt->param_array;
  Item_param **end= it + stmt->param_count;
873 874
  MYSQL_BIND *client_param= stmt->thd->client_params;

875
  DBUG_ENTER("emb_insert_params");
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
        if (param->state == Item_param::NO_VALUE)
          DBUG_RETURN(1);
895 896
      }
    }
897 898
    if (param->convert_str_value(thd))
      DBUG_RETURN(1);                           /* out of memory */
899 900 901 902
  }
  DBUG_RETURN(0);
}

903

904 905
static bool emb_insert_params_with_log(Prepared_statement *stmt,
                                       String *query)
906
{
907
  THD *thd= stmt->thd;
908 909
  Item_param **it= stmt->param_array;
  Item_param **end= it + stmt->param_count;
910 911
  MYSQL_BIND *client_param= thd->client_params;

912
  String str;
913
  const String *res;
914
  uint32 length= 0;
915

916
  DBUG_ENTER("emb_insert_params_with_log");
917

918
  if (query->copy(stmt->query, stmt->query_length, default_charset_info))
919
    DBUG_RETURN(1);
unknown's avatar
unknown committed
920

921 922 923
  for (; it < end; ++it, ++client_param)
  {
    Item_param *param= *it;
924 925
    setup_one_conversion_function(thd, param, client_param->buffer_type);
    if (param->state != Item_param::LONG_DATA_VALUE)
926 927
    {
      if (*client_param->is_null)
928
        param->set_null();
929 930
      else
      {
931
        uchar *buff= (uchar*)client_param->buffer;
unknown's avatar
unknown committed
932
        param->unsigned_flag= client_param->is_unsigned;
933
        param->set_param_func(param, &buff,
unknown's avatar
unknown committed
934 935
                              client_param->length ?
                              *client_param->length :
936
                              client_param->buffer_length);
937 938
        if (param->state == Item_param::NO_VALUE)
          DBUG_RETURN(1);
939 940
      }
    }
941 942 943 944
    res= param->query_val_str(&str);
    if (param->convert_str_value(thd))
      DBUG_RETURN(1);                           /* out of memory */

945
    if (query->replace(param->pos_in_query+length, 1, *res))
946
      DBUG_RETURN(1);
947

948 949 950 951 952
    length+= res->length()-1;
  }
  DBUG_RETURN(0);
}

unknown's avatar
SCRUM:  
unknown committed
953 954
#endif /*!EMBEDDED_LIBRARY*/

unknown's avatar
unknown committed
955 956 957
/**
  Setup data conversion routines using an array of parameter
  markers from the original prepared statement.
958
  Swap the parameter data of the original prepared
unknown's avatar
unknown committed
959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003
  statement to the new one.

  Used only when we re-prepare a prepared statement.
  There are two reasons for this function to exist:

  1) In the binary client/server protocol, parameter metadata
  is sent only at first execute. Consequently, if we need to
  reprepare a prepared statement at a subsequent execution,
  we may not have metadata information in the packet.
  In that case we use the parameter array of the original
  prepared statement to setup parameter types of the new
  prepared statement.

  2) In the binary client/server protocol, we may supply
  long data in pieces. When the last piece is supplied,
  we assemble the pieces and convert them from client
  character set to the connection character set. After
  that the parameter value is only available inside
  the parameter, the original pieces are lost, and thus
  we can only assign the corresponding parameter of the
  reprepared statement from the original value.

  @param[out]  param_array_dst  parameter markers of the new statement
  @param[in]   param_array_src  parameter markers of the original
                                statement
  @param[in]   param_count      total number of parameters. Is the
                                same in src and dst arrays, since
                                the statement query is the same

  @return this function never fails
*/

static void
swap_parameter_array(Item_param **param_array_dst,
                     Item_param **param_array_src,
                     uint param_count)
{
  Item_param **dst= param_array_dst;
  Item_param **src= param_array_src;
  Item_param **end= param_array_dst + param_count;

  for (; dst < end; ++src, ++dst)
    (*dst)->set_param_type_and_swap_value(*src);
}

unknown's avatar
unknown committed
1004

unknown's avatar
unknown committed
1005
/**
1006 1007
  Assign prepared statement parameters from user variables.

unknown's avatar
unknown committed
1008 1009 1010 1011 1012
  @param stmt      Statement
  @param varnames  List of variables. Caller must ensure that number
                   of variables in the list is equal to number of statement
                   parameters
  @param query     Ignored
unknown's avatar
unknown committed
1013 1014
*/

1015 1016
static bool insert_params_from_vars(Prepared_statement *stmt,
                                    List<LEX_STRING>& varnames,
1017
                                    String *query __attribute__((unused)))
unknown's avatar
unknown committed
1018 1019 1020 1021 1022 1023
{
  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);
1024 1025
  DBUG_ENTER("insert_params_from_vars");

unknown's avatar
unknown committed
1026 1027 1028 1029
  for (Item_param **it= begin; it < end; ++it)
  {
    Item_param *param= *it;
    varname= var_it++;
1030
    entry= (user_var_entry*)hash_search(&stmt->thd->user_vars,
1031
                                        (uchar*) varname->str,
1032 1033 1034 1035
                                         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
1036 1037 1038 1039
  }
  DBUG_RETURN(0);
}

1040

unknown's avatar
unknown committed
1041
/**
1042 1043
  Do the same as insert_params_from_vars but also construct query text for
  binary log.
1044

unknown's avatar
unknown committed
1045 1046 1047 1048 1049 1050
  @param stmt      Prepared statement
  @param varnames  List of variables. Caller must ensure that number of
                   variables in the list is equal to number of statement
                   parameters
  @param query     The query with parameter markers replaced with corresponding
                   user variables that were used to execute the query.
1051 1052
*/

unknown's avatar
unknown committed
1053
static bool insert_params_from_vars_with_log(Prepared_statement *stmt,
1054
                                             List<LEX_STRING>& varnames,
1055
                                             String *query)
unknown's avatar
unknown committed
1056 1057 1058 1059 1060 1061
{
  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);
1062 1063
  String buf;
  const String *val;
unknown's avatar
unknown committed
1064
  uint32 length= 0;
unknown's avatar
Fix for  
unknown committed
1065
  THD *thd= stmt->thd;
1066 1067 1068

  DBUG_ENTER("insert_params_from_vars");

1069
  if (query->copy(stmt->query, stmt->query_length, default_charset_info))
1070
    DBUG_RETURN(1);
unknown's avatar
unknown committed
1071 1072 1073 1074 1075 1076

  for (Item_param **it= begin; it < end; ++it)
  {
    Item_param *param= *it;
    varname= var_it++;

unknown's avatar
unknown committed
1077
    entry= (user_var_entry *) hash_search(&thd->user_vars, (uchar*) varname->str,
unknown's avatar
Fix for  
unknown committed
1078 1079 1080 1081 1082 1083 1084 1085
                                          varname->length);
    /*
      We have to call the setup_one_conversion_function() here to set
      the parameter's members that might be needed further
      (e.g. value.cs_info.character_set_client is used in the query_val_str()).
    */
    setup_one_conversion_function(thd, param, param->param_type);
    if (param->set_from_user_var(thd, entry))
1086
      DBUG_RETURN(1);
unknown's avatar
Fix for  
unknown committed
1087
    val= param->query_val_str(&buf);
1088

unknown's avatar
Fix for  
unknown committed
1089
    if (param->convert_str_value(thd))
1090
      DBUG_RETURN(1);                           /* out of memory */
1091

1092
    if (query->replace(param->pos_in_query+length, 1, *val))
1093
      DBUG_RETURN(1);
1094
    length+= val->length()-1;
unknown's avatar
unknown committed
1095 1096 1097 1098
  }
  DBUG_RETURN(0);
}

unknown's avatar
unknown committed
1099
/**
1100
  Validate INSERT statement.
unknown's avatar
unknown committed
1101

unknown's avatar
unknown committed
1102 1103
  @param stmt               prepared statement
  @param tables             global/local table list
unknown's avatar
unknown committed
1104

unknown's avatar
unknown committed
1105 1106 1107 1108
  @retval
    FALSE             success
  @retval
    TRUE              error, error message is set in THD
unknown's avatar
unknown committed
1109
*/
unknown's avatar
unknown committed
1110

unknown's avatar
unknown committed
1111 1112
static bool mysql_test_insert(Prepared_statement *stmt,
                              TABLE_LIST *table_list,
unknown's avatar
unknown committed
1113
                              List<Item> &fields,
unknown's avatar
unknown committed
1114 1115 1116 1117
                              List<List_item> &values_list,
                              List<Item> &update_fields,
                              List<Item> &update_values,
                              enum_duplicates duplic)
unknown's avatar
unknown committed
1118
{
1119
  THD *thd= stmt->thd;
unknown's avatar
unknown committed
1120 1121
  List_iterator_fast<List_item> its(values_list);
  List_item *values;
1122
  DBUG_ENTER("mysql_test_insert");
unknown's avatar
unknown committed
1123

unknown's avatar
unknown committed
1124 1125
  if (insert_precheck(thd, table_list))
    goto error;
unknown's avatar
unknown committed
1126

1127
  /*
unknown's avatar
unknown committed
1128 1129 1130 1131 1132 1133
    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
1134
  */
1135
  if (open_normal_and_derived_tables(thd, table_list, 0))
unknown's avatar
unknown committed
1136
    goto error;
unknown's avatar
unknown committed
1137

unknown's avatar
unknown committed
1138 1139 1140
  if ((values= its++))
  {
    uint value_count;
1141
    ulong counter= 0;
unknown's avatar
unknown committed
1142
    Item *unused_conds= 0;
unknown's avatar
unknown committed
1143

unknown's avatar
unknown committed
1144
    if (table_list->table)
1145 1146
    {
      // don't allocate insert_values
1147
      table_list->table->insert_values=(uchar *)1;
1148 1149
    }

unknown's avatar
unknown committed
1150 1151
    if (mysql_prepare_insert(thd, table_list, table_list->table,
                             fields, values, update_fields, update_values,
unknown's avatar
unknown committed
1152
                             duplic, &unused_conds, FALSE, FALSE, FALSE))
unknown's avatar
unknown committed
1153
      goto error;
1154

unknown's avatar
unknown committed
1155 1156
    value_count= values->elements;
    its.rewind();
1157

unknown's avatar
unknown committed
1158
    if (table_list->lock_type == TL_WRITE_DELAYED &&
1159
        !(table_list->table->file->ha_table_flags() & HA_CAN_INSERT_DELAYED))
unknown's avatar
unknown committed
1160
    {
1161 1162 1163
      my_error(ER_DELAYED_NOT_SUPPORTED, MYF(0), (table_list->view ?
                                                  table_list->view_name.str :
                                                  table_list->table_name));
unknown's avatar
unknown committed
1164 1165
      goto error;
    }
1166
    while ((values= its++))
unknown's avatar
unknown committed
1167 1168 1169 1170
    {
      counter++;
      if (values->elements != value_count)
      {
1171
        my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter);
1172
        goto error;
unknown's avatar
unknown committed
1173
      }
1174
      if (setup_fields(thd, 0, *values, MARK_COLUMNS_NONE, 0, 0))
unknown's avatar
unknown committed
1175
        goto error;
unknown's avatar
unknown committed
1176 1177
    }
  }
unknown's avatar
unknown committed
1178
  DBUG_RETURN(FALSE);
1179 1180

error:
1181
  /* insert_values is cleared in open_table */
unknown's avatar
unknown committed
1182
  DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
1183 1184 1185
}


unknown's avatar
unknown committed
1186 1187 1188 1189 1190
/**
  Validate UPDATE statement.

  @param stmt               prepared statement
  @param tables             list of tables used in this query
unknown's avatar
unknown committed
1191

unknown's avatar
unknown committed
1192 1193
  @todo
    - here we should send types of placeholders to the client.
unknown's avatar
unknown committed
1194

unknown's avatar
unknown committed
1195 1196 1197 1198 1199 1200
  @retval
    0                 success
  @retval
    1                 error, error message is set in THD
  @retval
    2                 convert to multi_update
unknown's avatar
unknown committed
1201
*/
unknown's avatar
unknown committed
1202

unknown's avatar
unknown committed
1203
static int mysql_test_update(Prepared_statement *stmt,
unknown's avatar
unknown committed
1204
                              TABLE_LIST *table_list)
unknown's avatar
unknown committed
1205
{
unknown's avatar
unknown committed
1206
  int res;
1207
  THD *thd= stmt->thd;
unknown's avatar
unknown committed
1208
  uint table_count= 0;
unknown's avatar
unknown committed
1209
  SELECT_LEX *select= &stmt->lex->select_lex;
1210
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
1211
  uint          want_privilege;
1212
#endif
unknown's avatar
unknown committed
1213 1214
  DBUG_ENTER("mysql_test_update");

1215
  if (update_precheck(thd, table_list) ||
1216
      open_tables(thd, &table_list, &table_count, 0))
unknown's avatar
unknown committed
1217 1218
    goto error;

1219
  if (table_list->multitable_view)
1220
  {
1221 1222 1223 1224 1225 1226
    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);
unknown's avatar
unknown committed
1227
  }
unknown's avatar
unknown committed
1228

unknown's avatar
unknown committed
1229 1230 1231 1232
  /*
    thd->fill_derived_tables() is false here for sure (because it is
    preparation of PS, so we even do not check it).
  */
1233
  if (mysql_handle_derived(thd->lex, &mysql_derived_prepare))
unknown's avatar
unknown committed
1234
    goto error;
unknown's avatar
unknown committed
1235

1236
#ifndef NO_EMBEDDED_ACCESS_CHECKS
1237 1238 1239
  /* Force privilege re-checking for views after they have been opened. */
  want_privilege= (table_list->view ? UPDATE_ACL :
                   table_list->grant.want_privilege);
1240 1241
#endif

unknown's avatar
unknown committed
1242 1243 1244 1245 1246
  if (mysql_prepare_update(thd, table_list, &select->where,
                           select->order_list.elements,
                           (ORDER *) select->order_list.first))
    goto error;

1247
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
1248 1249
  table_list->grant.want_privilege= want_privilege;
  table_list->table->grant.want_privilege= want_privilege;
1250
  table_list->register_want_access(want_privilege);
1251
#endif
1252
  thd->lex->select_lex.no_wrap_view_item= TRUE;
1253
  res= setup_fields(thd, 0, select->item_list, MARK_COLUMNS_READ, 0, 0);
1254
  thd->lex->select_lex.no_wrap_view_item= FALSE;
unknown's avatar
unknown committed
1255 1256
  if (res)
    goto error;
1257
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
1258 1259 1260 1261
  /* Check values */
  table_list->grant.want_privilege=
  table_list->table->grant.want_privilege=
    (SELECT_ACL & ~table_list->table->grant.privilege);
1262
  table_list->register_want_access(SELECT_ACL);
1263
#endif
1264
  if (setup_fields(thd, 0, stmt->lex->value_list, MARK_COLUMNS_NONE, 0, 0))
unknown's avatar
unknown committed
1265
    goto error;
unknown's avatar
unknown committed
1266
  /* TODO: here we should send types of placeholders to the client. */
unknown's avatar
unknown committed
1267 1268 1269
  DBUG_RETURN(0);
error:
  DBUG_RETURN(1);
unknown's avatar
unknown committed
1270 1271 1272
}


unknown's avatar
unknown committed
1273
/**
1274
  Validate DELETE statement.
unknown's avatar
unknown committed
1275

unknown's avatar
unknown committed
1276 1277
  @param stmt               prepared statement
  @param tables             list of tables used in this query
unknown's avatar
unknown committed
1278

unknown's avatar
unknown committed
1279 1280 1281 1282
  @retval
    FALSE             success
  @retval
    TRUE              error, error message is set in THD
unknown's avatar
unknown committed
1283
*/
unknown's avatar
unknown committed
1284 1285 1286

static bool mysql_test_delete(Prepared_statement *stmt,
                              TABLE_LIST *table_list)
unknown's avatar
unknown committed
1287
{
1288
  THD *thd= stmt->thd;
unknown's avatar
unknown committed
1289 1290
  LEX *lex= stmt->lex;
  DBUG_ENTER("mysql_test_delete");
unknown's avatar
unknown committed
1291

unknown's avatar
unknown committed
1292
  if (delete_precheck(thd, table_list) ||
1293
      open_normal_and_derived_tables(thd, table_list, 0))
unknown's avatar
unknown committed
1294
    goto error;
unknown's avatar
unknown committed
1295

unknown's avatar
unknown committed
1296
  if (!table_list->table)
unknown's avatar
unknown committed
1297
  {
unknown's avatar
unknown committed
1298 1299 1300
    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
1301
  }
unknown's avatar
unknown committed
1302 1303 1304

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

unknown's avatar
unknown committed
1308

unknown's avatar
unknown committed
1309
/**
unknown's avatar
unknown committed
1310 1311
  Validate SELECT statement.

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

unknown's avatar
unknown committed
1315 1316 1317 1318 1319 1320 1321 1322 1323
  @param stmt               prepared statement
  @param tables             list of tables used in the query

  @retval
    0                 success
  @retval
    1                 error, error message is set in THD
  @retval
    2                 success, and statement metadata has been sent
unknown's avatar
unknown committed
1324
*/
1325

1326
static int mysql_test_select(Prepared_statement *stmt,
unknown's avatar
unknown committed
1327
                             TABLE_LIST *tables)
unknown's avatar
unknown committed
1328
{
1329
  THD *thd= stmt->thd;
1330
  LEX *lex= stmt->lex;
1331
  SELECT_LEX_UNIT *unit= &lex->unit;
unknown's avatar
unknown committed
1332
  DBUG_ENTER("mysql_test_select");
unknown's avatar
unknown committed
1333

1334 1335
  lex->select_lex.context.resolve_in_select_list= TRUE;

1336 1337 1338
  ulong privilege= lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL;
  if (tables)
  {
1339
    if (check_table_access(thd, privilege, tables, UINT_MAX, FALSE))
unknown's avatar
unknown committed
1340
      goto error;
1341
  }
1342
  else if (check_access(thd, privilege, any_db,0,0,0,0))
unknown's avatar
unknown committed
1343
    goto error;
unknown's avatar
unknown committed
1344

unknown's avatar
unknown committed
1345
  if (!lex->result && !(lex->result= new (stmt->mem_root) select_send))
unknown's avatar
unknown committed
1346 1347 1348 1349
  {
    my_error(ER_OUTOFMEMORY, MYF(0), sizeof(select_send));
    goto error;
  }
1350

1351
  if (open_normal_and_derived_tables(thd, tables, 0))
unknown's avatar
unknown committed
1352
    goto error;
unknown's avatar
unknown committed
1353

1354 1355
  thd->used_tables= 0;                        // Updated by setup_fields

1356 1357 1358 1359 1360
  /*
    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
  */
1361
  if (unit->prepare(thd, 0, 0))
unknown's avatar
unknown committed
1362
    goto error;
1363
  if (!lex->describe && !stmt->is_sql_prepare())
unknown's avatar
unknown committed
1364
  {
1365 1366
    /* Make copy of item list, as change_columns may change it */
    List<Item> fields(lex->select_lex.item_list);
1367

1368 1369 1370
    /* Change columns if a procedure like analyse() */
    if (unit->last_procedure && unit->last_procedure->change_columns(fields))
      goto error;
1371

1372 1373 1374 1375 1376 1377 1378 1379 1380
    /*
      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);
unknown's avatar
unknown committed
1381
  }
1382
  DBUG_RETURN(0);
unknown's avatar
unknown committed
1383
error:
1384
  DBUG_RETURN(1);
unknown's avatar
unknown committed
1385 1386
}

1387

unknown's avatar
unknown committed
1388
/**
1389
  Validate and prepare for execution DO statement expressions.
1390

unknown's avatar
unknown committed
1391 1392 1393
  @param stmt               prepared statement
  @param tables             list of tables used in this query
  @param values             list of expressions
1394

unknown's avatar
unknown committed
1395 1396 1397 1398
  @retval
    FALSE             success
  @retval
    TRUE              error, error message is set in THD
1399 1400
*/

unknown's avatar
unknown committed
1401
static bool mysql_test_do_fields(Prepared_statement *stmt,
unknown's avatar
unknown committed
1402 1403
                                TABLE_LIST *tables,
                                List<Item> *values)
1404 1405
{
  THD *thd= stmt->thd;
unknown's avatar
unknown committed
1406 1407

  DBUG_ENTER("mysql_test_do_fields");
1408
  if (tables && check_table_access(thd, SELECT_ACL, tables, UINT_MAX, FALSE))
unknown's avatar
unknown committed
1409
    DBUG_RETURN(TRUE);
1410

1411
  if (open_normal_and_derived_tables(thd, tables, 0))
unknown's avatar
unknown committed
1412
    DBUG_RETURN(TRUE);
1413
  DBUG_RETURN(setup_fields(thd, 0, *values, MARK_COLUMNS_NONE, 0, 0));
1414 1415 1416
}


unknown's avatar
unknown committed
1417 1418
/**
  Validate and prepare for execution SET statement expressions.
1419

unknown's avatar
unknown committed
1420 1421 1422
  @param stmt               prepared statement
  @param tables             list of tables used in this query
  @param values             list of expressions
1423

unknown's avatar
unknown committed
1424 1425 1426 1427
  @retval
    FALSE             success
  @retval
    TRUE              error, error message is set in THD
1428
*/
unknown's avatar
unknown committed
1429

unknown's avatar
unknown committed
1430 1431 1432
static bool mysql_test_set_fields(Prepared_statement *stmt,
                                  TABLE_LIST *tables,
                                  List<set_var_base> *var_list)
1433 1434 1435 1436 1437
{
  DBUG_ENTER("mysql_test_set_fields");
  List_iterator_fast<set_var_base> it(*var_list);
  THD *thd= stmt->thd;
  set_var_base *var;
1438

Staale Smedseng's avatar
Staale Smedseng committed
1439 1440
  if ((tables && check_table_access(thd, SELECT_ACL, tables, UINT_MAX, FALSE)) 
      || open_normal_and_derived_tables(thd, tables, 0))
1441
    goto error;
unknown's avatar
unknown committed
1442

1443 1444 1445 1446 1447
  while ((var= it++))
  {
    if (var->light_check(thd))
      goto error;
  }
unknown's avatar
unknown committed
1448
  DBUG_RETURN(FALSE);
1449
error:
unknown's avatar
unknown committed
1450
  DBUG_RETURN(TRUE);
1451 1452 1453
}


1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474
/**
  Validate and prepare for execution CALL statement expressions.

  @param stmt               prepared statement
  @param tables             list of tables used in this query
  @param value_list         list of expressions

  @retval FALSE             success
  @retval TRUE              error, error message is set in THD
*/

static bool mysql_test_call_fields(Prepared_statement *stmt,
                                   TABLE_LIST *tables,
                                   List<Item> *value_list)
{
  DBUG_ENTER("mysql_test_call_fields");

  List_iterator<Item> it(*value_list);
  THD *thd= stmt->thd;
  Item *item;

Staale Smedseng's avatar
Staale Smedseng committed
1475
  if ((tables && check_table_access(thd, SELECT_ACL, tables, UINT_MAX, FALSE)) ||
1476 1477 1478 1479 1480
      open_normal_and_derived_tables(thd, tables, 0))
    goto err;

  while ((item= it++))
  {
Staale Smedseng's avatar
Staale Smedseng committed
1481
    if ((!item->fixed && item->fix_fields(thd, it.ref())) ||
1482 1483 1484 1485 1486 1487 1488 1489 1490
        item->check_cols(1))
      goto err;
  }
  DBUG_RETURN(FALSE);
err:
  DBUG_RETURN(TRUE);
}


unknown's avatar
unknown committed
1491 1492
/**
  Check internal SELECT of the prepared command.
1493

unknown's avatar
unknown committed
1494 1495 1496
  @param stmt                      prepared statement
  @param specific_prepare          function of command specific prepare
  @param setup_tables_done_option  options to be passed to LEX::unit.prepare()
1497

unknown's avatar
unknown committed
1498
  @note
1499 1500
    This function won't directly open tables used in select. They should
    be opened either by calling function (and in this case you probably
1501
    should use select_like_stmt_test_with_open()) or by
1502
    "specific_prepare" call (like this happens in case of multi-update).
1503

unknown's avatar
unknown committed
1504
  @retval
1505
    FALSE                success
unknown's avatar
unknown committed
1506
  @retval
1507
    TRUE                 error, error message is set in THD
1508
*/
1509 1510

static bool select_like_stmt_test(Prepared_statement *stmt,
1511
                                  int (*specific_prepare)(THD *thd),
1512
                                  ulong setup_tables_done_option)
1513
{
1514
  DBUG_ENTER("select_like_stmt_test");
1515 1516 1517
  THD *thd= stmt->thd;
  LEX *lex= stmt->lex;

1518 1519
  lex->select_lex.context.resolve_in_select_list= TRUE;

unknown's avatar
unknown committed
1520 1521
  if (specific_prepare && (*specific_prepare)(thd))
    DBUG_RETURN(TRUE);
unknown's avatar
VIEW  
unknown committed
1522

1523 1524
  thd->used_tables= 0;                        // Updated by setup_fields

unknown's avatar
unknown committed
1525
  /* Calls JOIN::prepare */
1526
  DBUG_RETURN(lex->unit.prepare(thd, 0, setup_tables_done_option));
1527 1528
}

unknown's avatar
unknown committed
1529
/**
1530 1531
  Check internal SELECT of the prepared command (with opening of used
  tables).
1532

unknown's avatar
unknown committed
1533 1534 1535 1536 1537
  @param stmt                      prepared statement
  @param tables                    list of tables to be opened
                                   before calling specific_prepare function
  @param specific_prepare          function of command specific prepare
  @param setup_tables_done_option  options to be passed to LEX::unit.prepare()
1538

unknown's avatar
unknown committed
1539
  @retval
1540
    FALSE                success
unknown's avatar
unknown committed
1541
  @retval
1542
    TRUE                 error
1543 1544 1545
*/

static bool
1546 1547
select_like_stmt_test_with_open(Prepared_statement *stmt,
                                TABLE_LIST *tables,
1548
                                int (*specific_prepare)(THD *thd),
1549
                                ulong setup_tables_done_option)
1550
{
1551
  DBUG_ENTER("select_like_stmt_test_with_open");
1552 1553

  /*
1554 1555 1556 1557
    We should not call LEX::unit.cleanup() after this
    open_normal_and_derived_tables() call because we don't allow
    prepared EXPLAIN yet so derived tables will clean up after
    themself.
1558
  */
1559
  if (open_normal_and_derived_tables(stmt->thd, tables, 0))
1560 1561 1562 1563 1564 1565 1566
    DBUG_RETURN(TRUE);

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


unknown's avatar
unknown committed
1567 1568
/**
  Validate and prepare for execution CREATE TABLE statement.
1569

unknown's avatar
unknown committed
1570 1571
  @param stmt               prepared statement
  @param tables             list of tables used in this query
1572

unknown's avatar
unknown committed
1573 1574 1575 1576
  @retval
    FALSE             success
  @retval
    TRUE              error, error message is set in THD
1577
*/
unknown's avatar
unknown committed
1578

unknown's avatar
unknown committed
1579
static bool mysql_test_create_table(Prepared_statement *stmt)
1580 1581 1582 1583
{
  DBUG_ENTER("mysql_test_create_table");
  THD *thd= stmt->thd;
  LEX *lex= stmt->lex;
1584
  SELECT_LEX *select_lex= &lex->select_lex;
unknown's avatar
unknown committed
1585
  bool res= FALSE;
1586
  /* Skip first table, which is the table we are creating */
unknown's avatar
VIEW  
unknown committed
1587 1588 1589
  bool link_to_local;
  TABLE_LIST *create_table= lex->unlink_first_table(&link_to_local);
  TABLE_LIST *tables= lex->query_tables;
1590

unknown's avatar
unknown committed
1591 1592 1593 1594
  if (create_table_precheck(thd, tables, create_table))
    DBUG_RETURN(TRUE);

  if (select_lex->item_list.elements)
1595
  {
unknown's avatar
unknown committed
1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607
    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_normal_and_derived_tables(stmt->thd, lex->query_tables, 0))
      DBUG_RETURN(TRUE);

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

1608
    select_lex->context.resolve_in_select_list= TRUE;
unknown's avatar
unknown committed
1609 1610

    res= select_like_stmt_test(stmt, 0, 0);
1611
  }
1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622
  else if (lex->create_info.options & HA_LEX_CREATE_TABLE_LIKE)
  {
    /*
      Check that the source table exist, and also record
      its metadata version. Even though not strictly necessary,
      we validate metadata of all CREATE TABLE statements,
      which keeps metadata validation code simple.
    */
    if (open_normal_and_derived_tables(stmt->thd, lex->query_tables, 0))
      DBUG_RETURN(TRUE);
  }
1623

unknown's avatar
unknown committed
1624
  /* put tables back for PS rexecuting */
unknown's avatar
VIEW  
unknown committed
1625
  lex->link_first_table_back(create_table, link_to_local);
1626 1627 1628
  DBUG_RETURN(res);
}

unknown's avatar
unknown committed
1629

unknown's avatar
unknown committed
1630
/**
1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667
  @brief Validate and prepare for execution CREATE VIEW statement

  @param stmt prepared statement

  @note This function handles create view commands.

  @retval FALSE Operation was a success.
  @retval TRUE An error occured.
*/

static bool mysql_test_create_view(Prepared_statement *stmt)
{
  DBUG_ENTER("mysql_test_create_view");
  THD *thd= stmt->thd;
  LEX *lex= stmt->lex;
  bool res= TRUE;
  /* Skip first table, which is the view we are creating */
  bool link_to_local;
  TABLE_LIST *view= lex->unlink_first_table(&link_to_local);
  TABLE_LIST *tables= lex->query_tables;

  if (create_view_precheck(thd, tables, view, lex->create_view_mode))
    goto err;

  if (open_normal_and_derived_tables(thd, tables, 0))
    goto err;

  lex->view_prepare_mode= 1;
  res= select_like_stmt_test(stmt, 0, 0);

err:
  /* put view back for PS rexecuting */
  lex->link_first_table_back(view, link_to_local);
  DBUG_RETURN(res);
}


1668
/*
1669
  Validate and prepare for execution a multi update statement.
1670

unknown's avatar
unknown committed
1671 1672 1673
  @param stmt               prepared statement
  @param tables             list of tables used in this query
  @param converted          converted to multi-update from usual update
1674

unknown's avatar
unknown committed
1675 1676 1677 1678
  @retval
    FALSE             success
  @retval
    TRUE              error, error message is set in THD
1679
*/
unknown's avatar
unknown committed
1680 1681

static bool mysql_test_multiupdate(Prepared_statement *stmt,
unknown's avatar
unknown committed
1682
                                  TABLE_LIST *tables,
1683
                                  bool converted)
1684
{
1685
  /* if we switched from normal update, rights are checked */
unknown's avatar
merge  
unknown committed
1686
  if (!converted && multi_update_precheck(stmt->thd, tables))
unknown's avatar
unknown committed
1687
    return TRUE;
1688 1689 1690

  return select_like_stmt_test(stmt, &mysql_multi_update_prepare,
                               OPTION_SETUP_TABLES_DONE);
1691 1692 1693
}


unknown's avatar
unknown committed
1694
/**
1695
  Validate and prepare for execution a multi delete statement.
1696

unknown's avatar
unknown committed
1697 1698
  @param stmt               prepared statement
  @param tables             list of tables used in this query
1699

unknown's avatar
unknown committed
1700 1701 1702 1703
  @retval
    FALSE             success
  @retval
    TRUE              error, error message in THD is set.
1704
*/
unknown's avatar
unknown committed
1705 1706

static bool mysql_test_multidelete(Prepared_statement *stmt,
unknown's avatar
unknown committed
1707
                                  TABLE_LIST *tables)
1708 1709 1710
{
  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
1711 1712 1713 1714
  {
    my_error(ER_OUTOFMEMORY, MYF(0), 0);
    goto error;
  }
1715

unknown's avatar
unknown committed
1716
  if (multi_delete_precheck(stmt->thd, tables) ||
1717 1718 1719
      select_like_stmt_test_with_open(stmt, tables,
                                      &mysql_multi_delete_prepare,
                                      OPTION_SETUP_TABLES_DONE))
unknown's avatar
unknown committed
1720
    goto error;
1721 1722 1723
  if (!tables->table)
  {
    my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
unknown's avatar
unknown committed
1724
             tables->view_db.str, tables->view_name.str);
unknown's avatar
unknown committed
1725
    goto error;
1726
  }
unknown's avatar
unknown committed
1727 1728 1729
  return FALSE;
error:
  return TRUE;
1730 1731 1732
}


unknown's avatar
unknown committed
1733
/**
1734
  Wrapper for mysql_insert_select_prepare, to make change of local tables
1735
  after open_normal_and_derived_tables() call.
1736

unknown's avatar
unknown committed
1737
  @param thd                thread handle
1738

unknown's avatar
unknown committed
1739
  @note
1740 1741 1742
    We need to remove the first local table after
    open_normal_and_derived_tables(), because mysql_handle_derived
    uses local tables lists.
1743 1744
*/

1745
static int mysql_insert_select_prepare_tester(THD *thd)
1746 1747
{
  SELECT_LEX *first_select= &thd->lex->select_lex;
1748 1749 1750
  TABLE_LIST *second_table= ((TABLE_LIST*)first_select->table_list.first)->
    next_local;

1751
  /* Skip first table, which is the table we are inserting in */
1752
  first_select->table_list.first= (uchar *) second_table;
1753 1754 1755 1756
  thd->lex->select_lex.context.table_list=
    thd->lex->select_lex.context.first_name_resolution_table= second_table;

  return mysql_insert_select_prepare(thd);
1757 1758 1759
}


unknown's avatar
unknown committed
1760
/**
1761
  Validate and prepare for execution INSERT ... SELECT statement.
1762

unknown's avatar
unknown committed
1763 1764
  @param stmt               prepared statement
  @param tables             list of tables used in this query
1765

unknown's avatar
unknown committed
1766 1767 1768 1769
  @retval
    FALSE             success
  @retval
    TRUE              error, error message is set in THD
1770
*/
unknown's avatar
unknown committed
1771

1772 1773
static bool mysql_test_insert_select(Prepared_statement *stmt,
                                     TABLE_LIST *tables)
1774 1775 1776
{
  int res;
  LEX *lex= stmt->lex;
unknown's avatar
unknown committed
1777 1778
  TABLE_LIST *first_local_table;

1779 1780 1781
  if (tables->table)
  {
    // don't allocate insert_values
1782
    tables->table->insert_values=(uchar *)1;
1783
  }
unknown's avatar
unknown committed
1784

unknown's avatar
unknown committed
1785 1786
  if (insert_precheck(stmt->thd, tables))
    return 1;
1787 1788 1789 1790 1791

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

1792
  res=
1793 1794 1795
    select_like_stmt_test_with_open(stmt, tables,
                                    &mysql_insert_select_prepare_tester,
                                    OPTION_SETUP_TABLES_DONE);
1796
  /* revert changes  made by mysql_insert_select_prepare_tester */
1797
  lex->select_lex.table_list.first= (uchar*) first_local_table;
1798 1799 1800 1801
  return res;
}


unknown's avatar
unknown committed
1802
/**
1803 1804 1805 1806 1807 1808 1809 1810
  Perform semantic analysis of the parsed tree and send a response packet
  to the client.

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

unknown's avatar
unknown committed
1811 1812 1813 1814 1815 1816
  @param stmt               prepared statement

  @retval
    FALSE             success, statement metadata is sent to client
  @retval
    TRUE              error, error message is set in THD (but not sent)
unknown's avatar
unknown committed
1817
*/
1818

unknown's avatar
unknown committed
1819
static bool check_prepared_statement(Prepared_statement *stmt)
1820
{
1821
  THD *thd= stmt->thd;
1822
  LEX *lex= stmt->lex;
1823
  SELECT_LEX *select_lex= &lex->select_lex;
unknown's avatar
VIEW  
unknown committed
1824
  TABLE_LIST *tables;
1825
  enum enum_sql_command sql_command= lex->sql_command;
unknown's avatar
unknown committed
1826
  int res= 0;
1827
  DBUG_ENTER("check_prepared_statement");
unknown's avatar
unknown committed
1828
  DBUG_PRINT("enter",("command: %d  param_count: %u",
1829
                      sql_command, stmt->param_count));
1830

unknown's avatar
VIEW  
unknown committed
1831 1832
  lex->first_lists_tables_same();
  tables= lex->query_tables;
1833

1834 1835 1836 1837
  /* set context for commands which do not use setup_tables */
  lex->select_lex.context.resolve_in_table_list_only(select_lex->
                                                     get_table_list());

Marc Alff's avatar
Marc Alff committed
1838 1839 1840 1841
  /* Reset warning count for each query that uses tables */
  if (tables)
    thd->warning_info->opt_clear_warning_info(thd->query_id);

1842
  switch (sql_command) {
1843
  case SQLCOM_REPLACE:
unknown's avatar
unknown committed
1844
  case SQLCOM_INSERT:
unknown's avatar
unknown committed
1845
    res= mysql_test_insert(stmt, tables, lex->field_list,
unknown's avatar
unknown committed
1846
                           lex->many_values,
unknown's avatar
unknown committed
1847
                           lex->update_list, lex->value_list,
unknown's avatar
unknown committed
1848
                           lex->duplicates);
unknown's avatar
unknown committed
1849 1850 1851
    break;

  case SQLCOM_UPDATE:
unknown's avatar
unknown committed
1852
    res= mysql_test_update(stmt, tables);
unknown's avatar
unknown committed
1853
    /* mysql_test_update returns 2 if we need to switch to multi-update */
1854 1855 1856 1857 1858
    if (res != 2)
      break;

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

unknown's avatar
unknown committed
1861
  case SQLCOM_DELETE:
unknown's avatar
unknown committed
1862
    res= mysql_test_delete(stmt, tables);
unknown's avatar
unknown committed
1863
    break;
1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878
  /* The following allow WHERE clause, so they must be tested like SELECT */
  case SQLCOM_SHOW_DATABASES:
  case SQLCOM_SHOW_TABLES:
  case SQLCOM_SHOW_TRIGGERS:
  case SQLCOM_SHOW_EVENTS:
  case SQLCOM_SHOW_OPEN_TABLES:
  case SQLCOM_SHOW_FIELDS:
  case SQLCOM_SHOW_KEYS:
  case SQLCOM_SHOW_COLLATIONS:
  case SQLCOM_SHOW_CHARSETS:
  case SQLCOM_SHOW_VARIABLES:
  case SQLCOM_SHOW_STATUS:
  case SQLCOM_SHOW_TABLE_STATUS:
  case SQLCOM_SHOW_STATUS_PROC:
  case SQLCOM_SHOW_STATUS_FUNC:
unknown's avatar
unknown committed
1879
  case SQLCOM_SELECT:
unknown's avatar
unknown committed
1880
    res= mysql_test_select(stmt, tables);
1881 1882 1883 1884 1885 1886
    if (res == 2)
    {
      /* Statement and field info has already been sent */
      DBUG_RETURN(FALSE);
    }
    break;
1887
  case SQLCOM_CREATE_TABLE:
unknown's avatar
VIEW  
unknown committed
1888
    res= mysql_test_create_table(stmt);
1889
    break;
unknown's avatar
unknown committed
1890

1891 1892 1893 1894 1895 1896
  case SQLCOM_CREATE_VIEW:
    if (lex->create_view_mode == VIEW_ALTER)
    {
      my_message(ER_UNSUPPORTED_PS, ER(ER_UNSUPPORTED_PS), MYF(0));
      goto error;
    }
1897
    res= mysql_test_create_view(stmt);
1898
    break;
1899
  case SQLCOM_DO:
unknown's avatar
unknown committed
1900 1901
    res= mysql_test_do_fields(stmt, tables, lex->insert_list);
    break;
1902

1903 1904 1905
  case SQLCOM_CALL:
    res= mysql_test_call_fields(stmt, tables, &lex->value_list);
    break;
1906
  case SQLCOM_SET_OPTION:
unknown's avatar
unknown committed
1907
    res= mysql_test_set_fields(stmt, tables, &lex->var_list);
1908 1909 1910
    break;

  case SQLCOM_DELETE_MULTI:
unknown's avatar
unknown committed
1911
    res= mysql_test_multidelete(stmt, tables);
1912 1913 1914
    break;

  case SQLCOM_INSERT_SELECT:
1915
  case SQLCOM_REPLACE_SELECT:
unknown's avatar
unknown committed
1916
    res= mysql_test_insert_select(stmt, tables);
1917 1918
    break;

1919 1920 1921 1922
    /*
      Note that we don't need to have cases in this list if they are
      marked with CF_STATUS_COMMAND in sql_command_flags
    */
1923 1924 1925 1926
  case SQLCOM_SHOW_PROCESSLIST:
  case SQLCOM_SHOW_STORAGE_ENGINES:
  case SQLCOM_SHOW_PRIVILEGES:
  case SQLCOM_SHOW_COLUMN_TYPES:
1927 1928 1929
  case SQLCOM_SHOW_ENGINE_LOGS:
  case SQLCOM_SHOW_ENGINE_STATUS:
  case SQLCOM_SHOW_ENGINE_MUTEX:
1930 1931
  case SQLCOM_SHOW_CREATE_DB:
  case SQLCOM_SHOW_GRANTS:
1932 1933 1934 1935 1936 1937
  case SQLCOM_SHOW_BINLOG_EVENTS:
  case SQLCOM_SHOW_MASTER_STAT:
  case SQLCOM_SHOW_SLAVE_STAT:
  case SQLCOM_SHOW_CREATE_PROC:
  case SQLCOM_SHOW_CREATE_FUNC:
  case SQLCOM_SHOW_CREATE_EVENT:
unknown's avatar
unknown committed
1938
  case SQLCOM_SHOW_CREATE_TRIGGER:
1939 1940 1941 1942 1943 1944 1945 1946
  case SQLCOM_SHOW_CREATE:
  case SQLCOM_SHOW_PROC_CODE:
  case SQLCOM_SHOW_FUNC_CODE:
  case SQLCOM_SHOW_AUTHORS:
  case SQLCOM_SHOW_CONTRIBUTORS:
  case SQLCOM_SHOW_WARNS:
  case SQLCOM_SHOW_ERRORS:
  case SQLCOM_SHOW_BINLOGS:
1947 1948
  case SQLCOM_DROP_TABLE:
  case SQLCOM_RENAME_TABLE:
1949 1950 1951 1952 1953 1954
  case SQLCOM_ALTER_TABLE:
  case SQLCOM_COMMIT:
  case SQLCOM_CREATE_INDEX:
  case SQLCOM_DROP_INDEX:
  case SQLCOM_ROLLBACK:
  case SQLCOM_TRUNCATE:
1955
  case SQLCOM_DROP_VIEW:
1956 1957 1958
  case SQLCOM_REPAIR:
  case SQLCOM_ANALYZE:
  case SQLCOM_OPTIMIZE:
1959 1960 1961 1962 1963 1964 1965 1966 1967
  case SQLCOM_CHANGE_MASTER:
  case SQLCOM_RESET:
  case SQLCOM_FLUSH:
  case SQLCOM_SLAVE_START:
  case SQLCOM_SLAVE_STOP:
  case SQLCOM_INSTALL_PLUGIN:
  case SQLCOM_UNINSTALL_PLUGIN:
  case SQLCOM_CREATE_DB:
  case SQLCOM_DROP_DB:
1968
  case SQLCOM_ALTER_DB_UPGRADE:
1969 1970 1971 1972 1973 1974 1975 1976 1977
  case SQLCOM_CHECKSUM:
  case SQLCOM_CREATE_USER:
  case SQLCOM_RENAME_USER:
  case SQLCOM_DROP_USER:
  case SQLCOM_ASSIGN_TO_KEYCACHE:
  case SQLCOM_PRELOAD_KEYS:
  case SQLCOM_GRANT:
  case SQLCOM_REVOKE:
  case SQLCOM_KILL:
1978 1979
    break;

1980 1981 1982
  case SQLCOM_PREPARE:
  case SQLCOM_EXECUTE:
  case SQLCOM_DEALLOCATE_PREPARE:
unknown's avatar
unknown committed
1983
  default:
1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994
    /*
      Trivial check of all status commands. This is easier than having
      things in the above case list, as it's less chance for mistakes.
    */
    if (!(sql_command_flags[sql_command] & CF_STATUS_COMMAND))
    {
      /* All other statements are not supported yet. */
      my_message(ER_UNSUPPORTED_PS, ER(ER_UNSUPPORTED_PS), MYF(0));
      goto error;
    }
    break;
unknown's avatar
unknown committed
1995
  }
unknown's avatar
unknown committed
1996
  if (res == 0)
1997
    DBUG_RETURN(stmt->is_sql_prepare() ?
unknown's avatar
unknown committed
1998
                FALSE : (send_prep_stmt(stmt, 0) || thd->protocol->flush()));
1999
error:
unknown's avatar
unknown committed
2000
  DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
2001 2002
}

unknown's avatar
unknown committed
2003
/**
2004 2005
  Initialize array of parameters in statement from LEX.
  (We need to have quick access to items by number in mysql_stmt_get_longdata).
2006
  This is to avoid using malloc/realloc in the parser.
unknown's avatar
unknown committed
2007
*/
unknown's avatar
unknown committed
2008

2009
static bool init_param_array(Prepared_statement *stmt)
unknown's avatar
unknown committed
2010
{
2011 2012 2013
  LEX *lex= stmt->lex;
  if ((stmt->param_count= lex->param_list.elements))
  {
2014 2015 2016
    if (stmt->param_count > (uint) UINT_MAX16)
    {
      /* Error code to be defined in 5.0 */
2017 2018
      my_message(ER_PS_MANY_PARAM, ER(ER_PS_MANY_PARAM), MYF(0));
      return TRUE;
2019
    }
2020 2021 2022 2023
    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
2024
                       alloc_root(stmt->thd->mem_root,
2025 2026
                                  sizeof(Item_param*) * stmt->param_count);
    if (!stmt->param_array)
2027
      return TRUE;
2028 2029 2030 2031 2032 2033 2034
    for (to= stmt->param_array;
         to < stmt->param_array + stmt->param_count;
         ++to)
    {
      *to= param_iterator++;
    }
  }
2035
  return FALSE;
unknown's avatar
unknown committed
2036
}
2037

2038

unknown's avatar
unknown committed
2039
/**
2040
  COM_STMT_PREPARE handler.
unknown's avatar
unknown committed
2041

2042 2043
    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
2044

2045
    If parameter markers are found in the query, then store the information
unknown's avatar
unknown committed
2046 2047
    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
2048
    field items.
unknown's avatar
unknown committed
2049

unknown's avatar
unknown committed
2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060
  @param packet             query to be prepared
  @param packet_length      query string length, including ignored
                            trailing NULL or quote char.

  @note
    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.

  @return
2061 2062
    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
2063 2064
*/

2065
void mysqld_stmt_prepare(THD *thd, const char *packet, uint packet_length)
unknown's avatar
unknown committed
2066
{
2067
  Protocol *save_protocol= thd->protocol;
unknown's avatar
unknown committed
2068
  Prepared_statement *stmt;
2069
  bool error;
2070
  DBUG_ENTER("mysqld_stmt_prepare");
unknown's avatar
unknown committed
2071

unknown's avatar
unknown committed
2072
  DBUG_PRINT("prep_query", ("%s", packet));
unknown's avatar
unknown committed
2073

unknown's avatar
unknown committed
2074 2075 2076
  /* First of all clear possible warnings from the previous command */
  mysql_reset_thd_for_next_command(thd);

2077
  if (! (stmt= new Prepared_statement(thd)))
2078
    DBUG_VOID_RETURN; /* out of memory: error is set in Sql_alloc */
2079

2080
  if (thd->stmt_map.insert(thd, stmt))
2081
  {
2082
    /*
2083
      The error is set in the insert. The statement itself
2084 2085
      will be also deleted there (this is how the hash works).
    */
2086
    DBUG_VOID_RETURN;
2087
  }
unknown's avatar
unknown committed
2088

2089 2090 2091
  sp_cache_flush_obsolete(&thd->sp_proc_cache);
  sp_cache_flush_obsolete(&thd->sp_func_cache);

2092 2093
  thd->protocol= &thd->protocol_binary;

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

2097
  error= stmt->prepare(packet, packet_length);
unknown's avatar
unknown committed
2098 2099

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

2102
  if (error)
2103
  {
2104 2105
    /* Statement map deletes statement on erase */
    thd->stmt_map.erase(stmt);
2106
  }
2107 2108 2109

  thd->protocol= save_protocol;

2110 2111 2112 2113
  /* check_prepared_statemnt sends the metadata packet in case of success */
  DBUG_VOID_RETURN;
}

unknown's avatar
unknown committed
2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129
/**
  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.

  @param[in]  lex               main lex
  @param[out] query_len         length of the SQL statement (is set only
    in case of success)

  @retval
    non-zero  success
  @retval
    0         in case of error (out of memory)
2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143
*/

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;
2144
    String *var_value= &str;
2145 2146 2147 2148 2149 2150 2151 2152
    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,
2153
                                      (uchar*)lex->prepared_stmt_code.str,
2154 2155 2156 2157
                                      lex->prepared_stmt_code.length))
        && entry->value)
    {
      my_bool is_var_null;
2158
      var_value= entry->val_str(&is_var_null, &str, NOT_FIXED_DEC);
2159 2160 2161 2162 2163
      /*
        NULL value of variable checked early as entry->value so here
        we can't get NULL in normal conditions
      */
      DBUG_ASSERT(!is_var_null);
2164
      if (!var_value)
2165 2166 2167 2168 2169 2170 2171 2172
        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
      */
2173
      str.set(STRING_WITH_LEN("NULL"), &my_charset_latin1);
2174 2175
    }

2176 2177 2178
    needs_conversion= String::needs_conversion(var_value->length(),
                                               var_value->charset(), to_cs,
                                               &unused);
2179

2180 2181
    len= (needs_conversion ? var_value->length() * to_cs->mbmaxlen :
          var_value->length());
2182
    if (!(query_str= (char*) alloc_root(thd->mem_root, len+1)))
2183 2184 2185 2186 2187
      goto end;

    if (needs_conversion)
    {
      uint dummy_errors;
2188 2189 2190
      len= copy_and_convert(query_str, len, to_cs, var_value->ptr(),
                            var_value->length(), var_value->charset(),
                            &dummy_errors);
2191 2192
    }
    else
2193 2194
      memcpy(query_str, var_value->ptr(), var_value->length());
    query_str[len]= '\0';                       // Safety (mostly for debug)
2195
    *query_len= len;
2196
  }
2197
  else
unknown's avatar
unknown committed
2198
  {
2199 2200
    query_str= lex->prepared_stmt_code.str;
    *query_len= lex->prepared_stmt_code.length;
unknown's avatar
unknown committed
2201
  }
2202 2203
end:
  return query_str;
unknown's avatar
unknown committed
2204 2205
}

unknown's avatar
unknown committed
2206

unknown's avatar
unknown committed
2207
/** Init PS/SP specific parse tree members.  */
2208

2209
static void init_stmt_after_parse(LEX *lex)
2210 2211
{
  SELECT_LEX *sl= lex->all_selects_list;
2212 2213 2214 2215
  /*
    Switch off a temporary flag that prevents evaluation of
    subqueries in statement prepare.
  */
2216 2217
  for (; sl; sl= sl->next_select_in_list())
   sl->uncacheable&= ~UNCACHEABLE_PREPARE;
2218 2219
}

unknown's avatar
unknown committed
2220
/**
2221 2222 2223 2224 2225 2226
  SQLCOM_PREPARE implementation.

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

unknown's avatar
unknown committed
2227 2228 2229
  @param thd     thread handle

  @return
2230 2231 2232 2233 2234 2235 2236 2237 2238 2239
    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;
Staale Smedseng's avatar
Staale Smedseng committed
2240
  uint query_len= 0;
2241
  DBUG_ENTER("mysql_sql_stmt_prepare");
2242

2243 2244 2245 2246 2247 2248
  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.
    */
unknown's avatar
unknown committed
2249 2250 2251
    if (stmt->is_in_use())
    {
      my_error(ER_PS_NO_RECURSION, MYF(0));
2252
      DBUG_VOID_RETURN;
unknown's avatar
unknown committed
2253 2254 2255
    }

    stmt->deallocate();
2256 2257 2258
  }

  if (! (query= get_dynamic_sql_string(lex, &query_len)) ||
2259
      ! (stmt= new Prepared_statement(thd)))
2260 2261 2262 2263
  {
    DBUG_VOID_RETURN;                           /* out of memory */
  }

2264 2265
  stmt->set_sql_prepare();

2266 2267
  /* Set the name first, insert should know that this statement has a name */
  if (stmt->set_name(name))
2268 2269 2270 2271
  {
    delete stmt;
    DBUG_VOID_RETURN;
  }
2272

2273
  if (thd->stmt_map.insert(thd, stmt))
2274
  {
2275
    /* The statement is deleted and an error is set if insert fails */
2276 2277 2278
    DBUG_VOID_RETURN;
  }

2279
  if (stmt->prepare(query, query_len))
2280 2281 2282 2283 2284
  {
    /* Statement map deletes the statement on erase */
    thd->stmt_map.erase(stmt);
  }
  else
2285
    my_ok(thd, 0L, 0L, "Statement prepared");
2286 2287 2288

  DBUG_VOID_RETURN;
}
2289

unknown's avatar
unknown committed
2290 2291 2292 2293 2294 2295 2296 2297
/**
  Reinit prepared statement/stored procedure before execution.

  @todo
    When the new table structure is ready, then have a status bit
    to indicate the table is altered, and re-do the setup_*
    and open the tables back.
*/
unknown's avatar
unknown committed
2298

2299
void reinit_stmt_before_use(THD *thd, LEX *lex)
2300
{
2301
  SELECT_LEX *sl= lex->all_selects_list;
2302
  DBUG_ENTER("reinit_stmt_before_use");
unknown's avatar
unknown committed
2303

2304 2305 2306 2307 2308 2309 2310
  /*
    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
2311 2312 2313
  if (lex->empty_field_list_on_rset)
  {
    lex->empty_field_list_on_rset= 0;
2314
    lex->field_list.empty();
unknown's avatar
VIEW  
unknown committed
2315
  }
2316
  for (; sl; sl= sl->next_select_in_list())
2317
  {
2318 2319
    if (!sl->first_execution)
    {
unknown's avatar
unknown committed
2320 2321 2322
      /* remove option which was put by mysql_explain_union() */
      sl->options&= ~SELECT_DESCRIBE;

2323 2324 2325
      /* see unique_table() */
      sl->exclude_from_table_unique_test= FALSE;

2326
      /*
unknown's avatar
unknown committed
2327 2328
        Copy WHERE, HAVING clause pointers to avoid damaging them
        by optimisation
2329
      */
unknown's avatar
unknown committed
2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340
      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);
2341 2342 2343 2344 2345 2346 2347 2348
      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;
    }
2349 2350 2351 2352
    {
      SELECT_LEX_UNIT *unit= sl->master_unit();
      unit->unclean();
      unit->types.empty();
2353
      /* for derived tables & PS (which can't be reset by Item_subquery) */
2354
      unit->reinit_exec_mechanism();
2355
      unit->set_thd(thd);
2356
    }
2357
  }
unknown's avatar
VIEW  
unknown committed
2358 2359

  /*
unknown's avatar
unknown committed
2360 2361
    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
2362 2363
    and open the tables back.
  */
2364 2365 2366 2367 2368
  /*
    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
2369
  for (TABLE_LIST *tables= lex->query_tables;
2370 2371
       tables;
       tables= tables->next_global)
unknown's avatar
VIEW  
unknown committed
2372
  {
2373 2374
    tables->reinit_before_use(thd);
  }
2375 2376 2377 2378 2379
  /*
    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.
  */
2380
  for (TABLE_LIST *tables= (TABLE_LIST*) lex->auxiliary_table_list.first;
2381
       tables;
2382
       tables= tables->next_global)
unknown's avatar
VIEW  
unknown committed
2383
  {
2384
    tables->reinit_before_use(thd);
unknown's avatar
VIEW  
unknown committed
2385
  }
2386
  lex->current_select= &lex->select_lex;
2387 2388 2389 2390 2391

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

2392
  if (lex->result)
2393
  {
2394
    lex->result->cleanup();
2395 2396
    lex->result->set_thd(thd);
  }
unknown's avatar
unknown committed
2397 2398
  lex->allow_sum_func= 0;
  lex->in_sum_func= NULL;
2399
  DBUG_VOID_RETURN;
2400 2401
}

2402

unknown's avatar
unknown committed
2403 2404
/**
  Clears parameters from data left from previous execution or long data.
unknown's avatar
unknown committed
2405

unknown's avatar
unknown committed
2406 2407
  @param stmt               prepared statement for which parameters should
                            be reset
2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418
*/

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


unknown's avatar
unknown committed
2419
/**
2420
  COM_STMT_EXECUTE handler: execute a previously prepared statement.
2421

2422 2423 2424 2425 2426
    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.

unknown's avatar
unknown committed
2427 2428 2429 2430 2431
  @param thd                current thread
  @param packet_arg         parameter types and data, if any
  @param packet_length      packet length, including the terminator character.

  @return
2432 2433
    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
2434 2435
*/

2436
void mysqld_stmt_execute(THD *thd, char *packet_arg, uint packet_length)
unknown's avatar
unknown committed
2437
{
2438
  uchar *packet= (uchar*)packet_arg; // GCC 4.0.1 workaround
unknown's avatar
unknown committed
2439
  ulong stmt_id= uint4korr(packet);
unknown's avatar
unknown committed
2440
  ulong flags= (ulong) packet[4];
2441
  /* Query text for binary, general or slow log, if any of them is open */
2442
  String expanded_query;
2443
  uchar *packet_end= packet + packet_length;
2444
  Prepared_statement *stmt;
2445
  Protocol *save_protocol= thd->protocol;
unknown's avatar
unknown committed
2446
  bool open_cursor;
2447
  DBUG_ENTER("mysqld_stmt_execute");
2448 2449

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

unknown's avatar
unknown committed
2451 2452 2453
  /* First of all clear possible warnings from the previous command */
  mysql_reset_thd_for_next_command(thd);

unknown's avatar
unknown committed
2454 2455 2456 2457
  if (!(stmt= find_prepared_statement(thd, stmt_id)))
  {
    char llbuf[22];
    my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), sizeof(llbuf),
2458
             llstr(stmt_id, llbuf), "mysqld_stmt_execute");
2459
    DBUG_VOID_RETURN;
unknown's avatar
unknown committed
2460
  }
2461

2462
#if defined(ENABLED_PROFILING)
2463
  thd->profiling.set_query_source(stmt->query, stmt->query_length);
2464
#endif
2465
  DBUG_PRINT("exec_query", ("%s", stmt->query));
unknown's avatar
unknown committed
2466
  DBUG_PRINT("info",("stmt: 0x%lx", (long) stmt));
unknown's avatar
unknown committed
2467

2468 2469 2470
  sp_cache_flush_obsolete(&thd->sp_proc_cache);
  sp_cache_flush_obsolete(&thd->sp_func_cache);

unknown's avatar
unknown committed
2471
  open_cursor= test(flags & (ulong) CURSOR_TYPE_READ_ONLY);
2472

2473
  thd->protocol= &thd->protocol_binary;
unknown's avatar
unknown committed
2474
  stmt->execute_loop(&expanded_query, open_cursor, packet, packet_end);
2475
  thd->protocol= save_protocol;
2476

2477 2478 2479
  /* Close connection socket; for use with client testing (Bug#43560). */
  DBUG_EXECUTE_IF("close_conn_after_stmt_execute", vio_close(thd->net.vio););

2480
  DBUG_VOID_RETURN;
unknown's avatar
unknown committed
2481

unknown's avatar
unknown committed
2482 2483
}

2484

unknown's avatar
unknown committed
2485
/**
2486 2487 2488 2489 2490 2491 2492 2493 2494
  SQLCOM_EXECUTE implementation.

    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.

unknown's avatar
unknown committed
2495 2496 2497
  @param thd                thread handle

  @return
2498 2499
    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
2500 2501
*/

2502
void mysql_sql_stmt_execute(THD *thd)
unknown's avatar
unknown committed
2503
{
2504
  LEX *lex= thd->lex;
2505
  Prepared_statement *stmt;
2506 2507
  LEX_STRING *name= &lex->prepared_stmt_name;
  /* Query text for binary, general or slow log, if any of them is open */
2508
  String expanded_query;
2509
  DBUG_ENTER("mysql_sql_stmt_execute");
2510
  DBUG_PRINT("info", ("EXECUTE: %.*s\n", (int) name->length, name->str));
2511

2512
  if (!(stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name)))
2513
  {
2514 2515
    my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0),
             name->length, name->str, "EXECUTE");
2516
    DBUG_VOID_RETURN;
2517 2518
  }

2519
  if (stmt->param_count != lex->prepared_stmt_params.elements)
unknown's avatar
unknown committed
2520
  {
2521
    my_error(ER_WRONG_ARGUMENTS, MYF(0), "EXECUTE");
unknown's avatar
unknown committed
2522 2523 2524
    DBUG_VOID_RETURN;
  }

unknown's avatar
unknown committed
2525
  DBUG_PRINT("info",("stmt: 0x%lx", (long) stmt));
2526

unknown's avatar
unknown committed
2527
  (void) stmt->execute_loop(&expanded_query, FALSE, NULL, NULL);
2528

unknown's avatar
unknown committed
2529 2530 2531
  DBUG_VOID_RETURN;
}

2532

unknown's avatar
unknown committed
2533 2534
/**
  COM_STMT_FETCH handler: fetches requested amount of rows from cursor.
unknown's avatar
unknown committed
2535

unknown's avatar
unknown committed
2536 2537 2538
  @param thd                Thread handle
  @param packet             Packet from client (with stmt_id & num_rows)
  @param packet_length      Length of packet
2539 2540
*/

2541
void mysqld_stmt_fetch(THD *thd, char *packet, uint packet_length)
2542 2543 2544
{
  /* assume there is always place for 8-16 bytes */
  ulong stmt_id= uint4korr(packet);
2545
  ulong num_rows= uint4korr(packet+4);
2546
  Prepared_statement *stmt;
unknown's avatar
unknown committed
2547
  Statement stmt_backup;
2548
  Server_side_cursor *cursor;
2549
  DBUG_ENTER("mysqld_stmt_fetch");
2550

unknown's avatar
unknown committed
2551
  /* First of all clear possible warnings from the previous command */
2552
  mysql_reset_thd_for_next_command(thd);
2553
  status_var_increment(thd->status_var.com_stmt_fetch);
unknown's avatar
unknown committed
2554 2555 2556 2557
  if (!(stmt= find_prepared_statement(thd, stmt_id)))
  {
    char llbuf[22];
    my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), sizeof(llbuf),
2558
             llstr(stmt_id, llbuf), "mysqld_stmt_fetch");
2559
    DBUG_VOID_RETURN;
unknown's avatar
unknown committed
2560
  }
2561

2562
  cursor= stmt->cursor;
2563
  if (!cursor)
2564
  {
2565
    my_error(ER_STMT_HAS_NO_OPEN_CURSOR, MYF(0), stmt_id);
2566 2567
    DBUG_VOID_RETURN;
  }
2568

unknown's avatar
Rename:  
unknown committed
2569
  thd->stmt_arena= stmt;
unknown's avatar
unknown committed
2570
  thd->set_n_backup_statement(stmt, &stmt_backup);
2571 2572 2573 2574

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

2575
  cursor->fetch(num_rows);
2576 2577 2578 2579

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

2580
  if (!cursor->is_open())
2581
  {
2582 2583
    stmt->close_cursor();
    thd->cursor= 0;
2584 2585 2586
    reset_stmt_params(stmt);
  }

2587
  thd->restore_backup_statement(stmt, &stmt_backup);
unknown's avatar
Rename:  
unknown committed
2588
  thd->stmt_arena= thd;
2589

2590 2591 2592 2593
  DBUG_VOID_RETURN;
}


unknown's avatar
unknown committed
2594
/**
2595
  Reset a prepared statement in case there was a recoverable error.
2596

2597 2598
    This function resets statement to the state it was right after prepare.
    It can be used to:
2599
    - clear an error happened during mysqld_stmt_send_long_data
unknown's avatar
unknown committed
2600
    - cancel long data stream for all placeholders without
2601
      having to call mysqld_stmt_execute.
unknown's avatar
unknown committed
2602
    - close an open cursor
2603 2604
    Sends 'OK' packet in case of success (statement was reset)
    or 'ERROR' packet (unrecoverable error/statement not found/etc).
unknown's avatar
unknown committed
2605 2606 2607

  @param thd                Thread handle
  @param packet             Packet with stmt id
unknown's avatar
unknown committed
2608 2609
*/

2610
void mysqld_stmt_reset(THD *thd, char *packet)
unknown's avatar
unknown committed
2611
{
2612
  /* There is always space for 4 bytes in buffer */
2613
  ulong stmt_id= uint4korr(packet);
2614
  Prepared_statement *stmt;
2615
  DBUG_ENTER("mysqld_stmt_reset");
unknown's avatar
unknown committed
2616

unknown's avatar
unknown committed
2617 2618 2619
  /* First of all clear possible warnings from the previous command */
  mysql_reset_thd_for_next_command(thd);

2620
  status_var_increment(thd->status_var.com_stmt_reset);
unknown's avatar
unknown committed
2621 2622 2623 2624
  if (!(stmt= find_prepared_statement(thd, stmt_id)))
  {
    char llbuf[22];
    my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), sizeof(llbuf),
2625
             llstr(stmt_id, llbuf), "mysqld_stmt_reset");
2626
    DBUG_VOID_RETURN;
unknown's avatar
unknown committed
2627
  }
2628

2629 2630 2631 2632
  stmt->close_cursor();

  /*
    Clear parameters from data which could be set by
2633
    mysqld_stmt_send_long_data() call.
2634 2635
  */
  reset_stmt_params(stmt);
2636

unknown's avatar
unknown committed
2637
  stmt->state= Query_arena::PREPARED;
2638

2639 2640
  general_log_print(thd, thd->command, NullS);

2641
  my_ok(thd);
unknown's avatar
unknown committed
2642

2643 2644 2645 2646
  DBUG_VOID_RETURN;
}


unknown's avatar
unknown committed
2647
/**
2648
  Delete a prepared statement from memory.
unknown's avatar
unknown committed
2649 2650 2651

  @note
    we don't send any reply to this command.
2652 2653
*/

2654
void mysqld_stmt_close(THD *thd, char *packet)
2655
{
2656
  /* There is always space for 4 bytes in packet buffer */
2657
  ulong stmt_id= uint4korr(packet);
2658
  Prepared_statement *stmt;
2659
  DBUG_ENTER("mysqld_stmt_close");
2660

Marc Alff's avatar
Marc Alff committed
2661
  thd->stmt_da->disable_status();
unknown's avatar
unknown committed
2662

unknown's avatar
unknown committed
2663
  if (!(stmt= find_prepared_statement(thd, stmt_id)))
2664
    DBUG_VOID_RETURN;
2665

2666 2667 2668 2669
  /*
    The only way currently a statement can be deallocated when it's
    in use is from within Dynamic SQL.
  */
unknown's avatar
unknown committed
2670 2671
  DBUG_ASSERT(! stmt->is_in_use());
  stmt->deallocate();
2672
  general_log_print(thd, thd->command, NullS);
2673

unknown's avatar
unknown committed
2674 2675 2676
  DBUG_VOID_RETURN;
}

2677

unknown's avatar
unknown committed
2678
/**
2679 2680 2681 2682 2683 2684
  SQLCOM_DEALLOCATE implementation.

    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.

unknown's avatar
unknown committed
2685
  @return
2686 2687 2688 2689 2690 2691 2692 2693
    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;
2694 2695
  DBUG_PRINT("info", ("DEALLOCATE PREPARE: %.*s\n", (int) name->length,
                      name->str));
2696 2697 2698 2699

  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");
unknown's avatar
unknown committed
2700 2701 2702 2703 2704
  else if (stmt->is_in_use())
    my_error(ER_PS_NO_RECURSION, MYF(0));
  else
  {
    stmt->deallocate();
2705
    my_ok(thd);
unknown's avatar
unknown committed
2706
  }
2707 2708
}

unknown's avatar
unknown committed
2709
/**
2710
  Handle long data in pieces from client.
2711

2712 2713 2714 2715 2716
    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).
unknown's avatar
unknown committed
2717 2718 2719 2720

  @param thd                Thread handle
  @param packet             String to append
  @param packet_length      Length of string (including end \\0)
2721 2722
*/

2723
void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
2724
{
2725 2726
  ulong stmt_id;
  uint param_number;
2727
  Prepared_statement *stmt;
2728
  Item_param *param;
2729
#ifndef EMBEDDED_LIBRARY
2730
  char *packet_end= packet + packet_length;
2731
#endif
2732 2733
  DBUG_ENTER("mysql_stmt_get_longdata");

2734
  status_var_increment(thd->status_var.com_stmt_send_long_data);
2735

Marc Alff's avatar
Marc Alff committed
2736
  thd->stmt_da->disable_status();
unknown's avatar
unknown committed
2737
#ifndef EMBEDDED_LIBRARY
2738
  /* Minimal size of long data packet is 6 bytes */
2739
  if (packet_length < MYSQL_LONG_DATA_HEADER)
2740
    DBUG_VOID_RETURN;
unknown's avatar
unknown committed
2741
#endif
2742

2743 2744
  stmt_id= uint4korr(packet);
  packet+= 4;
2745

unknown's avatar
unknown committed
2746
  if (!(stmt=find_prepared_statement(thd, stmt_id)))
2747 2748
    DBUG_VOID_RETURN;

2749 2750
  param_number= uint2korr(packet);
  packet+= 2;
unknown's avatar
unknown committed
2751
#ifndef EMBEDDED_LIBRARY
2752 2753
  if (param_number >= stmt->param_count)
  {
unknown's avatar
unknown committed
2754
    /* Error will be sent in execute call */
unknown's avatar
unknown committed
2755
    stmt->state= Query_arena::ERROR;
unknown's avatar
unknown committed
2756
    stmt->last_errno= ER_WRONG_ARGUMENTS;
2757
    sprintf(stmt->last_error, ER(ER_WRONG_ARGUMENTS),
2758
            "mysqld_stmt_send_long_data");
2759 2760
    DBUG_VOID_RETURN;
  }
unknown's avatar
unknown committed
2761 2762
#endif

2763 2764
  param= stmt->param_array[param_number];

unknown's avatar
unknown committed
2765
#ifndef EMBEDDED_LIBRARY
2766
  if (param->set_longdata(packet, (ulong) (packet_end - packet)))
unknown's avatar
unknown committed
2767
#else
2768
  if (param->set_longdata(thd->extra_data, thd->extra_length))
unknown's avatar
unknown committed
2769
#endif
2770
  {
unknown's avatar
unknown committed
2771
    stmt->state= Query_arena::ERROR;
2772 2773 2774
    stmt->last_errno= ER_OUTOFMEMORY;
    sprintf(stmt->last_error, ER(ER_OUTOFMEMORY), 0);
  }
2775 2776 2777

  general_log_print(thd, thd->command, NullS);

2778 2779
  DBUG_VOID_RETURN;
}
unknown's avatar
unknown committed
2780

2781

2782
/***************************************************************************
unknown's avatar
unknown committed
2783
 Select_fetch_protocol_binary
2784 2785
****************************************************************************/

unknown's avatar
unknown committed
2786
Select_fetch_protocol_binary::Select_fetch_protocol_binary(THD *thd_arg)
2787
  :protocol(thd_arg)
2788 2789
{}

unknown's avatar
unknown committed
2790
bool Select_fetch_protocol_binary::send_fields(List<Item> &list, uint flags)
2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807
{
  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;
}

unknown's avatar
unknown committed
2808
bool Select_fetch_protocol_binary::send_eof()
2809
{
2810
  ::my_eof(thd);
2811 2812 2813 2814 2815
  return FALSE;
}


bool
unknown's avatar
unknown committed
2816
Select_fetch_protocol_binary::send_data(List<Item> &fields)
2817 2818 2819 2820 2821 2822 2823 2824 2825 2826
{
  Protocol *save_protocol= thd->protocol;
  bool rc;

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

Marc Alff's avatar
Marc Alff committed
2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850
/*******************************************************************
* Reprepare_observer
*******************************************************************/
/** Push an error to the error stack and return TRUE for now. */

bool
Reprepare_observer::report_error(THD *thd)
{
  /*
    This 'error' is purely internal to the server:
    - No exception handler is invoked,
    - No condition is added in the condition area (warn_list).
    The diagnostics area is set to an error status to enforce
    that this thread execution stops and returns to the caller,
    backtracking all the way to Prepared_statement::execute_loop().
  */
  thd->stmt_da->set_error_status(thd, ER_NEED_REPREPARE,
                                 ER(ER_NEED_REPREPARE), "HY000");
  m_invalidated= TRUE;

  return TRUE;
}


2851 2852 2853 2854
/***************************************************************************
 Prepared_statement
****************************************************************************/

2855
Prepared_statement::Prepared_statement(THD *thd_arg)
2856
  :Statement(NULL, &main_mem_root,
2857
             INITIALIZED, ++thd_arg->statement_id_counter),
2858
  thd(thd_arg),
2859
  result(thd_arg),
2860
  param_array(0),
2861
  param_count(0),
2862
  last_errno(0),
Konstantin Osipov's avatar
Konstantin Osipov committed
2863 2864
  flags((uint) IS_IN_USE),
  m_sp_cache_version(0)
2865
{
2866
  init_sql_alloc(&main_mem_root, thd_arg->variables.query_alloc_block_size,
2867
                  thd_arg->variables.query_prealloc_size);
2868 2869 2870
  *last_error= '\0';
}

2871

2872 2873
void Prepared_statement::setup_set_params()
{
2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884
  /*
    Note: BUG#25843 applies here too (query cache lookup uses thd->db, not
    db from "prepare" time).
  */
  if (query_cache_maybe_disabled(thd)) // we won't expand the query
    lex->safe_to_cache_query= FALSE;   // so don't cache it at Execution

  /*
    Decide if we have to expand the query (because we must write it to logs or
    because we want to look it up in the query cache) or not.
  */
2885
  if ((mysql_bin_log.is_open() && is_update_query(lex->sql_command)) ||
2886 2887
      opt_log || opt_slow_log ||
      query_cache_is_cacheable_query(lex))
2888
  {
2889
    set_params_from_vars= insert_params_from_vars_with_log;
2890
#ifndef EMBEDDED_LIBRARY
2891
    set_params= insert_params_with_log;
2892
#else
2893
    set_params_data= emb_insert_params_with_log;
2894 2895 2896
#endif
  }
  else
2897 2898
  {
    set_params_from_vars= insert_params_from_vars;
2899
#ifndef EMBEDDED_LIBRARY
2900
    set_params= insert_params;
2901
#else
2902
    set_params_data= emb_insert_params;
2903
#endif
2904
  }
2905 2906
}

2907

unknown's avatar
unknown committed
2908 2909 2910 2911 2912 2913
/**
  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.
2914 2915
*/

2916 2917
Prepared_statement::~Prepared_statement()
{
2918
  DBUG_ENTER("Prepared_statement::~Prepared_statement");
unknown's avatar
unknown committed
2919 2920
  DBUG_PRINT("enter",("stmt: 0x%lx  cursor: 0x%lx",
                      (long) this, (long) cursor));
2921
  delete cursor;
2922 2923 2924 2925 2926
  /*
    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();
unknown's avatar
unknown committed
2927 2928 2929 2930 2931
  if (lex)
  {
    delete lex->result;
    delete (st_lex_local *) lex;
  }
2932
  free_root(&main_mem_root, MYF(0));
2933
  DBUG_VOID_RETURN;
2934 2935 2936
}


unknown's avatar
unknown committed
2937
Query_arena::Type Prepared_statement::type() const
2938 2939 2940
{
  return PREPARED_STATEMENT;
}
2941 2942


2943
void Prepared_statement::cleanup_stmt()
2944
{
2945
  DBUG_ENTER("Prepared_statement::cleanup_stmt");
unknown's avatar
unknown committed
2946
  DBUG_PRINT("enter",("stmt: 0x%lx", (long) this));
2947

2948
  DBUG_ASSERT(lex->sphead == 0);
2949 2950 2951 2952 2953 2954 2955
  /* The order is important */
  lex->unit.cleanup();
  cleanup_items(free_list);
  thd->cleanup_after_query();
  close_thread_tables(thd);
  thd->rollback_item_tree_changes();

2956
  DBUG_VOID_RETURN;
2957
}
2958 2959 2960 2961 2962


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

unknown's avatar
unknown committed
2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994

/**
  Remember the current database.

  We must reset/restore the current database during execution of
  a prepared statement since it affects execution environment:
  privileges, @@character_set_database, and other.

  @return Returns an error if out of memory.
*/

bool
Prepared_statement::set_db(const char *db_arg, uint db_length_arg)
{
  /* Remember the current database. */
  if (db_arg && db_length_arg)
  {
    db= this->strmake(db_arg, db_length_arg);
    db_length= db_length_arg;
  }
  else
  {
    db= NULL;
    db_length= 0;
  }
  return db_arg != NULL && db == NULL;
}

2995 2996 2997 2998 2999 3000 3001
/**************************************************************************
  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.
***************************************************************************/

unknown's avatar
unknown committed
3002
/**
3003 3004 3005 3006 3007 3008
  Parse statement text, validate the statement, and prepare it for execution.

    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.

unknown's avatar
unknown committed
3009 3010 3011 3012 3013
  @param packet             statement text
  @param packet_len

  @note
    Precondition:
3014 3015 3016 3017
    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.

unknown's avatar
unknown committed
3018 3019
  @note
    Postcondition:
3020 3021 3022 3023 3024
    thd->mem_root contains unused memory allocated during validation.
*/

bool Prepared_statement::prepare(const char *packet, uint packet_len)
{
3025
  bool error;
3026 3027 3028 3029 3030 3031 3032 3033
  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.
  */
3034
  status_var_increment(thd->status_var.com_stmt_prepare);
3035

unknown's avatar
unknown committed
3036 3037 3038 3039 3040 3041
  if (! (lex= new (mem_root) st_lex_local))
    DBUG_RETURN(TRUE);

  if (set_db(thd->db, thd->db_length))
    DBUG_RETURN(TRUE);

3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058
  /*
    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;

3059 3060
  Parser_state parser_state(thd, thd->query, thd->query_length);
  parser_state.m_lip.stmt_prepare_mode= TRUE;
3061
  lex_start(thd);
3062

3063
  error= parse_sql(thd, & parser_state, NULL) ||
3064
         thd->is_error() ||
3065
         init_param_array(this);
3066

3067
  lex->set_trg_event_type_for_tables();
3068

3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083
  /*
    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());
3084 3085 3086 3087 3088

  /* 
   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.
3089 3090
  */

3091
  if (error == 0)
unknown's avatar
unknown committed
3092
    error= check_prepared_statement(this);
3093

3094 3095 3096 3097 3098 3099 3100
  /*
    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)
3101
  {
3102 3103
    delete lex->sphead;
    lex->sphead= NULL;
3104
  }
3105

3106
  lex_end(lex);
3107
  cleanup_stmt();
3108 3109 3110
  thd->restore_backup_statement(this, &stmt_backup);
  thd->stmt_arena= old_stmt_arena;

3111
  if (error == 0)
3112 3113 3114 3115
  {
    setup_set_params();
    init_stmt_after_parse(lex);
    state= Query_arena::PREPARED;
3116
    flags&= ~ (uint) IS_IN_USE;
Konstantin Osipov's avatar
Konstantin Osipov committed
3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130
    /*
      This is for prepared statement validation purposes.
      A statement looks up and pre-loads all its stored functions
      at prepare. Later on, if a function is gone from the cache,
      execute may fail.
      Remember the cache version to be able to invalidate the prepared
      statement at execute if it changes.
      We only need to care about version of the stored functions cache:
      if a prepared statement uses a stored procedure, it's indirect,
      via a stored function. The only exception is SQLCOM_CALL,
      but the latter one looks up the stored procedure each time
      it's invoked, rather than once at prepare.
    */
    m_sp_cache_version= sp_cache_version(&thd->sp_func_cache);
3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147

    /* 
      Log COM_EXECUTE to the general log. Note, that in case of SQL
      prepared statements this causes two records to be output:

      Query       PREPARE stmt from @user_variable
      Prepare     <statement SQL text>

      This is considered user-friendly, since in the
      second log entry we output the actual statement text.

      Do not print anything if this is an SQL prepared statement and
      we're inside a stored procedure (also called Dynamic SQL) --
      sub-statements inside stored procedures are not logged into
      the general log.
    */
    if (thd->spcont == NULL)
3148
      general_log_write(thd, COM_STMT_PREPARE, query, query_length);
3149
  }
3150
  DBUG_RETURN(error);
3151 3152
}

unknown's avatar
unknown committed
3153

3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173
/**
  Assign parameter values either from variables, in case of SQL PS
  or from the execute packet.

  @param expanded_query  a container with the original SQL statement.
                         '?' placeholders will be replaced with
                         their values in case of success.
                         The result is used for logging and replication
  @param packet          pointer to execute packet.
                         NULL in case of SQL PS
  @param packet_end      end of the packet. NULL in case of SQL PS

  @todo Use a paremeter source class family instead of 'if's, and
  support stored procedure variables.

  @retval TRUE an error occurred when assigning a parameter (likely
          a conversion error or out of memory, or malformed packet)
  @retval FALSE success
*/

unknown's avatar
unknown committed
3174 3175 3176 3177 3178
bool
Prepared_statement::set_parameters(String *expanded_query,
                                   uchar *packet, uchar *packet_end)
{
  bool is_sql_ps= packet == NULL;
3179
  bool res= FALSE;
unknown's avatar
unknown committed
3180 3181 3182 3183

  if (is_sql_ps)
  {
    /* SQL prepared statement */
3184 3185
    res= set_params_from_vars(this, thd->lex->prepared_stmt_params,
                              expanded_query);
unknown's avatar
unknown committed
3186 3187 3188 3189 3190
  }
  else if (param_count)
  {
#ifndef EMBEDDED_LIBRARY
    uchar *null_array= packet;
3191 3192
    res= (setup_conversion_functions(this, &packet, packet_end) ||
          set_params(this, null_array, packet, packet_end, expanded_query));
unknown's avatar
unknown committed
3193
#else
3194 3195 3196 3197 3198 3199
    /*
      In embedded library we re-install conversion routines each time
      we set parameters, and also we don't need to parse packet.
      So we do it in one function.
    */
    res= set_params_data(this, expanded_query);
unknown's avatar
unknown committed
3200 3201
#endif
  }
3202 3203 3204
  if (res)
  {
    my_error(ER_WRONG_ARGUMENTS, MYF(0),
3205
             is_sql_ps ? "EXECUTE" : "mysqld_stmt_execute");
3206 3207 3208
    reset_stmt_params(this);
  }
  return res;
unknown's avatar
unknown committed
3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246
}


/**
  Execute a prepared statement. Re-prepare it a limited number
  of times if necessary.

  Try to execute a prepared statement. If there is a metadata
  validation error, prepare a new copy of the prepared statement,
  swap the old and the new statements, and try again.
  If there is a validation error again, repeat the above, but
  perform no more than MAX_REPREPARE_ATTEMPTS.

  @note We have to try several times in a loop since we
  release metadata locks on tables after prepared statement
  prepare. Therefore, a DDL statement may sneak in between prepare
  and execute of a new statement. If this happens repeatedly
  more than MAX_REPREPARE_ATTEMPTS times, we give up.

  In future we need to be able to keep the metadata locks between
  prepare and execute, but right now open_and_lock_tables(), as
  well as close_thread_tables() are buried deep inside
  execution code (mysql_execute_command()).

  @return TRUE if an error, FALSE if success
  @retval  TRUE    either MAX_REPREPARE_ATTEMPTS has been reached,
                   or some general error
  @retval  FALSE   successfully executed the statement, perhaps
                   after having reprepared it a few times.
*/

bool
Prepared_statement::execute_loop(String *expanded_query,
                                 bool open_cursor,
                                 uchar *packet,
                                 uchar *packet_end)
{
  const int MAX_REPREPARE_ATTEMPTS= 3;
3247
  Reprepare_observer reprepare_observer;
unknown's avatar
unknown committed
3248 3249 3250 3251 3252 3253 3254
  bool error;
  int reprepare_attempt= 0;

  if (set_parameters(expanded_query, packet, packet_end))
    return TRUE;

reexecute:
3255
  reprepare_observer.reset_reprepare_observer();
unknown's avatar
unknown committed
3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272

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

  /*
    Install the metadata observer. If some metadata version is
    different from prepare time and an observer is installed,
    the observer method will be invoked to push an error into
    the error stack.
  */
  if (sql_command_flags[lex->sql_command] &
      CF_REEXECUTION_FRAGILE)
  {
3273 3274
    DBUG_ASSERT(thd->m_reprepare_observer == NULL);
    thd->m_reprepare_observer = &reprepare_observer;
unknown's avatar
unknown committed
3275 3276 3277 3278 3279 3280 3281 3282 3283 3284
  }

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

  error= execute(expanded_query, open_cursor) || thd->is_error();

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

3285
  thd->m_reprepare_observer= NULL;
unknown's avatar
unknown committed
3286 3287

  if (error && !thd->is_fatal_error && !thd->killed &&
3288
      reprepare_observer.is_invalidated() &&
unknown's avatar
unknown committed
3289 3290
      reprepare_attempt++ < MAX_REPREPARE_ATTEMPTS)
  {
Marc Alff's avatar
Marc Alff committed
3291
    DBUG_ASSERT(thd->stmt_da->sql_errno() == ER_NEED_REPREPARE);
unknown's avatar
unknown committed
3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325
    thd->clear_error();

    error= reprepare();

    if (! error)                                /* Success */
      goto reexecute;
  }
  reset_stmt_params(this);

  return error;
}


/**
  Reprepare this prepared statement.

  Currently this is implemented by creating a new prepared
  statement, preparing it with the original query and then
  swapping the new statement and the original one.

  @retval  TRUE   an error occurred. Possible errors include
                  incompatibility of new and old result set
                  metadata
  @retval  FALSE  success, the statement has been reprepared
*/

bool
Prepared_statement::reprepare()
{
  char saved_cur_db_name_buf[NAME_LEN+1];
  LEX_STRING saved_cur_db_name=
    { saved_cur_db_name_buf, sizeof(saved_cur_db_name_buf) };
  LEX_STRING stmt_db_name= { db, db_length };
  bool cur_db_changed;
3326
  bool error;
unknown's avatar
unknown committed
3327

3328 3329 3330
  Prepared_statement copy(thd);

  copy.set_sql_prepare(); /* To suppress sending metadata to the client. */
unknown's avatar
unknown committed
3331

3332
  status_var_increment(thd->status_var.com_stmt_reprepare);
unknown's avatar
unknown committed
3333 3334 3335

  if (mysql_opt_change_db(thd, &stmt_db_name, &saved_cur_db_name, TRUE,
                          &cur_db_changed))
3336
    return TRUE;
unknown's avatar
unknown committed
3337

Staale Smedseng's avatar
Staale Smedseng committed
3338
  error= ((name.str && copy.set_name(&name)) ||
3339 3340
          copy.prepare(query, query_length) ||
          validate_metadata(&copy));
unknown's avatar
unknown committed
3341 3342 3343 3344 3345 3346

  if (cur_db_changed)
    mysql_change_db(thd, &saved_cur_db_name, TRUE);

  if (! error)
  {
3347 3348
    swap_prepared_statement(&copy);
    swap_parameter_array(param_array, copy.param_array, param_count);
unknown's avatar
unknown committed
3349
#ifndef DBUG_OFF
unknown's avatar
unknown committed
3350
    is_reprepared= TRUE;
unknown's avatar
unknown committed
3351
#endif
unknown's avatar
unknown committed
3352
    /*
3353
      Clear possible warnings during reprepare, it has to be completely
Marc Alff's avatar
Marc Alff committed
3354
      transparent to the user. We use clear_warning_info() since
unknown's avatar
unknown committed
3355
      there were no separate query id issued for re-prepare.
3356 3357
      Sic: we can't simply silence warnings during reprepare, because if
      it's failed, we need to return all the warnings to the user.
unknown's avatar
unknown committed
3358
    */
Marc Alff's avatar
Marc Alff committed
3359
    thd->warning_info->clear_warning_info(thd->query_id);
unknown's avatar
unknown committed
3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375
  }
  return error;
}


/**
  Validate statement result set metadata (if the statement returns
  a result set).

  Currently we only check that the number of columns of the result
  set did not change.
  This is a helper method used during re-prepare.

  @param[in]  copy  the re-prepared prepared statement to verify
                    the metadata of

3376
  @retval TRUE  error, ER_PS_REBIND is reported
unknown's avatar
unknown committed
3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387
  @retval FALSE statement return no or compatible metadata
*/


bool Prepared_statement::validate_metadata(Prepared_statement *copy)
{
  /**
    If this is an SQL prepared statement or EXPLAIN,
    return FALSE -- the metadata of the original SELECT,
    if any, has not been sent to the client.
  */
3388
  if (is_sql_prepare() || lex->describe)
unknown's avatar
unknown committed
3389 3390 3391 3392 3393
    return FALSE;

  if (lex->select_lex.item_list.elements !=
      copy->lex->select_lex.item_list.elements)
  {
3394 3395
    /** Column counts mismatch, update the client */
    thd->server_status|= SERVER_STATUS_METADATA_CHANGED;
unknown's avatar
unknown committed
3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443
  }

  return FALSE;
}


/**
  Replace the original prepared statement with a prepared copy.

  This is a private helper that is used as part of statement
  reprepare

  @return This function does not return any errors.
*/

void
Prepared_statement::swap_prepared_statement(Prepared_statement *copy)
{
  Statement tmp_stmt;

  /* Swap memory roots. */
  swap_variables(MEM_ROOT, main_mem_root, copy->main_mem_root);

  /* Swap the arenas */
  tmp_stmt.set_query_arena(this);
  set_query_arena(copy);
  copy->set_query_arena(&tmp_stmt);

  /* Swap the statement parent classes */
  tmp_stmt.set_statement(this);
  set_statement(copy);
  copy->set_statement(&tmp_stmt);

  /* Swap ids back, we need the original id */
  swap_variables(ulong, id, copy->id);
  /* Swap mem_roots back, they must continue pointing at the main_mem_roots */
  swap_variables(MEM_ROOT *, mem_root, copy->mem_root);
  /*
    Swap the old and the new parameters array. The old array
    is allocated in the old arena.
  */
  swap_variables(Item_param **, param_array, copy->param_array);
  /* Swap flags: this is perhaps unnecessary */
  swap_variables(uint, flags, copy->flags);
  /* Swap names, the old name is allocated in the wrong memory root */
  swap_variables(LEX_STRING, name, copy->name);
  /* Ditto */
  swap_variables(char *, db, copy->db);
Konstantin Osipov's avatar
Konstantin Osipov committed
3444
  swap_variables(ulong, m_sp_cache_version, copy->m_sp_cache_version);
unknown's avatar
unknown committed
3445 3446 3447 3448 3449 3450 3451 3452 3453

  DBUG_ASSERT(db_length == copy->db_length);
  DBUG_ASSERT(param_count == copy->param_count);
  DBUG_ASSERT(thd == copy->thd);
  last_error[0]= '\0';
  last_errno= 0;
}


unknown's avatar
unknown committed
3454
/**
3455 3456 3457 3458 3459 3460
  Execute a prepared statement.

    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.

unknown's avatar
unknown committed
3461 3462 3463 3464 3465 3466 3467 3468
  @param expanded_query     A query for binlogging which has all parameter
                            markers ('?') replaced with their actual values.
  @param open_cursor        True if an attempt to open a cursor should be made.
                            Currenlty used only in the binary protocol.

  @note
    Preconditions, postconditions.
    - See the comment for Prepared_statement::prepare().
3469

unknown's avatar
unknown committed
3470 3471 3472
  @retval
    FALSE	    ok
  @retval
3473
    TRUE		Error
3474 3475 3476 3477 3478 3479
*/

bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
{
  Statement stmt_backup;
  Query_arena *old_stmt_arena;
3480
  bool error= TRUE;
3481

3482 3483 3484 3485 3486 3487 3488
  char saved_cur_db_name_buf[NAME_LEN+1];
  LEX_STRING saved_cur_db_name=
    { saved_cur_db_name_buf, sizeof(saved_cur_db_name_buf) };
  bool cur_db_changed;

  LEX_STRING stmt_db_name= { db, db_length };

3489
  status_var_increment(thd->status_var.com_stmt_execute);
3490 3491 3492 3493 3494

  /* Check if we got an error when sending long data */
  if (state == Query_arena::ERROR)
  {
    my_message(last_errno, last_error, MYF(0));
3495
    return TRUE;
3496
  }
3497
  if (flags & (uint) IS_IN_USE)
3498 3499
  {
    my_error(ER_PS_NO_RECURSION, MYF(0));
3500
    return TRUE;
3501
  }
3502

Konstantin Osipov's avatar
Konstantin Osipov committed
3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515
  /*
    Reprepare the statement if we're using stored functions
    and the version of the stored routines cache has changed.
  */
  if (lex->uses_stored_routines() &&
      m_sp_cache_version != sp_cache_version(&thd->sp_func_cache) &&
      thd->m_reprepare_observer &&
      thd->m_reprepare_observer->report_error(thd))
  {
    return TRUE;
  }


3516 3517 3518 3519 3520 3521 3522 3523 3524 3525
  /*
    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.
  */

3526
  if (open_cursor && lex->result && lex->result->check_simple_select())
3527 3528 3529 3530 3531
  {
    DBUG_PRINT("info",("Cursor asked for not SELECT stmt"));
    return TRUE;
  }

3532 3533 3534
  /* In case the command has a call to SP which re-uses this statement name */
  flags|= IS_IN_USE;

3535
  close_cursor();
3536 3537 3538 3539 3540 3541

  /*
    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());
3542 3543 3544 3545 3546 3547 3548

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

3549
  thd->set_n_backup_statement(this, &stmt_backup);
3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564

  /*
    Change the current database (if needed).

    Force switching, because the database of the prepared statement may be
    NULL (prepared statements can be created while no current database
    selected).
  */

  if (mysql_opt_change_db(thd, &stmt_db_name, &saved_cur_db_name, TRUE,
                          &cur_db_changed))
    goto error;

  /* Allocate query. */

3565 3566
  if (expanded_query->length() &&
      alloc_query(thd, (char*) expanded_query->ptr(),
3567
                  expanded_query->length()))
3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590
  {
    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;

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

3591 3592
  /* Go! */

3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605
  if (open_cursor)
    error= mysql_open_cursor(thd, (uint) ALWAYS_MATERIALIZED_CURSOR,
                             &result, &cursor);
  else
  {
    /*
      Try to find it in the query cache, if not, execute it.
      Note that multi-statements cannot exist here (they are not supported in
      prepared statements).
    */
    if (query_cache_send_result_to_client(thd, thd->query,
                                          thd->query_length) <= 0)
    {
3606 3607 3608 3609 3610 3611
      MYSQL_QUERY_EXEC_START(thd->query,
                             thd->thread_id,
                             (char *) (thd->db ? thd->db : ""),
                             thd->security_ctx->priv_user,
                             (char *) thd->security_ctx->host_or_ip,
                             1);
3612
      error= mysql_execute_command(thd);
3613
      MYSQL_QUERY_EXEC_DONE(error);
3614 3615 3616
    }
  }

3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627
  /*
    Restore the current database (if changed).

    Force switching back to the saved current database (if changed),
    because it may be NULL. In this case, mysql_change_db() would generate
    an error.
  */

  if (cur_db_changed)
    mysql_change_db(thd, &saved_cur_db_name, TRUE);

3628
  /* Assert that if an error, no cursor is open */
unknown's avatar
unknown committed
3629
  DBUG_ASSERT(! (error && cursor));
3630

3631 3632
  if (! cursor)
    cleanup_stmt();
3633 3634 3635 3636 3637 3638 3639

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

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

3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655
  /*
    Log COM_EXECUTE to the general log. Note, that in case of SQL
    prepared statements this causes two records to be output:

    Query       EXECUTE <statement name>
    Execute     <statement SQL text>

    This is considered user-friendly, since in the
    second log entry we output values of parameter markers.

    Do not print anything if this is an SQL prepared statement and
    we're inside a stored procedure (also called Dynamic SQL) --
    sub-statements inside stored procedures are not logged into
    the general log.
  */
  if (error == 0 && thd->spcont == NULL)
3656
    general_log_write(thd, COM_STMT_EXECUTE, thd->query, thd->query_length);
3657

3658
error:
3659 3660
  flags&= ~ (uint) IS_IN_USE;
  return error;
3661 3662 3663
}


3664
/** Common part of DEALLOCATE PREPARE and mysqld_stmt_close. */
3665

unknown's avatar
unknown committed
3666
void Prepared_statement::deallocate()
3667
{
3668
  /* We account deallocate in the same manner as mysqld_stmt_close */
3669
  status_var_increment(thd->status_var.com_stmt_close);
3670 3671 3672
  /* Statement map calls delete stmt on erase */
  thd->stmt_map.erase(this);
}