sql_prepare.cc 63.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/* Copyright (C) 1995-2002 MySQL AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA */
16 17 18 19 20 21

/**********************************************************************
This file contains the implementation of prepare and executes. 

Prepare:

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

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

Long data handling:
57

58 59
  - Server gets the long data in pieces with command type 'COM_LONG_DATA'.
  - The packet recieved will have the format as:
60 61 62
    [COM_LONG_DATA:1][STMT_ID:4][parameter_number:2][data]
  - data from the packet is appended to long data value buffer for this
    placeholder.
63
  - It's up to the client to check for read data ended. The server doesn't
64 65 66
    care; and also server doesn't notify to the client that it got the 
    data or not; if there is any error; then during execute; the error 
    will be returned
67

68 69 70
***********************************************************************/

#include "mysql_priv.h"
71
#include "sql_select.h" // for JOIN
72
#include <m_ctype.h>  // for isspace()
73
#include "sp_head.h"
74
#include "sp.h"
75 76 77
#ifdef EMBEDDED_LIBRARY
/* include MYSQL_BIND headers */
#include <mysql.h>
78 79
#else
#include <mysql_com.h>
80
#endif
81

82 83 84
/******************************************************************************
  Prepared_statement: statement which can contain placeholders
******************************************************************************/
85

86 87 88 89
class Prepared_statement: public Statement
{
public:
  THD *thd;
90
  Item_param **param_array;
91 92 93 94
  uint param_count;
  uint last_errno;
  char last_error[MYSQL_ERRMSG_SIZE];
#ifndef EMBEDDED_LIBRARY
95
  bool (*set_params)(Prepared_statement *st, uchar *data, uchar *data_end,
96
                     uchar *read_pos, String *expanded_query);
hf@deer.(none)'s avatar
hf@deer.(none) committed
97
#else
98
  bool (*set_params_data)(Prepared_statement *st, String *expanded_query);
hf@deer.(none)'s avatar
hf@deer.(none) committed
99
#endif
sergefp@mysql.com's avatar
sergefp@mysql.com committed
100
  bool (*set_params_from_vars)(Prepared_statement *stmt, 
101 102
                               List<LEX_STRING>& varnames,
                               String *expanded_query);
103 104 105
public:
  Prepared_statement(THD *thd_arg);
  virtual ~Prepared_statement();
106
  void setup_set_params();
107
  virtual Item_arena::Type type() const;
108
};
hf@deer.(none)'s avatar
hf@deer.(none) committed
109

110
static void execute_stmt(THD *thd, Prepared_statement *stmt,
111
                         String *expanded_query);
112

113 114 115
/******************************************************************************
  Implementation
******************************************************************************/
116 117


118
inline bool is_param_null(const uchar *pos, ulong param_no)
119
{
120
  return pos[param_no/8] & (1 << (param_no & 7));
121 122
}

123
enum { STMT_QUERY_LOG_LENGTH= 8192 };
124 125

/*
126 127
  Seek prepared statement in statement map by id: returns zero if statement
  was not found, pointer otherwise.
128 129
*/

130
static Prepared_statement *
131
find_prepared_statement(THD *thd, ulong id, const char *where)
132 133 134
{
  Statement *stmt= thd->stmt_map.find(id);

135
  if (stmt == 0 || stmt->type() != Item_arena::PREPARED_STATEMENT)
136
  {
137 138
    char llbuf[22];
    my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), 22, llstr(id, llbuf), where);
139 140 141
    return 0;
  }
  return (Prepared_statement *) stmt;
142 143
}

144

145 146 147 148
/*
  Send prepared stmt info to client after prepare
*/

hf@deer.(none)'s avatar
SCRUM:  
hf@deer.(none) committed
149
#ifndef EMBEDDED_LIBRARY
150
static bool send_prep_stmt(Prepared_statement *stmt, uint columns)
151
{
152
  NET *net= &stmt->thd->net;
monty@mysql.com's avatar
monty@mysql.com committed
153 154
  char buff[12];
  uint tmp;
monty@mysql.com's avatar
monty@mysql.com committed
155 156
  DBUG_ENTER("send_prep_stmt");

157
  buff[0]= 0;                                   /* OK packet indicator */
158
  int4store(buff+1, stmt->id);
159 160
  int2store(buff+5, columns);
  int2store(buff+7, stmt->param_count);
monty@mysql.com's avatar
monty@mysql.com committed
161 162 163 164
  buff[9]= 0;                                   // Guard against a 4.1 client
  tmp= min(stmt->thd->total_warn_count, 65535);
  int2store(buff+10, tmp);

165 166 167 168
  /*
    Send types and names of placeholders to the client
    XXX: fix this nasty upcast from List<Item_param> to List<Item>
  */
monty@mysql.com's avatar
monty@mysql.com committed
169 170 171 172
  DBUG_RETURN(my_net_write(net, buff, sizeof(buff)) || 
              (stmt->param_count &&
               stmt->thd->protocol_simple.send_fields((List<Item> *)
                                                      &stmt->lex->param_list,
173
                                                      Protocol::SEND_EOF)));
hf@deer.(none)'s avatar
SCRUM:  
hf@deer.(none) committed
174
}
175
#else
176 177
static bool send_prep_stmt(Prepared_statement *stmt,
                           uint columns __attribute__((unused)))
hf@deer.(none)'s avatar
SCRUM:  
hf@deer.(none) committed
178
{
hf@deer.(none)'s avatar
SCRUM  
hf@deer.(none) committed
179 180
  THD *thd= stmt->thd;

181
  thd->client_stmt_id= stmt->id;
hf@deer.(none)'s avatar
SCRUM  
hf@deer.(none) committed
182
  thd->client_param_count= stmt->param_count;
183
  thd->clear_error();
hf@deer.(none)'s avatar
SCRUM:  
hf@deer.(none) committed
184

hf@deer.(none)'s avatar
SCRUM  
hf@deer.(none) committed
185
  return 0;
186
}
konstantin@oak.local's avatar
konstantin@oak.local committed
187
#endif /*!EMBEDDED_LIBRARY*/
188

189 190

/*
191 192
  Read the length of the parameter data and return back to
  caller by positing the pointer to param data.
193 194
*/

hf@deer.(none)'s avatar
hf@deer.(none) committed
195
#ifndef EMBEDDED_LIBRARY
196
static ulong get_param_length(uchar **packet, ulong len)
197 198
{
  reg1 uchar *pos= *packet;
199 200
  if (len < 1)
    return 0;
201 202 203 204 205
  if (*pos < 251)
  {
    (*packet)++;
    return (ulong) *pos;
  }
206 207
  if (len < 3)
    return 0;
208 209 210 211 212
  if (*pos == 252)
  {
    (*packet)+=3;
    return (ulong) uint2korr(pos+1);
  }
213 214
  if (len < 4)
    return 0;
215 216 217 218 219
  if (*pos == 253)
  {
    (*packet)+=4;
    return (ulong) uint3korr(pos+1);
  }
220 221
  if (len < 5)
    return 0;
222
  (*packet)+=9; // Must be 254 when here 
223 224 225 226 227 228 229
  /*
    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.
  */
230 231
  return (ulong) uint4korr(pos+1);
}
hf@deer.(none)'s avatar
hf@deer.(none) committed
232
#else
233
#define get_param_length(packet, len) len
hf@deer.(none)'s avatar
hf@deer.(none) committed
234 235
#endif /*!EMBEDDED_LIBRARY*/

venu@myvenu.com's avatar
venu@myvenu.com committed
236
 /*
237 238 239 240 241 242
   Data conversion routines
   SYNOPSIS
   set_param_xx()
    param   parameter item
    pos     input data buffer
    len     length of data in the buffer
venu@myvenu.com's avatar
venu@myvenu.com committed
243

244 245
  All these functions read the data from pos, convert it to requested type 
  and assign to param; pos is advanced to predefined length.
venu@myvenu.com's avatar
venu@myvenu.com committed
246 247 248 249 250

  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.

251 252
  RETURN VALUE
    none
253 254
*/

255
static void set_param_tiny(Item_param *param, uchar **pos, ulong len)
256
{
257 258 259 260
#ifndef EMBEDDED_LIBRARY
  if (len < 1)
    return;
#endif
261 262
  int8 value= (int8) **pos;
  param->set_int(param->unsigned_flag ? (longlong) ((uint8) value) : 
263
                                        (longlong) value, 4);
venu@myvenu.com's avatar
venu@myvenu.com committed
264 265 266
  *pos+= 1;
}

267
static void set_param_short(Item_param *param, uchar **pos, ulong len)
venu@myvenu.com's avatar
venu@myvenu.com committed
268
{
269
  int16 value;
270 271 272
#ifndef EMBEDDED_LIBRARY
  if (len < 2)
    return;
273
  value= sint2korr(*pos);
274 275
#else
  shortget(value, *pos);
276
#endif
277
  param->set_int(param->unsigned_flag ? (longlong) ((uint16) value) :
278
                                        (longlong) value, 6);
venu@myvenu.com's avatar
venu@myvenu.com committed
279 280 281
  *pos+= 2;
}

282
static void set_param_int32(Item_param *param, uchar **pos, ulong len)
venu@myvenu.com's avatar
venu@myvenu.com committed
283
{
284
  int32 value;
285 286 287
#ifndef EMBEDDED_LIBRARY
  if (len < 4)
    return;
288
  value= sint4korr(*pos);
289 290
#else
  longget(value, *pos);
291
#endif
292
  param->set_int(param->unsigned_flag ? (longlong) ((uint32) value) :
293
                                        (longlong) value, 11);
venu@myvenu.com's avatar
venu@myvenu.com committed
294 295 296
  *pos+= 4;
}

297
static void set_param_int64(Item_param *param, uchar **pos, ulong len)
venu@myvenu.com's avatar
venu@myvenu.com committed
298
{
299
  longlong value;
300 301 302
#ifndef EMBEDDED_LIBRARY
  if (len < 8)
    return;
303
  value= (longlong) sint8korr(*pos);
304 305
#else
  longlongget(value, *pos);
306
#endif
307
  param->set_int(value, 21);
venu@myvenu.com's avatar
venu@myvenu.com committed
308 309 310
  *pos+= 8;
}

311
static void set_param_float(Item_param *param, uchar **pos, ulong len)
venu@myvenu.com's avatar
venu@myvenu.com committed
312
{
313 314 315 316
#ifndef EMBEDDED_LIBRARY
  if (len < 4)
    return;
#endif
venu@myvenu.com's avatar
venu@myvenu.com committed
317 318 319 320 321 322
  float data;
  float4get(data,*pos);
  param->set_double((double) data);
  *pos+= 4;
}

