sql_prepare.cc 129 KB
Newer Older
1 2
/* Copyright (c) 2002, 2015, Oracle and/or its affiliates.
   Copyright (c) 2008, 2015, MariaDB
unknown's avatar
unknown committed
3 4 5

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

   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
15
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
unknown's avatar
unknown committed
16

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

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

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

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

42 43 44 45 46 47
  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.

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

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

69 70 71 72
  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.

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

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

87
#include "my_global.h"                          /* NO_EMBEDDED_ACCESS_CHECKS */
88 89 90
#include "sql_priv.h"
#include "unireg.h"
#include "sql_class.h"                          // set_var.h: THD
91
#include "set_var.h"
92
#include "sql_prepare.h"
93
#include "sql_parse.h" // insert_precheck, update_precheck, delete_precheck
94
#include "sql_base.h"  // open_normal_and_derived_tables
95 96 97
#include "sql_cache.h"                          // query_cache_*
#include "sql_view.h"                          // create_view_precheck
#include "sql_delete.h"                        // mysql_prepare_delete
unknown's avatar
unknown committed
98
#include "sql_select.h" // for JOIN
99 100 101 102 103 104
#include "sql_insert.h" // upgrade_lock_type_for_insert, mysql_prepare_insert
#include "sql_update.h" // mysql_prepare_update
#include "sql_db.h"     // mysql_opt_change_db, mysql_change_db
#include "sql_acl.h"    // *_ACL
#include "sql_derived.h" // mysql_derived_prepare,
                         // mysql_handle_derived
105
#include "sql_cursor.h"
106
#include "sp_head.h"
107
#include "sp.h"
unknown's avatar
unknown committed
108
#include "sp_cache.h"
109
#include "probes_mysql.h"
110 111 112
#ifdef EMBEDDED_LIBRARY
/* include MYSQL_BIND headers */
#include <mysql.h>
113 114
#else
#include <mysql_com.h>
115
#endif
116
#include "lock.h"                               // MYSQL_OPEN_FORCE_SHARED_MDL
117
#include "sql_handler.h"
118
#include "transaction.h"                        // trans_rollback_implicit
unknown's avatar
unknown committed
119

unknown's avatar
unknown committed
120 121 122
/**
  A result class used to send cursor rows using the binary protocol.
*/
123

unknown's avatar
unknown committed
124
class Select_fetch_protocol_binary: public select_send
125
{
unknown's avatar
unknown committed
126
  Protocol_binary protocol;
127
public:
unknown's avatar
unknown committed
128
  Select_fetch_protocol_binary(THD *thd);
129
  virtual bool send_result_set_metadata(List<Item> &list, uint flags);
130
  virtual int send_data(List<Item> &items);
131
  virtual bool send_eof();
132 133 134 135 136 137
#ifdef EMBEDDED_LIBRARY
  void begin_dataset()
  {
    protocol.begin_dataset();
  }
#endif
138 139
};

140 141 142
/****************************************************************************/

/**
unknown's avatar
unknown committed
143
  Prepared_statement: a statement that can contain placeholders.
144
*/
145

146 147 148
class Prepared_statement: public Statement
{
public:
149 150
  enum flag_values
  {
151 152
    IS_IN_USE= 1,
    IS_SQL_PREPARE= 2
153 154
  };

155
  THD *thd;
unknown's avatar
unknown committed
156
  Select_fetch_protocol_binary result;
157
  Item_param **param_array;
158
  Server_side_cursor *cursor;
159 160
  uint param_count;
  uint last_errno;
161
  uint flags;
162 163
  char last_error[MYSQL_ERRMSG_SIZE];
#ifndef EMBEDDED_LIBRARY
164
  bool (*set_params)(Prepared_statement *st, uchar *data, uchar *data_end,
165
                     uchar *read_pos, String *expanded_query);
unknown's avatar
unknown committed
166
#else
167
  bool (*set_params_data)(Prepared_statement *st, String *expanded_query);
unknown's avatar
unknown committed
168
#endif
unknown's avatar
unknown committed
169
  bool (*set_params_from_vars)(Prepared_statement *stmt,
170 171
                               List<LEX_STRING>& varnames,
                               String *expanded_query);
172
public:
173
  Prepared_statement(THD *thd_arg);
174
  virtual ~Prepared_statement();
175
  void setup_set_params();
unknown's avatar
unknown committed
176
  virtual Query_arena::Type type() const;
177
  virtual void cleanup_stmt();
178
  bool set_name(LEX_STRING *name);
179
  inline void close_cursor() { delete cursor; cursor= 0; }
unknown's avatar
unknown committed
180
  inline bool is_in_use() { return flags & (uint) IS_IN_USE; }
181 182
  inline bool is_sql_prepare() const { return flags & (uint) IS_SQL_PREPARE; }
  void set_sql_prepare() { flags|= (uint) IS_SQL_PREPARE; }
183
  bool prepare(const char *packet, uint packet_length);
unknown's avatar
unknown committed
184 185 186
  bool execute_loop(String *expanded_query,
                    bool open_cursor,
                    uchar *packet_arg, uchar *packet_end_arg);
187
  bool execute_server_runnable(Server_runnable *server_runnable);
188
  /* Destroy this statement */
unknown's avatar
unknown committed
189
  void deallocate();
190 191 192 193 194 195
private:
  /**
    The memory root to allocate parsed tree elements (instances of Item,
    SELECT_LEX and other classes).
  */
  MEM_ROOT main_mem_root;
unknown's avatar
unknown committed
196 197 198 199 200 201 202 203
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);
204
};
205

206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
/**
  Execute one SQL statement in an isolated context.
*/

class Execute_sql_statement: public Server_runnable
{
public:
  Execute_sql_statement(LEX_STRING sql_text);
  virtual bool execute_server_code(THD *thd);
private:
  LEX_STRING m_sql_text;
};


class Ed_connection;

/**
  Protocol_local: a helper class to intercept the result
  of the data written to the network. 
*/

class Protocol_local :public Protocol
{
public:
  Protocol_local(THD *thd, Ed_connection *ed_connection);
  ~Protocol_local() { free_root(&m_rset_root, MYF(0)); }
protected:
  virtual void prepare_for_resend();
  virtual bool write();
  virtual bool store_null();
  virtual bool store_tiny(longlong from);
  virtual bool store_short(longlong from);
  virtual bool store_long(longlong from);
  virtual bool store_longlong(longlong from, bool unsigned_flag);
  virtual bool store_decimal(const my_decimal *);
  virtual bool store(const char *from, size_t length, CHARSET_INFO *cs);
  virtual bool store(const char *from, size_t length,
                     CHARSET_INFO *fromcs, CHARSET_INFO *tocs);
Sergei Golubchik's avatar
Sergei Golubchik committed
244
  virtual bool store(MYSQL_TIME *time, int decimals);
245
  virtual bool store_date(MYSQL_TIME *time);
Sergei Golubchik's avatar
Sergei Golubchik committed
246
  virtual bool store_time(MYSQL_TIME *time, int decimals);
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
  virtual bool store(float value, uint32 decimals, String *buffer);
  virtual bool store(double value, uint32 decimals, String *buffer);
  virtual bool store(Field *field);

  virtual bool send_result_set_metadata(List<Item> *list, uint flags);
  virtual bool send_out_parameters(List<Item_param> *sp_params);
#ifdef EMBEDDED_LIBRARY
  void remove_last_row();
#endif
  virtual enum enum_protocol_type type() { return PROTOCOL_LOCAL; };

  virtual bool send_ok(uint server_status, uint statement_warn_count,
                       ulonglong affected_rows, ulonglong last_insert_id,
                       const char *message);

  virtual bool send_eof(uint server_status, uint statement_warn_count);
  virtual bool send_error(uint sql_errno, const char *err_msg, const char* sqlstate);
private:
  bool store_string(const char *str, size_t length,
                    CHARSET_INFO *src_cs, CHARSET_INFO *dst_cs);

  bool store_column(const void *data, size_t length);
  void opt_add_row_to_rset();
private:
  Ed_connection *m_connection;
  MEM_ROOT m_rset_root;
  List<Ed_row> *m_rset;
  size_t m_column_count;
  Ed_column *m_current_row;
  Ed_column *m_current_column;
};
unknown's avatar
unknown committed
278

279 280 281
/******************************************************************************
  Implementation
******************************************************************************/
282 283


284
inline bool is_param_null(const uchar *pos, ulong param_no)
285
{
286
  return pos[param_no/8] & (1 << (param_no & 7));
287 288
}

unknown's avatar
unknown committed
289
/**
290 291 292 293
  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
294 295 296 297 298 299
  @param thd                thread handle
  @param id                 statement id
  @param where              the place from which this function is called (for
                            error reporting).

  @return
300
    0 if the statement was not found, a pointer otherwise.
301 302
*/

303
static Prepared_statement *
unknown's avatar
unknown committed
304
find_prepared_statement(THD *thd, ulong id)
305
{
306 307 308 309 310
  /*
    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.
  */
311 312
  Statement *stmt= thd->stmt_map.find(id);

unknown's avatar
unknown committed
313
  if (stmt == 0 || stmt->type() != Query_arena::PREPARED_STATEMENT)
unknown's avatar
unknown committed
314 315
    return NULL;

316
  return (Prepared_statement *) stmt;
317 318
}

319

unknown's avatar
unknown committed
320
/**
321 322
  Send prepared statement id and metadata to the client after prepare.

unknown's avatar
unknown committed
323 324
  @todo
    Fix this nasty upcast from List<Item_param> to List<Item>
325

unknown's avatar
unknown committed
326
  @return
327
    0 in case of success, 1 otherwise
328 329
*/

unknown's avatar
unknown committed
330
#ifndef EMBEDDED_LIBRARY
331
static bool send_prep_stmt(Prepared_statement *stmt, uint columns)
332
{
333
  NET *net= &stmt->thd->net;
334
  uchar buff[12];
unknown's avatar
unknown committed
335
  uint tmp;
336 337
  int error;
  THD *thd= stmt->thd;
unknown's avatar
unknown committed
338
  DBUG_ENTER("send_prep_stmt");
339 340
  DBUG_PRINT("enter",("stmt->id: %lu  columns: %d  param_count: %d",
                      stmt->id, columns, stmt->param_count));
unknown's avatar
unknown committed
341

342
  buff[0]= 0;                                   /* OK packet indicator */
343
  int4store(buff+1, stmt->id);
344 345
  int2store(buff+5, columns);
  int2store(buff+7, stmt->param_count);
unknown's avatar
unknown committed
346
  buff[9]= 0;                                   // Guard against a 4.1 client
Marc Alff's avatar
Marc Alff committed
347
  tmp= min(stmt->thd->warning_info->statement_warn_count(), 65535);
unknown's avatar
unknown committed
348 349
  int2store(buff+10, tmp);

350 351 352 353
  /*
    Send types and names of placeholders to the client
    XXX: fix this nasty upcast from List<Item_param> to List<Item>
  */
354 355 356
  error= my_net_write(net, buff, sizeof(buff));
  if (stmt->param_count && ! error)
  {
357
    error= thd->protocol_text.send_result_set_metadata((List<Item> *)
358 359 360
                                          &stmt->lex->param_list,
                                          Protocol::SEND_EOF);
  }
361 362 363

  if (!error)
    /* Flag that a response has already been sent */
364
    thd->stmt_da->disable_status();
365

366
  DBUG_RETURN(error);
unknown's avatar
unknown committed
367
}
368
#else
369 370
static bool send_prep_stmt(Prepared_statement *stmt,
                           uint columns __attribute__((unused)))
unknown's avatar
unknown committed
371
{
unknown's avatar
SCRUM  
unknown committed
372 373
  THD *thd= stmt->thd;

374
  thd->client_stmt_id= stmt->id;
unknown's avatar
SCRUM  
unknown committed
375
  thd->client_param_count= stmt->param_count;
unknown's avatar
unknown committed
376
  thd->clear_error();
Marc Alff's avatar
Marc Alff committed
377
  thd->stmt_da->disable_status();
unknown's avatar
unknown committed
378

unknown's avatar
SCRUM  
unknown committed
379
  return 0;
380
}
unknown's avatar
unknown committed
381
#endif /*!EMBEDDED_LIBRARY*/
382

unknown's avatar
unknown committed
383

unknown's avatar
unknown committed
384 385 386
#ifndef EMBEDDED_LIBRARY

/**
387 388 389 390 391 392
  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
393 394 395 396
  @param packet             a pointer to the data
  @param len                remaining packet length

  @return
397
    Length of data piece.
unknown's avatar
unknown committed
398 399
*/

400
static ulong get_param_length(uchar **packet, ulong len)
unknown's avatar
unknown committed
401 402
{
  reg1 uchar *pos= *packet;
403 404
  if (len < 1)
    return 0;
unknown's avatar
unknown committed
405 406 407 408 409
  if (*pos < 251)
  {
    (*packet)++;
    return (ulong) *pos;
  }
410 411
  if (len < 3)
    return 0;
unknown's avatar
unknown committed
412 413 414 415 416
  if (*pos == 252)
  {
    (*packet)+=3;
    return (ulong) uint2korr(pos+1);
  }
417 418
  if (len < 4)
    return 0;
unknown's avatar
unknown committed
419 420 421 422 423
  if (*pos == 253)
  {
    (*packet)+=4;
    return (ulong) uint3korr(pos+1);
  }
424 425
  if (len < 5)
    return 0;
unknown's avatar
unknown committed
426
  (*packet)+=9; // Must be 254 when here
427 428 429 430 431 432 433
  /*
    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
434 435
  return (ulong) uint4korr(pos+1);
}
unknown's avatar
unknown committed
436
#else
437
#define get_param_length(packet, len) len
unknown's avatar
unknown committed
438 439
#endif /*!EMBEDDED_LIBRARY*/

unknown's avatar
unknown committed
440 441
/**
  Data conversion routines.
unknown's avatar
unknown committed
442

443 444
    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
445

446 447 448
    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
449

unknown's avatar
unknown committed
450 451 452
  @param  param             parameter item
  @param  pos               input data buffer
  @param  len               length of data in the buffer
unknown's avatar
unknown committed
453 454
*/

455
static void set_param_tiny(Item_param *param, uchar **pos, ulong len)
unknown's avatar
unknown committed
456
{
457 458 459 460
#ifndef EMBEDDED_LIBRARY
  if (len < 1)
    return;
#endif
461
  int8 value= (int8) **pos;
unknown's avatar
unknown committed
462
  param->set_int(param->unsigned_flag ? (longlong) ((uint8) value) :
463
                                        (longlong) value, 4);
unknown's avatar
unknown committed
464 465 466
  *pos+= 1;
}

467
static void set_param_short(Item_param *param, uchar **pos, ulong len)
unknown's avatar
unknown committed
468
{
469
  int16 value;
470 471 472
#ifndef EMBEDDED_LIBRARY
  if (len < 2)
    return;
473
  value= sint2korr(*pos);
474 475
#else
  shortget(value, *pos);
476
#endif
477
  param->set_int(param->unsigned_flag ? (longlong) ((uint16) value) :
478
                                        (longlong) value, 6);
unknown's avatar
unknown committed
479 480 481
  *pos+= 2;
}

482
static void set_param_int32(Item_param *param, uchar **pos, ulong len)
unknown's avatar
unknown committed
483
{
484
  int32 value;
485 486 487
#ifndef EMBEDDED_LIBRARY
  if (len < 4)
    return;
488
  value= sint4korr(*pos);
489 490
#else
  longget(value, *pos);
491
#endif
492
  param->set_int(param->unsigned_flag ? (longlong) ((uint32) value) :
493
                                        (longlong) value, 11);
unknown's avatar
unknown committed
494 495 496
  *pos+= 4;
}

497
static void set_param_int64(Item_param *param, uchar **pos, ulong len)
unknown's avatar
unknown committed
498
{
499
  longlong value;
500 501 502
#ifndef EMBEDDED_LIBRARY
  if (len < 8)
    return;
503
  value= (longlong) sint8korr(*pos);
504 505
#else
  longlongget(value, *pos);
506
#endif
507
  param->set_int(value, 21);
unknown's avatar
unknown committed
508 509 510
  *pos+= 8;
}

511
static void set_param_float(Item_param *param, uchar **pos, ulong len)
unknown's avatar
unknown committed
512
{
unknown's avatar
unknown committed
513
  float data;
514 515 516
#ifndef EMBEDDED_LIBRARY
  if (len < 4)
    return;
unknown's avatar
unknown committed
517
  float4get(data,*pos);
unknown's avatar
unknown committed
518
#else
519
  floatget(data, *pos);
unknown's avatar
unknown committed
520
#endif
unknown's avatar
unknown committed
521 522 523 524
  param->set_double((double) data);
  *pos+= 4;
}

525
static void set_param_double(Item_param *param, uchar **pos, ulong len)
unknown's avatar
unknown committed
526
{
unknown's avatar
unknown committed
527
  double data;
528 529 530
#ifndef EMBEDDED_LIBRARY
  if (len < 8)
    return;
unknown's avatar
unknown committed
531
  float8get(data,*pos);
unknown's avatar
unknown committed
532
#else
533
  doubleget(data, *pos);
unknown's avatar
unknown committed
534
#endif
unknown's avatar
unknown committed
535 536 537 538
  param->set_double((double) data);
  *pos+= 8;
}

unknown's avatar
unknown committed
539 540 541 542
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);
543
  *pos+= length;