323
static void set_param_double(Item_param *param, uchar **pos, ulong len)
venu@myvenu.com's avatar
venu@myvenu.com committed
324
{
325 326 327 328
#ifndef EMBEDDED_LIBRARY
  if (len < 8)
    return;
#endif
venu@myvenu.com's avatar
venu@myvenu.com committed
329 330 331 332 333 334
  double data;
  float8get(data,*pos);
  param->set_double((double) data);
  *pos+= 8;
}

335
#ifndef EMBEDDED_LIBRARY
336 337 338 339 340 341 342

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

343
static void set_param_time(Item_param *param, uchar **pos, ulong len)
344
{
345 346
  MYSQL_TIME tm;
  ulong length= get_param_length(pos, len);
347

348
  if (length >= 8)
349 350
  {
    uchar *to= *pos;
351
    uint day;
352

353 354
    tm.neg= (bool) to[0];
    day= (uint) sint4korr(to+1);
355
    tm.hour=   (uint) to[5] + day * 24;
356 357
    tm.minute= (uint) to[6];
    tm.second= (uint) to[7];
358
    tm.second_part= (length > 8) ? (ulong) sint4korr(to+8) : 0;
359 360 361 362 363 364 365 366
    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;
367
  }
368
  else
369
    set_zero_time(&tm, MYSQL_TIMESTAMP_TIME);
370 371
  param->set_time(&tm, MYSQL_TIMESTAMP_TIME,
                  MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
372 373 374
  *pos+= length;
}

375
static void set_param_datetime(Item_param *param, uchar **pos, ulong len)
376
{
377 378
  MYSQL_TIME tm;
  ulong length= get_param_length(pos, len);
379

380
  if (length >= 4)
381 382
  {
    uchar *to= *pos;
383 384 385 386 387

    tm.neg=    0;
    tm.year=   (uint) sint2korr(to);
    tm.month=  (uint) to[2];
    tm.day=    (uint) to[3];
388 389 390 391 392 393 394 395 396
    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;

397
    tm.second_part= (length > 7) ? (ulong) sint4korr(to+7) : 0;
398
  }
399
  else
400
    set_zero_time(&tm, MYSQL_TIMESTAMP_DATETIME);
401 402
  param->set_time(&tm, MYSQL_TIMESTAMP_DATETIME,
                  MAX_DATETIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
403 404 405
  *pos+= length;
}

406

407
static void set_param_date(Item_param *param, uchar **pos, ulong len)
408
{
409 410 411 412
  MYSQL_TIME tm;
  ulong length= get_param_length(pos, len);

  if (length >= 4)
413 414
  {
    uchar *to= *pos;
415

416
    tm.year=  (uint) sint2korr(to);
417 418 419 420 421 422 423
    tm.month=  (uint) to[2];
    tm.day= (uint) to[3];

    tm.hour= tm.minute= tm.second= 0;
    tm.second_part= 0;
    tm.neg= 0;
  }
424
  else
425
    set_zero_time(&tm, MYSQL_TIMESTAMP_DATE);
426 427
  param->set_time(&tm, MYSQL_TIMESTAMP_DATE,
                  MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
428 429 430
  *pos+= length;
}

431 432 433
#else/*!EMBEDDED_LIBRARY*/
void set_param_time(Item_param *param, uchar **pos, ulong len)
{
434 435 436 437 438 439 440 441 442 443 444
  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,
445
                  MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
446 447 448 449 450 451 452

}

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

453
  param->set_time(to, MYSQL_TIMESTAMP_DATETIME,
454
                  MAX_DATETIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
455 456 457 458 459 460
}

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

461
  param->set_time(to, MYSQL_TIMESTAMP_DATE,
462
                  MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
463 464 465
}
#endif /*!EMBEDDED_LIBRARY*/

466 467

static void set_param_str(Item_param *param, uchar **pos, ulong len)
venu@myvenu.com's avatar
venu@myvenu.com committed
468
{
469
  ulong length= get_param_length(pos, len);
470
  param->set_str((const char *)*pos, length);
471
  *pos+= length;
venu@myvenu.com's avatar
venu@myvenu.com committed
472 473
}

474 475 476 477 478

#undef get_param_length 

static void setup_one_conversion_function(THD *thd, Item_param *param,
                                          uchar param_type)
venu@myvenu.com's avatar
venu@myvenu.com committed
479
{
480
  switch (param_type) {
481
  case MYSQL_TYPE_TINY:
482
    param->set_param_func= set_param_tiny;
483
    param->item_type= Item::INT_ITEM;
484
    param->item_result_type= INT_RESULT;
485
    break;
486
  case MYSQL_TYPE_SHORT:
487
    param->set_param_func= set_param_short;
488
    param->item_type= Item::INT_ITEM;
489
    param->item_result_type= INT_RESULT;
490
    break;
491
  case MYSQL_TYPE_LONG:
492
    param->set_param_func= set_param_int32;
493
    param->item_type= Item::INT_ITEM;
494
    param->item_result_type= INT_RESULT;
495
    break;
496
  case MYSQL_TYPE_LONGLONG:
497
    param->set_param_func= set_param_int64;
498
    param->item_type= Item::INT_ITEM;
499
    param->item_result_type= INT_RESULT;
500
    break;
501
  case MYSQL_TYPE_FLOAT:
502
    param->set_param_func= set_param_float;
503
    param->item_type= Item::REAL_ITEM;
504
    param->item_result_type= REAL_RESULT;
505
    break;
506
  case MYSQL_TYPE_DOUBLE:
507
    param->set_param_func= set_param_double;
508
    param->item_type= Item::REAL_ITEM;
509
    param->item_result_type= REAL_RESULT;
510
    break;
511
  case MYSQL_TYPE_TIME:
512
    param->set_param_func= set_param_time;
513
    param->item_type= Item::STRING_ITEM;
514
    param->item_result_type= STRING_RESULT;
515
    break;
516
  case MYSQL_TYPE_DATE:
517
    param->set_param_func= set_param_date;
518
    param->item_type= Item::STRING_ITEM;
519
    param->item_result_type= STRING_RESULT;
520
    break;
521 522
  case MYSQL_TYPE_DATETIME:
  case MYSQL_TYPE_TIMESTAMP:
523
    param->set_param_func= set_param_datetime;
524
    param->item_type= Item::STRING_ITEM;
525
    param->item_result_type= STRING_RESULT;
526
    break;
527 528 529 530
  case MYSQL_TYPE_TINY_BLOB:
  case MYSQL_TYPE_MEDIUM_BLOB:
  case MYSQL_TYPE_LONG_BLOB:
  case MYSQL_TYPE_BLOB:
531
    param->set_param_func= set_param_str;
532 533 534
    param->value.cs_info.character_set_client= &my_charset_bin;
    param->value.cs_info.final_character_set_of_str_value= &my_charset_bin;
    param->item_type= Item::STRING_ITEM;
535
    param->item_result_type= STRING_RESULT;
536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565
    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;

      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;
    }
566
  }
567
  param->param_type= (enum enum_field_types) param_type;
568 569
}

hf@deer.(none)'s avatar
SCRUM:  
hf@deer.(none) committed
570
#ifndef EMBEDDED_LIBRARY
571
/*
572 573
  Update the parameter markers by reading data from client packet 
  and if binary/update log is set, generate the valid query.
574 575
*/

576
static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array,
577 578
                                  uchar *read_pos, uchar *data_end, 
                                  String *query)
579
{
580 581 582 583 584
  THD  *thd= stmt->thd;
  Item_param **begin= stmt->param_array;
  Item_param **end= begin + stmt->param_count;
  uint32 length= 0;

585
  String str; 
586
  const String *res;
587

588
  DBUG_ENTER("insert_params_withlog"); 
589

590
  if (query->copy(stmt->query, stmt->query_length, default_charset_info))
591
    DBUG_RETURN(1);
592
  
593
  for (Item_param **it= begin; it < end; ++it)
594
  {
595
    Item_param *param= *it;
596
    if (param->state != Item_param::LONG_DATA_VALUE)
597
    {
598
      if (is_param_null(null_array, it - begin))
599
        param->set_null();
600 601
      else
      {
602 603 604
        if (read_pos >= data_end)
          DBUG_RETURN(1);
        param->set_param_func(param, &read_pos, data_end - read_pos);
605 606
      }
    }
607 608 609 610
    res= param->query_val_str(&str);
    if (param->convert_str_value(thd))
      DBUG_RETURN(1);                           /* out of memory */

611
    if (query->replace(param->pos_in_query+length, 1, *res))
612 613 614 615 616 617 618
      DBUG_RETURN(1);
    
    length+= res->length()-1;
  }
  DBUG_RETURN(0);
}

619

620
static bool insert_params(Prepared_statement *stmt, uchar *null_array,
621 622
                          uchar *read_pos, uchar *data_end, 
                          String *expanded_query)
623
{
624 625
  Item_param **begin= stmt->param_array;
  Item_param **end= begin + stmt->param_count;
626 627 628

  DBUG_ENTER("insert_params"); 

629
  for (Item_param **it= begin; it < end; ++it)
630
  {
631
    Item_param *param= *it;
632
    if (param->state != Item_param::LONG_DATA_VALUE)
633
    {
634
      if (is_param_null(null_array, it - begin))
635
        param->set_null();
636 637
      else
      {
638 639 640
        if (read_pos >= data_end)
          DBUG_RETURN(1);
        param->set_param_func(param, &read_pos, data_end - read_pos);
641 642
      }
    }
643 644
    if (param->convert_str_value(stmt->thd))
      DBUG_RETURN(1);                           /* out of memory */
645 646 647 648
  }
  DBUG_RETURN(0);
}

649

650
static bool setup_conversion_functions(Prepared_statement *stmt,
651
                                       uchar **data, uchar *data_end)
652 653 654
{
  /* skip null bits */
  uchar *read_pos= *data + (stmt->param_count+7) / 8;
655

656
  DBUG_ENTER("setup_conversion_functions");
657

venu@myvenu.com's avatar
venu@myvenu.com committed
658
  if (*read_pos++) //types supplied / first execute
659
  {
venu@myvenu.com's avatar
venu@myvenu.com committed
660 661 662 663
    /*
      First execute or types altered by the client, setup the 
      conversion routines for all parameters (one time)
    */
664 665
    Item_param **it= stmt->param_array;
    Item_param **end= it + stmt->param_count;
666
    THD *thd= stmt->thd;
667 668
    for (; it < end; ++it)
    {
669 670 671
      ushort typecode;
      const uint signed_bit= 1 << 15;

672 673
      if (read_pos >= data_end)
        DBUG_RETURN(1);
674 675

      typecode= sint2korr(read_pos);
venu@myvenu.com's avatar
venu@myvenu.com committed
676
      read_pos+= 2;
677
      (**it).unsigned_flag= test(typecode & signed_bit);
678
      setup_one_conversion_function(thd, *it, (uchar) (typecode & ~signed_bit));
679
    }
680 681
  }
  *data= read_pos;
682 683 684
  DBUG_RETURN(0);
}

685 686
#else

687
static bool emb_insert_params(Prepared_statement *stmt, String *expanded_query)
688
{
689
  THD *thd= stmt->thd;
690 691
  Item_param **it= stmt->param_array;
  Item_param **end= it + stmt->param_count;
692 693
  MYSQL_BIND *client_param= stmt->thd->client_params;

694
  DBUG_ENTER("emb_insert_params");
695

696 697 698
  for (; it < end; ++it, ++client_param)
  {
    Item_param *param= *it;
699 700
    setup_one_conversion_function(thd, param, client_param->buffer_type);
    if (param->state != Item_param::LONG_DATA_VALUE)
701 702
    {
      if (*client_param->is_null)
703
        param->set_null();
704 705
      else
      {
706
        uchar *buff= (uchar*) client_param->buffer;
hf@deer.(none)'s avatar
hf@deer.(none) committed
707
        param->unsigned_flag= client_param->is_unsigned;
708 709 710 711
        param->set_param_func(param, &buff,
                              client_param->length ? 
                              *client_param->length : 
                              client_param->buffer_length);
712 713
      }
    }
714 715
    if (param->convert_str_value(thd))
      DBUG_RETURN(1);                           /* out of memory */
716 717 718 719
  }
  DBUG_RETURN(0);
}

720

721
static bool emb_insert_params_withlog(Prepared_statement *stmt, String *query)
722
{
723
  THD *thd= stmt->thd;
724 725
  Item_param **it= stmt->param_array;
  Item_param **end= it + stmt->param_count;
726 727
  MYSQL_BIND *client_param= thd->client_params;

728
  String str;
729
  const String *res;
730
  uint32 length= 0;
731

732
  DBUG_ENTER("emb_insert_params_withlog");
733

734
  if (query->copy(stmt->query, stmt->query_length, default_charset_info))
735 736
    DBUG_RETURN(1);
  
737 738 739
  for (; it < end; ++it, ++client_param)
  {
    Item_param *param= *it;
740 741
    setup_one_conversion_function(thd, param, client_param->buffer_type);
    if (param->state != Item_param::LONG_DATA_VALUE)
742 743
    {
      if (*client_param->is_null)
744
        param->set_null();
745 746
      else
      {
747
        uchar *buff= (uchar*)client_param->buffer;
748
	param->unsigned_flag= client_param->is_unsigned;
749 750 751 752
        param->set_param_func(param, &buff,
                              client_param->length ? 
                              *client_param->length : 
                              client_param->buffer_length);
753 754
      }
    }
755 756 757 758
    res= param->query_val_str(&str);
    if (param->convert_str_value(thd))
      DBUG_RETURN(1);                           /* out of memory */

759
    if (query->replace(param->pos_in_query+length, 1, *res))
760
      DBUG_RETURN(1);
761

762 763 764 765 766
    length+= res->length()-1;
  }
  DBUG_RETURN(0);
}

hf@deer.(none)'s avatar
SCRUM:  
hf@deer.(none) committed
767 768
#endif /*!EMBEDDED_LIBRARY*/

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

770
/*
sergefp@mysql.com's avatar
sergefp@mysql.com committed
771 772 773 774 775 776
  Set prepared statement parameters from user variables.
  SYNOPSIS
    insert_params_from_vars()
      stmt      Statement
      varnames  List of variables. Caller must ensure that number of variables
                in the list is equal to number of statement parameters
777
      query     Ignored
sergefp@mysql.com's avatar
sergefp@mysql.com committed
778 779
*/

780 781
static bool insert_params_from_vars(Prepared_statement *stmt,
                                    List<LEX_STRING>& varnames,
782
                                    String *query __attribute__((unused)))
sergefp@mysql.com's avatar
sergefp@mysql.com committed
783 784 785 786 787 788
{
  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);
789 790
  DBUG_ENTER("insert_params_from_vars");

sergefp@mysql.com's avatar
sergefp@mysql.com committed
791 792 793 794
  for (Item_param **it= begin; it < end; ++it)
  {
    Item_param *param= *it;
    varname= var_it++;
795 796 797 798 799 800
    entry= (user_var_entry*)hash_search(&stmt->thd->user_vars,
                                        (byte*) varname->str,
                                         varname->length);
    if (param->set_from_user_var(stmt->thd, entry) ||
        param->convert_str_value(stmt->thd))
      DBUG_RETURN(1);
sergefp@mysql.com's avatar
sergefp@mysql.com committed
801 802 803 804
  }
  DBUG_RETURN(0);
}

805

806
/*
807 808 809 810 811 812 813 814 815 816
  Do the same as insert_params_from_vars but also construct query text for
  binary log.
  SYNOPSIS
    insert_params_from_vars()
      stmt      Statement
      varnames  List of variables. Caller must ensure that number of variables
                in the list is equal to number of statement parameters
      query     The query with parameter markers replaced with their values
*/

sergefp@mysql.com's avatar
sergefp@mysql.com committed
817
static bool insert_params_from_vars_with_log(Prepared_statement *stmt,
818
                                             List<LEX_STRING>& varnames,
819
                                             String *query)
sergefp@mysql.com's avatar
sergefp@mysql.com committed
820 821 822 823 824
{
  Item_param **begin= stmt->param_array;
  Item_param **end= begin + stmt->param_count;
  user_var_entry *entry;
  LEX_STRING *varname;
825
  DBUG_ENTER("insert_params_from_vars");
sergefp@mysql.com's avatar
sergefp@mysql.com committed
826 827

  List_iterator<LEX_STRING> var_it(varnames);
828
  String str;
sergefp@mysql.com's avatar
sergefp@mysql.com committed
829
  uint32 length= 0;
830
  if (query->copy(stmt->query, stmt->query_length, default_charset_info))
831
    DBUG_RETURN(1);
sergefp@mysql.com's avatar
sergefp@mysql.com committed
832 833 834 835 836

  for (Item_param **it= begin; it < end; ++it)
  {
    Item_param *param= *it;
    varname= var_it++;
837 838 839
    if (get_var_with_binlog(stmt->thd, *varname, &entry))
        DBUG_RETURN(1);
    DBUG_ASSERT(entry);
sergefp@mysql.com's avatar
sergefp@mysql.com committed
840

841 842 843
    if (param->set_from_user_var(stmt->thd, entry))
      DBUG_RETURN(1);
    /* Insert @'escaped-varname' instead of parameter in the query */
844 845 846
    char *buf, *ptr;
    str.length(0);
    if (str.reserve(entry->name.length*2+3))
sergefp@mysql.com's avatar
sergefp@mysql.com committed
847
      DBUG_RETURN(1);
848 849 850 851 852

    buf= str.c_ptr_quick();
    ptr= buf;
    *ptr++= '@';
    *ptr++= '\'';
853 854
    ptr+=
      escape_string_for_mysql(&my_charset_utf8_general_ci,
855 856 857 858 859 860
                              ptr, entry->name.str, entry->name.length);
    *ptr++= '\'';
    str.length(ptr - buf);

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

862 863 864
    if (query->replace(param->pos_in_query+length, 1, str))
      DBUG_RETURN(1);
    length+= str.length()-1;
sergefp@mysql.com's avatar
sergefp@mysql.com committed
865 866 867 868
  }
  DBUG_RETURN(0);
}

869
/*
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
870 871
  Validate INSERT statement: 

872
  SYNOPSIS
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
873 874
    mysql_test_insert()
    stmt	prepared statemen handler
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
875
    tables	global/local table list  
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
876

877
  RETURN VALUE
878 879
    FALSE OK
    TRUE  error
880
*/
monty@mysql.com's avatar
monty@mysql.com committed
881

882 883 884 885 886 887 888
static bool mysql_test_insert(Prepared_statement *stmt,
                              TABLE_LIST *table_list,
                              List<Item> &fields, 
                              List<List_item> &values_list,
                              List<Item> &update_fields,
                              List<Item> &update_values,
                              enum_duplicates duplic)
889
{
890
  THD *thd= stmt->thd;
891
  LEX *lex= stmt->lex;
892 893
  List_iterator_fast<List_item> its(values_list);
  List_item *values;
894
  bool res;
895
  DBUG_ENTER("mysql_test_insert");
896

897
  if ((res= insert_precheck(thd, table_list)))
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
898
    DBUG_RETURN(res);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
899

900
  /*
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
901 902 903
     open temporary memory pool for temporary data allocated by derived
     tables & preparation procedure
  */
904
  if (open_and_lock_tables(thd, table_list))
905
  {
906
    DBUG_RETURN(TRUE);
907 908
  }

909

910 911 912
  if ((values= its++))
  {
    uint value_count;
913
    ulong counter= 0;
monty@mysql.com's avatar
monty@mysql.com committed
914
    Item *unused_conds= 0;
915

serg@sergbook.mysql.com's avatar
serg@sergbook.mysql.com committed
916
    if (table_list->table)
917 918 919 920 921
    {
      // don't allocate insert_values
      table_list->table->insert_values=(byte *)1;
    }

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
922 923
    if ((res= mysql_prepare_insert(thd, table_list, table_list->table, 
				   fields, values, update_fields,
monty@mysql.com's avatar
monty@mysql.com committed
924 925
				   update_values, duplic,
                                   &unused_conds, FALSE)))
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
926
      goto error;
927

928 929
    value_count= values->elements;
    its.rewind();
930

931 932 933 934 935 936 937 938 939 940
    res= TRUE;

    if (table_list->lock_type == TL_WRITE_DELAYED &&
        !(table_list->table->file->table_flags() & HA_CAN_INSERT_DELAYED))
    {
      my_error(ER_ILLEGAL_HA, MYF(0), (table_list->view ?
                                       table_list->view_name.str :
                                       table_list->real_name));
      goto error;
    }
941
    while ((values= its++))
942 943 944 945
    {
      counter++;
      if (values->elements != value_count)
      {
946
        my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter);
947
        goto error;
948
      }
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
949
      if (setup_fields(thd, 0, table_list, *values, 0, 0, 0))
950
	goto error;
951 952
    }
  }
953

954
  res= FALSE;
955 956
error:
  lex->unit.cleanup();