unknown's avatar
unknown committed
544 545
}

546
#ifndef EMBEDDED_LIBRARY
547 548 549 550 551 552 553

/*
  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
554 555 556 557
/**
  @todo
    Add warning 'Data truncated' here
*/
558
static void set_param_time(Item_param *param, uchar **pos, ulong len)
559
{
560 561
  MYSQL_TIME tm;
  ulong length= get_param_length(pos, len);
562

563
  if (length >= 8)
564 565
  {
    uchar *to= *pos;
566
    uint day;
567

568 569
    tm.neg= (bool) to[0];
    day= (uint) sint4korr(to+1);
570
    tm.hour=   (uint) to[5] + day * 24;
571 572
    tm.minute= (uint) to[6];
    tm.second= (uint) to[7];
573
    tm.second_part= (length > 8) ? (ulong) sint4korr(to+8) : 0;
574 575 576 577 578 579 580 581
    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;
582
  }
583
  else
584
    set_zero_time(&tm, MYSQL_TIMESTAMP_TIME);
585
  param->set_time(&tm, MYSQL_TIMESTAMP_TIME, MAX_TIME_FULL_WIDTH);
586 587 588
  *pos+= length;
}

589
static void set_param_datetime(Item_param *param, uchar **pos, ulong len)
590
{
591 592
  MYSQL_TIME tm;
  ulong length= get_param_length(pos, len);
593

594
  if (length >= 4)
595 596
  {
    uchar *to= *pos;
597 598 599 600 601

    tm.neg=    0;
    tm.year=   (uint) sint2korr(to);
    tm.month=  (uint) to[2];
    tm.day=    (uint) to[3];
602 603 604 605 606 607 608 609 610
    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;

611
    tm.second_part= (length > 7) ? (ulong) sint4korr(to+7) : 0;
612
  }
613
  else
614
    set_zero_time(&tm, MYSQL_TIMESTAMP_DATETIME);
615 616
  param->set_time(&tm, MYSQL_TIMESTAMP_DATETIME,
                  MAX_DATETIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
617 618 619
  *pos+= length;
}

620

621
static void set_param_date(Item_param *param, uchar **pos, ulong len)
622
{
623 624 625 626
  MYSQL_TIME tm;
  ulong length= get_param_length(pos, len);

  if (length >= 4)
627 628
  {
    uchar *to= *pos;
629

630
    tm.year=  (uint) sint2korr(to);
631 632 633 634 635 636 637
    tm.month=  (uint) to[2];
    tm.day= (uint) to[3];

    tm.hour= tm.minute= tm.second= 0;
    tm.second_part= 0;
    tm.neg= 0;
  }
638
  else
639
    set_zero_time(&tm, MYSQL_TIMESTAMP_DATE);
640 641
  param->set_time(&tm, MYSQL_TIMESTAMP_DATE,
                  MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
642 643 644
  *pos+= length;
}

645
#else/*!EMBEDDED_LIBRARY*/
unknown's avatar
unknown committed
646 647 648 649
/**
  @todo
    Add warning 'Data truncated' here
*/
650 651
void set_param_time(Item_param *param, uchar **pos, ulong len)
{
652 653 654 655 656 657 658 659 660 661 662
  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,
663
                  MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
664 665 666 667 668

}

void set_param_datetime(Item_param *param, uchar **pos, ulong len)
{
669 670
  MYSQL_TIME tm= *((MYSQL_TIME*)*pos);
  tm.neg= 0;
671

672
  param->set_time(&tm, MYSQL_TIMESTAMP_DATETIME,
673
                  MAX_DATETIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
674 675 676 677 678 679
}

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

680
  param->set_time(to, MYSQL_TIMESTAMP_DATE,
681
                  MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
682 683 684
}
#endif /*!EMBEDDED_LIBRARY*/

685 686

static void set_param_str(Item_param *param, uchar **pos, ulong len)
unknown's avatar
unknown committed
687
{
688
  ulong length= get_param_length(pos, len);
689 690
  if (length > len)
    length= len;
691
  param->set_str((const char *)*pos, length);
692
  *pos+= length;
unknown's avatar
unknown committed
693 694
}

695

unknown's avatar
unknown committed
696
#undef get_param_length
697 698 699

static void setup_one_conversion_function(THD *thd, Item_param *param,
                                          uchar param_type)
unknown's avatar
unknown committed
700
{
unknown's avatar
unknown committed
701
  switch (param_type) {
702
  case MYSQL_TYPE_TINY:
703
    param->set_param_func= set_param_tiny;
704
    param->item_type= Item::INT_ITEM;
705
    param->item_result_type= INT_RESULT;
unknown's avatar
unknown committed
706
    break;
707
  case MYSQL_TYPE_SHORT:
708
    param->set_param_func= set_param_short;
709
    param->item_type= Item::INT_ITEM;
710
    param->item_result_type= INT_RESULT;
unknown's avatar
unknown committed
711
    break;
712
  case MYSQL_TYPE_LONG:
713
    param->set_param_func= set_param_int32;
714
    param->item_type= Item::INT_ITEM;
715
    param->item_result_type= INT_RESULT;
unknown's avatar
unknown committed
716
    break;
717
  case MYSQL_TYPE_LONGLONG:
718
    param->set_param_func= set_param_int64;
719
    param->item_type= Item::INT_ITEM;
720
    param->item_result_type= INT_RESULT;
unknown's avatar
unknown committed
721
    break;
722
  case MYSQL_TYPE_FLOAT:
723
    param->set_param_func= set_param_float;
724
    param->item_type= Item::REAL_ITEM;
725
    param->item_result_type= REAL_RESULT;
unknown's avatar
unknown committed
726
    break;
727
  case MYSQL_TYPE_DOUBLE:
728
    param->set_param_func= set_param_double;
729
    param->item_type= Item::REAL_ITEM;
730
    param->item_result_type= REAL_RESULT;
unknown's avatar
unknown committed
731
    break;
unknown's avatar
unknown committed
732 733 734 735 736 737
  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;
738
  case MYSQL_TYPE_TIME:
739
    param->set_param_func= set_param_time;
740
    param->item_type= Item::STRING_ITEM;
741
    param->item_result_type= STRING_RESULT;
742
    break;
743
  case MYSQL_TYPE_DATE:
744
    param->set_param_func= set_param_date;
745
    param->item_type= Item::STRING_ITEM;
746
    param->item_result_type= STRING_RESULT;
747
    break;
748 749
  case MYSQL_TYPE_DATETIME:
  case MYSQL_TYPE_TIMESTAMP:
750
    param->set_param_func= set_param_datetime;
751
    param->item_type= Item::STRING_ITEM;
752
    param->item_result_type= STRING_RESULT;
753
    break;
754 755 756 757
  case MYSQL_TYPE_TINY_BLOB:
  case MYSQL_TYPE_MEDIUM_BLOB:
  case MYSQL_TYPE_LONG_BLOB:
  case MYSQL_TYPE_BLOB:
758
    param->set_param_func= set_param_str;
759 760 761
    param->value.cs_info.character_set_of_placeholder= &my_charset_bin;
    param->value.cs_info.character_set_client=
      thd->variables.character_set_client;
762
    DBUG_ASSERT(thd->variables.character_set_client);
763 764
    param->value.cs_info.final_character_set_of_str_value= &my_charset_bin;
    param->item_type= Item::STRING_ITEM;
765
    param->item_result_type= STRING_RESULT;
766 767 768 769 770 771 772 773 774 775 776 777
    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;

778
      param->value.cs_info.character_set_of_placeholder= fromcs;
779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796
      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
797
  }
798
  param->param_type= (enum enum_field_types) param_type;
unknown's avatar
unknown committed
799 800
}

unknown's avatar
unknown committed
801
#ifndef EMBEDDED_LIBRARY
802 803 804 805 806 807 808 809 810 811 812 813

/**
  Check whether this parameter data type is compatible with long data.
  Used to detect whether a long data stream has been supplied to a
  incompatible data type.
*/
inline bool is_param_long_data_type(Item_param *param)
{
  return ((param->param_type >= MYSQL_TYPE_TINY_BLOB) &&
          (param->param_type <= MYSQL_TYPE_STRING));
}

814

unknown's avatar
unknown committed
815
/**
816 817 818 819 820
  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
821
  @note
822
    This function, along with other _with_log functions is called when one of
823 824 825 826 827 828
    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
829
    @verbatim
830
     mysqld_stmt_prepare("UPDATE t1 SET a=a*1.25 WHERE a=?")
831
       --> general logs gets [Prepare] UPDATE t1 SET a*1.25 WHERE a=?"
832
     mysqld_stmt_execute(stmt);
833 834
       --> general and binary logs get
                             [Execute] UPDATE t1 SET a*1.25 WHERE a=1"
unknown's avatar
unknown committed
835 836 837 838
    @endverbatim

    If a statement has been prepared using SQL syntax:
    @verbatim
839 840 841 842 843
     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
844 845
                             [Query]   EXECUTE stmt USING @a;
    @endverbatim
846

unknown's avatar
unknown committed
847 848 849 850
  @retval
    0  if success
  @retval
    1  otherwise
unknown's avatar
unknown committed
851 852
*/

853 854 855
static bool insert_params_with_log(Prepared_statement *stmt, uchar *null_array,
                                   uchar *read_pos, uchar *data_end,
                                   String *query)
856
{
857 858 859 860
  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
861
  String str;
862
  const String *res;
863
  DBUG_ENTER("insert_params_with_log");
864

865
  if (query->copy(stmt->query(), stmt->query_length(), default_charset_info))
866
    DBUG_RETURN(1);
unknown's avatar
unknown committed
867

868
  for (Item_param **it= begin; it < end; ++it)
869
  {
870
    Item_param *param= *it;
871
    if (param->state != Item_param::LONG_DATA_VALUE)
872
    {
873
      if (is_param_null(null_array, (uint) (it - begin)))
874
        param->set_null();
875 876
      else
      {
877 878
        if (read_pos >= data_end)
          DBUG_RETURN(1);
879
        param->set_param_func(param, &read_pos, (uint) (data_end - read_pos));
880 881
        if (param->state == Item_param::NO_VALUE)
          DBUG_RETURN(1);
882

883
        if (param->limit_clause_param && param->state != Item_param::INT_VALUE)
884 885 886 887 888 889
        {
          param->set_int(param->val_int(), MY_INT64_NUM_DECIMAL_DIGITS);
          param->item_type= Item::INT_ITEM;
          if (!param->unsigned_flag && param->value.integer < 0)
            DBUG_RETURN(1);
        }
890 891
      }
    }
892 893 894 895 896 897
    /*
      A long data stream was supplied for this parameter marker.
      This was done after prepare, prior to providing a placeholder
      type (the types are supplied at execute). Check that the
      supplied type of placeholder can accept a data stream.
    */
898
    else if (! is_param_long_data_type(param))
899
      DBUG_RETURN(1);
900
    res= param->query_val_str(thd, &str);
901 902 903
    if (param->convert_str_value(thd))
      DBUG_RETURN(1);                           /* out of memory */

904
    if (query->replace(param->pos_in_query+length, 1, *res))
905
      DBUG_RETURN(1);
unknown's avatar
unknown committed
906

907 908 909 910 911
    length+= res->length()-1;
  }
  DBUG_RETURN(0);
}

912

913
static bool insert_params(Prepared_statement *stmt, uchar *null_array,
unknown's avatar
unknown committed
914
                          uchar *read_pos, uchar *data_end,
915
                          String *expanded_query)
916
{
917 918
  Item_param **begin= stmt->param_array;
  Item_param **end= begin + stmt->param_count;
919

unknown's avatar
unknown committed
920
  DBUG_ENTER("insert_params");
921

922
  for (Item_param **it= begin; it < end; ++it)
923
  {
924
    Item_param *param= *it;
925
    if (param->state != Item_param::LONG_DATA_VALUE)
926
    {
927
      if (is_param_null(null_array, (uint) (it - begin)))
928
        param->set_null();
929 930
      else
      {
931 932
        if (read_pos >= data_end)
          DBUG_RETURN(1);
933
        param->set_param_func(param, &read_pos, (uint) (data_end - read_pos));
934 935
        if (param->state == Item_param::NO_VALUE)
          DBUG_RETURN(1);
936 937
      }
    }
938 939 940 941 942 943
    /*
      A long data stream was supplied for this parameter marker.
      This was done after prepare, prior to providing a placeholder
      type (the types are supplied at execute). Check that the
      supplied type of placeholder can accept a data stream.
    */
944
    else if (! is_param_long_data_type(param))
945
      DBUG_RETURN(1);
946 947
    if (param->convert_str_value(stmt->thd))
      DBUG_RETURN(1);                           /* out of memory */
948 949 950 951
  }
  DBUG_RETURN(0);
}

952

953
static bool setup_conversion_functions(Prepared_statement *stmt,
954
                                       uchar **data, uchar *data_end)
955 956 957
{
  /* skip null bits */
  uchar *read_pos= *data + (stmt->param_count+7) / 8;
unknown's avatar
unknown committed
958

959
  DBUG_ENTER("setup_conversion_functions");
960

unknown's avatar
unknown committed
961
  if (*read_pos++) //types supplied / first execute
962
  {
unknown's avatar
unknown committed
963
    /*
unknown's avatar
unknown committed
964
      First execute or types altered by the client, setup the
unknown's avatar
unknown committed
965 966
      conversion routines for all parameters (one time)
    */
967 968
    Item_param **it= stmt->param_array;
    Item_param **end= it + stmt->param_count;
969
    THD *thd= stmt->thd;
970 971
    for (; it < end; ++it)
    {
972 973 974
      ushort typecode;
      const uint signed_bit= 1 << 15;

975 976
      if (read_pos >= data_end)
        DBUG_RETURN(1);
977 978

      typecode= sint2korr(read_pos);
unknown's avatar
unknown committed
979
      read_pos+= 2;
980
      (**it).unsigned_flag= test(typecode & signed_bit);
981
      setup_one_conversion_function(thd, *it, (uchar) (typecode & ~signed_bit));
unknown's avatar
unknown committed
982
    }
983 984
  }
  *data= read_pos;
unknown's avatar
unknown committed
985 986 987
  DBUG_RETURN(0);
}

988 989
#else

unknown's avatar
unknown committed
990
/**
991 992 993 994
  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
995

996 997 998 999 1000
    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).
*/

1001
static bool emb_insert_params(Prepared_statement *stmt, String *expanded_query)
1002
{
1003
  THD *thd= stmt->thd;
1004 1005
  Item_param **it= stmt->param_array;
  Item_param **end= it + stmt->param_count;
1006 1007
  MYSQL_BIND *client_param= stmt->thd->client_params;

1008
  DBUG_ENTER("emb_insert_params");
1009

1010 1011 1012
  for (; it < end; ++it, ++client_param)
  {
    Item_param *param= *it;
1013 1014
    setup_one_conversion_function(thd, param, client_param->buffer_type);
    if (param->state != Item_param::LONG_DATA_VALUE)
1015 1016
    {
      if (*client_param->is_null)
1017
        param->set_null();
1018 1019
      else
      {
1020
        uchar *buff= (uchar*) client_param->buffer;
unknown's avatar
unknown committed
1021
        param->unsigned_flag= client_param->is_unsigned;
1022
        param->set_param_func(param, &buff,
unknown's avatar
unknown committed
1023 1024
                              client_param->length ?
                              *client_param->length :
1025
                              client_param->buffer_length);
1026 1027
        if (param->state == Item_param::NO_VALUE)
          DBUG_RETURN(1);
1028 1029
      }
    }
1030 1031
    if (param->convert_str_value(thd))
      DBUG_RETURN(1);                           /* out of memory */
1032 1033 1034 1035
  }
  DBUG_RETURN(0);
}

1036

1037 1038
static bool emb_insert_params_with_log(Prepared_statement *stmt,
                                       String *query)
1039
{
1040
  THD *thd= stmt->thd;
1041 1042
  Item_param **it= stmt->param_array;
  Item_param **end= it + stmt->param_count;
1043 1044
  MYSQL_BIND *client_param= thd->client_params;

1045
  String str;
1046
  const String *res;
1047
  uint32 length= 0;
1048

1049
  DBUG_ENTER("emb_insert_params_with_log");
1050

1051
  if (query->copy(stmt->query(), stmt->query_length(), default_charset_info))
1052
    DBUG_RETURN(1);
unknown's avatar
unknown committed
1053

1054 1055 1056
  for (; it < end; ++it, ++client_param)
  {
    Item_param *param= *it;
1057 1058
    setup_one_conversion_function(thd, param, client_param->buffer_type);
    if (param->state != Item_param::LONG_DATA_VALUE)
1059 1060
    {
      if (*client_param->is_null)
1061
        param->set_null();
1062 1063
      else
      {
1064
        uchar *buff= (uchar*)client_param->buffer;
unknown's avatar
unknown committed
1065
        param->unsigned_flag= client_param->is_unsigned;
1066
        param->set_param_func(param, &buff,
unknown's avatar
unknown committed
1067 1068
                              client_param->length ?
                              *client_param->length :
1069
                              client_param->buffer_length);
1070 1071
        if (param->state == Item_param::NO_VALUE)
          DBUG_RETURN(1);
1072 1073
      }
    }
1074
    res= param->query_val_str(thd, &str);
1075 1076 1077
    if (param->convert_str_value(thd))
      DBUG_RETURN(1);                           /* out of memory */

1078
    if (query->replace(param->pos_in_query+length, 1, *res))
1079
      DBUG_RETURN(1);
1080

1081 1082 1083 1084 1085
    length+= res->length()-1;
  }
  DBUG_RETURN(0);
}

unknown's avatar
unknown committed
1086 1087
#endif /*!EMBEDDED_LIBRARY*/

unknown's avatar
unknown committed
1088 1089 1090
/**
  Setup data conversion routines using an array of parameter
  markers from the original prepared statement.
1091
  Swap the parameter data of the original prepared
unknown's avatar
unknown committed
1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136
  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
1137

unknown's avatar
unknown committed
1138
/**
1139 1140
  Assign prepared statement parameters from user variables.

unknown's avatar
unknown committed
1141 1142 1143 1144 1145
  @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
1146 1147
*/

1148 1149
static bool insert_params_from_vars(Prepared_statement *stmt,
                                    List<LEX_STRING>& varnames,
1150
                                    String *query __attribute__((unused)))
unknown's avatar
unknown committed
1151 1152 1153 1154 1155 1156
{
  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);
1157 1158
  DBUG_ENTER("insert_params_from_vars");

unknown's avatar
unknown committed
1159 1160 1161 1162
  for (Item_param **it= begin; it < end; ++it)
  {
    Item_param *param= *it;
    varname= var_it++;
Konstantin Osipov's avatar
Konstantin Osipov committed
1163 1164 1165
    entry= (user_var_entry*)my_hash_search(&stmt->thd->user_vars,
                                           (uchar*) varname->str,
                                           varname->length);
1166 1167 1168
    if (param->set_from_user_var(stmt->thd, entry) ||
        param->convert_str_value(stmt->thd))
      DBUG_RETURN(1);
unknown's avatar
unknown committed
1169 1170 1171 1172
  }
  DBUG_RETURN(0);
}

1173

unknown's avatar
unknown committed
1174
/**
1175 1176
  Do the same as insert_params_from_vars but also construct query text for
  binary log.
1177

unknown's avatar
unknown committed
1178 1179 1180 1181 1182 1183
  @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.
1184 1185
*/

unknown's avatar
unknown committed
1186
static bool insert_params_from_vars_with_log(Prepared_statement *stmt,
1187
                                             List<LEX_STRING>& varnames,
1188
                                             String *query)
unknown's avatar
unknown committed
1189 1190 1191 1192 1193 1194
{
  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);
1195 1196
  String buf;
  const String *val;
unknown's avatar
unknown committed
1197
  uint32 length= 0;
unknown's avatar
unknown committed
1198
  THD *thd= stmt->thd;
1199

1200
  DBUG_ENTER("insert_params_from_vars_with_log");
1201

1202
  if (query->copy(stmt->query(), stmt->query_length(), default_charset_info))
1203
    DBUG_RETURN(1);
unknown's avatar
unknown committed
1204 1205 1206 1207 1208 1209

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

Konstantin Osipov's avatar
Konstantin Osipov committed
1210 1211
    entry= (user_var_entry *) my_hash_search(&thd->user_vars, (uchar*)
                                             varname->str, varname->length);
unknown's avatar
unknown committed
1212 1213 1214 1215 1216 1217 1218
    /*
      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))
1219
      DBUG_RETURN(1);
1220
    val= param->query_val_str(thd, &buf);
1221

unknown's avatar
unknown committed
1222
    if (param->convert_str_value(thd))
1223
      DBUG_RETURN(1);                           /* out of memory */
1224

1225
    if (query->replace(param->pos_in_query+length, 1, *val))
1226
      DBUG_RETURN(1);
1227
    length+= val->length()-1;
unknown's avatar
unknown committed
1228 1229 1230 1231
  }
  DBUG_RETURN(0);
}