957
  /* insert_values is cleared in open_table */
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
958
  DBUG_RETURN(res);
959 960 961 962
}


/*
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
963 964
  Validate UPDATE statement

965
  SYNOPSIS
966
    mysql_test_update()
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
967 968 969
    stmt	prepared statemen handler
    tables	list of tables queries

970 971
  RETURN VALUE
    0   success
972
    2   convert to multi_update
bell@sanja.is.com.ua's avatar
merge  
bell@sanja.is.com.ua committed
973
    1   error
974
*/
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
975
static int mysql_test_update(Prepared_statement *stmt,
976
                              TABLE_LIST *table_list)
977
{
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
978
  int res;
979
  THD *thd= stmt->thd;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
980
  uint table_count= 0;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
981
  SELECT_LEX *select= &stmt->lex->select_lex;
982 983 984
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  uint		want_privilege;
#endif
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
985 986
  DBUG_ENTER("mysql_test_update");

bell@sanja.is.com.ua's avatar
merge  
bell@sanja.is.com.ua committed
987 988
  if (update_precheck(thd, table_list))
    DBUG_RETURN(1);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
989

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
990
  if (!open_tables(thd, table_list, &table_count))
991
  {
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
992
    if (table_list->ancestor && table_list->ancestor->next_local)
993
    {
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
994 995 996 997 998 999 1000 1001 1002
      DBUG_ASSERT(table_list->view);
      DBUG_PRINT("info", ("Switch to multi-update"));
      /* pass counter value */
      thd->lex->table_count= table_count;
      /*
	give correct value to multi_lock_option, because it will be used
	in multiupdate
      */
      thd->lex->multi_lock_option= table_list->lock_type;
1003 1004 1005
      /* convert to multiupdate */
      return 2;
    }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1006

1007 1008 1009 1010
    /*
      thd->fill_derived_tables() is false here for sure (because it is
      preparation of PS, so we even do not check it
    */
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1011
    if (lock_tables(thd, table_list, table_count) ||
1012
	mysql_handle_derived(thd->lex, &mysql_derived_prepare))
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1013 1014
      DBUG_RETURN(1);

1015 1016 1017 1018 1019
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  /* TABLE_LIST contain right privilages request */
  want_privilege= table_list->grant.want_privilege;
#endif

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1020 1021 1022 1023 1024
    if (!(res= mysql_prepare_update(thd, table_list,
				    &select->where,
				    select->order_list.elements,
				    (ORDER *) select->order_list.first)))
    {
1025 1026 1027 1028 1029
#ifndef NO_EMBEDDED_ACCESS_CHECKS
      table_list->grant.want_privilege=
        table_list->table->grant.want_privilege=
        want_privilege;
#endif
1030 1031 1032
      thd->lex->select_lex.no_wrap_view_item= 1;
      if (setup_fields(thd, 0, table_list, select->item_list, 1, 0, 0))
      {
bell@sanja.is.com.ua's avatar
merge  
bell@sanja.is.com.ua committed
1033
        res= 1;
1034 1035 1036 1037 1038
        thd->lex->select_lex.no_wrap_view_item= 0;
      }
      else
      {
        thd->lex->select_lex.no_wrap_view_item= 0;
1039 1040 1041 1042 1043 1044
#ifndef NO_EMBEDDED_ACCESS_CHECKS
        /* Check values */
        table_list->grant.want_privilege=
          table_list->table->grant.want_privilege=
          (SELECT_ACL & ~table_list->table->grant.privilege);
#endif
1045 1046
        if (setup_fields(thd, 0, table_list,
                         stmt->lex->value_list, 0, 0, 0))
bell@sanja.is.com.ua's avatar
merge  
bell@sanja.is.com.ua committed
1047
          res= 1;
1048
      }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1049
    }
1050
    stmt->lex->unit.cleanup();
1051
  }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1052 1053
  else
    res= 1;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1054 1055
  /* TODO: here we should send types of placeholders to the client. */ 
  DBUG_RETURN(res);
1056 1057 1058 1059
}


/*
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1060 1061
  Validate DELETE statement

1062
  SYNOPSIS
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1063 1064 1065 1066
    mysql_test_delete()
    stmt	prepared statemen handler
    tables	list of tables queries

1067
  RETURN VALUE
1068 1069
    FALSE success
    TRUE  error
1070
*/
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1071 1072
static int mysql_test_delete(Prepared_statement *stmt,
			     TABLE_LIST *table_list)
1073
{
1074
  THD *thd= stmt->thd;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1075 1076
  LEX *lex= stmt->lex;
  DBUG_ENTER("mysql_test_delete");
1077

1078 1079
  if (delete_precheck(thd, table_list))
    DBUG_RETURN(TRUE);
1080

1081
  if (!open_and_lock_tables(thd, table_list))
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1082
  {
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1083
    bool res;
1084 1085 1086 1087 1088 1089 1090 1091 1092
    if (!table_list->table)
    {
      DBUG_ASSERT(table_list->view &&
                  table_list->ancestor && table_list->ancestor->next_local);
      my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
               table_list->view_db.str, table_list->view_name.str);
      DBUG_RETURN(-1);
    }

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1093
    res= mysql_prepare_delete(thd, table_list, &lex->select_lex.where);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1094
    lex->unit.cleanup();
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1095
    DBUG_RETURN(res);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1096 1097
  }
  /* TODO: here we should send types of placeholders to the client. */ 
1098
  DBUG_RETURN(TRUE);
1099 1100
}

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

1102
/*
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1103
  Validate SELECT statement.
1104 1105
  In case of success, if this query is not EXPLAIN, send column list info
  back to client. 
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1106

1107
  SYNOPSIS
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1108 1109 1110 1111
    mysql_test_select()
    stmt	prepared statemen handler
    tables	list of tables queries

1112
  RETURN VALUE
1113 1114
    FALSE success
    TRUE  error, sent to client
1115
*/
1116

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1117
static int mysql_test_select(Prepared_statement *stmt,
sergefp@mysql.com's avatar
Merged  
sergefp@mysql.com committed
1118
			     TABLE_LIST *tables, bool text_protocol)
1119
{
1120
  THD *thd= stmt->thd;
1121
  LEX *lex= stmt->lex;
1122
  SELECT_LEX_UNIT *unit= &lex->unit;
1123
  bool result;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1124
  DBUG_ENTER("mysql_test_select");
1125

hf@deer.(none)'s avatar
SCRUM:  
hf@deer.(none) committed
1126
#ifndef NO_EMBEDDED_ACCESS_CHECKS
1127 1128 1129
  ulong privilege= lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL;
  if (tables)
  {
hf@deer.(none)'s avatar
SCRUM:  
hf@deer.(none) committed
1130
    if (check_table_access(thd, privilege, tables,0))
1131
      DBUG_RETURN(TRUE);
1132
  }
1133
  else if (check_access(thd, privilege, any_db,0,0,0))
1134
    DBUG_RETURN(TRUE);
hf@deer.(none)'s avatar
SCRUM:  
hf@deer.(none) committed
1135
#endif
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1136

1137
  result= TRUE;
monty@mysql.com's avatar
monty@mysql.com committed
1138
  if (!lex->result && !(lex->result= new (stmt->mem_root) select_send))
1139 1140
    goto err;

1141
  if (open_and_lock_tables(thd, tables))
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1142
    goto err;
1143

1144

1145 1146
  thd->used_tables= 0;                        // Updated by setup_fields

1147 1148 1149 1150 1151
  /*
    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
  */
1152 1153 1154 1155
  if (unit->prepare(thd, 0, 0))
  {
    goto err_prep;
  }
1156
  if (!text_protocol)
1157
  {
1158 1159
    if (lex->describe)
    {
1160
      if (send_prep_stmt(stmt, 0) || thd->protocol->flush())
1161 1162 1163
        goto err_prep;
    }
    else
1164
    {
1165 1166 1167 1168 1169 1170 1171 1172
      /* Make copy of item list, as change_columns may change it */
      List<Item> fields(lex->select_lex.item_list);

      /* Change columns if a procedure like analyse() */
      if (unit->last_procedure &&
          unit->last_procedure->change_columns(fields))
        goto err_prep;

1173 1174 1175 1176 1177
      /*
        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)) ||
1178
          lex->result->send_fields(fields, Protocol::SEND_EOF) ||
1179
          thd->protocol->flush())
sergefp@mysql.com's avatar
sergefp@mysql.com committed
1180 1181
        goto err_prep;
    }
1182
  }
1183
  result= FALSE;                                    // ok
1184 1185 1186 1187

err_prep:
  unit->cleanup();
err:
1188
  DBUG_RETURN(result);
1189 1190
}

1191

1192 1193 1194 1195 1196 1197 1198 1199 1200 1201
/*
  Validate and prepare for execution DO statement expressions

  SYNOPSIS
    mysql_test_do_fields()
    stmt	prepared statemen handler
    tables	list of tables queries
    values	list of expressions

  RETURN VALUE
1202 1203
    FALSE success
    TRUE  error, sent to client
1204 1205
*/

1206
static bool mysql_test_do_fields(Prepared_statement *stmt,
1207 1208 1209 1210 1211
				TABLE_LIST *tables,
				List<Item> *values)
{
  DBUG_ENTER("mysql_test_do_fields");
  THD *thd= stmt->thd;
1212 1213 1214
  bool res;
  if (tables && check_table_access(thd, SELECT_ACL, tables, 0))
    DBUG_RETURN(TRUE);
1215

1216
  if (tables && open_and_lock_tables(thd, tables))
1217
  {
1218
    DBUG_RETURN(TRUE);
1219 1220 1221
  }
  res= setup_fields(thd, 0, 0, *values, 0, 0, 0);
  stmt->lex->unit.cleanup();
1222
  DBUG_RETURN(res);
1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235
}


/*
  Validate and prepare for execution SET statement expressions

  SYNOPSIS
    mysql_test_set_fields()
    stmt	prepared statemen handler
    tables	list of tables queries
    values	list of expressions

  RETURN VALUE
1236 1237
    FALSE success
    TRUE  error
1238
*/
1239 1240 1241
static bool mysql_test_set_fields(Prepared_statement *stmt,
                                  TABLE_LIST *tables,
                                  List<set_var_base> *var_list)
1242 1243 1244 1245 1246
{
  DBUG_ENTER("mysql_test_set_fields");
  List_iterator_fast<set_var_base> it(*var_list);
  THD *thd= stmt->thd;
  set_var_base *var;
1247
  bool res= 0;
1248

1249 1250
  if (tables && check_table_access(thd, SELECT_ACL, tables, 0))
    DBUG_RETURN(TRUE);
1251

1252 1253 1254 1255 1256 1257 1258
  if (tables && (res= open_and_lock_tables(thd, tables)))
    goto error;
  while ((var= it++))
  {
    if (var->light_check(thd))
    {
      stmt->lex->unit.cleanup();
1259
      res= TRUE;
1260 1261 1262 1263
      goto error;
    }
  }
error:
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1264
  stmt->lex->unit.cleanup();
1265 1266 1267 1268 1269 1270 1271 1272 1273
  DBUG_RETURN(res);
}


/*
  Check internal SELECT of the prepared command

  SYNOPSIS
    select_like_statement_test()
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1274 1275 1276
      stmt              - prepared table handler
      tables            - global list of tables
      specific_prepare  - function of command specific prepare
1277

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1278
  RETURN VALUE
1279 1280
    FALSE success
    TRUE  error
1281
*/
1282 1283
static bool select_like_statement_test(Prepared_statement *stmt,
                                       TABLE_LIST *tables,
1284 1285
                                       bool (*specific_prepare)(THD *thd),
                                       ulong setup_tables_done_option)
1286 1287 1288 1289
{
  DBUG_ENTER("select_like_statement_test");
  THD *thd= stmt->thd;
  LEX *lex= stmt->lex;
1290
  bool res= 0;
1291

1292 1293 1294 1295
  /* check that tables was not opened during conversion from usual update */
  if (tables &&
      (!tables->table && !tables->view) &&
      (res= open_and_lock_tables(thd, tables)))
1296 1297
    goto end;

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1298 1299 1300
  if (specific_prepare && (res= (*specific_prepare)(thd)))
    goto end;

1301 1302
  thd->used_tables= 0;                        // Updated by setup_fields

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1303
  // JOIN::prepare calls
1304
  if (lex->unit.prepare(thd, 0, setup_tables_done_option))
1305
  {
1306
    res= TRUE;
1307 1308 1309 1310 1311 1312 1313 1314
  }
end:
  lex->unit.cleanup();
  DBUG_RETURN(res);
}


/*
1315
  Validate and prepare for execution CREATE TABLE statement
1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326

  SYNOPSIS
    mysql_test_create_table()
    stmt	prepared statemen handler
    tables	list of tables queries

  RETURN VALUE
    0   success
    1   error, sent to client
   -1   error, not sent to client
*/
monty@mysql.com's avatar
monty@mysql.com committed
1327

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1328
static int mysql_test_create_table(Prepared_statement *stmt)
1329 1330 1331 1332
{
  DBUG_ENTER("mysql_test_create_table");
  THD *thd= stmt->thd;
  LEX *lex= stmt->lex;
1333
  SELECT_LEX *select_lex= &lex->select_lex;
1334 1335
  int res= 0;
  /* Skip first table, which is the table we are creating */
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1336 1337 1338
  bool link_to_local;
  TABLE_LIST *create_table= lex->unlink_first_table(&link_to_local);
  TABLE_LIST *tables= lex->query_tables;
1339

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1340
  if (!(res= create_table_precheck(thd, tables, create_table)) &&
1341 1342 1343
      select_lex->item_list.elements)
  {
    select_lex->resolve_mode= SELECT_LEX::SELECT_MODE;
1344
    res= select_like_statement_test(stmt, tables, 0, 0);
1345 1346
    select_lex->resolve_mode= SELECT_LEX::NOMATTER_MODE;
  }
1347

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1348
  /* put tables back for PS rexecuting */
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1349
  lex->link_first_table_back(create_table, link_to_local);
1350 1351 1352
  DBUG_RETURN(res);
}

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

1354
/*
1355
  Validate and prepare for execution multi update statement
1356 1357 1358 1359 1360

  SYNOPSIS
    mysql_test_multiupdate()
    stmt	prepared statemen handler
    tables	list of tables queries
1361
    converted   converted to multi-update from usual update
1362 1363

  RETURN VALUE
1364 1365
    FALSE success
    TRUE error
1366
*/
1367 1368

static bool mysql_test_multiupdate(Prepared_statement *stmt,
1369 1370
				  TABLE_LIST *tables,
                                  bool converted)
1371
{
1372
  /* if we switched from normal update, rights are checked */
bell@sanja.is.com.ua's avatar
merge  
bell@sanja.is.com.ua committed
1373
  if (!converted && multi_update_precheck(stmt->thd, tables))
1374
    return TRUE;
1375 1376 1377 1378
  /*
    here we do not pass tables for opening, tables will be opened and locked
    by mysql_multi_update_prepare
  */
1379 1380
  return select_like_statement_test(stmt, 0, &mysql_multi_update_prepare,
                                    OPTION_SETUP_TABLES_DONE);
1381 1382 1383 1384
}


/*
1385
  Validate and prepare for execution multi delete statement
1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404

  SYNOPSIS
    mysql_test_multidelete()
    stmt	prepared statemen handler
    tables	list of tables queries

  RETURN VALUE
    0   success
    1   error, sent to client
   -1   error, not sent to client
*/
static int mysql_test_multidelete(Prepared_statement *stmt,
				  TABLE_LIST *tables)
{
  int res;
  stmt->thd->lex->current_select= &stmt->thd->lex->select_lex;
  if (add_item_to_list(stmt->thd, new Item_null()))
    return -1;

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1405
  uint fake_counter;
1406 1407
  if ((res= multi_delete_precheck(stmt->thd, tables, &fake_counter)))
    return res;
1408
  if ((res= select_like_statement_test(stmt, tables,
1409 1410
                                       &mysql_multi_delete_prepare,
                                       OPTION_SETUP_TABLES_DONE)))
1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421
    return res;
  if (!tables->table)
  {
    DBUG_ASSERT(tables->view &&
		tables->ancestor && tables->ancestor->next_local);
    my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
	     tables->view_db.str, tables->view_name.str);
    return -1;
  }
  return 0;

1422 1423 1424
}


1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451
/*
  Wrapper for mysql_insert_select_prepare, to make change of local tables
  after open_and_lock_tables() call.

  SYNOPSIS
    mysql_insert_select_prepare_tester()
    thd     thread handler

  NOTE: we need remove first local tables after open_and_lock_tables,
  because mysql_handle_derived use local tables lists
*/

static bool mysql_insert_select_prepare_tester(THD *thd)
{
  SELECT_LEX *first_select= &thd->lex->select_lex;
  /* Skip first table, which is the table we are inserting in */
  first_select->table_list.first= (byte*)((TABLE_LIST*)first_select->
                                          table_list.first)->next_local;
  /*
    insert/replace from SELECT give its SELECT_LEX for SELECT,
    and item_list belong to SELECT
  */
  first_select->resolve_mode= SELECT_LEX::SELECT_MODE;
  mysql_insert_select_prepare(thd);
}


1452 1453 1454 1455 1456 1457
/*
  Validate and prepare for execution INSERT ... SELECT statement

  SYNOPSIS
    mysql_test_insert_select()
    stmt	prepared statemen handler
1458
    tables	list of tables of query
1459 1460 1461 1462 1463 1464

  RETURN VALUE
    0   success
    1   error, sent to client
   -1   error, not sent to client
*/
monty@mysql.com's avatar
monty@mysql.com committed
1465

1466 1467 1468 1469 1470
static int mysql_test_insert_select(Prepared_statement *stmt,
				    TABLE_LIST *tables)
{
  int res;
  LEX *lex= stmt->lex;
monty@mysql.com's avatar
monty@mysql.com committed
1471 1472
  TABLE_LIST *first_local_table;

1473 1474 1475 1476 1477
  if (tables->table)
  {
    // don't allocate insert_values
    tables->table->insert_values=(byte *)1;
  }
monty@mysql.com's avatar
monty@mysql.com committed
1478

1479 1480 1481 1482 1483 1484 1485 1486 1487
  if ((res= insert_precheck(stmt->thd, tables)))
    return res;

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

  res= select_like_statement_test(stmt, tables,
                                  &mysql_insert_select_prepare_tester,
1488
                                  OPTION_SETUP_TABLES_DONE);
1489
  /* revert changes  made by mysql_insert_select_prepare_tester */
miguel@hegel.local's avatar
miguel@hegel.local committed
1490
  lex->select_lex.table_list.first= (byte*) first_local_table;
1491 1492 1493 1494 1495
  lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE;
  return res;
}


1496
/*
1497 1498 1499
  Perform semantic analysis of the parsed tree and send a response packet
  to the client.

1500
  SYNOPSIS
1501 1502 1503 1504 1505 1506 1507 1508 1509
    check_prepared_statement()
      stmt  prepared statement

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

1510 1511 1512
  RETURN VALUE
    0   success
    1   error, sent to client
1513
*/
1514 1515 1516 1517

static int check_prepared_statement(Prepared_statement *stmt,
                                    bool text_protocol)
{
1518
  THD *thd= stmt->thd;
1519
  LEX *lex= stmt->lex;
1520
  SELECT_LEX *select_lex= &lex->select_lex;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1521
  TABLE_LIST *tables;
1522
  enum enum_sql_command sql_command= lex->sql_command;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1523
  int res= 0;
1524
  DBUG_ENTER("check_prepared_statement");
1525
  DBUG_PRINT("enter",("command: %d, param_count: %ld",
1526
                      sql_command, stmt->param_count));
1527

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1528 1529
  lex->first_lists_tables_same();
  tables= lex->query_tables;
1530

1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544
  /*
    Preopen 'proc' system table and cache all functions used in this
    statement. We must do that before we open ordinary tables to avoid
    deadlocks. We can't open and lock any table once query tables were
    opened.
  */
  if (lex->sql_command != SQLCOM_CREATE_PROCEDURE &&
      lex->sql_command != SQLCOM_CREATE_SPFUNCTION)
  {
    /* the error is print inside */
    if (sp_cache_functions(thd, lex))
      DBUG_RETURN(1);
  }

1545
  switch (sql_command) {
1546
  case SQLCOM_REPLACE:
1547
  case SQLCOM_INSERT:
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1548 1549 1550
    res= mysql_test_insert(stmt, tables, lex->field_list,
			   lex->many_values,
			   select_lex->item_list, lex->value_list,
1551
			   lex->duplicates);
1552 1553 1554
    break;

  case SQLCOM_UPDATE:
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1555
    res= mysql_test_update(stmt, tables);
1556
    /* mysql_test_update return 2 if we need to switch to multi-update */
1557 1558 1559 1560 1561
    if (res != 2)
      break;

  case SQLCOM_UPDATE_MULTI:
    res= mysql_test_multiupdate(stmt, tables, res == 2);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1562 1563
    break;

1564
  case SQLCOM_DELETE:
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1565
    res= mysql_test_delete(stmt, tables);
1566 1567 1568
    break;

  case SQLCOM_SELECT:
sergefp@mysql.com's avatar
Merged  
sergefp@mysql.com committed
1569
    if ((res= mysql_test_select(stmt, tables, text_protocol)))
1570 1571 1572
      goto error;
    /* Statement and field info has already been sent */
    DBUG_RETURN(0);
1573

1574
  case SQLCOM_CREATE_TABLE:
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1575
    res= mysql_test_create_table(stmt);
1576 1577 1578
    break;
  
  case SQLCOM_DO:
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1579 1580
    res= mysql_test_do_fields(stmt, tables, lex->insert_list);
    break;
1581 1582

  case SQLCOM_SET_OPTION:
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1583
    res= mysql_test_set_fields(stmt, tables, &lex->var_list);
1584 1585 1586
    break;

  case SQLCOM_DELETE_MULTI:
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1587
    res= mysql_test_multidelete(stmt, tables);
1588 1589 1590
    break;

  case SQLCOM_INSERT_SELECT:
1591
  case SQLCOM_REPLACE_SELECT:
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1592
    res= mysql_test_insert_select(stmt, tables);
1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612
    break;

  case SQLCOM_SHOW_DATABASES:
  case SQLCOM_SHOW_PROCESSLIST:
  case SQLCOM_SHOW_STORAGE_ENGINES:
  case SQLCOM_SHOW_PRIVILEGES:
  case SQLCOM_SHOW_COLUMN_TYPES:
  case SQLCOM_SHOW_STATUS:
  case SQLCOM_SHOW_VARIABLES:
  case SQLCOM_SHOW_LOGS:
  case SQLCOM_SHOW_TABLES:
  case SQLCOM_SHOW_OPEN_TABLES:
  case SQLCOM_SHOW_CHARSETS:
  case SQLCOM_SHOW_COLLATIONS:
  case SQLCOM_SHOW_FIELDS:
  case SQLCOM_SHOW_KEYS:
  case SQLCOM_SHOW_CREATE_DB:
  case SQLCOM_SHOW_GRANTS:
  case SQLCOM_DROP_TABLE:
  case SQLCOM_RENAME_TABLE:
1613 1614 1615 1616 1617 1618
  case SQLCOM_ALTER_TABLE:
  case SQLCOM_COMMIT:
  case SQLCOM_CREATE_INDEX:
  case SQLCOM_DROP_INDEX:
  case SQLCOM_ROLLBACK:
  case SQLCOM_TRUNCATE:
1619 1620
    break;

1621
  default:
1622 1623
    /*
      All other is not supported yet
1624
    */
1625
    res= -1;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1626
    my_message(ER_UNSUPPORTED_PS, ER(ER_UNSUPPORTED_PS), MYF(0));
1627
    goto error;
1628
  }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1629
  if (res == 0)
1630 1631
    DBUG_RETURN(text_protocol? 0 : (send_prep_stmt(stmt, 0) ||
                                    thd->protocol->flush()));
1632
error:
1633
  DBUG_RETURN(1);
1634 1635
}

venu@myvenu.com's avatar
venu@myvenu.com committed
1636
/*
1637 1638
  Initialize array of parameters in statement from LEX.
  (We need to have quick access to items by number in mysql_stmt_get_longdata).
1639
  This is to avoid using malloc/realloc in the parser.
venu@myvenu.com's avatar
venu@myvenu.com committed
1640
*/
1641

1642
static bool init_param_array(Prepared_statement *stmt)
venu@myvenu.com's avatar
venu@myvenu.com committed
1643
{
1644
  LEX *lex= stmt->lex;
1645
  THD *thd= stmt->thd;
1646 1647
  if ((stmt->param_count= lex->param_list.elements))
  {
1648 1649 1650
    if (stmt->param_count > (uint) UINT_MAX16)
    {
      /* Error code to be defined in 5.0 */
1651 1652
      my_message(ER_PS_MANY_PARAM, ER(ER_PS_MANY_PARAM), MYF(0));
      return TRUE;
1653
    }
1654 1655 1656 1657
    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 **)
monty@mysql.com's avatar
monty@mysql.com committed
1658
                       alloc_root(stmt->thd->mem_root,
1659 1660
                                  sizeof(Item_param*) * stmt->param_count);
    if (!stmt->param_array)
1661
      return TRUE;
1662 1663 1664 1665 1666 1667 1668
    for (to= stmt->param_array;
         to < stmt->param_array + stmt->param_count;
         ++to)
    {
      *to= param_iterator++;
    }
  }
1669
  return FALSE;
venu@myvenu.com's avatar
venu@myvenu.com committed
1670
}
1671

1672
/*
1673 1674 1675
  Given a query string with parameter markers, create a Prepared Statement
  from it and send PS info back to the client.
  
1676 1677
  SYNOPSIS
    mysql_stmt_prepare()
1678 1679 1680
      packet         query to be prepared 
      packet_length  query string length, including ignored trailing NULL or 
                     quote char.
1681
      name           NULL or statement name. For unnamed statements binary PS
1682
                     protocol is used, for named statements text protocol is 
1683
                     used.
1684 1685 1686 1687
  RETURN
    FALSE  OK, statement prepared successfully
    TRUE  Error

1688 1689 1690 1691 1692 1693 1694 1695 1696 1697
  NOTES
    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. 

    If parameter markers are found in the query, then store the information
    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 
    field items.
1698
   
1699 1700
*/

1701 1702
bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
                        LEX_STRING *name)