unknown's avatar
unknown committed
1232
/**
1233
  Validate INSERT statement.
unknown's avatar
unknown committed
1234

unknown's avatar
unknown committed
1235 1236
  @param stmt               prepared statement
  @param tables             global/local table list
unknown's avatar
unknown committed
1237

unknown's avatar
unknown committed
1238 1239 1240 1241
  @retval
    FALSE             success
  @retval
    TRUE              error, error message is set in THD
unknown's avatar
unknown committed
1242
*/
unknown's avatar
unknown committed
1243

unknown's avatar
unknown committed
1244 1245
static bool mysql_test_insert(Prepared_statement *stmt,
                              TABLE_LIST *table_list,
unknown's avatar
unknown committed
1246
                              List<Item> &fields,
unknown's avatar
unknown committed
1247 1248 1249 1250
                              List<List_item> &values_list,
                              List<Item> &update_fields,
                              List<Item> &update_values,
                              enum_duplicates duplic)
unknown's avatar
unknown committed
1251
{
1252
  THD *thd= stmt->thd;
unknown's avatar
unknown committed
1253 1254
  List_iterator_fast<List_item> its(values_list);
  List_item *values;
1255
  DBUG_ENTER("mysql_test_insert");
unknown's avatar
unknown committed
1256

unknown's avatar
unknown committed
1257 1258
  if (insert_precheck(thd, table_list))
    goto error;
unknown's avatar
unknown committed
1259

1260 1261
  //upgrade_lock_type_for_insert(thd, &table_list->lock_type, duplic,
  //                             values_list.elements > 1);
1262
  /*
unknown's avatar
unknown committed
1263 1264 1265 1266 1267 1268
    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
1269
  */
1270
  if (open_normal_and_derived_tables(thd, table_list,
Sergei Golubchik's avatar
Sergei Golubchik committed
1271
                                     MYSQL_OPEN_FORCE_SHARED_MDL, DT_INIT))
unknown's avatar
unknown committed
1272
    goto error;
unknown's avatar
unknown committed
1273

unknown's avatar
unknown committed
1274 1275 1276
  if ((values= its++))
  {
    uint value_count;
1277
    ulong counter= 0;
unknown's avatar
unknown committed
1278
    Item *unused_conds= 0;
unknown's avatar
unknown committed
1279

unknown's avatar
unknown committed
1280
    if (table_list->table)
1281 1282
    {
      // don't allocate insert_values
1283
      table_list->table->insert_values=(uchar *)1;
1284 1285
    }

unknown's avatar
unknown committed
1286 1287
    if (mysql_prepare_insert(thd, table_list, table_list->table,
                             fields, values, update_fields, update_values,
unknown's avatar
unknown committed
1288
                             duplic, &unused_conds, FALSE, FALSE, FALSE))
unknown's avatar
unknown committed
1289
      goto error;
1290

unknown's avatar
unknown committed
1291 1292
    value_count= values->elements;
    its.rewind();
1293

unknown's avatar
unknown committed
1294
    if (table_list->lock_type == TL_WRITE_DELAYED &&
1295
        !(table_list->table->file->ha_table_flags() & HA_CAN_INSERT_DELAYED))
unknown's avatar
unknown committed
1296
    {
1297 1298 1299
      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
1300 1301
      goto error;
    }
1302
    while ((values= its++))
unknown's avatar
unknown committed
1303 1304 1305 1306
    {
      counter++;
      if (values->elements != value_count)
      {
1307
        my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter);
1308
        goto error;
unknown's avatar
unknown committed
1309
      }
1310
      if (setup_fields(thd, 0, *values, MARK_COLUMNS_NONE, 0, NULL, 0))
unknown's avatar
unknown committed
1311
        goto error;
unknown's avatar
unknown committed
1312 1313
    }
  }
unknown's avatar
unknown committed
1314
  DBUG_RETURN(FALSE);
1315 1316

error:
1317
  /* insert_values is cleared in open_table */
unknown's avatar
unknown committed
1318
  DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
1319 1320 1321
}


unknown's avatar
unknown committed
1322 1323 1324 1325 1326
/**
  Validate UPDATE statement.

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

unknown's avatar
unknown committed
1328 1329
  @todo
    - here we should send types of placeholders to the client.
unknown's avatar
unknown committed
1330

unknown's avatar
unknown committed
1331 1332 1333 1334 1335 1336
  @retval
    0                 success
  @retval
    1                 error, error message is set in THD
  @retval
    2                 convert to multi_update
unknown's avatar
unknown committed
1337
*/
unknown's avatar
unknown committed
1338

unknown's avatar
unknown committed
1339
static int mysql_test_update(Prepared_statement *stmt,
unknown's avatar
unknown committed
1340
                              TABLE_LIST *table_list)
unknown's avatar
unknown committed
1341
{
unknown's avatar
unknown committed
1342
  int res;
1343
  THD *thd= stmt->thd;
unknown's avatar
unknown committed
1344
  uint table_count= 0;
unknown's avatar
unknown committed
1345
  SELECT_LEX *select= &stmt->lex->select_lex;
1346
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
1347
  uint          want_privilege;
1348
#endif
unknown's avatar
unknown committed
1349 1350
  DBUG_ENTER("mysql_test_update");

1351
  if (update_precheck(thd, table_list) ||
1352
      open_tables(thd, &table_list, &table_count, MYSQL_OPEN_FORCE_SHARED_MDL))
unknown's avatar
unknown committed
1353 1354
    goto error;

1355 1356 1357 1358
  if (mysql_handle_derived(thd->lex, DT_INIT))
    goto error;

  if (table_list->is_multitable())
1359
  {
1360 1361 1362 1363 1364 1365
    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
1366
  }
unknown's avatar
unknown committed
1367

unknown's avatar
unknown committed
1368 1369 1370 1371
  /*
    thd->fill_derived_tables() is false here for sure (because it is
    preparation of PS, so we even do not check it).
  */
Igor Babaev's avatar
Igor Babaev committed
1372 1373 1374
  if (table_list->handle_derived(thd->lex, DT_MERGE_FOR_INSERT))
    goto error;
  if (table_list->handle_derived(thd->lex, DT_PREPARE))
1375 1376
    goto error;

1377
  if (!table_list->single_table_updatable())
1378 1379
  {
    my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "UPDATE");
unknown's avatar
unknown committed
1380
    goto error;
1381
  }
unknown's avatar
unknown committed
1382

1383
#ifndef NO_EMBEDDED_ACCESS_CHECKS
1384 1385 1386
  /* Force privilege re-checking for views after they have been opened. */
  want_privilege= (table_list->view ? UPDATE_ACL :
                   table_list->grant.want_privilege);
1387 1388
#endif

unknown's avatar
unknown committed
1389 1390
  if (mysql_prepare_update(thd, table_list, &select->where,
                           select->order_list.elements,
1391
                           select->order_list.first))
unknown's avatar
unknown committed
1392 1393
    goto error;

1394
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
1395 1396
  table_list->grant.want_privilege= want_privilege;
  table_list->table->grant.want_privilege= want_privilege;
1397
  table_list->register_want_access(want_privilege);
1398
#endif
1399
  thd->lex->select_lex.no_wrap_view_item= TRUE;
1400
  res= setup_fields(thd, 0, select->item_list, MARK_COLUMNS_READ, 0, NULL, 0);
1401
  thd->lex->select_lex.no_wrap_view_item= FALSE;
unknown's avatar
unknown committed
1402 1403
  if (res)
    goto error;
1404
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
1405 1406 1407 1408
  /* Check values */
  table_list->grant.want_privilege=
  table_list->table->grant.want_privilege=
    (SELECT_ACL & ~table_list->table->grant.privilege);
1409
  table_list->register_want_access(SELECT_ACL);
1410
#endif
1411 1412
  if (setup_fields(thd, 0, stmt->lex->value_list, MARK_COLUMNS_NONE, 0, NULL,
                   0) ||
1413
      check_unique_table(thd, table_list))
unknown's avatar
unknown committed
1414
    goto error;
unknown's avatar
unknown committed
1415
  /* TODO: here we should send types of placeholders to the client. */
unknown's avatar
unknown committed
1416 1417 1418
  DBUG_RETURN(0);
error:
  DBUG_RETURN(1);
unknown's avatar
unknown committed
1419 1420 1421
}


unknown's avatar
unknown committed
1422
/**
1423
  Validate DELETE statement.
unknown's avatar
unknown committed
1424

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

unknown's avatar
unknown committed
1428 1429 1430 1431
  @retval
    FALSE             success
  @retval
    TRUE              error, error message is set in THD
unknown's avatar
unknown committed
1432
*/
unknown's avatar
unknown committed
1433 1434 1435

static bool mysql_test_delete(Prepared_statement *stmt,
                              TABLE_LIST *table_list)
unknown's avatar
unknown committed
1436
{
1437
  uint table_count= 0;
1438
  THD *thd= stmt->thd;
unknown's avatar
unknown committed
1439 1440
  LEX *lex= stmt->lex;
  DBUG_ENTER("mysql_test_delete");
unknown's avatar
unknown committed
1441

unknown's avatar
unknown committed
1442
  if (delete_precheck(thd, table_list) ||
Sergei Golubchik's avatar
Sergei Golubchik committed
1443
      open_tables(thd, &table_list, &table_count, MYSQL_OPEN_FORCE_SHARED_MDL))
unknown's avatar
unknown committed
1444
    goto error;
unknown's avatar
unknown committed
1445

Igor Babaev's avatar
Igor Babaev committed
1446 1447 1448 1449 1450
  if (mysql_handle_derived(thd->lex, DT_INIT))
    goto error;
  if (mysql_handle_derived(thd->lex, DT_MERGE_FOR_INSERT))
    goto error;
  if (mysql_handle_derived(thd->lex, DT_PREPARE))
unknown's avatar
unknown committed
1451
    goto error;
unknown's avatar
unknown committed
1452

1453
  if (!table_list->single_table_updatable())
1454 1455 1456 1457 1458
  {
    my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "DELETE");
    goto error;
  }
  if (!table_list->table || !table_list->table->created)
unknown's avatar
unknown committed
1459
  {
unknown's avatar
unknown committed
1460 1461 1462
    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
1463
  }
unknown's avatar
unknown committed
1464 1465 1466

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

unknown's avatar
unknown committed
1470

unknown's avatar
unknown committed
1471
/**
unknown's avatar
unknown committed
1472 1473
  Validate SELECT statement.

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

unknown's avatar
unknown committed
1477 1478 1479 1480 1481 1482 1483 1484 1485
  @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
1486
*/
1487

1488
static int mysql_test_select(Prepared_statement *stmt,
unknown's avatar
unknown committed
1489
                             TABLE_LIST *tables)