1703
{
1704 1705
  LEX *lex;
  Prepared_statement *stmt= new Prepared_statement(thd);
1706
  bool error;
1707
  DBUG_ENTER("mysql_stmt_prepare");
1708

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1709
  DBUG_PRINT("prep_query", ("%s", packet));
1710

1711
  if (stmt == 0)
1712
    DBUG_RETURN(TRUE);
1713 1714 1715 1716

  if (name)
  {
    stmt->name.length= name->length;
monty@mysql.com's avatar
monty@mysql.com committed
1717
    if (!(stmt->name.str= memdup_root(stmt->mem_root, (char*)name->str,
1718
                                      name->length)))
1719 1720
    {
      delete stmt;
1721
      DBUG_RETURN(TRUE);
1722
    }
1723
  }
1724

1725
  if (thd->stmt_map.insert(stmt))
1726 1727
  {
    delete stmt;
1728
    DBUG_RETURN(TRUE);
1729
  }
1730

1731 1732
  thd->set_n_backup_statement(stmt, &thd->stmt_backup);
  thd->set_n_backup_item_arena(stmt, &thd->stmt_backup);
1733

1734
  if (alloc_query(thd, packet, packet_length))
1735
  {
1736 1737
    thd->restore_backup_statement(stmt, &thd->stmt_backup);
    thd->restore_backup_item_arena(stmt, &thd->stmt_backup);
1738 1739
    /* Statement map deletes statement on erase */
    thd->stmt_map.erase(stmt);
1740
    DBUG_RETURN(TRUE);
1741
  }
1742

1743
  mysql_log.write(thd, COM_PREPARE, "%s", packet);
1744

1745
  thd->current_arena= stmt;
1746
  mysql_init_query(thd, (uchar *) thd->query, thd->query_length);
1747 1748
  /* Reset warnings from previous command */
  mysql_reset_errors(thd);
1749
  lex= thd->lex;
1750 1751
  lex->safe_to_cache_query= 0;

1752
  error= yyparse((void *)thd) || thd->is_fatal_error ||
1753
         thd->net.report_error || init_param_array(stmt);
1754
  /*
1755 1756
    While doing context analysis of the query (in check_prepared_statement)
    we allocate a lot of additional memory: for open tables, JOINs, derived
1757 1758 1759 1760 1761 1762 1763 1764
    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_backup_item_arena(stmt, &thd->stmt_backup);

  if (!error)
1765
    error= check_prepared_statement(stmt, test(name));
1766

1767
  /* restore to WAIT_PRIOR: QUERY_PRIOR is set inside alloc_query */
1768
  if (!(specialflag & SPECIAL_NO_PRIOR))
venu@myvenu.com's avatar
venu@myvenu.com committed
1769
    my_pthread_setprio(pthread_self(),WAIT_PRIOR);
pem@mysql.com's avatar
pem@mysql.com committed
1770
  if (error && thd->lex->sphead)
pem@mysql.comhem.se's avatar
pem@mysql.comhem.se committed
1771 1772 1773 1774 1775 1776
  {
    if (lex != thd->lex)
      thd->lex->sphead->restore_lex(thd);
    delete thd->lex->sphead;
    thd->lex->sphead= NULL;
  }
1777
  lex_end(lex);
1778 1779 1780
  thd->restore_backup_statement(stmt, &thd->stmt_backup);
  cleanup_items(stmt->free_list);
  close_thread_tables(thd);
1781
  thd->rollback_item_tree_changes();
1782
  thd->cleanup_after_query();
1783
  thd->current_arena= thd;
1784

1785
  if (error)
1786
  {
1787 1788
    /* Statement map deletes statement on erase */
    thd->stmt_map.erase(stmt);
sergefp@mysql.com's avatar
sergefp@mysql.com committed
1789
    stmt= NULL;
1790
  }
1791
  else
monty@mysql.com's avatar
monty@mysql.com committed
1792 1793 1794 1795 1796 1797 1798 1799 1800
  {
    stmt->setup_set_params();
    SELECT_LEX *sl= stmt->lex->all_selects_list;
    /*
      Save WHERE clause pointers, because they may be changed during query
      optimisation.
    */
    for (; sl; sl= sl->next_select_in_list())
      sl->prep_where= sl->where;
1801
    stmt->state= Item_arena::PREPARED;
monty@mysql.com's avatar
monty@mysql.com committed
1802
  }
1803
  DBUG_RETURN(!stmt);
1804 1805
}

monty@mysql.com's avatar
monty@mysql.com committed
1806

1807
/* Reinit statement before execution */
1808