unknown's avatar
unknown committed
1490
{
1491
  THD *thd= stmt->thd;
1492
  LEX *lex= stmt->lex;
1493
  SELECT_LEX_UNIT *unit= &lex->unit;
unknown's avatar
unknown committed
1494
  DBUG_ENTER("mysql_test_select");
unknown's avatar
unknown committed
1495

1496 1497
  lex->select_lex.context.resolve_in_select_list= TRUE;

1498 1499 1500
  ulong privilege= lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL;
  if (tables)
  {
1501
    if (check_table_access(thd, privilege, tables, FALSE, UINT_MAX, FALSE))
unknown's avatar
unknown committed
1502
      goto error;
1503
  }
Marc Alff's avatar
Marc Alff committed
1504
  else if (check_access(thd, privilege, any_db, NULL, NULL, 0, 0))
unknown's avatar
unknown committed
1505
    goto error;
unknown's avatar
unknown committed
1506

unknown's avatar
unknown committed
1507
  if (!lex->result && !(lex->result= new (stmt->mem_root) select_send))
unknown's avatar
unknown committed
1508
  {
1509 1510
    my_error(ER_OUTOFMEMORY, MYF(ME_FATALERROR), 
             static_cast<int>(sizeof(select_send)));
unknown's avatar
unknown committed
1511 1512
    goto error;
  }
1513

Sergei Golubchik's avatar
Sergei Golubchik committed
1514
  if (open_normal_and_derived_tables(thd, tables,  MYSQL_OPEN_FORCE_SHARED_MDL,
1515
                                     DT_PREPARE | DT_CREATE))
unknown's avatar
unknown committed
1516
    goto error;
unknown's avatar
unknown committed
1517

1518
  thd->lex->used_tables= 0;                        // Updated by setup_fields
1519

1520 1521 1522 1523 1524
  /*
    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
  */
1525
  if (unit->prepare(thd, 0, 0))
unknown's avatar
unknown committed
1526
    goto error;
1527
  if (!lex->describe && !stmt->is_sql_prepare())
1528
  {
1529 1530
    /* Make copy of item list, as change_columns may change it */
    List<Item> fields(lex->select_lex.item_list);
1531

1532 1533 1534
    /* Change columns if a procedure like analyse() */
    if (unit->last_procedure && unit->last_procedure->change_columns(fields))
      goto error;
1535

1536 1537 1538 1539 1540
    /*
      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)) ||
1541
        lex->result->send_result_set_metadata(fields, Protocol::SEND_EOF) ||
1542 1543 1544
        thd->protocol->flush())
      goto error;
    DBUG_RETURN(2);
1545
  }
1546
  DBUG_RETURN(0);
unknown's avatar
unknown committed
1547
error:
1548
  DBUG_RETURN(1);
unknown's avatar
unknown committed
1549 1550
}

1551

unknown's avatar
unknown committed
1552
/**
1553
  Validate and prepare for execution DO statement expressions.
1554

unknown's avatar
unknown committed
1555 1556 1557
  @param stmt               prepared statement
  @param tables             list of tables used in this query
  @param values             list of expressions
1558

unknown's avatar
unknown committed
1559 1560 1561 1562
  @retval
    FALSE             success
  @retval
    TRUE              error, error message is set in THD
1563 1564
*/

unknown's avatar
unknown committed
1565
static bool mysql_test_do_fields(Prepared_statement *stmt,
unknown's avatar
unknown committed
1566 1567
                                TABLE_LIST *tables,
                                List<Item> *values)
1568 1569
{
  THD *thd= stmt->thd;
unknown's avatar
unknown committed
1570 1571

  DBUG_ENTER("mysql_test_do_fields");
1572 1573
  if (tables && check_table_access(thd, SELECT_ACL, tables, FALSE,
                                   UINT_MAX, FALSE))
unknown's avatar
unknown committed
1574
    DBUG_RETURN(TRUE);
1575

Sergei Golubchik's avatar
Sergei Golubchik committed
1576
  if (open_normal_and_derived_tables(thd, tables, MYSQL_OPEN_FORCE_SHARED_MDL,
1577
                                     DT_PREPARE | DT_CREATE))
unknown's avatar
unknown committed
1578
    DBUG_RETURN(TRUE);
1579
  DBUG_RETURN(setup_fields(thd, 0, *values, MARK_COLUMNS_NONE, 0, NULL, 0));
1580 1581 1582
}


unknown's avatar
unknown committed
1583 1584
/**
  Validate and prepare for execution SET statement expressions.
1585

unknown's avatar
unknown committed
1586 1587 1588
  @param stmt               prepared statement
  @param tables             list of tables used in this query
  @param values             list of expressions
1589

unknown's avatar
unknown committed
1590 1591 1592 1593
  @retval
    FALSE             success
  @retval
    TRUE              error, error message is set in THD
1594
*/
unknown's avatar
unknown committed
1595

unknown's avatar
unknown committed
1596 1597 1598
static bool mysql_test_set_fields(Prepared_statement *stmt,
                                  TABLE_LIST *tables,
                                  List<set_var_base> *var_list)
1599 1600 1601 1602 1603
{
  DBUG_ENTER("mysql_test_set_fields");
  List_iterator_fast<set_var_base> it(*var_list);
  THD *thd= stmt->thd;
  set_var_base *var;
1604

1605
  if ((tables &&
Sergei Golubchik's avatar
Sergei Golubchik committed
1606 1607
       check_table_access(thd, SELECT_ACL, tables, FALSE, UINT_MAX, FALSE)) ||
      open_normal_and_derived_tables(thd, tables, MYSQL_OPEN_FORCE_SHARED_MDL,
1608
                                     DT_PREPARE | DT_CREATE))
1609
    goto error;
unknown's avatar
unknown committed
1610

1611 1612 1613 1614 1615
  while ((var= it++))
  {
    if (var->light_check(thd))
      goto error;
  }
unknown's avatar
unknown committed
1616
  DBUG_RETURN(FALSE);
1617
error:
unknown's avatar
unknown committed
1618
  DBUG_RETURN(TRUE);
1619 1620 1621
}


1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642
/**
  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;

1643
  if ((tables &&
Sergei Golubchik's avatar
Sergei Golubchik committed
1644 1645
       check_table_access(thd, SELECT_ACL, tables, FALSE, UINT_MAX, FALSE)) ||
      open_normal_and_derived_tables(thd, tables, MYSQL_OPEN_FORCE_SHARED_MDL, DT_PREPARE))
1646 1647 1648 1649
    goto err;

  while ((item= it++))
  {
Staale Smedseng's avatar
Staale Smedseng committed
1650
    if ((!item->fixed && item->fix_fields(thd, it.ref())) ||
1651 1652 1653 1654 1655 1656 1657 1658 1659
        item->check_cols(1))
      goto err;
  }
  DBUG_RETURN(FALSE);
err:
  DBUG_RETURN(TRUE);
}


unknown's avatar
unknown committed
1660 1661
/**
  Check internal SELECT of the prepared command.
1662

unknown's avatar
unknown committed
1663 1664 1665
  @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()
1666

unknown's avatar
unknown committed
1667
  @note
1668 1669
    This function won't directly open tables used in select. They should
    be opened either by calling function (and in this case you probably
1670
    should use select_like_stmt_test_with_open()) or by
1671
    "specific_prepare" call (like this happens in case of multi-update).
1672

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

static bool select_like_stmt_test(Prepared_statement *stmt,
1680
                                  int (*specific_prepare)(THD *thd),
1681
                                  ulong setup_tables_done_option)
1682
{
1683
  DBUG_ENTER("select_like_stmt_test");
1684 1685 1686
  THD *thd= stmt->thd;
  LEX *lex= stmt->lex;

1687 1688
  lex->select_lex.context.resolve_in_select_list= TRUE;

unknown's avatar
unknown committed
1689 1690
  if (specific_prepare && (*specific_prepare)(thd))
    DBUG_RETURN(TRUE);
unknown's avatar
VIEW  
unknown committed
1691

1692
  thd->lex->used_tables= 0;                        // Updated by setup_fields
1693

unknown's avatar
unknown committed
1694
  /* Calls JOIN::prepare */
1695
  DBUG_RETURN(lex->unit.prepare(thd, 0, setup_tables_done_option));
1696 1697
}

unknown's avatar
unknown committed
1698
/**
1699 1700
  Check internal SELECT of the prepared command (with opening of used
  tables).
1701

unknown's avatar
unknown committed
1702 1703 1704 1705 1706
  @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()
1707

unknown's avatar
unknown committed
1708
  @retval
1709
    FALSE                success
unknown's avatar
unknown committed
1710
  @retval
1711
    TRUE                 error
1712 1713 1714
*/

static bool
1715 1716
select_like_stmt_test_with_open(Prepared_statement *stmt,
                                TABLE_LIST *tables,
1717
                                int (*specific_prepare)(THD *thd),
1718
                                ulong setup_tables_done_option)
1719
{
1720
  uint table_count= 0;
1721
  DBUG_ENTER("select_like_stmt_test_with_open");
1722 1723

  /*
1724 1725 1726 1727
    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.
1728
  */
1729
  THD *thd= stmt->thd;
Sergei Golubchik's avatar
Sergei Golubchik committed
1730
  if (open_tables(thd, &tables, &table_count, MYSQL_OPEN_FORCE_SHARED_MDL))
1731 1732 1733 1734 1735 1736 1737
    DBUG_RETURN(TRUE);

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


unknown's avatar
unknown committed
1738 1739
/**
  Validate and prepare for execution CREATE TABLE statement.
1740

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

unknown's avatar
unknown committed
1744 1745 1746 1747
  @retval
    FALSE             success
  @retval
    TRUE              error, error message is set in THD
1748
*/
unknown's avatar
unknown committed
1749

unknown's avatar
unknown committed
1750
static bool mysql_test_create_table(Prepared_statement *stmt)
1751 1752 1753 1754
{
  DBUG_ENTER("mysql_test_create_table");
  THD *thd= stmt->thd;
  LEX *lex= stmt->lex;
1755
  SELECT_LEX *select_lex= &lex->select_lex;
unknown's avatar
unknown committed
1756
  bool res= FALSE;
unknown's avatar
VIEW  
unknown committed
1757
  bool link_to_local;
1758 1759
  TABLE_LIST *create_table= lex->query_tables;
  TABLE_LIST *tables= lex->create_last_non_select_table->next_global;
1760

unknown's avatar
unknown committed
1761 1762 1763 1764
  if (create_table_precheck(thd, tables, create_table))
    DBUG_RETURN(TRUE);

  if (select_lex->item_list.elements)
1765
  {
1766
    /* Base table and temporary table are not in the same name space. */
unknown's avatar
unknown committed
1767
    if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
1768
      create_table->open_type= OT_BASE_ONLY;
unknown's avatar
unknown committed
1769

1770
    if (open_normal_and_derived_tables(stmt->thd, lex->query_tables,
Sergei Golubchik's avatar
Sergei Golubchik committed
1771
                                       MYSQL_OPEN_FORCE_SHARED_MDL,
1772
                                       DT_PREPARE | DT_CREATE))
unknown's avatar
unknown committed
1773 1774
      DBUG_RETURN(TRUE);

1775
    select_lex->context.resolve_in_select_list= TRUE;
unknown's avatar
unknown committed
1776

1777 1778
    lex->unlink_first_table(&link_to_local);

unknown's avatar
unknown committed
1779
    res= select_like_stmt_test(stmt, 0, 0);
1780

1781
    lex->link_first_table_back(create_table, link_to_local);
1782
  }
1783
  else
1784 1785 1786 1787 1788 1789 1790
  {
    /*
      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.
    */
1791
    if (open_normal_and_derived_tables(stmt->thd, lex->query_tables,
Sergei Golubchik's avatar
Sergei Golubchik committed
1792
                                       MYSQL_OPEN_FORCE_SHARED_MDL,
1793
                                       DT_PREPARE))
1794 1795
      DBUG_RETURN(TRUE);
  }
1796 1797 1798 1799

  DBUG_RETURN(res);
}

unknown's avatar
unknown committed
1800

unknown's avatar
unknown committed
1801
/**
1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825
  @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;

Sergei Golubchik's avatar
Sergei Golubchik committed
1826 1827
  if (open_normal_and_derived_tables(thd, tables, MYSQL_OPEN_FORCE_SHARED_MDL,
                                     DT_PREPARE))
1828 1829
    goto err;

Sergey Glukhov's avatar
Sergey Glukhov committed
1830
  lex->context_analysis_only|=  CONTEXT_ANALYSIS_ONLY_VIEW;
1831 1832 1833 1834 1835 1836 1837 1838 1839
  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);
}


1840
/*
1841
  Validate and prepare for execution a multi update statement.
1842

unknown's avatar
unknown committed
1843 1844 1845
  @param stmt               prepared statement
  @param tables             list of tables used in this query
  @param converted          converted to multi-update from usual update
1846

unknown's avatar
unknown committed
1847 1848 1849 1850
  @retval
    FALSE             success
  @retval
    TRUE              error, error message is set in THD
1851
*/
unknown's avatar
unknown committed
1852 1853

static bool mysql_test_multiupdate(Prepared_statement *stmt,
unknown's avatar
unknown committed
1854
                                  TABLE_LIST *tables,
1855
                                  bool converted)
1856
{
1857
  /* if we switched from normal update, rights are checked */
unknown's avatar
merge  
unknown committed
1858
  if (!converted && multi_update_precheck(stmt->thd, tables))
unknown's avatar
unknown committed
1859
    return TRUE;
1860 1861 1862

  return select_like_stmt_test(stmt, &mysql_multi_update_prepare,
                               OPTION_SETUP_TABLES_DONE);
1863 1864 1865
}


unknown's avatar
unknown committed
1866
/**
1867
  Validate and prepare for execution a multi delete statement.
1868

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

unknown's avatar
unknown committed
1872 1873 1874 1875
  @retval
    FALSE             success
  @retval
    TRUE              error, error message in THD is set.
1876
*/
unknown's avatar
unknown committed
1877 1878

static bool mysql_test_multidelete(Prepared_statement *stmt,
unknown's avatar
unknown committed
1879
                                  TABLE_LIST *tables)
1880 1881 1882
{
  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
1883
  {
1884
    my_error(ER_OUTOFMEMORY, MYF(ME_FATALERROR), 0);
unknown's avatar
unknown committed
1885 1886
    goto error;
  }
1887

unknown's avatar
unknown committed
1888
  if (multi_delete_precheck(stmt->thd, tables) ||
1889 1890 1891
      select_like_stmt_test_with_open(stmt, tables,
                                      &mysql_multi_delete_prepare,
                                      OPTION_SETUP_TABLES_DONE))
unknown's avatar
unknown committed
1892
    goto error;
1893 1894 1895
  if (!tables->table)
  {
    my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
unknown's avatar
unknown committed
1896
             tables->view_db.str, tables->view_name.str);
unknown's avatar
unknown committed
1897
    goto error;
1898
  }
unknown's avatar
unknown committed
1899 1900 1901
  return FALSE;
error:
  return TRUE;
1902 1903 1904
}


unknown's avatar
unknown committed
1905
/**
1906
  Wrapper for mysql_insert_select_prepare, to make change of local tables
1907
  after open_normal_and_derived_tables() call.
1908

unknown's avatar
unknown committed
1909
  @param thd                thread handle
1910

unknown's avatar
unknown committed
1911
  @note
1912 1913 1914
    We need to remove the first local table after
    open_normal_and_derived_tables(), because mysql_handle_derived
    uses local tables lists.
1915 1916
*/

1917
static int mysql_insert_select_prepare_tester(THD *thd)
1918 1919
{
  SELECT_LEX *first_select= &thd->lex->select_lex;
1920
  TABLE_LIST *second_table= first_select->table_list.first->next_local;
1921

1922
  /* Skip first table, which is the table we are inserting in */
1923
  first_select->table_list.first= second_table;
1924 1925 1926 1927
  thd->lex->select_lex.context.table_list=
    thd->lex->select_lex.context.first_name_resolution_table= second_table;

  return mysql_insert_select_prepare(thd);
1928 1929 1930
}


unknown's avatar
unknown committed
1931
/**
1932
  Validate and prepare for execution INSERT ... SELECT statement.
1933

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

unknown's avatar
unknown committed
1937 1938 1939 1940
  @retval
    FALSE             success
  @retval
    TRUE              error, error message is set in THD
1941
*/
unknown's avatar
unknown committed
1942

1943 1944
static bool mysql_test_insert_select(Prepared_statement *stmt,
                                     TABLE_LIST *tables)
1945 1946 1947
{
  int res;
  LEX *lex= stmt->lex;
unknown's avatar
unknown committed
1948 1949
  TABLE_LIST *first_local_table;

1950 1951 1952
  if (tables->table)
  {
    // don't allocate insert_values
1953
    tables->table->insert_values=(uchar *)1;
1954
  }
unknown's avatar
unknown committed
1955

unknown's avatar
unknown committed
1956 1957
  if (insert_precheck(stmt->thd, tables))
    return 1;
1958 1959

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

1963
  res=
1964 1965 1966
    select_like_stmt_test_with_open(stmt, tables,
                                    &mysql_insert_select_prepare_tester,
                                    OPTION_SETUP_TABLES_DONE);
1967
  /* revert changes  made by mysql_insert_select_prepare_tester */
1968
  lex->select_lex.table_list.first= first_local_table;
1969 1970 1971
  return res;
}

1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991
/**
  Validate SELECT statement.

    In case of success, if this query is not EXPLAIN, send column list info
    back to the client.

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

static int mysql_test_handler_read(Prepared_statement *stmt,
                                   TABLE_LIST *tables)
{
  THD *thd= stmt->thd;
  LEX *lex= stmt->lex;
  SQL_HANDLER *ha_table;
1992
  DBUG_ENTER("mysql_test_handler_read");
1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013

  lex->select_lex.context.resolve_in_select_list= TRUE;

  /*
    We don't have to test for permissions as this is already done during
    HANDLER OPEN
  */
  if (!(ha_table= mysql_ha_read_prepare(thd, tables, lex->ha_read_mode,
                                        lex->ident.str,
                                        lex->insert_list,
                                        lex->select_lex.where)))
    DBUG_RETURN(1);

  if (!stmt->is_sql_prepare())
  {
    if (!lex->result && !(lex->result= new (stmt->mem_root) select_send))
    {
      my_error(ER_OUTOFMEMORY, MYF(0), sizeof(select_send));
      DBUG_RETURN(1);
    }
    if (send_prep_stmt(stmt, ha_table->fields.elements) ||
Sergei Golubchik's avatar
Sergei Golubchik committed
2014
        lex->result->send_result_set_metadata(ha_table->fields, Protocol::SEND_EOF) ||
2015 2016 2017 2018 2019 2020 2021
        thd->protocol->flush())
      DBUG_RETURN(1);
    DBUG_RETURN(2);
  }
  DBUG_RETURN(0);
}

2022

unknown's avatar
unknown committed
2023
/**
2024 2025 2026 2027 2028 2029 2030 2031
  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
2032 2033 2034 2035 2036 2037
  @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
2038
*/
2039

unknown's avatar
unknown committed
2040
static bool check_prepared_statement(Prepared_statement *stmt)
2041
{
2042
  THD *thd= stmt->thd;
2043
  LEX *lex= stmt->lex;
2044
  SELECT_LEX *select_lex= &lex->select_lex;
unknown's avatar
VIEW  
unknown committed
2045
  TABLE_LIST *tables;
2046
  enum enum_sql_command sql_command= lex->sql_command;
unknown's avatar
unknown committed
2047
  int res= 0;
2048
  DBUG_ENTER("check_prepared_statement");
unknown's avatar
unknown committed
2049
  DBUG_PRINT("enter",("command: %d  param_count: %u",
2050
                      sql_command, stmt->param_count));
2051

unknown's avatar
VIEW  
unknown committed
2052 2053
  lex->first_lists_tables_same();
  tables= lex->query_tables;
2054

2055 2056 2057 2058
  /* 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
2059 2060 2061 2062
  /* Reset warning count for each query that uses tables */
  if (tables)
    thd->warning_info->opt_clear_warning_info(thd->query_id);

2063
  switch (sql_command) {
2064
  case SQLCOM_REPLACE:
unknown's avatar
unknown committed
2065
  case SQLCOM_INSERT:
unknown's avatar
unknown committed
2066
    res= mysql_test_insert(stmt, tables, lex->field_list,
unknown's avatar
unknown committed
2067
                           lex->many_values,
unknown's avatar
unknown committed
2068
                           lex->update_list, lex->value_list,
unknown's avatar
unknown committed
2069
                           lex->duplicates);
unknown's avatar
unknown committed
2070 2071 2072
    break;

  case SQLCOM_UPDATE:
unknown's avatar
unknown committed
2073
    res= mysql_test_update(stmt, tables);
unknown's avatar
unknown committed
2074
    /* mysql_test_update returns 2 if we need to switch to multi-update */
2075 2076 2077
    if (res != 2)
      break;

2078
    /* fall through */
2079 2080
  case SQLCOM_UPDATE_MULTI:
    res= mysql_test_multiupdate(stmt, tables, res == 2);
unknown's avatar
unknown committed
2081 2082
    break;

unknown's avatar
unknown committed
2083
  case SQLCOM_DELETE:
unknown's avatar
unknown committed
2084
    res= mysql_test_delete(stmt, tables);
unknown's avatar
unknown committed
2085
    break;
2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100
  /* 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
2101
  case SQLCOM_SELECT:
unknown's avatar
unknown committed
2102
    res= mysql_test_select(stmt, tables);
2103 2104 2105 2106 2107 2108
    if (res == 2)
    {
      /* Statement and field info has already been sent */
      DBUG_RETURN(FALSE);
    }
    break;
2109
  case SQLCOM_CREATE_TABLE:
unknown's avatar
VIEW  
unknown committed
2110
    res= mysql_test_create_table(stmt);
2111
    break;
unknown's avatar
unknown committed
2112

2113 2114 2115 2116 2117 2118
  case SQLCOM_CREATE_VIEW:
    if (lex->create_view_mode == VIEW_ALTER)
    {
      my_message(ER_UNSUPPORTED_PS, ER(ER_UNSUPPORTED_PS), MYF(0));
      goto error;
    }
2119
    res= mysql_test_create_view(stmt);
2120
    break;
2121
  case SQLCOM_DO:
unknown's avatar
unknown committed
2122 2123
    res= mysql_test_do_fields(stmt, tables, lex->insert_list);
    break;
2124

2125 2126 2127
  case SQLCOM_CALL:
    res= mysql_test_call_fields(stmt, tables, &lex->value_list);
    break;
2128
  case SQLCOM_SET_OPTION:
unknown's avatar
unknown committed
2129
    res= mysql_test_set_fields(stmt, tables, &lex->var_list);
2130 2131 2132
    break;

  case SQLCOM_DELETE_MULTI:
unknown's avatar
unknown committed
2133
    res= mysql_test_multidelete(stmt, tables);
2134 2135 2136
    break;

  case SQLCOM_INSERT_SELECT:
2137
  case SQLCOM_REPLACE_SELECT:
unknown's avatar
unknown committed
2138
    res= mysql_test_insert_select(stmt, tables);
2139 2140
    break;

2141 2142
  case SQLCOM_HA_READ:
    res= mysql_test_handler_read(stmt, tables);
2143 2144
    /* Statement and field info has already been sent */
    DBUG_RETURN(res == 1 ? TRUE : FALSE);
2145

2146 2147 2148 2149
    /*
      Note that we don't need to have cases in this list if they are
      marked with CF_STATUS_COMMAND in sql_command_flags
    */
2150 2151
  case SQLCOM_DROP_TABLE:
  case SQLCOM_RENAME_TABLE:
2152 2153 2154 2155 2156 2157
  case SQLCOM_ALTER_TABLE:
  case SQLCOM_COMMIT:
  case SQLCOM_CREATE_INDEX:
  case SQLCOM_DROP_INDEX:
  case SQLCOM_ROLLBACK:
  case SQLCOM_TRUNCATE:
2158
  case SQLCOM_DROP_VIEW:
2159 2160 2161
  case SQLCOM_REPAIR:
  case SQLCOM_ANALYZE:
  case SQLCOM_OPTIMIZE:
2162 2163 2164 2165 2166 2167 2168 2169 2170
  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:
2171
  case SQLCOM_ALTER_DB_UPGRADE:
2172 2173 2174 2175 2176 2177 2178 2179 2180
  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:
2181 2182
    break;

2183 2184 2185
  case SQLCOM_PREPARE:
  case SQLCOM_EXECUTE:
  case SQLCOM_DEALLOCATE_PREPARE:
unknown's avatar
unknown committed
2186
  default:
2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197
    /*
      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
2198
  }
unknown's avatar
unknown committed
2199
  if (res == 0)
2200
    DBUG_RETURN(stmt->is_sql_prepare() ?
unknown's avatar
unknown committed
2201
                FALSE : (send_prep_stmt(stmt, 0) || thd->protocol->flush()));
2202
error:
unknown's avatar
unknown committed
2203
  DBUG_RETURN(TRUE);
unknown's avatar
unknown committed
2204 2205
}

unknown's avatar
unknown committed
2206
/**
2207 2208
  Initialize array of parameters in statement from LEX.
  (We need to have quick access to items by number in mysql_stmt_get_longdata).
2209
  This is to avoid using malloc/realloc in the parser.
unknown's avatar
unknown committed
2210
*/
unknown's avatar
unknown committed
2211

2212
static bool init_param_array(Prepared_statement *stmt)
unknown's avatar
unknown committed
2213
{
2214 2215 2216
  LEX *lex= stmt->lex;
  if ((stmt->param_count= lex->param_list.elements))
  {
2217 2218 2219
    if (stmt->param_count > (uint) UINT_MAX16)
    {
      /* Error code to be defined in 5.0 */
2220 2221
      my_message(ER_PS_MANY_PARAM, ER(ER_PS_MANY_PARAM), MYF(0));
      return TRUE;
2222
    }
2223 2224 2225 2226
    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
2227
                       alloc_root(stmt->thd->mem_root,
2228 2229
                                  sizeof(Item_param*) * stmt->param_count);
    if (!stmt->param_array)
2230
      return TRUE;
2231 2232 2233 2234 2235 2236 2237
    for (to= stmt->param_array;
         to < stmt->param_array + stmt->param_count;
         ++to)
    {
      *to= param_iterator++;
    }
  }
2238
  return FALSE;
unknown's avatar
unknown committed
2239
}
2240

2241

unknown's avatar
unknown committed
2242
/**
2243
  COM_STMT_PREPARE handler.
unknown's avatar
unknown committed
2244

2245 2246
    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
2247

2248
    If parameter markers are found in the query, then store the information
unknown's avatar
unknown committed
2249 2250
    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
2251
    field items.
unknown's avatar
unknown committed
2252

unknown's avatar
unknown committed
2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263
  @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
2264 2265
    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
2266 2267
*/

2268
void mysqld_stmt_prepare(THD *thd, const char *packet, uint packet_length)
unknown's avatar
unknown committed
2269
{
2270
  Protocol *save_protocol= thd->protocol;
unknown's avatar
unknown committed
2271
  Prepared_statement *stmt;
2272
  DBUG_ENTER("mysqld_stmt_prepare");
unknown's avatar
unknown committed
2273
  DBUG_PRINT("prep_query", ("%s", packet));
unknown's avatar
unknown committed
2274

unknown's avatar
unknown committed
2275
  /* First of all clear possible warnings from the previous command */
2276
  mysql_reset_thd_for_next_command(thd);
unknown's avatar
unknown committed
2277

2278
  if (! (stmt= new Prepared_statement(thd)))
2279
    goto end;           /* out of memory: error is set in Sql_alloc */
2280

2281
  if (thd->stmt_map.insert(thd, stmt))
2282
  {
2283
    /*
2284
      The error is set in the insert. The statement itself
2285 2286
      will be also deleted there (this is how the hash works).
    */
2287
    goto end;
2288
  }
unknown's avatar
unknown committed
2289

2290 2291
  thd->protocol= &thd->protocol_binary;

2292
  if (stmt->prepare(packet, packet_length))
2293
  {
2294 2295
    /* Statement map deletes statement on erase */
    thd->stmt_map.erase(stmt);
2296
  }
2297 2298 2299

  thd->protocol= save_protocol;

2300 2301 2302
  sp_cache_enforce_limit(thd->sp_proc_cache, stored_program_cache_size);
  sp_cache_enforce_limit(thd->sp_func_cache, stored_program_cache_size);

2303
  /* check_prepared_statemnt sends the metadata packet in case of success */
2304
end:
2305 2306 2307
  DBUG_VOID_RETURN;
}

unknown's avatar
unknown committed
2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323
/**
  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)
2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337
*/

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;
2338
    String *var_value= &str;
2339 2340 2341 2342 2343 2344 2345
    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=
Konstantin Osipov's avatar
Konstantin Osipov committed
2346 2347 2348
         (user_var_entry*)my_hash_search(&thd->user_vars,
                                         (uchar*)lex->prepared_stmt_code.str,
                                         lex->prepared_stmt_code.length))
2349 2350
        && entry->value)
    {
2351
      bool is_var_null;
2352
      var_value= entry->val_str(&is_var_null, &str, NOT_FIXED_DEC);
2353 2354 2355 2356 2357
      /*
        NULL value of variable checked early as entry->value so here
        we can't get NULL in normal conditions
      */
      DBUG_ASSERT(!is_var_null);
2358
      if (!var_value)
2359 2360 2361 2362 2363 2364 2365 2366
        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
      */
2367
      str.set(STRING_WITH_LEN("NULL"), &my_charset_latin1);
2368 2369
    }

2370 2371 2372
    needs_conversion= String::needs_conversion(var_value->length(),
                                               var_value->charset(), to_cs,
                                               &unused);
2373

2374 2375
    len= (needs_conversion ? var_value->length() * to_cs->mbmaxlen :
          var_value->length());
2376
    if (!(query_str= (char*) alloc_root(thd->mem_root, len+1)))
2377 2378 2379 2380 2381
      goto end;

    if (needs_conversion)
    {
      uint dummy_errors;
2382 2383 2384
      len= copy_and_convert(query_str, len, to_cs, var_value->ptr(),
                            var_value->length(), var_value->charset(),
                            &dummy_errors);
2385 2386
    }
    else
2387 2388
      memcpy(query_str, var_value->ptr(), var_value->length());
    query_str[len]= '\0';                       // Safety (mostly for debug)
2389
    *query_len= len;
2390
  }
2391
  else
unknown's avatar
unknown committed
2392
  {
2393 2394
    query_str= lex->prepared_stmt_code.str;
    *query_len= lex->prepared_stmt_code.length;
unknown's avatar
unknown committed
2395
  }
2396 2397
end:
  return query_str;
unknown's avatar
unknown committed
2398 2399
}

unknown's avatar
unknown committed
2400

unknown's avatar
unknown committed
2401
/**
2402 2403 2404 2405 2406 2407
  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
2408 2409 2410
  @param thd     thread handle

  @return
2411 2412 2413 2414 2415 2416 2417 2418 2419 2420
    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
2421
  uint query_len= 0;
2422
  DBUG_ENTER("mysql_sql_stmt_prepare");
2423

2424 2425 2426 2427 2428 2429
  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
2430 2431 2432
    if (stmt->is_in_use())
    {
      my_error(ER_PS_NO_RECURSION, MYF(0));
2433
      DBUG_VOID_RETURN;
unknown's avatar
unknown committed
2434 2435 2436
    }

    stmt->deallocate();
2437 2438 2439
  }

  if (! (query= get_dynamic_sql_string(lex, &query_len)) ||
2440
      ! (stmt= new Prepared_statement(thd)))
2441 2442 2443 2444
  {
    DBUG_VOID_RETURN;                           /* out of memory */
  }

2445 2446
  stmt->set_sql_prepare();

2447 2448
  /* Set the name first, insert should know that this statement has a name */
  if (stmt->set_name(name))
2449 2450 2451 2452
  {
    delete stmt;
    DBUG_VOID_RETURN;
  }
2453

2454
  if (thd->stmt_map.insert(thd, stmt))
2455
  {
2456
    /* The statement is deleted and an error is set if insert fails */
2457 2458 2459
    DBUG_VOID_RETURN;
  }

2460
  if (stmt->prepare(query, query_len))
2461 2462 2463 2464 2465
  {
    /* Statement map deletes the statement on erase */
    thd->stmt_map.erase(stmt);
  }
  else
2466
    my_ok(thd, 0L, 0L, "Statement prepared");
2467 2468 2469

  DBUG_VOID_RETURN;
}
2470

unknown's avatar
unknown committed
2471 2472 2473 2474 2475 2476 2477 2478
/**
  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
2479

2480
void reinit_stmt_before_use(THD *thd, LEX *lex)
2481
{
2482
  SELECT_LEX *sl= lex->all_selects_list;
2483
  DBUG_ENTER("reinit_stmt_before_use");
unknown's avatar
unknown committed
2484

2485 2486 2487 2488 2489 2490 2491
  /*
    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
2492 2493 2494
  if (lex->empty_field_list_on_rset)
  {
    lex->empty_field_list_on_rset= 0;
2495
    lex->field_list.empty();
unknown's avatar
VIEW  
unknown committed
2496
  }
2497
  for (; sl; sl= sl->next_select_in_list())
2498
  {
2499 2500
    if (!sl->first_execution)
    {
unknown's avatar
unknown committed
2501 2502 2503
      /* remove option which was put by mysql_explain_union() */
      sl->options&= ~SELECT_DESCRIBE;

2504 2505 2506
      /* see unique_table() */
      sl->exclude_from_table_unique_test= FALSE;

2507
      /*
unknown's avatar
unknown committed
2508 2509
        Copy WHERE, HAVING clause pointers to avoid damaging them
        by optimisation
2510
      */
unknown's avatar
unknown committed
2511 2512
      if (sl->prep_where)
      {
unknown's avatar
unknown committed
2513 2514 2515 2516 2517 2518
        /*
          We need this rollback because memory allocated in
          copy_andor_structure() will be freed
        */
        thd->change_item_tree((Item**)&sl->where,
                              sl->prep_where->copy_andor_structure(thd));
unknown's avatar
unknown committed
2519 2520
        sl->where->cleanup();
      }
2521 2522
      else
        sl->where= NULL;
unknown's avatar
unknown committed
2523 2524
      if (sl->prep_having)
      {
unknown's avatar
unknown committed
2525 2526 2527 2528 2529 2530
        /*
          We need this rollback because memory allocated in
          copy_andor_structure() will be freed
        */
        thd->change_item_tree((Item**)&sl->having,
                              sl->prep_having->copy_andor_structure(thd));
unknown's avatar
unknown committed
2531 2532
        sl->having->cleanup();
      }
2533 2534
      else
        sl->having= NULL;
unknown's avatar
unknown committed
2535
      DBUG_ASSERT(sl->join == 0);
2536 2537
      ORDER *order;
      /* Fix GROUP list */
2538 2539 2540 2541 2542 2543 2544 2545
      if (sl->group_list_ptrs && sl->group_list_ptrs->size() > 0)
      {
        for (uint ix= 0; ix < sl->group_list_ptrs->size() - 1; ++ix)
        {
          order= sl->group_list_ptrs->at(ix);
          order->next= sl->group_list_ptrs->at(ix+1);
        }
      }
2546
      for (order= sl->group_list.first; order; order= order->next)
2547 2548
        order->item= &order->item_ptr;
      /* Fix ORDER list */
2549
      for (order= sl->order_list.first; order; order= order->next)
2550
        order->item= &order->item_ptr;
2551 2552 2553 2554 2555 2556 2557
      {
#ifndef DBUG_OFF
        bool res=
#endif
          sl->handle_derived(lex, DT_REINIT);
        DBUG_ASSERT(res == 0);
      }
2558
    }
2559 2560 2561 2562
    {
      SELECT_LEX_UNIT *unit= sl->master_unit();
      unit->unclean();
      unit->types.empty();
2563
      /* for derived tables & PS (which can't be reset by Item_subquery) */
2564
      unit->reinit_exec_mechanism();
2565
      unit->set_thd(thd);
2566
    }
2567
  }
unknown's avatar
VIEW  
unknown committed
2568 2569

  /*
unknown's avatar
unknown committed
2570 2571
    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
2572 2573
    and open the tables back.
  */
2574 2575 2576 2577 2578
  /*
    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
2579
  for (TABLE_LIST *tables= lex->query_tables;
2580 2581
       tables;
       tables= tables->next_global)
unknown's avatar
VIEW  
unknown committed
2582
  {
2583 2584
    tables->reinit_before_use(thd);
  }
Konstantin Osipov's avatar
Konstantin Osipov committed
2585 2586 2587 2588 2589 2590 2591

  /* Reset MDL tickets for procedures/functions */
  for (Sroutine_hash_entry *rt=
         (Sroutine_hash_entry*)thd->lex->sroutines_list.first;
       rt; rt= rt->next)
    rt->mdl_request.ticket= NULL;