1809
void reset_stmt_for_execute(THD *thd, LEX *lex)
1810
{
1811
  SELECT_LEX *sl= lex->all_selects_list;
monty@mysql.com's avatar
monty@mysql.com committed
1812
  DBUG_ENTER("reset_stmt_for_execute");
1813

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1814 1815 1816
  if (lex->empty_field_list_on_rset)
  {
    lex->empty_field_list_on_rset= 0;
1817
    lex->field_list.empty();
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1818
  }
1819
  for (; sl; sl= sl->next_select_in_list())
1820
  {
1821 1822
    if (!sl->first_execution)
    {
monty@mysql.com's avatar
monty@mysql.com committed
1823 1824 1825
      /* remove option which was put by mysql_explain_union() */
      sl->options&= ~SELECT_DESCRIBE;

1826 1827 1828 1829
      /*
        Copy WHERE clause pointers to avoid damaging they by optimisation
      */
      if (sl->prep_where)
pem@mysql.com's avatar
pem@mysql.com committed
1830
      {
1831
        sl->where= sl->prep_where->copy_andor_structure(thd);
pem@mysql.com's avatar
pem@mysql.com committed
1832 1833
        sl->where->cleanup();
      }
1834 1835 1836 1837 1838 1839 1840 1841 1842
      DBUG_ASSERT(sl->join == 0);
      ORDER *order;
      /* Fix GROUP list */
      for (order= (ORDER *)sl->group_list.first; order; order= order->next)
        order->item= &order->item_ptr;
      /* Fix ORDER list */
      for (order= (ORDER *)sl->order_list.first; order; order= order->next)
        order->item= &order->item_ptr;
    }
1843 1844 1845 1846
    {
      SELECT_LEX_UNIT *unit= sl->master_unit();
      unit->unclean();
      unit->types.empty();
1847
      /* for derived tables & PS (which can't be reset by Item_subquery) */
1848 1849
      unit->reinit_exec_mechanism();
    }
1850
  }
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865

  /*
    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.
  */
  for (TABLE_LIST *tables= lex->query_tables;
	 tables;
	 tables= tables->next_global)
  {
    /*
      Reset old pointers to TABLEs: they are not valid since the tables
      were closed in the end of previous prepare or execute call.
    */
    tables->table= 0;
1866 1867
    if (tables->nested_join)
      tables->nested_join->counter= 0;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1868
  }
1869
  lex->current_select= &lex->select_lex;
1870 1871 1872 1873 1874

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

1875 1876
  if (lex->result)
    lex->result->cleanup();
monty@mysql.com's avatar
monty@mysql.com committed
1877 1878

  DBUG_VOID_RETURN;
1879 1880
}

1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898

/* 
    Clears parameters from data left from previous execution or long data
    
  SYNOPSIS
    reset_stmt_params()
      stmt - prepared statement for which parameters should be reset
*/

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


1899 1900 1901 1902
/*
  Executes previously prepared query.
  If there is any parameters, then replace markers with the data supplied
  from client, and then execute the query.
1903
  SYNOPSIS
1904
    mysql_stmt_execute()
1905 1906 1907
      thd            Current thread
      packet         Query string
      packet_length  Query string length, including terminator character.
1908 1909
*/

1910
void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
1911
{
1912
  ulong stmt_id= uint4korr(packet);
1913
  ulong flags= (ulong) ((uchar) packet[4]);
1914 1915 1916 1917 1918
  /*
    Query text for binary log, or empty string if the query is not put into
    binary log.
  */
  String expanded_query;
monty@mysql.com's avatar
monty@mysql.com committed
1919
#ifndef EMBEDDED_LIBRARY
1920
  uchar *packet_end= (uchar *) packet + packet_length - 1;
monty@mysql.com's avatar
monty@mysql.com committed
1921
#endif
1922 1923
  Prepared_statement *stmt;
  DBUG_ENTER("mysql_stmt_execute");
1924 1925

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

1927
  if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_execute")))
1928 1929
    DBUG_VOID_RETURN;

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1930
  DBUG_PRINT("exec_query:", ("%s", stmt->query));
1931

1932
  /* Check if we got an error when sending long data */
1933
  if (stmt->state == Item_arena::ERROR)
1934
  {
1935
    my_message(stmt->last_errno, stmt->last_error, MYF(0));
1936 1937 1938
    DBUG_VOID_RETURN;
  }

1939 1940
  DBUG_ASSERT(thd->free_list == NULL);
  mysql_reset_thd_for_next_command(thd);
1941 1942
  if (flags & (ulong) CURSOR_TYPE_READ_ONLY)
  {
monty@mysql.com's avatar
monty@mysql.com committed
1943
    if (!stmt->lex->result || !stmt->lex->result->simple_select())
1944
    {
monty@mysql.com's avatar
monty@mysql.com committed
1945
      DBUG_PRINT("info",("Cursor asked for not SELECT stmt"));
1946 1947 1948 1949 1950 1951 1952 1953
      /*
        If lex->result is set in the parser, this is not a SELECT
        statement: we can't open a cursor for it.
      */
      flags= 0;
    }
    else
    {
monty@mysql.com's avatar
monty@mysql.com committed
1954
      DBUG_PRINT("info",("Using READ_ONLY cursor"));
1955
      if (!stmt->cursor &&
monty@mysql.com's avatar
monty@mysql.com committed
1956
          !(stmt->cursor= new (&stmt->main_mem_root) Cursor()))
1957 1958 1959 1960 1961
        DBUG_VOID_RETURN;
      /* If lex->result is set, mysql_execute_command will use it */
      stmt->lex->result= &stmt->cursor->result;
    }
  }
hf@deer.(none)'s avatar
SCRUM:  
hf@deer.(none) committed
1962
#ifndef EMBEDDED_LIBRARY
1963
  if (stmt->param_count)
1964
  {
1965
    uchar *null_array= (uchar *) packet;
1966
    if (setup_conversion_functions(stmt, (uchar **) &packet, packet_end) ||
1967
        stmt->set_params(stmt, null_array, (uchar *) packet, packet_end,
1968
                         &expanded_query))
1969
      goto set_params_data_err;
1970
  }
hf@deer.(none)'s avatar
SCRUM:  
hf@deer.(none) committed
1971
#else
1972
  /*
1973 1974 1975
    In embedded library we re-install conversion routines each time 
    we set params, and also we don't need to parse packet. 
    So we do it in one function.
1976
  */
1977
  if (stmt->param_count && stmt->set_params_data(stmt, &expanded_query))
1978
    goto set_params_data_err;
hf@deer.(none)'s avatar
SCRUM:  
hf@deer.(none) committed
1979
#endif
1980 1981
  thd->stmt_backup.set_statement(thd);
  thd->set_statement(stmt);
1982
  thd->current_arena= stmt;
1983 1984 1985 1986 1987 1988 1989 1990 1991 1992
  reset_stmt_for_execute(thd, stmt->lex);
  /* From now cursors assume that thd->mem_root is clean */
  if (expanded_query.length() &&
      alloc_query(thd, (char *)expanded_query.ptr(),
                  expanded_query.length()+1))
  {
    my_error(ER_OUTOFMEMORY, 0, expanded_query.length());
    goto err;
  }

1993
  thd->protocol= &thd->protocol_prep;           // Switch to binary protocol
1994 1995 1996 1997 1998
  if (!(specialflag & SPECIAL_NO_PRIOR))
    my_pthread_setprio(pthread_self(),QUERY_PRIOR);
  mysql_execute_command(thd);
  if (!(specialflag & SPECIAL_NO_PRIOR))
    my_pthread_setprio(pthread_self(), WAIT_PRIOR);
1999
  thd->protocol= &thd->protocol_simple;         // Use normal protocol
2000 2001 2002 2003 2004

  if (flags & (ulong) CURSOR_TYPE_READ_ONLY)
  {
    if (stmt->cursor->is_open())
      stmt->cursor->init_from_thd(thd);
2005
    stmt->cursor->state= stmt->state;
2006 2007 2008 2009 2010 2011 2012
  }
  else
  {
    thd->lex->unit.cleanup();
    cleanup_items(stmt->free_list);
    reset_stmt_params(stmt);
    close_thread_tables(thd);                   /* to close derived tables */
monty@mysql.com's avatar
monty@mysql.com committed
2013
    thd->rollback_item_tree_changes();
2014
    thd->cleanup_after_query();
2015 2016 2017
  }

  thd->set_statement(&thd->stmt_backup);
2018
  thd->current_arena= thd;
2019
  DBUG_VOID_RETURN;
venu@myvenu.com's avatar
venu@myvenu.com committed
2020

2021
set_params_data_err:
2022
  reset_stmt_params(stmt);
2023
  my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_stmt_execute");
2024
err:
2025 2026 2027
  DBUG_VOID_RETURN;
}

2028

sergefp@mysql.com's avatar
sergefp@mysql.com committed
2029
/*
2030
  Execute prepared statement using parameter values from
sergefp@mysql.com's avatar
sergefp@mysql.com committed
2031 2032 2033
  lex->prepared_stmt_params and send result to the client using text protocol.
*/

2034
void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name)
sergefp@mysql.com's avatar
sergefp@mysql.com committed
2035
{
2036
  Prepared_statement *stmt;
2037
  /*
2038 2039
    Query text for binary log, or empty string if the query is not put into
    binary log.
2040
  */
2041
  String expanded_query;
2042
  DBUG_ENTER("mysql_sql_stmt_execute");
2043

2044 2045
  DBUG_ASSERT(thd->free_list == NULL);

2046 2047
  if (!(stmt= (Prepared_statement*)thd->stmt_map.find_by_name(stmt_name)))
  {
2048 2049 2050
    my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), stmt_name->length,
             stmt_name->str, "EXECUTE");
    DBUG_VOID_RETURN;
2051 2052
  }

sergefp@mysql.com's avatar
sergefp@mysql.com committed
2053 2054
  if (stmt->param_count != thd->lex->prepared_stmt_params.elements)
  {
2055
    my_error(ER_WRONG_ARGUMENTS, MYF(0), "EXECUTE");
sergefp@mysql.com's avatar
sergefp@mysql.com committed
2056 2057 2058
    DBUG_VOID_RETURN;
  }

2059 2060
  /* Must go before setting variables, as it clears thd->user_var_events */
  mysql_reset_thd_for_next_command(thd);
2061
  thd->set_n_backup_statement(stmt, &thd->stmt_backup);
2062
  thd->set_statement(stmt);
2063 2064
  if (stmt->set_params_from_vars(stmt,
                                 thd->stmt_backup.lex->prepared_stmt_params,
2065
                                 &expanded_query))
sergefp@mysql.com's avatar
sergefp@mysql.com committed
2066
  {
2067
    my_error(ER_WRONG_ARGUMENTS, MYF(0), "EXECUTE");
sergefp@mysql.com's avatar
sergefp@mysql.com committed
2068
  }
2069
  execute_stmt(thd, stmt, &expanded_query);
2070
  DBUG_VOID_RETURN;
2071
}
2072

2073

2074 2075
/*
  Execute prepared statement.
2076 2077 2078 2079
  SYNOPSIS
    execute_stmt()
      thd            Current thread
      stmt           Statement to execute
2080
      expanded_query If binary log is enabled, query string with parameter
2081 2082 2083
                     placeholders replaced with actual values. Otherwise empty
                     string.
  NOTES
2084
    Caller must set parameter values and thd::protocol.
2085
*/
2086