2592 2593 2594 2595 2596
  /*
    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.
  */
2597
  for (TABLE_LIST *tables= lex->auxiliary_table_list.first;
2598
       tables;
2599
       tables= tables->next_global)
unknown's avatar
VIEW  
unknown committed
2600
  {
2601
    tables->reinit_before_use(thd);
unknown's avatar
VIEW  
unknown committed
2602
  }
2603
  lex->current_select= &lex->select_lex;
2604 2605


2606
  if (lex->result)
2607
  {
2608
    lex->result->cleanup();
2609 2610
    lex->result->set_thd(thd);
  }
unknown's avatar
unknown committed
2611 2612
  lex->allow_sum_func= 0;
  lex->in_sum_func= NULL;
2613
  DBUG_VOID_RETURN;
2614 2615
}

2616

unknown's avatar
unknown committed
2617 2618
/**
  Clears parameters from data left from previous execution or long data.
unknown's avatar
unknown committed
2619

unknown's avatar
unknown committed
2620 2621
  @param stmt               prepared statement for which parameters should
                            be reset
2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632
*/

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
2633
/**
2634
  COM_STMT_EXECUTE handler: execute a previously prepared statement.
2635

2636 2637 2638 2639 2640
    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
2641 2642 2643 2644 2645
  @param thd                current thread
  @param packet_arg         parameter types and data, if any
  @param packet_length      packet length, including the terminator character.

  @return
2646 2647
    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
2648 2649
*/

2650
void mysqld_stmt_execute(THD *thd, char *packet_arg, uint packet_length)
unknown's avatar
unknown committed
2651
{
2652
  uchar *packet= (uchar*)packet_arg; // GCC 4.0.1 workaround
unknown's avatar
unknown committed
2653
  ulong stmt_id= uint4korr(packet);
unknown's avatar
unknown committed
2654
  ulong flags= (ulong) packet[4];
2655
  /* Query text for binary, general or slow log, if any of them is open */
2656
  String expanded_query;
2657
  uchar *packet_end= packet + packet_length;
2658
  Prepared_statement *stmt;
2659
  Protocol *save_protocol= thd->protocol;
unknown's avatar
unknown committed
2660
  bool open_cursor;
2661
  DBUG_ENTER("mysqld_stmt_execute");
2662 2663

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

unknown's avatar
unknown committed
2665
  /* First of all clear possible warnings from the previous command */
2666
  mysql_reset_thd_for_next_command(thd);
unknown's avatar
unknown committed
2667

unknown's avatar
unknown committed
2668 2669 2670
  if (!(stmt= find_prepared_statement(thd, stmt_id)))
  {
    char llbuf[22];
2671
    my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), static_cast<int>(sizeof(llbuf)),
2672
             llstr(stmt_id, llbuf), "mysqld_stmt_execute");
2673
    DBUG_VOID_RETURN;
unknown's avatar
unknown committed
2674
  }
2675

2676
#if defined(ENABLED_PROFILING)
2677
  thd->profiling.set_query_source(stmt->query(), stmt->query_length());
2678
#endif
2679
  DBUG_PRINT("exec_query", ("%s", stmt->query()));
unknown's avatar
unknown committed
2680
  DBUG_PRINT("info",("stmt: 0x%lx", (long) stmt));
unknown's avatar
unknown committed
2681

unknown's avatar
unknown committed
2682
  open_cursor= test(flags & (ulong) CURSOR_TYPE_READ_ONLY);
2683

2684
  thd->protocol= &thd->protocol_binary;
unknown's avatar
unknown committed
2685
  stmt->execute_loop(&expanded_query, open_cursor, packet, packet_end);
2686
  thd->protocol= save_protocol;
2687

2688 2689 2690
  sp_cache_enforce_limit(thd->sp_proc_cache, stored_program_cache_size);
  sp_cache_enforce_limit(thd->sp_func_cache, stored_program_cache_size);

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

2694
  DBUG_VOID_RETURN;
unknown's avatar
unknown committed
2695 2696
}

2697

unknown's avatar
unknown committed
2698
/**
2699 2700 2701 2702 2703 2704 2705 2706 2707
  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
2708 2709 2710
  @param thd                thread handle

  @return
2711 2712
    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
2713 2714
*/

2715
void mysql_sql_stmt_execute(THD *thd)
unknown's avatar
unknown committed
2716
{
2717
  LEX *lex= thd->lex;
2718
  Prepared_statement *stmt;
2719 2720
  LEX_STRING *name= &lex->prepared_stmt_name;
  /* Query text for binary, general or slow log, if any of them is open */
2721
  String expanded_query;
2722
  DBUG_ENTER("mysql_sql_stmt_execute");
2723
  DBUG_PRINT("info", ("EXECUTE: %.*s\n", (int) name->length, name->str));
2724

2725
  if (!(stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name)))
2726
  {
2727
    my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0),
2728
             static_cast<int>(name->length), name->str, "EXECUTE");
2729
    DBUG_VOID_RETURN;
2730 2731
  }

2732
  if (stmt->param_count != lex->prepared_stmt_params.elements)
unknown's avatar
unknown committed
2733
  {
2734
    my_error(ER_WRONG_ARGUMENTS, MYF(0), "EXECUTE");
unknown's avatar
unknown committed
2735 2736 2737
    DBUG_VOID_RETURN;
  }

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

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

unknown's avatar
unknown committed
2742 2743 2744
  DBUG_VOID_RETURN;
}

2745

unknown's avatar
unknown committed
2746 2747
/**
  COM_STMT_FETCH handler: fetches requested amount of rows from cursor.
unknown's avatar
unknown committed
2748

unknown's avatar
unknown committed
2749 2750 2751
  @param thd                Thread handle
  @param packet             Packet from client (with stmt_id & num_rows)
  @param packet_length      Length of packet
2752 2753
*/

2754
void mysqld_stmt_fetch(THD *thd, char *packet, uint packet_length)
2755 2756 2757
{
  /* assume there is always place for 8-16 bytes */
  ulong stmt_id= uint4korr(packet);
2758
  ulong num_rows= uint4korr(packet+4);
2759
  Prepared_statement *stmt;
unknown's avatar
unknown committed
2760
  Statement stmt_backup;
2761
  Server_side_cursor *cursor;
2762
  DBUG_ENTER("mysqld_stmt_fetch");
2763

unknown's avatar
unknown committed
2764
  /* First of all clear possible warnings from the previous command */
2765
  mysql_reset_thd_for_next_command(thd);
2766

2767
  status_var_increment(thd->status_var.com_stmt_fetch);
unknown's avatar
unknown committed
2768 2769 2770
  if (!(stmt= find_prepared_statement(thd, stmt_id)))
  {
    char llbuf[22];
2771
    my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), static_cast<int>(sizeof(llbuf)),
2772
             llstr(stmt_id, llbuf), "mysqld_stmt_fetch");
2773
    DBUG_VOID_RETURN;
unknown's avatar
unknown committed
2774
  }
2775

2776
  cursor= stmt->cursor;
2777
  if (!cursor)
2778
  {
2779
    my_error(ER_STMT_HAS_NO_OPEN_CURSOR, MYF(0), stmt_id);
2780 2781
    DBUG_VOID_RETURN;
  }
2782

unknown's avatar
unknown committed
2783
  thd->stmt_arena= stmt;
unknown's avatar
unknown committed
2784
  thd->set_n_backup_statement(stmt, &stmt_backup);
2785

2786
  cursor->fetch(num_rows);
2787

2788
  if (!cursor->is_open())
2789
  {
2790
    stmt->close_cursor();
2791 2792 2793
    reset_stmt_params(stmt);
  }

2794
  thd->restore_backup_statement(stmt, &stmt_backup);
unknown's avatar
unknown committed
2795
  thd->stmt_arena= thd;
2796

2797 2798 2799 2800
  DBUG_VOID_RETURN;
}


unknown's avatar
unknown committed
2801
/**
2802
  Reset a prepared statement in case there was a recoverable error.
2803

2804 2805
    This function resets statement to the state it was right after prepare.
    It can be used to:
2806
    - clear an error happened during mysqld_stmt_send_long_data
unknown's avatar
unknown committed
2807
    - cancel long data stream for all placeholders without
2808
      having to call mysqld_stmt_execute.
unknown's avatar
unknown committed
2809
    - close an open cursor
2810 2811
    Sends 'OK' packet in case of success (statement was reset)
    or 'ERROR' packet (unrecoverable error/statement not found/etc).
unknown's avatar
unknown committed
2812 2813 2814

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

2817
void mysqld_stmt_reset(THD *thd, char *packet)
unknown's avatar
unknown committed
2818
{
2819
  /* There is always space for 4 bytes in buffer */
2820
  ulong stmt_id= uint4korr(packet);
2821
  Prepared_statement *stmt;
2822
  DBUG_ENTER("mysqld_stmt_reset");
unknown's avatar
unknown committed
2823

unknown's avatar
unknown committed
2824
  /* First of all clear possible warnings from the previous command */
2825
  mysql_reset_thd_for_next_command(thd);
unknown's avatar
unknown committed
2826

2827
  status_var_increment(thd->status_var.com_stmt_reset);
unknown's avatar
unknown committed
2828 2829 2830
  if (!(stmt= find_prepared_statement(thd, stmt_id)))
  {
    char llbuf[22];
2831
    my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), static_cast<int>(sizeof(llbuf)),
2832
             llstr(stmt_id, llbuf), "mysqld_stmt_reset");
2833
    DBUG_VOID_RETURN;
unknown's avatar
unknown committed
2834
  }
2835

2836 2837 2838 2839
  stmt->close_cursor();

  /*
    Clear parameters from data which could be set by
2840
    mysqld_stmt_send_long_data() call.
2841 2842
  */
  reset_stmt_params(stmt);
2843

2844
  stmt->state= Query_arena::STMT_PREPARED;
2845

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

2848
  my_ok(thd);
unknown's avatar
unknown committed
2849

2850 2851 2852 2853
  DBUG_VOID_RETURN;
}


unknown's avatar
unknown committed
2854
/**
2855
  Delete a prepared statement from memory.
unknown's avatar
unknown committed
2856 2857 2858

  @note
    we don't send any reply to this command.
2859 2860
*/

2861
void mysqld_stmt_close(THD *thd, char *packet)
2862
{
2863
  /* There is always space for 4 bytes in packet buffer */
2864
  ulong stmt_id= uint4korr(packet);
2865
  Prepared_statement *stmt;
2866
  DBUG_ENTER("mysqld_stmt_close");
2867

Marc Alff's avatar
Marc Alff committed
2868
  thd->stmt_da->disable_status();
unknown's avatar
unknown committed
2869

unknown's avatar
unknown committed
2870
  if (!(stmt= find_prepared_statement(thd, stmt_id)))
2871
    DBUG_VOID_RETURN;
2872

2873 2874 2875 2876
  /*
    The only way currently a statement can be deallocated when it's
    in use is from within Dynamic SQL.
  */
unknown's avatar
unknown committed
2877 2878
  DBUG_ASSERT(! stmt->is_in_use());
  stmt->deallocate();
2879
  general_log_print(thd, thd->command, NullS);
2880

unknown's avatar
unknown committed
2881 2882 2883
  DBUG_VOID_RETURN;
}

2884

unknown's avatar
unknown committed
2885
/**
2886 2887 2888 2889 2890 2891
  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
2892
  @return
2893 2894 2895 2896 2897 2898 2899 2900
    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;
2901 2902
  DBUG_PRINT("info", ("DEALLOCATE PREPARE: %.*s\n", (int) name->length,
                      name->str));
2903 2904 2905

  if (! (stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name)))
    my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0),
2906
             static_cast<int>(name->length), name->str, "DEALLOCATE PREPARE");
unknown's avatar
unknown committed
2907 2908 2909 2910 2911
  else if (stmt->is_in_use())
    my_error(ER_PS_NO_RECURSION, MYF(0));
  else
  {
    stmt->deallocate();
2912
    my_ok(thd);
unknown's avatar
unknown committed
2913
  }
2914 2915
}

2916

unknown's avatar
unknown committed
2917
/**
2918
  Handle long data in pieces from client.
2919

2920 2921 2922 2923 2924
    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
2925 2926 2927 2928

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

2931
void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
2932
{
2933 2934
  ulong stmt_id;
  uint param_number;
2935
  Prepared_statement *stmt;
2936
  Item_param *param;
2937
#ifndef EMBEDDED_LIBRARY
2938
  char *packet_end= packet + packet_length;
2939
#endif
2940 2941
  DBUG_ENTER("mysql_stmt_get_longdata");

2942
  status_var_increment(thd->status_var.com_stmt_send_long_data);
2943

Marc Alff's avatar
Marc Alff committed
2944
  thd->stmt_da->disable_status();
unknown's avatar
unknown committed
2945
#ifndef EMBEDDED_LIBRARY
2946
  /* Minimal size of long data packet is 6 bytes */
2947
  if (packet_length < MYSQL_LONG_DATA_HEADER)
2948
    DBUG_VOID_RETURN;
unknown's avatar
unknown committed
2949
#endif
2950

2951 2952
  stmt_id= uint4korr(packet);
  packet+= 4;
2953

unknown's avatar
unknown committed
2954
  if (!(stmt=find_prepared_statement(thd, stmt_id)))
2955 2956
    DBUG_VOID_RETURN;

2957 2958
  param_number= uint2korr(packet);
  packet+= 2;
unknown's avatar
unknown committed
2959
#ifndef EMBEDDED_LIBRARY
2960 2961
  if (param_number >= stmt->param_count)
  {
unknown's avatar
unknown committed
2962
    /* Error will be sent in execute call */
2963
    stmt->state= Query_arena::STMT_ERROR;
unknown's avatar
unknown committed
2964
    stmt->last_errno= ER_WRONG_ARGUMENTS;
2965
    sprintf(stmt->last_error, ER(ER_WRONG_ARGUMENTS),
2966
            "mysqld_stmt_send_long_data");
2967 2968
    DBUG_VOID_RETURN;
  }
unknown's avatar
unknown committed
2969 2970
#endif

2971 2972
  param= stmt->param_array[param_number];

2973
  Diagnostics_area new_stmt_da, *save_stmt_da= thd->stmt_da;
2974 2975
  Warning_info new_warnning_info(thd->query_id, false);
  Warning_info *save_warinig_info= thd->warning_info;
2976 2977 2978 2979

  thd->stmt_da= &new_stmt_da;
  thd->warning_info= &new_warnning_info;

unknown's avatar
unknown committed
2980
#ifndef EMBEDDED_LIBRARY
2981
  param->set_longdata(packet, (ulong) (packet_end - packet));
unknown's avatar
unknown committed
2982
#else
2983
  param->set_longdata(thd->extra_data, thd->extra_length);
unknown's avatar
unknown committed
2984
#endif
2985
  if (thd->stmt_da->is_error())
2986
  {
2987
    stmt->state= Query_arena::STMT_ERROR;
2988 2989
    stmt->last_errno= thd->stmt_da->sql_errno();
    strncpy(stmt->last_error, thd->stmt_da->message(), MYSQL_ERRMSG_SIZE);
2990
  }
2991 2992
  thd->stmt_da= save_stmt_da;
  thd->warning_info= save_warinig_info;
2993 2994 2995

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

2996 2997
  DBUG_VOID_RETURN;
}
unknown's avatar
unknown committed
2998

2999

3000
/***************************************************************************
unknown's avatar
unknown committed
3001
 Select_fetch_protocol_binary
3002 3003
****************************************************************************/

unknown's avatar
unknown committed
3004
Select_fetch_protocol_binary::Select_fetch_protocol_binary(THD *thd_arg)
3005
  :protocol(thd_arg)
3006 3007
{}

3008
bool Select_fetch_protocol_binary::send_result_set_metadata(List<Item> &list, uint flags)
3009 3010 3011 3012 3013
{
  bool rc;
  Protocol *save_protocol= thd->protocol;

  /*
3014
    Protocol::send_result_set_metadata caches the information about column types:
3015 3016 3017 3018 3019
    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;
3020
  rc= select_send::send_result_set_metadata(list, flags);
3021 3022 3023 3024 3025
  thd->protocol= save_protocol;

  return rc;
}

unknown's avatar
unknown committed
3026
bool Select_fetch_protocol_binary::send_eof()
3027
{
3028 3029 3030 3031 3032 3033 3034
  /*
    Don't send EOF if we're in error condition (which implies we've already
    sent or are sending an error)
  */
  if (thd->is_error())
    return true;

3035
  ::my_eof(thd);
3036
  return false;
3037 3038 3039
}


3040
int
unknown's avatar
unknown committed
3041
Select_fetch_protocol_binary::send_data(List<Item> &fields)
3042 3043
{
  Protocol *save_protocol= thd->protocol;
3044
  int rc;
3045 3046 3047 3048 3049 3050 3051

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

Marc Alff's avatar
Marc Alff committed
3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075
/*******************************************************************
* 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;
}


3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108
/*******************************************************************
* Server_runnable
*******************************************************************/

Server_runnable::~Server_runnable()
{
}

///////////////////////////////////////////////////////////////////////////

Execute_sql_statement::
Execute_sql_statement(LEX_STRING sql_text)
  :m_sql_text(sql_text)
{}


/**
  Parse and execute a statement. Does not prepare the query.

  Allows to execute a statement from within another statement.
  The main property of the implementation is that it does not
  affect the environment -- i.e. you  can run many
  executions without having to cleanup/reset THD in between.
*/

bool
Execute_sql_statement::execute_server_code(THD *thd)
{
  bool error;

  if (alloc_query(thd, m_sql_text.str, m_sql_text.length))
    return TRUE;

3109 3110 3111
  Parser_state parser_state;
  if (parser_state.init(thd, thd->query(), thd->query_length()))
    return TRUE;
3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127

  parser_state.m_lip.multi_statements= FALSE;
  lex_start(thd);

  error= parse_sql(thd, &parser_state, NULL) || thd->is_error();

  if (error)
    goto end;

  thd->lex->set_trg_event_type_for_tables();

  error= mysql_execute_command(thd);

  /* report error issued during command execution */
  if (error == 0 && thd->spcont == NULL)
    general_log_write(thd, COM_STMT_EXECUTE,
3128
                      thd->query(), thd->query_length());
3129 3130 3131 3132 3133 3134 3135

end:
  lex_end(thd->lex);

  return error;
}

3136 3137 3138 3139
/***************************************************************************
 Prepared_statement
****************************************************************************/

3140
Prepared_statement::Prepared_statement(THD *thd_arg)
3141
  :Statement(NULL, &main_mem_root,
3142
             STMT_INITIALIZED, ++thd_arg->statement_id_counter),
3143
  thd(thd_arg),
3144
  result(thd_arg),
3145
  param_array(0),
3146
  cursor(0),
3147
  param_count(0),
3148
  last_errno(0),
Konstantin Osipov's avatar
Konstantin Osipov committed
3149
  flags((uint) IS_IN_USE)
3150
{
3151
  init_sql_alloc(&main_mem_root, thd_arg->variables.query_alloc_block_size,
3152
                  thd_arg->variables.query_prealloc_size);
3153 3154 3155
  *last_error= '\0';
}

3156

3157 3158
void Prepared_statement::setup_set_params()
{
3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169
  /*
    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.
  */
3170
  if ((mysql_bin_log.is_open() && is_update_query(lex->sql_command)) ||
3171 3172
      opt_log || opt_slow_log ||
      query_cache_is_cacheable_query(lex))
3173
  {
3174
    set_params_from_vars= insert_params_from_vars_with_log;
3175
#ifndef EMBEDDED_LIBRARY
3176
    set_params= insert_params_with_log;
3177
#else
3178
    set_params_data= emb_insert_params_with_log;
3179 3180 3181
#endif
  }
  else
3182 3183
  {
    set_params_from_vars= insert_params_from_vars;
3184
#ifndef EMBEDDED_LIBRARY
3185
    set_params= insert_params;
3186
#else
3187
    set_params_data= emb_insert_params;
3188
#endif
3189
  }
3190 3191
}

3192

unknown's avatar
unknown committed
3193 3194 3195 3196 3197 3198
/**
  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.
3199 3200
*/

3201 3202
Prepared_statement::~Prepared_statement()
{
3203
  DBUG_ENTER("Prepared_statement::~Prepared_statement");
unknown's avatar
unknown committed
3204 3205
  DBUG_PRINT("enter",("stmt: 0x%lx  cursor: 0x%lx",
                      (long) this, (long) cursor));
3206
  delete cursor;
3207 3208 3209 3210 3211
  /*
    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
3212 3213 3214 3215 3216
  if (lex)
  {
    delete lex->result;
    delete (st_lex_local *) lex;
  }
3217
  free_root(&main_mem_root, MYF(0));
3218
  DBUG_VOID_RETURN;
3219 3220 3221
}


unknown's avatar
unknown committed
3222
Query_arena::Type Prepared_statement::type() const
3223 3224 3225
{
  return PREPARED_STATEMENT;
}
3226 3227


3228
void Prepared_statement::cleanup_stmt()
3229
{
3230
  DBUG_ENTER("Prepared_statement::cleanup_stmt");
unknown's avatar
unknown committed
3231
  DBUG_PRINT("enter",("stmt: 0x%lx", (long) this));
3232

3233
  thd->rollback_item_tree_changes();
3234 3235 3236
  cleanup_items(free_list);
  thd->cleanup_after_query();

3237
  DBUG_VOID_RETURN;
3238
}
3239 3240 3241 3242 3243


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

unknown's avatar
unknown committed
3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275

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

3276 3277 3278 3279 3280 3281 3282
/**************************************************************************
  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
3283
/**
3284 3285 3286 3287 3288 3289
  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
3290 3291 3292 3293 3294
  @param packet             statement text
  @param packet_len

  @note
    Precondition:
3295 3296 3297 3298
    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
3299 3300
  @note
    Postcondition:
3301 3302 3303 3304 3305
    thd->mem_root contains unused memory allocated during validation.
*/

bool Prepared_statement::prepare(const char *packet, uint packet_len)
{
3306
  bool error;
3307 3308 3309 3310 3311 3312 3313 3314
  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.
  */
3315
  status_var_increment(thd->status_var.com_stmt_prepare);
3316

unknown's avatar
unknown committed
3317 3318 3319 3320 3321 3322
  if (! (lex= new (mem_root) st_lex_local))
    DBUG_RETURN(TRUE);

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

3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339
  /*
    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;

3340
  Parser_state parser_state;
3341
  if (parser_state.init(thd, thd->query(), thd->query_length()))
3342
  {
3343 3344 3345 3346
    thd->restore_backup_statement(this, &stmt_backup);
    thd->restore_active_arena(this, &stmt_backup);
    thd->stmt_arena= old_stmt_arena;
    DBUG_RETURN(TRUE);
3347
  }
3348

3349
  parser_state.m_lip.stmt_prepare_mode= TRUE;
3350
  parser_state.m_lip.multi_statements= FALSE;
3351

3352
  lex_start(thd);
Sergey Glukhov's avatar
Sergey Glukhov committed
3353
  lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_PREPARE;
3354

3355
  error= parse_sql(thd, & parser_state, NULL) ||
3356 3357
    thd->is_error() ||
    init_param_array(this);
3358

3359
  lex->set_trg_event_type_for_tables();
3360

3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375
  /*
    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());
3376

3377 3378 3379 3380
  /*
    Marker used to release metadata locks acquired while the prepared
    statement is being checked.
  */
3381
  MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
3382

3383 3384 3385 3386
  /* 
   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.
3387 3388
  */

3389
  if (error == 0)
unknown's avatar
unknown committed
3390
    error= check_prepared_statement(this);
3391

3392 3393 3394 3395 3396 3397
  /*
    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);
3398 3399 3400 3401 3402
  /* The order is important */
  lex->unit.cleanup();

  /* No need to commit statement transaction, it's not started. */
  DBUG_ASSERT(thd->transaction.stmt.is_empty());
3403

3404 3405
  close_thread_tables(thd);
  thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421

  /*
    Transaction rollback was requested since MDL deadlock was discovered
    while trying to open tables. Rollback transaction in all storage
    engines including binary log and release all locks.

    Once dynamic SQL is allowed as substatements the below if-statement
    has to be adjusted to not do rollback in substatement.
  */
  DBUG_ASSERT(! thd->in_sub_stmt);
  if (thd->transaction_rollback_request)
  {
    trans_rollback_implicit(thd);
    thd->mdl_context.release_transactional_locks();
  }

3422 3423
  /* Preserve CHANGE MASTER attributes */
  lex_end_stage1(lex);
3424
  cleanup_stmt();
3425 3426 3427
  thd->restore_backup_statement(this, &stmt_backup);
  thd->stmt_arena= old_stmt_arena;

3428
  if (error == 0)
3429 3430
  {
    setup_set_params();
Sergey Glukhov's avatar
Sergey Glukhov committed
3431
    lex->context_analysis_only&= ~CONTEXT_ANALYSIS_ONLY_PREPARE;
3432
    state= Query_arena::STMT_PREPARED;
3433
    flags&= ~ (uint) IS_IN_USE;
3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450

    /* 
      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)
3451
      general_log_write(thd, COM_STMT_PREPARE, query(), query_length());
3452
  }
3453
  DBUG_RETURN(error);
3454 3455
}

unknown's avatar
unknown committed
3456

3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476
/**
  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
3477 3478 3479 3480 3481
bool
Prepared_statement::set_parameters(String *expanded_query,
                                   uchar *packet, uchar *packet_end)
{
  bool is_sql_ps= packet == NULL;
3482
  bool res= FALSE;
unknown's avatar
unknown committed
3483 3484 3485 3486

  if (is_sql_ps)
  {
    /* SQL prepared statement */
3487 3488
    res= set_params_from_vars(this, thd->lex->prepared_stmt_params,
                              expanded_query);
unknown's avatar
unknown committed
3489 3490 3491 3492 3493
  }
  else if (param_count)
  {
#ifndef EMBEDDED_LIBRARY
    uchar *null_array= packet;
3494 3495
    res= (setup_conversion_functions(this, &packet, packet_end) ||
          set_params(this, null_array, packet, packet_end, expanded_query));
unknown's avatar
unknown committed
3496
#else
3497 3498 3499 3500 3501 3502
    /*
      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
3503 3504
#endif
  }
3505 3506 3507
  if (res)
  {
    my_error(ER_WRONG_ARGUMENTS, MYF(0),
3508
             is_sql_ps ? "EXECUTE" : "mysqld_stmt_execute");
3509 3510 3511
    reset_stmt_params(this);
  }
  return res;
unknown's avatar
unknown committed
3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544
}


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

  @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;
3545
  Reprepare_observer reprepare_observer;
unknown's avatar
unknown committed
3546 3547
  bool error;
  int reprepare_attempt= 0;
Sergei Golubchik's avatar
Sergei Golubchik committed
3548
  bool need_set_parameters= true;
unknown's avatar
unknown committed
3549

3550
  /* Check if we got an error when sending long data */
Mikael Ronstrom's avatar
Mikael Ronstrom committed
3551
  if (state == Query_arena::STMT_ERROR)
3552 3553 3554 3555 3556
  {
    my_message(last_errno, last_error, MYF(0));
    return TRUE;
  }

Sergei Golubchik's avatar
Sergei Golubchik committed
3557 3558 3559
reexecute:
  if (need_set_parameters &&
      set_parameters(expanded_query, packet, packet_end))
unknown's avatar
unknown committed
3560 3561
    return TRUE;

Sergei Golubchik's avatar
Sergei Golubchik committed
3562 3563 3564 3565 3566 3567 3568
  /*
    if set_parameters() has generated warnings,
    we need to repeat it when reexecuting, to recreate these
    warnings.
  */
  need_set_parameters= thd->warning_info->statement_warn_count();

3569
  reprepare_observer.reset_reprepare_observer();
unknown's avatar
unknown committed
3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586

  /*
    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)
  {
3587 3588
    DBUG_ASSERT(thd->m_reprepare_observer == NULL);
    thd->m_reprepare_observer = &reprepare_observer;
unknown's avatar
unknown committed
3589 3590 3591 3592
  }

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

3593
  thd->m_reprepare_observer= NULL;
unknown's avatar
unknown committed
3594 3595

  if (error && !thd->is_fatal_error && !thd->killed &&
3596
      reprepare_observer.is_invalidated() &&
unknown's avatar
unknown committed
3597 3598
      reprepare_attempt++ < MAX_REPREPARE_ATTEMPTS)
  {
Marc Alff's avatar
Marc Alff committed
3599
    DBUG_ASSERT(thd->stmt_da->sql_errno() == ER_NEED_REPREPARE);
unknown's avatar
unknown committed
3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612
    thd->clear_error();

    error= reprepare();

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

  return error;
}


3613 3614 3615 3616 3617 3618 3619
bool
Prepared_statement::execute_server_runnable(Server_runnable *server_runnable)
{
  Statement stmt_backup;
  bool error;
  Query_arena *save_stmt_arena= thd->stmt_arena;
  Item_change_list save_change_list;
Tor Didriksen's avatar
Tor Didriksen committed
3620
  thd->change_list.move_elements_to(&save_change_list);
3621

3622
  state= STMT_CONVENTIONAL_EXECUTION;
3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638

  if (!(lex= new (mem_root) st_lex_local))
    return TRUE;

  thd->set_n_backup_statement(this, &stmt_backup);
  thd->set_n_backup_active_arena(this, &stmt_backup);
  thd->stmt_arena= this;

  error= server_runnable->execute_server_code(thd);

  thd->cleanup_after_query();

  thd->restore_active_arena(this, &stmt_backup);
  thd->restore_backup_statement(this, &stmt_backup);
  thd->stmt_arena= save_stmt_arena;

Tor Didriksen's avatar
Tor Didriksen committed
3639
  save_change_list.move_elements_to(&thd->change_list);
3640 3641 3642 3643 3644 3645 3646

  /* Items and memory will freed in destructor */

  return error;
}


unknown's avatar
unknown committed
3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662
/**
  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()
{
3663
  char saved_cur_db_name_buf[SAFE_NAME_LEN+1];
unknown's avatar
unknown committed
3664 3665 3666 3667
  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;
3668
  bool error;
unknown's avatar
unknown committed
3669

3670 3671 3672
  Prepared_statement copy(thd);

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

3674
  status_var_increment(thd->status_var.com_stmt_reprepare);
unknown's avatar
unknown committed
3675 3676 3677

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

Staale Smedseng's avatar
Staale Smedseng committed
3680
  error= ((name.str && copy.set_name(&name)) ||
3681
          copy.prepare(query(), query_length()) ||
3682
          validate_metadata(&copy));
unknown's avatar
unknown committed
3683 3684 3685 3686 3687 3688

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

  if (! error)
  {
3689 3690
    swap_prepared_statement(&copy);
    swap_parameter_array(param_array, copy.param_array, param_count);
unknown's avatar
unknown committed
3691
#ifndef DBUG_OFF
unknown's avatar
unknown committed
3692
    is_reprepared= TRUE;
unknown's avatar
unknown committed
3693
#endif
unknown's avatar
unknown committed
3694
    /*
3695
      Clear possible warnings during reprepare, it has to be completely
Marc Alff's avatar
Marc Alff committed
3696
      transparent to the user. We use clear_warning_info() since
unknown's avatar
unknown committed
3697
      there were no separate query id issued for re-prepare.
3698 3699
      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
3700
    */
Marc Alff's avatar
Marc Alff committed
3701
    thd->warning_info->clear_warning_info(thd->query_id);
unknown's avatar
unknown committed
3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717
  }
  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

3718
  @retval TRUE  error, ER_PS_REBIND is reported
unknown's avatar
unknown committed
3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729
  @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.
  */
3730
  if (is_sql_prepare() || lex->describe)
unknown's avatar
unknown committed
3731 3732 3733 3734 3735
    return FALSE;

  if (lex->select_lex.item_list.elements !=
      copy->lex->select_lex.item_list.elements)
  {
3736 3737
    /** Column counts mismatch, update the client */
    thd->server_status|= SERVER_STATUS_METADATA_CHANGED;
unknown's avatar
unknown committed
3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779
  }

  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);
Konstantin Osipov's avatar
Konstantin Osipov committed
3780 3781
  /* Don't swap flags: the copy has IS_SQL_PREPARE always set. */
  /* swap_variables(uint, flags, copy->flags); */
unknown's avatar
unknown committed
3782 3783 3784 3785
  /* 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);
3786
  swap_variables(size_t, db_length, copy->db_length);
unknown's avatar
unknown committed
3787 3788 3789 3790 3791 3792 3793 3794

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


unknown's avatar
unknown committed
3795
/**
3796 3797 3798 3799 3800 3801
  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
3802 3803 3804 3805 3806 3807 3808 3809
  @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().
3810

unknown's avatar
unknown committed
3811 3812 3813
  @retval
    FALSE	    ok
  @retval
3814
    TRUE		Error
3815 3816 3817 3818 3819 3820
*/

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

3823
  char saved_cur_db_name_buf[SAFE_NAME_LEN+1];
3824 3825 3826 3827 3828 3829
  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 };

3830
  status_var_increment(thd->status_var.com_stmt_execute);
3831

3832
  if (flags & (uint) IS_IN_USE)
3833 3834
  {
    my_error(ER_PS_NO_RECURSION, MYF(0));
3835
    return TRUE;
3836
  }
3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847

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

3848
  if (open_cursor && lex->result && lex->result->check_simple_select())
3849 3850 3851 3852 3853
  {
    DBUG_PRINT("info",("Cursor asked for not SELECT stmt"));
    return TRUE;
  }

3854 3855 3856
  /* In case the command has a call to SP which re-uses this statement name */
  flags|= IS_IN_USE;

3857
  close_cursor();
3858 3859 3860 3861 3862 3863

  /*
    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());
3864 3865 3866 3867 3868 3869 3870

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

3871
  thd->set_n_backup_statement(this, &stmt_backup);
3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886

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

3887 3888
  if (expanded_query->length() &&
      alloc_query(thd, (char*) expanded_query->ptr(),
3889
                  expanded_query->length()))
3890
  {
3891
    my_error(ER_OUTOFMEMORY, MYF(ME_FATALERROR), expanded_query->length());
3892 3893 3894 3895 3896 3897 3898
    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.
  */