2087
static void execute_stmt(THD *thd, Prepared_statement *stmt,
2088
                         String *expanded_query)
2089 2090
{
  DBUG_ENTER("execute_stmt");
monty@mysql.com's avatar
monty@mysql.com committed
2091

monty@mysql.com's avatar
monty@mysql.com committed
2092
  reset_stmt_for_execute(thd, stmt->lex);
2093 2094 2095

  if (expanded_query->length() &&
      alloc_query(thd, (char *)expanded_query->ptr(),
2096 2097
                  expanded_query->length()+1))
  {
2098
    my_error(ER_OUTOFMEMORY, MYF(0), expanded_query->length());
2099 2100
    DBUG_VOID_RETURN;
  }
2101 2102 2103 2104 2105
  /*
    At first execution of prepared statement we will perform logical
    transformations of the query tree (i.e. negations elimination).
    This should be done permanently on the parse tree of this statement.
  */
2106
  thd->current_arena= stmt;
2107

2108
  if (!(specialflag & SPECIAL_NO_PRIOR))
2109
    my_pthread_setprio(pthread_self(),QUERY_PRIOR);
2110
  mysql_execute_command(thd);
2111
  if (!(specialflag & SPECIAL_NO_PRIOR))
2112
    my_pthread_setprio(pthread_self(), WAIT_PRIOR);
2113

2114
  thd->lex->unit.cleanup();
2115
  thd->current_arena= thd;
hf@deer.(none)'s avatar
hf@deer.(none) committed
2116
  cleanup_items(stmt->free_list);
2117
  thd->rollback_item_tree_changes();
2118
  reset_stmt_params(stmt);
2119
  close_thread_tables(thd);                    // to close derived tables
2120
  thd->set_statement(&thd->stmt_backup);
2121 2122
  thd->cleanup_after_query();

2123 2124
  if (stmt->state == Item_arena::PREPARED)
    stmt->state= Item_arena::EXECUTED;
2125 2126 2127
  DBUG_VOID_RETURN;
}

2128

2129 2130
/*
  COM_FETCH handler: fetches requested amount of rows from cursor
monty@mysql.com's avatar
monty@mysql.com committed
2131

2132
  SYNOPSIS
monty@mysql.com's avatar
monty@mysql.com committed
2133 2134 2135 2136
    mysql_stmt_fetch()
    thd			Thread handler
    packet		Packet from client (with stmt_id & num_rows)
    packet_length	Length of packet
2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154
*/

void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length)
{
  /* assume there is always place for 8-16 bytes */
  ulong stmt_id= uint4korr(packet);
  ulong num_rows= uint4korr(packet+=4);
  Statement *stmt;
  int error;
  DBUG_ENTER("mysql_stmt_fetch");

  if (!(stmt= thd->stmt_map.find(stmt_id)) ||
      !stmt->cursor ||
      !stmt->cursor->is_open())
  {
    my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), stmt_id, "fetch");
    DBUG_VOID_RETURN;
  }
monty@mysql.com's avatar
monty@mysql.com committed
2155
  thd->current_arena= stmt;
2156
  thd->set_n_backup_statement(stmt, &thd->stmt_backup);
2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170
  stmt->cursor->init_thd(thd);

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

  thd->protocol= &thd->protocol_prep;		// Switch to binary protocol
  error= stmt->cursor->fetch(num_rows);
  thd->protocol= &thd->protocol_simple;         // Use normal protocol

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

  /* Restore THD state */
  stmt->cursor->reset_thd(thd);
2171 2172
  thd->restore_backup_statement(stmt, &thd->stmt_backup);
  thd->current_arena= thd;
2173 2174 2175 2176 2177

  DBUG_VOID_RETURN;
}


2178
/*
2179
  Reset a prepared statement in case there was a recoverable error.
2180 2181
  SYNOPSIS
    mysql_stmt_reset()
2182
      thd       Thread handle
2183
      packet	Packet with stmt id
2184 2185

  DESCRIPTION
2186 2187 2188 2189 2190 2191 2192
    This function resets statement to the state it was right after prepare.
    It can be used to:
     - clear an error happened during mysql_stmt_send_long_data
     - cancel long data stream for all placeholders without
       having to call mysql_stmt_execute.
    Sends 'OK' packet in case of success (statement was reset)
    or 'ERROR' packet (unrecoverable error/statement not found/etc).
2193 2194
*/

2195
void mysql_stmt_reset(THD *thd, char *packet)
2196
{
2197
  /* There is always space for 4 bytes in buffer */
2198
  ulong stmt_id= uint4korr(packet);
2199 2200
  Prepared_statement *stmt;
  
2201
  DBUG_ENTER("mysql_stmt_reset");
2202

2203
  if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_reset")))
2204 2205
    DBUG_VOID_RETURN;

2206
  stmt->state= Item_arena::PREPARED;
2207

2208 2209 2210 2211 2212
  /* 
    Clear parameters from data which could be set by 
    mysql_stmt_send_long_data() call.
  */
  reset_stmt_params(stmt);
2213

2214
  mysql_reset_thd_for_next_command(thd);
2215
  send_ok(thd);
2216
  
2217 2218 2219 2220 2221
  DBUG_VOID_RETURN;
}


/*
2222 2223
  Delete a prepared statement from memory.
  Note: we don't send any reply to that command. 
2224 2225
*/

2226
void mysql_stmt_free(THD *thd, char *packet)
2227
{
2228
  /* There is always space for 4 bytes in packet buffer */
2229
  ulong stmt_id= uint4korr(packet);
2230 2231
  Prepared_statement *stmt;

2232
  DBUG_ENTER("mysql_stmt_free");
2233

2234
  if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_close")))
2235
    DBUG_VOID_RETURN;
2236 2237 2238

  /* Statement map deletes statement on erase */
  thd->stmt_map.erase(stmt);
2239 2240 2241
  DBUG_VOID_RETURN;
}

2242 2243

/*
2244
  Long data in pieces from client
2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261

  SYNOPSIS
    mysql_stmt_get_longdata()
    thd			Thread handle
    pos			String to append
    packet_length	Length of string

  DESCRIPTION
    Get a part of a long data.
    To make the protocol efficient, we are not sending any return packages
    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)
*/

2262
void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
2263
{
2264 2265
  ulong stmt_id;
  uint param_number;
2266
  Prepared_statement *stmt;
2267 2268
  Item_param *param;
  char *packet_end= packet + packet_length - 1;
2269
  
2270 2271
  DBUG_ENTER("mysql_stmt_get_longdata");

hf@deer.(none)'s avatar
hf@deer.(none) committed
2272
#ifndef EMBEDDED_LIBRARY
2273 2274
  /* Minimal size of long data packet is 6 bytes */
  if ((ulong) (packet_end - packet) < MYSQL_LONG_DATA_HEADER)
2275
  {
2276
    my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_stmt_send_long_data");
2277 2278
    DBUG_VOID_RETURN;
  }
hf@deer.(none)'s avatar
hf@deer.(none) committed
2279
#endif
2280

2281 2282
  stmt_id= uint4korr(packet);
  packet+= 4;
2283

2284 2285
  if (!(stmt=find_prepared_statement(thd, stmt_id,
                                     "mysql_stmt_send_long_data")))
2286 2287
    DBUG_VOID_RETURN;

2288 2289
  param_number= uint2korr(packet);
  packet+= 2;
hf@deer.(none)'s avatar
hf@deer.(none) committed
2290
#ifndef EMBEDDED_LIBRARY
2291 2292
  if (param_number >= stmt->param_count)
  {
venu@myvenu.com's avatar
venu@myvenu.com committed
2293
    /* Error will be sent in execute call */
2294
    stmt->state= Item_arena::ERROR;
venu@myvenu.com's avatar
venu@myvenu.com committed
2295
    stmt->last_errno= ER_WRONG_ARGUMENTS;
2296 2297
    sprintf(stmt->last_error, ER(ER_WRONG_ARGUMENTS),
            "mysql_stmt_send_long_data");
2298 2299
    DBUG_VOID_RETURN;
  }
hf@deer.(none)'s avatar
hf@deer.(none) committed
2300 2301
#endif

2302 2303
  param= stmt->param_array[param_number];

hf@deer.(none)'s avatar
hf@deer.(none) committed
2304
#ifndef EMBEDDED_LIBRARY
2305
  if (param->set_longdata(packet, (ulong) (packet_end - packet)))
hf@deer.(none)'s avatar
hf@deer.(none) committed
2306
#else
2307
  if (param->set_longdata(thd->extra_data, thd->extra_length))
hf@deer.(none)'s avatar
hf@deer.(none) committed
2308
#endif
2309
  {
2310
    stmt->state= Item_arena::ERROR;
2311 2312 2313
    stmt->last_errno= ER_OUTOFMEMORY;
    sprintf(stmt->last_error, ER(ER_OUTOFMEMORY), 0);
  }
2314 2315
  DBUG_VOID_RETURN;
}
venu@myvenu.com's avatar
venu@myvenu.com committed
2316

2317 2318 2319 2320

Prepared_statement::Prepared_statement(THD *thd_arg)
  :Statement(thd_arg),
  thd(thd_arg),
2321
  param_array(0),
2322
  param_count(0),
2323
  last_errno(0)
2324 2325 2326 2327
{
  *last_error= '\0';
}

2328 2329 2330 2331
void Prepared_statement::setup_set_params()
{
  /* Setup binary logging */
  if (mysql_bin_log.is_open() && is_update_query(lex->sql_command))
2332
  {
2333
    set_params_from_vars= insert_params_from_vars_with_log;
2334
#ifndef EMBEDDED_LIBRARY
2335
    set_params= insert_params_withlog;
2336
#else
2337
    set_params_data= emb_insert_params_withlog;
2338 2339 2340
#endif
  }
  else
2341 2342
  {
    set_params_from_vars= insert_params_from_vars;
2343
#ifndef EMBEDDED_LIBRARY
2344
    set_params= insert_params;
2345
#else
2346
    set_params_data= emb_insert_params;
2347
#endif
2348
  }
2349 2350
}

2351

2352 2353
Prepared_statement::~Prepared_statement()
{
2354 2355
  if (cursor)
    cursor->Cursor::~Cursor();
2356
  free_items(free_list);
2357
  delete lex->result;
2358 2359 2360
}


2361
Item_arena::Type Prepared_statement::type() const
2362 2363 2364
{
  return PREPARED_STATEMENT;
}