3899
  stmt_backup.set_query_inner(thd->query_string);
3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911

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

3912 3913
  /* Go! */

3914
  if (open_cursor)
3915
    error= mysql_open_cursor(thd, &result, &cursor);
3916 3917 3918 3919 3920 3921 3922
  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).
    */
3923 3924
    if (query_cache_send_result_to_client(thd, thd->query(),
                                          thd->query_length()) <= 0)
3925
    {
3926
      MYSQL_QUERY_EXEC_START(thd->query(),
3927 3928
                             thd->thread_id,
                             (char *) (thd->db ? thd->db : ""),
3929
                             &thd->security_ctx->priv_user[0],
3930 3931
                             (char *) thd->security_ctx->host_or_ip,
                             1);
3932
      error= mysql_execute_command(thd);
3933
      MYSQL_QUERY_EXEC_DONE(error);
3934
    }
3935 3936 3937 3938 3939 3940
    else
    {
      thd->lex->sql_command= SQLCOM_SELECT;
      status_var_increment(thd->status_var.com_stat[SQLCOM_SELECT]);
      thd->update_stats();
    }
3941 3942
  }

3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953
  /*
    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);

3954
  /* Assert that if an error, no cursor is open */
unknown's avatar
unknown committed
3955
  DBUG_ASSERT(! (error && cursor));
3956

3957 3958
  if (! cursor)
    cleanup_stmt();
3959 3960 3961 3962

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

3963 3964
  if (state == Query_arena::STMT_PREPARED)
    state= Query_arena::STMT_EXECUTED;
3965

3966
  if (error == 0 && this->lex->sql_command == SQLCOM_CALL)
3967 3968 3969 3970 3971 3972 3973
  {
    if (is_sql_prepare())
      thd->protocol_text.send_out_parameters(&this->lex->param_list);
    else
      thd->protocol->send_out_parameters(&this->lex->param_list);
  }

3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989
  /*
    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)
3990
    general_log_write(thd, COM_STMT_EXECUTE, thd->query(), thd->query_length());
3991

3992
error:
3993 3994
  flags&= ~ (uint) IS_IN_USE;
  return error;
3995 3996 3997
}


3998
/** Common part of DEALLOCATE PREPARE and mysqld_stmt_close. */
3999

unknown's avatar
unknown committed
4000
void Prepared_statement::deallocate()
4001
{
4002
  /* We account deallocate in the same manner as mysqld_stmt_close */
4003
  status_var_increment(thd->status_var.com_stmt_close);
4004 4005 4006 4007

  /* It should now be safe to reset CHANGE MASTER parameters */
  lex_end_stage2(lex);

4008 4009 4010
  /* Statement map calls delete stmt on erase */
  thd->stmt_map.erase(this);
}
4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068


/***************************************************************************
* Ed_result_set
***************************************************************************/
/**
  Use operator delete to free memory of Ed_result_set.
  Accessing members of a class after the class has been destroyed
  is a violation of the C++ standard but is commonly used in the
  server code.
*/

void Ed_result_set::operator delete(void *ptr, size_t size) throw ()
{
  if (ptr)
  {
    /*
      Make a stack copy, otherwise free_root() will attempt to
      write to freed memory.
    */
    MEM_ROOT own_root= ((Ed_result_set*) ptr)->m_mem_root;
    free_root(&own_root, MYF(0));
  }
}


/**
  Initialize an instance of Ed_result_set.

  Instances of the class, as well as all result set rows, are
  always allocated in the memory root passed over as the second
  argument. In the constructor, we take over ownership of the
  memory root. It will be freed when the class is destroyed.

  sic: Ed_result_est is not designed to be allocated on stack.
*/

Ed_result_set::Ed_result_set(List<Ed_row> *rows_arg,
                             size_t column_count_arg,
                             MEM_ROOT *mem_root_arg)
  :m_mem_root(*mem_root_arg),
  m_column_count(column_count_arg),
  m_rows(rows_arg),
  m_next_rset(NULL)
{
  /* Take over responsibility for the memory */
  clear_alloc_root(mem_root_arg);
}

/***************************************************************************
* Ed_result_set
***************************************************************************/

/**
  Create a new "execute direct" connection.
*/

Ed_connection::Ed_connection(THD *thd)
4069
  :m_warning_info(thd->query_id, false),
4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434
  m_thd(thd),
  m_rsets(0),
  m_current_rset(0)
{
}


/**
  Free all result sets of the previous statement, if any,
  and reset warnings and errors.

  Called before execution of the next query.
*/

void
Ed_connection::free_old_result()
{
  while (m_rsets)
  {
    Ed_result_set *rset= m_rsets->m_next_rset;
    delete m_rsets;
    m_rsets= rset;
  }
  m_current_rset= m_rsets;
  m_diagnostics_area.reset_diagnostics_area();
  m_warning_info.clear_warning_info(m_thd->query_id);
}


/**
  A simple wrapper that uses a helper class to execute SQL statements.
*/

bool
Ed_connection::execute_direct(LEX_STRING sql_text)
{
  Execute_sql_statement execute_sql_statement(sql_text);
  DBUG_PRINT("ed_query", ("%s", sql_text.str));

  return execute_direct(&execute_sql_statement);
}


/**
  Execute a fragment of server functionality without an effect on
  thd, and store results in memory.

  Conventions:
  - the code fragment must finish with OK, EOF or ERROR.
  - the code fragment doesn't have to close thread tables,
  free memory, commit statement transaction or do any other
  cleanup that is normally done in the end of dispatch_command().

  @param server_runnable A code fragment to execute.
*/

bool Ed_connection::execute_direct(Server_runnable *server_runnable)
{
  bool rc= FALSE;
  Protocol_local protocol_local(m_thd, this);
  Prepared_statement stmt(m_thd);
  Protocol *save_protocol= m_thd->protocol;
  Diagnostics_area *save_diagnostics_area= m_thd->stmt_da;
  Warning_info *save_warning_info= m_thd->warning_info;

  DBUG_ENTER("Ed_connection::execute_direct");

  free_old_result(); /* Delete all data from previous execution, if any */

  m_thd->protocol= &protocol_local;
  m_thd->stmt_da= &m_diagnostics_area;
  m_thd->warning_info= &m_warning_info;

  rc= stmt.execute_server_runnable(server_runnable);
  m_thd->protocol->end_statement();

  m_thd->protocol= save_protocol;
  m_thd->stmt_da= save_diagnostics_area;
  m_thd->warning_info= save_warning_info;
  /*
    Protocol_local makes use of m_current_rset to keep
    track of the last result set, while adding result sets to the end.
    Reset it to point to the first result set instead.
  */
  m_current_rset= m_rsets;

  DBUG_RETURN(rc);
}


/**
  A helper method that is called only during execution.

  Although Ed_connection doesn't support multi-statements,
  a statement may generate many result sets. All subsequent
  result sets are appended to the end.

  @pre This is called only by Protocol_local.
*/

void
Ed_connection::add_result_set(Ed_result_set *ed_result_set)
{
  if (m_rsets)
  {
    m_current_rset->m_next_rset= ed_result_set;
    /* While appending, use m_current_rset as a pointer to the tail. */
    m_current_rset= ed_result_set;
  }
  else
    m_current_rset= m_rsets= ed_result_set;
}


/**
  Release ownership of the current result set to the client.

  Since we use a simple linked list for result sets,
  this method uses a linear search of the previous result
  set to exclude the released instance from the list.

  @todo Use double-linked list, when this is really used.

  XXX: This has never been tested with more than one result set!

  @pre There must be a result set.
*/

Ed_result_set *
Ed_connection::store_result_set()
{
  Ed_result_set *ed_result_set;

  DBUG_ASSERT(m_current_rset);

  if (m_current_rset == m_rsets)
  {
    /* Assign the return value */
    ed_result_set= m_current_rset;
    /* Exclude the return value from the list. */
    m_current_rset= m_rsets= m_rsets->m_next_rset;
  }
  else
  {
    Ed_result_set *prev_rset= m_rsets;
    /* Assign the return value. */
    ed_result_set= m_current_rset;

    /* Exclude the return value from the list */
    while (prev_rset->m_next_rset != m_current_rset)
      prev_rset= ed_result_set->m_next_rset;
    m_current_rset= prev_rset->m_next_rset= m_current_rset->m_next_rset;
  }
  ed_result_set->m_next_rset= NULL; /* safety */

  return ed_result_set;
}

/*************************************************************************
* Protocol_local
**************************************************************************/

Protocol_local::Protocol_local(THD *thd, Ed_connection *ed_connection)
  :Protocol(thd),
  m_connection(ed_connection),
  m_rset(NULL),
  m_column_count(0),
  m_current_row(NULL),
  m_current_column(NULL)
{
  clear_alloc_root(&m_rset_root);
}

/**
  Called between two result set rows.

  Prepare structures to fill result set rows.
  Unfortunately, we can't return an error here. If memory allocation
  fails, we'll have to return an error later. And so is done
  in methods such as @sa store_column().
*/

void Protocol_local::prepare_for_resend()
{
  DBUG_ASSERT(alloc_root_inited(&m_rset_root));

  opt_add_row_to_rset();
  /* Start a new row. */
  m_current_row= (Ed_column *) alloc_root(&m_rset_root,
                                          sizeof(Ed_column) * m_column_count);
  m_current_column= m_current_row;
}


/**
  In "real" protocols this is called to finish a result set row.
  Unused in the local implementation.
*/

bool Protocol_local::write()
{
  return FALSE;
}

/**
  A helper function to add the current row to the current result
  set. Called in @sa prepare_for_resend(), when a new row is started,
  and in send_eof(), when the result set is finished.
*/

void Protocol_local::opt_add_row_to_rset()
{
  if (m_current_row)
  {
    /* Add the old row to the result set */
    Ed_row *ed_row= new (&m_rset_root) Ed_row(m_current_row, m_column_count);
    if (ed_row)
      m_rset->push_back(ed_row, &m_rset_root);
  }
}


/**
  Add a NULL column to the current row.
*/

bool Protocol_local::store_null()
{
  if (m_current_column == NULL)
    return TRUE; /* prepare_for_resend() failed to allocate memory. */

  bzero(m_current_column, sizeof(*m_current_column));
  ++m_current_column;
  return FALSE;
}


/**
  A helper method to add any column to the current row
  in its binary form.

  Allocates memory for the data in the result set memory root.
*/

bool Protocol_local::store_column(const void *data, size_t length)
{
  if (m_current_column == NULL)
    return TRUE; /* prepare_for_resend() failed to allocate memory. */
  /*
    alloc_root() automatically aligns memory, so we don't need to
    do any extra alignment if we're pointing to, say, an integer.
  */
  m_current_column->str= (char*) memdup_root(&m_rset_root,
                                             data,
                                             length + 1 /* Safety */);
  if (! m_current_column->str)
    return TRUE;
  m_current_column->str[length]= '\0'; /* Safety */
  m_current_column->length= length;
  ++m_current_column;
  return FALSE;
}


/**
  Store a string value in a result set column, optionally
  having converted it to character_set_results.
*/

bool
Protocol_local::store_string(const char *str, size_t length,
                             CHARSET_INFO *src_cs, CHARSET_INFO *dst_cs)
{
  /* Store with conversion */
  uint error_unused;

  if (dst_cs && !my_charset_same(src_cs, dst_cs) &&
      src_cs != &my_charset_bin &&
      dst_cs != &my_charset_bin)
  {
    if (convert->copy(str, length, src_cs, dst_cs, &error_unused))
      return TRUE;
    str= convert->ptr();
    length= convert->length();
  }
  return store_column(str, length);
}


/** Store a tiny int as is (1 byte) in a result set column. */

bool Protocol_local::store_tiny(longlong value)
{
  char v= (char) value;
  return store_column(&v, 1);
}


/** Store a short as is (2 bytes, host order) in a result set column. */

bool Protocol_local::store_short(longlong value)
{
  int16 v= (int16) value;
  return store_column(&v, 2);
}


/** Store a "long" as is (4 bytes, host order) in a result set column.  */

bool Protocol_local::store_long(longlong value)
{
  int32 v= (int32) value;
  return store_column(&v, 4);
}


/** Store a "longlong" as is (8 bytes, host order) in a result set column. */

bool Protocol_local::store_longlong(longlong value, bool unsigned_flag)
{
  int64 v= (int64) value;
  return store_column(&v, 8);
}


/** Store a decimal in string format in a result set column */

bool Protocol_local::store_decimal(const my_decimal *value)
{
  char buf[DECIMAL_MAX_STR_LENGTH];
  String str(buf, sizeof (buf), &my_charset_bin);
  int rc;

  rc= my_decimal2string(E_DEC_FATAL_ERROR, value, 0, 0, 0, &str);

  if (rc)
    return TRUE;

  return store_column(str.ptr(), str.length());
}


/** Convert to cs_results and store a string. */

bool Protocol_local::store(const char *str, size_t length,
                           CHARSET_INFO *src_cs)
{
  CHARSET_INFO *dst_cs;

  dst_cs= m_connection->m_thd->variables.character_set_results;
  return store_string(str, length, src_cs, dst_cs);
}


/** Store a string. */

bool Protocol_local::store(const char *str, size_t length,
                           CHARSET_INFO *src_cs, CHARSET_INFO *dst_cs)
{
  return store_string(str, length, src_cs, dst_cs);
}


/* Store MYSQL_TIME (in binary format) */

Sergei Golubchik's avatar
Sergei Golubchik committed
4435
bool Protocol_local::store(MYSQL_TIME *time, int decimals)
4436
{
Sergei Golubchik's avatar
Sergei Golubchik committed
4437 4438
  if (decimals != AUTO_SEC_PART_DIGITS)
    time->second_part= sec_part_truncate(time->second_part, decimals);
4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452
  return store_column(time, sizeof(MYSQL_TIME));
}


/** Store MYSQL_TIME (in binary format) */

bool Protocol_local::store_date(MYSQL_TIME *time)
{
  return store_column(time, sizeof(MYSQL_TIME));
}


/** Store MYSQL_TIME (in binary format) */

Sergei Golubchik's avatar
Sergei Golubchik committed
4453
bool Protocol_local::store_time(MYSQL_TIME *time, int decimals)
4454
{
Sergei Golubchik's avatar
Sergei Golubchik committed
4455 4456
  if (decimals != AUTO_SEC_PART_DIGITS)
    time->second_part= sec_part_truncate(time->second_part, decimals);
4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584
  return store_column(time, sizeof(MYSQL_TIME));
}


/* Store a floating point number, as is. */

bool Protocol_local::store(float value, uint32 decimals, String *buffer)
{
  return store_column(&value, sizeof(float));
}


/* Store a double precision number, as is. */

bool Protocol_local::store(double value, uint32 decimals, String *buffer)
{
  return store_column(&value, sizeof (double));
}


/* Store a Field. */

bool Protocol_local::store(Field *field)
{
  if (field->is_null())
    return store_null();
  return field->send_binary(this);
}


/** Called to start a new result set. */

bool Protocol_local::send_result_set_metadata(List<Item> *columns, uint)
{
  DBUG_ASSERT(m_rset == 0 && !alloc_root_inited(&m_rset_root));

  init_sql_alloc(&m_rset_root, MEM_ROOT_BLOCK_SIZE, 0);

  if (! (m_rset= new (&m_rset_root) List<Ed_row>))
    return TRUE;

  m_column_count= columns->elements;

  return FALSE;
}


/**
  Normally this is a separate result set with OUT parameters
  of stored procedures. Currently unsupported for the local
  version.
*/

bool Protocol_local::send_out_parameters(List<Item_param> *sp_params)
{
  return FALSE;
}


/** Called for statements that don't have a result set, at statement end. */

bool
Protocol_local::send_ok(uint server_status, uint statement_warn_count,
                        ulonglong affected_rows, ulonglong last_insert_id,
                        const char *message)
{
  /*
    Just make sure nothing is sent to the client, we have grabbed
    the status information in the connection diagnostics area.
  */
  return FALSE;
}


/**
  Called at the end of a result set. Append a complete
  result set to the list in Ed_connection.

  Don't send anything to the client, but instead finish
  building of the result set at hand.
*/

bool Protocol_local::send_eof(uint server_status, uint statement_warn_count)
{
  Ed_result_set *ed_result_set;

  DBUG_ASSERT(m_rset);

  opt_add_row_to_rset();
  m_current_row= 0;

  ed_result_set= new (&m_rset_root) Ed_result_set(m_rset, m_column_count,
                                                  &m_rset_root);

  m_rset= NULL;

  if (! ed_result_set)
    return TRUE;

  /* In case of successful allocation memory ownership was transferred. */
  DBUG_ASSERT(!alloc_root_inited(&m_rset_root));

  /*
    Link the created Ed_result_set instance into the list of connection
    result sets. Never fails.
  */
  m_connection->add_result_set(ed_result_set);
  return FALSE;
}


/** Called to send an error to the client at the end of a statement. */

bool
Protocol_local::send_error(uint sql_errno, const char *err_msg, const char*)
{
  /*
    Just make sure that nothing is sent to the client (default
    implementation).
  */
  return FALSE;
}


#ifdef EMBEDDED_LIBRARY
void Protocol_local::remove_last_row()
{ }
#endif