sql_prepare.cc 65.3 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
    char llbuf[22];
138 139
    my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), sizeof(llbuf), llstr(id, llbuf),
             where);
140 141 142
    return 0;
  }
  return (Prepared_statement *) stmt;
143 144
}

145

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

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

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

166 167 168 169
  /*
    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
170 171 172 173
  DBUG_RETURN(my_net_write(net, buff, sizeof(buff)) || 
              (stmt->param_count &&
               stmt->thd->protocol_simple.send_fields((List<Item> *)
                                                      &stmt->lex->param_list,
174
                                                      Protocol::SEND_EOF)));
hf@deer.(none)'s avatar
hf@deer.(none) committed
175
}
176
#else
177 178
static bool send_prep_stmt(Prepared_statement *stmt,
                           uint columns __attribute__((unused)))
hf@deer.(none)'s avatar
hf@deer.(none) committed
179
{
hf@deer.(none)'s avatar
SCRUM  
hf@deer.(none) committed
180 181
  THD *thd= stmt->thd;

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

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

190 191

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

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

venu@myvenu.com's avatar
venu@myvenu.com committed
237
 /*
238 239 240 241 242 243
   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
244

245 246
  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
247 248 249 250 251

  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.

252 253
  RETURN VALUE
    none
254 255
*/

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

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

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

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

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

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

336 337 338 339 340 341 342
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);
  *pos+= len;
}

343
#ifndef EMBEDDED_LIBRARY
344 345 346 347 348 349 350

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

351
static void set_param_time(Item_param *param, uchar **pos, ulong len)
352
{
353 354
  MYSQL_TIME tm;
  ulong length= get_param_length(pos, len);
355

356
  if (length >= 8)
357 358
  {
    uchar *to= *pos;
359
    uint day;
360

361 362
    tm.neg= (bool) to[0];
    day= (uint) sint4korr(to+1);
363
    tm.hour=   (uint) to[5] + day * 24;
364 365
    tm.minute= (uint) to[6];
    tm.second= (uint) to[7];
366
    tm.second_part= (length > 8) ? (ulong) sint4korr(to+8) : 0;
367 368 369 370 371 372 373 374
    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;
375
  }
376
  else
377
    set_zero_time(&tm, MYSQL_TIMESTAMP_TIME);
378 379
  param->set_time(&tm, MYSQL_TIMESTAMP_TIME,
                  MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
380 381 382
  *pos+= length;
}

383
static void set_param_datetime(Item_param *param, uchar **pos, ulong len)
384
{
385 386
  MYSQL_TIME tm;
  ulong length= get_param_length(pos, len);
387

388
  if (length >= 4)
389 390
  {
    uchar *to= *pos;
391 392 393 394 395

    tm.neg=    0;
    tm.year=   (uint) sint2korr(to);
    tm.month=  (uint) to[2];
    tm.day=    (uint) to[3];
396 397 398 399 400 401 402 403 404
    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;

405
    tm.second_part= (length > 7) ? (ulong) sint4korr(to+7) : 0;
406
  }
407
  else
408
    set_zero_time(&tm, MYSQL_TIMESTAMP_DATETIME);
409 410
  param->set_time(&tm, MYSQL_TIMESTAMP_DATETIME,
                  MAX_DATETIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
411 412 413
  *pos+= length;
}

414

415
static void set_param_date(Item_param *param, uchar **pos, ulong len)
416
{
417 418 419 420
  MYSQL_TIME tm;
  ulong length= get_param_length(pos, len);

  if (length >= 4)
421 422
  {
    uchar *to= *pos;
423

424
    tm.year=  (uint) sint2korr(to);
425 426 427 428 429 430 431
    tm.month=  (uint) to[2];
    tm.day= (uint) to[3];

    tm.hour= tm.minute= tm.second= 0;
    tm.second_part= 0;
    tm.neg= 0;
  }
432
  else
433
    set_zero_time(&tm, MYSQL_TIMESTAMP_DATE);
434 435
  param->set_time(&tm, MYSQL_TIMESTAMP_DATE,
                  MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
436 437 438
  *pos+= length;
}

439 440 441
#else/*!EMBEDDED_LIBRARY*/
void set_param_time(Item_param *param, uchar **pos, ulong len)
{
442 443 444 445 446 447 448 449 450 451 452
  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,
453
                  MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
454 455 456 457 458 459 460

}

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

461
  param->set_time(to, MYSQL_TIMESTAMP_DATETIME,
462
                  MAX_DATETIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
463 464 465 466 467 468
}

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

469
  param->set_time(to, MYSQL_TIMESTAMP_DATE,
470
                  MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
471 472 473
}
#endif /*!EMBEDDED_LIBRARY*/

474 475

static void set_param_str(Item_param *param, uchar **pos, ulong len)
venu@myvenu.com's avatar
venu@myvenu.com committed
476
{
477
  ulong length= get_param_length(pos, len);
478
  param->set_str((const char *)*pos, length);
479
  *pos+= length;
venu@myvenu.com's avatar
venu@myvenu.com committed
480 481
}

482 483 484 485 486

#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
487
{
488
  switch (param_type) {
489
  case MYSQL_TYPE_TINY:
490
    param->set_param_func= set_param_tiny;
491
    param->item_type= Item::INT_ITEM;
492
    param->item_result_type= INT_RESULT;
493
    break;
494
  case MYSQL_TYPE_SHORT:
495
    param->set_param_func= set_param_short;
496
    param->item_type= Item::INT_ITEM;
497
    param->item_result_type= INT_RESULT;
498
    break;
499
  case MYSQL_TYPE_LONG:
500
    param->set_param_func= set_param_int32;
501
    param->item_type= Item::INT_ITEM;
502
    param->item_result_type= INT_RESULT;
503
    break;
504
  case MYSQL_TYPE_LONGLONG:
505
    param->set_param_func= set_param_int64;
506
    param->item_type= Item::INT_ITEM;
507
    param->item_result_type= INT_RESULT;
508
    break;
509
  case MYSQL_TYPE_FLOAT:
510
    param->set_param_func= set_param_float;
511
    param->item_type= Item::REAL_ITEM;
512
    param->item_result_type= REAL_RESULT;
513
    break;
514
  case MYSQL_TYPE_DOUBLE:
515
    param->set_param_func= set_param_double;
516
    param->item_type= Item::REAL_ITEM;
517
    param->item_result_type= REAL_RESULT;
518
    break;
519 520 521 522 523 524
  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;
525
  case MYSQL_TYPE_TIME:
526
    param->set_param_func= set_param_time;
527
    param->item_type= Item::STRING_ITEM;
528
    param->item_result_type= STRING_RESULT;
529
    break;
530
  case MYSQL_TYPE_DATE:
531
    param->set_param_func= set_param_date;
532
    param->item_type= Item::STRING_ITEM;
533
    param->item_result_type= STRING_RESULT;
534
    break;
535 536
  case MYSQL_TYPE_DATETIME:
  case MYSQL_TYPE_TIMESTAMP:
537
    param->set_param_func= set_param_datetime;
538
    param->item_type= Item::STRING_ITEM;
539
    param->item_result_type= STRING_RESULT;
540
    break;
541 542 543 544
  case MYSQL_TYPE_TINY_BLOB:
  case MYSQL_TYPE_MEDIUM_BLOB:
  case MYSQL_TYPE_LONG_BLOB:
  case MYSQL_TYPE_BLOB:
545
    param->set_param_func= set_param_str;
546 547 548
    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;
549
    param->item_result_type= STRING_RESULT;
550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579
    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;
    }
580
  }
581
  param->param_type= (enum enum_field_types) param_type;
582 583
}

hf@deer.(none)'s avatar
hf@deer.(none) committed
584
#ifndef EMBEDDED_LIBRARY
585
/*
586 587
  Update the parameter markers by reading data from client packet 
  and if binary/update log is set, generate the valid query.
588 589
*/

590
static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array,
591 592
                                  uchar *read_pos, uchar *data_end, 
                                  String *query)
593
{
594 595 596 597 598
  THD  *thd= stmt->thd;
  Item_param **begin= stmt->param_array;
  Item_param **end= begin + stmt->param_count;
  uint32 length= 0;

599
  String str; 
600
  const String *res;
601

602
  DBUG_ENTER("insert_params_withlog"); 
603

604
  if (query->copy(stmt->query, stmt->query_length, default_charset_info))
605
    DBUG_RETURN(1);
606
  
607
  for (Item_param **it= begin; it < end; ++it)
608
  {
609
    Item_param *param= *it;
610
    if (param->state != Item_param::LONG_DATA_VALUE)
611
    {
612
      if (is_param_null(null_array, it - begin))
613
        param->set_null();
614 615
      else
      {
616 617 618
        if (read_pos >= data_end)
          DBUG_RETURN(1);
        param->set_param_func(param, &read_pos, data_end - read_pos);
619 620
      }
    }
621 622 623 624
    res= param->query_val_str(&str);
    if (param->convert_str_value(thd))
      DBUG_RETURN(1);                           /* out of memory */

625
    if (query->replace(param->pos_in_query+length, 1, *res))
626 627 628 629 630 631 632
      DBUG_RETURN(1);
    
    length+= res->length()-1;
  }
  DBUG_RETURN(0);
}

633

634
static bool insert_params(Prepared_statement *stmt, uchar *null_array,
635 636
                          uchar *read_pos, uchar *data_end, 
                          String *expanded_query)
637
{
638 639
  Item_param **begin= stmt->param_array;
  Item_param **end= begin + stmt->param_count;
640 641 642

  DBUG_ENTER("insert_params"); 

643
  for (Item_param **it= begin; it < end; ++it)
644
  {
645
    Item_param *param= *it;
646
    if (param->state != Item_param::LONG_DATA_VALUE)
647
    {
648
      if (is_param_null(null_array, it - begin))
649
        param->set_null();
650 651
      else
      {
652 653 654
        if (read_pos >= data_end)
          DBUG_RETURN(1);
        param->set_param_func(param, &read_pos, data_end - read_pos);
655 656
      }
    }
657 658
    if (param->convert_str_value(stmt->thd))
      DBUG_RETURN(1);                           /* out of memory */
659 660 661 662
  }
  DBUG_RETURN(0);
}

663

664
static bool setup_conversion_functions(Prepared_statement *stmt,
665
                                       uchar **data, uchar *data_end)
666 667 668
{
  /* skip null bits */
  uchar *read_pos= *data + (stmt->param_count+7) / 8;
669

670
  DBUG_ENTER("setup_conversion_functions");
671

venu@myvenu.com's avatar
venu@myvenu.com committed
672
  if (*read_pos++) //types supplied / first execute
673
  {
venu@myvenu.com's avatar
venu@myvenu.com committed
674 675 676 677
    /*
      First execute or types altered by the client, setup the 
      conversion routines for all parameters (one time)
    */
678 679
    Item_param **it= stmt->param_array;
    Item_param **end= it + stmt->param_count;
680
    THD *thd= stmt->thd;
681 682
    for (; it < end; ++it)
    {
683 684 685
      ushort typecode;
      const uint signed_bit= 1 << 15;

686 687
      if (read_pos >= data_end)
        DBUG_RETURN(1);
688 689

      typecode= sint2korr(read_pos);
venu@myvenu.com's avatar
venu@myvenu.com committed
690
      read_pos+= 2;
691
      (**it).unsigned_flag= test(typecode & signed_bit);
692
      setup_one_conversion_function(thd, *it, (uchar) (typecode & ~signed_bit));
693
    }
694 695
  }
  *data= read_pos;
696 697 698
  DBUG_RETURN(0);
}

699 700
#else

701
static bool emb_insert_params(Prepared_statement *stmt, String *expanded_query)
702
{
703
  THD *thd= stmt->thd;
704 705
  Item_param **it= stmt->param_array;
  Item_param **end= it + stmt->param_count;
706 707
  MYSQL_BIND *client_param= stmt->thd->client_params;

708
  DBUG_ENTER("emb_insert_params");
709

710 711 712
  for (; it < end; ++it, ++client_param)
  {
    Item_param *param= *it;
713 714
    setup_one_conversion_function(thd, param, client_param->buffer_type);
    if (param->state != Item_param::LONG_DATA_VALUE)
715 716
    {
      if (*client_param->is_null)
717
        param->set_null();
718 719
      else
      {
720
        uchar *buff= (uchar*) client_param->buffer;
hf@deer.(none)'s avatar
hf@deer.(none) committed
721
        param->unsigned_flag= client_param->is_unsigned;
722 723 724 725
        param->set_param_func(param, &buff,
                              client_param->length ? 
                              *client_param->length : 
                              client_param->buffer_length);
726 727
      }
    }
728 729
    if (param->convert_str_value(thd))
      DBUG_RETURN(1);                           /* out of memory */
730 731 732 733
  }
  DBUG_RETURN(0);
}

734

735
static bool emb_insert_params_withlog(Prepared_statement *stmt, String *query)
736
{
737
  THD *thd= stmt->thd;
738 739
  Item_param **it= stmt->param_array;
  Item_param **end= it + stmt->param_count;
740 741
  MYSQL_BIND *client_param= thd->client_params;

742
  String str;
743
  const String *res;
744
  uint32 length= 0;
745

746
  DBUG_ENTER("emb_insert_params_withlog");
747

748
  if (query->copy(stmt->query, stmt->query_length, default_charset_info))
749 750
    DBUG_RETURN(1);
  
751 752 753
  for (; it < end; ++it, ++client_param)
  {
    Item_param *param= *it;
754 755
    setup_one_conversion_function(thd, param, client_param->buffer_type);
    if (param->state != Item_param::LONG_DATA_VALUE)
756 757
    {
      if (*client_param->is_null)
758
        param->set_null();
759 760
      else
      {
761
        uchar *buff= (uchar*)client_param->buffer;
762
	param->unsigned_flag= client_param->is_unsigned;
763 764 765 766
        param->set_param_func(param, &buff,
                              client_param->length ? 
                              *client_param->length : 
                              client_param->buffer_length);
767 768
      }
    }
769 770 771 772
    res= param->query_val_str(&str);
    if (param->convert_str_value(thd))
      DBUG_RETURN(1);                           /* out of memory */

773
    if (query->replace(param->pos_in_query+length, 1, *res))
774
      DBUG_RETURN(1);
775

776 777 778 779 780
    length+= res->length()-1;
  }
  DBUG_RETURN(0);
}

hf@deer.(none)'s avatar
hf@deer.(none) committed
781 782
#endif /*!EMBEDDED_LIBRARY*/

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

784
/*
sergefp@mysql.com's avatar
sergefp@mysql.com committed
785 786 787 788 789 790
  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
791
      query     Ignored
sergefp@mysql.com's avatar
sergefp@mysql.com committed
792 793
*/

794 795
static bool insert_params_from_vars(Prepared_statement *stmt,
                                    List<LEX_STRING>& varnames,
796
                                    String *query __attribute__((unused)))
sergefp@mysql.com's avatar
sergefp@mysql.com committed
797 798 799 800 801 802
{
  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);
803 804
  DBUG_ENTER("insert_params_from_vars");

sergefp@mysql.com's avatar
sergefp@mysql.com committed
805 806 807 808
  for (Item_param **it= begin; it < end; ++it)
  {
    Item_param *param= *it;
    varname= var_it++;
809 810 811 812 813 814
    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
815 816 817 818
  }
  DBUG_RETURN(0);
}

819

820
/*
821 822 823 824 825 826 827 828 829 830
  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
831
static bool insert_params_from_vars_with_log(Prepared_statement *stmt,
832
                                             List<LEX_STRING>& varnames,
833
                                             String *query)
sergefp@mysql.com's avatar
sergefp@mysql.com committed
834 835 836 837 838
{
  Item_param **begin= stmt->param_array;
  Item_param **end= begin + stmt->param_count;
  user_var_entry *entry;
  LEX_STRING *varname;
839
  DBUG_ENTER("insert_params_from_vars");
sergefp@mysql.com's avatar
sergefp@mysql.com committed
840 841

  List_iterator<LEX_STRING> var_it(varnames);
842
  String str;
sergefp@mysql.com's avatar
sergefp@mysql.com committed
843
  uint32 length= 0;
844
  if (query->copy(stmt->query, stmt->query_length, default_charset_info))
845
    DBUG_RETURN(1);
sergefp@mysql.com's avatar
sergefp@mysql.com committed
846 847 848 849 850

  for (Item_param **it= begin; it < end; ++it)
  {
    Item_param *param= *it;
    varname= var_it++;
851 852
    if (get_var_with_binlog(stmt->thd, *varname, &entry))
        DBUG_RETURN(1);
853
    DBUG_ASSERT(entry != 0);
sergefp@mysql.com's avatar
sergefp@mysql.com committed
854

855 856 857
    if (param->set_from_user_var(stmt->thd, entry))
      DBUG_RETURN(1);
    /* Insert @'escaped-varname' instead of parameter in the query */
858 859 860
    char *buf, *ptr;
    str.length(0);
    if (str.reserve(entry->name.length*2+3))
sergefp@mysql.com's avatar
sergefp@mysql.com committed
861
      DBUG_RETURN(1);
862 863 864 865 866

    buf= str.c_ptr_quick();
    ptr= buf;
    *ptr++= '@';
    *ptr++= '\'';
867 868
    ptr+=
      escape_string_for_mysql(&my_charset_utf8_general_ci,
serg@serg.mylan's avatar
serg@serg.mylan committed
869
                              ptr, 0, entry->name.str, entry->name.length);
870 871 872 873 874
    *ptr++= '\'';
    str.length(ptr - buf);

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

876 877 878
    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
879 880 881 882
  }
  DBUG_RETURN(0);
}

883
/*
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
884 885
  Validate INSERT statement: 

886
  SYNOPSIS
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
887 888
    mysql_test_insert()
    stmt	prepared statemen handler
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
889
    tables	global/local table list  
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
890

891
  RETURN VALUE
892 893
    FALSE OK
    TRUE  error
894
*/
monty@mysql.com's avatar
monty@mysql.com committed
895

896 897 898 899 900 901 902
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)
903
{
904
  THD *thd= stmt->thd;
905
  LEX *lex= stmt->lex;
906 907
  List_iterator_fast<List_item> its(values_list);
  List_item *values;
908
  bool res;
909
  DBUG_ENTER("mysql_test_insert");
910

911
  if ((res= insert_precheck(thd, table_list)))
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
912
    DBUG_RETURN(res);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
913

914
  /*
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
915 916
     open temporary memory pool for temporary data allocated by derived
     tables & preparation procedure
917 918 919 920
     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.
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
921
  */
922
  if (open_normal_and_derived_tables(thd, table_list))
923
  {
924
    DBUG_RETURN(TRUE);
925 926
  }

927

928 929 930
  if ((values= its++))
  {
    uint value_count;
931
    ulong counter= 0;
monty@mysql.com's avatar
monty@mysql.com committed
932
    Item *unused_conds= 0;
933

serg@sergbook.mysql.com's avatar
serg@sergbook.mysql.com committed
934
    if (table_list->table)
935 936 937 938 939
    {
      // 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
940 941
    if ((res= mysql_prepare_insert(thd, table_list, table_list->table, 
				   fields, values, update_fields,
monty@mysql.com's avatar
monty@mysql.com committed
942 943
				   update_values, duplic,
                                   &unused_conds, FALSE)))
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
944
      goto error;
945

946 947
    value_count= values->elements;
    its.rewind();
948

949 950 951 952 953 954 955
    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 :
956
                                       table_list->table_name));
957 958
      goto error;
    }
959
    while ((values= its++))
960 961 962 963
    {
      counter++;
      if (values->elements != value_count)
      {
964
        my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter);
965
        goto error;
966
      }
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
967
      if (setup_fields(thd, 0, table_list, *values, 0, 0, 0))
968
	goto error;
969 970
    }
  }
971

972
  res= FALSE;
973 974
error:
  lex->unit.cleanup();
975
  /* insert_values is cleared in open_table */
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
976
  DBUG_RETURN(res);
977 978 979 980
}


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

983
  SYNOPSIS
984
    mysql_test_update()
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
985 986 987
    stmt	prepared statemen handler
    tables	list of tables queries

988 989
  RETURN VALUE
    0   success
990
    2   convert to multi_update
bell@sanja.is.com.ua's avatar
merge  
bell@sanja.is.com.ua committed
991
    1   error
992
*/
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
993
static int mysql_test_update(Prepared_statement *stmt,
994
                              TABLE_LIST *table_list)
995
{
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
996
  int res;
997
  THD *thd= stmt->thd;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
998
  uint table_count= 0;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
999
  SELECT_LEX *select= &stmt->lex->select_lex;
1000 1001 1002
#ifndef NO_EMBEDDED_ACCESS_CHECKS
  uint		want_privilege;
#endif
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1003 1004
  DBUG_ENTER("mysql_test_update");

bell@sanja.is.com.ua's avatar
merge  
bell@sanja.is.com.ua committed
1005 1006
  if (update_precheck(thd, table_list))
    DBUG_RETURN(1);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1007

1008
  if (!open_tables(thd, &table_list, &table_count))
1009
  {
igor@rurik.mysql.com's avatar
igor@rurik.mysql.com committed
1010
    if (table_list->multitable_view)
1011
    {
1012
      DBUG_ASSERT(table_list->view != 0);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1013 1014 1015
      DBUG_PRINT("info", ("Switch to multi-update"));
      /* pass counter value */
      thd->lex->table_count= table_count;
1016 1017 1018
      /* convert to multiupdate */
      return 2;
    }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1019

1020 1021 1022 1023
    /*
      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
1024
    if (lock_tables(thd, table_list, table_count) ||
1025
	mysql_handle_derived(thd->lex, &mysql_derived_prepare))
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1026 1027
      DBUG_RETURN(1);

1028 1029 1030 1031 1032
#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
1033 1034 1035 1036 1037
    if (!(res= mysql_prepare_update(thd, table_list,
				    &select->where,
				    select->order_list.elements,
				    (ORDER *) select->order_list.first)))
    {
1038 1039 1040 1041 1042
#ifndef NO_EMBEDDED_ACCESS_CHECKS
      table_list->grant.want_privilege=
        table_list->table->grant.want_privilege=
        want_privilege;
#endif
1043 1044 1045
      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
1046
        res= 1;
1047 1048 1049 1050 1051
        thd->lex->select_lex.no_wrap_view_item= 0;
      }
      else
      {
        thd->lex->select_lex.no_wrap_view_item= 0;
1052 1053 1054 1055 1056 1057
#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
1058 1059
        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
1060
          res= 1;
1061
      }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1062
    }
1063
    stmt->lex->unit.cleanup();
1064
  }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1065 1066
  else
    res= 1;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1067 1068
  /* TODO: here we should send types of placeholders to the client. */ 
  DBUG_RETURN(res);
1069 1070 1071 1072
}


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

1075
  SYNOPSIS
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1076 1077 1078 1079
    mysql_test_delete()
    stmt	prepared statemen handler
    tables	list of tables queries

1080
  RETURN VALUE
1081 1082
    FALSE success
    TRUE  error
1083
*/
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1084 1085
static int mysql_test_delete(Prepared_statement *stmt,
			     TABLE_LIST *table_list)
1086
{
1087
  THD *thd= stmt->thd;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1088 1089
  LEX *lex= stmt->lex;
  DBUG_ENTER("mysql_test_delete");
1090

1091 1092
  if (delete_precheck(thd, table_list))
    DBUG_RETURN(TRUE);
1093

1094
  if (!open_and_lock_tables(thd, table_list))
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1095
  {
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1096
    bool res;
1097 1098 1099 1100 1101 1102 1103
    if (!table_list->table)
    {
      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
1104
    res= mysql_prepare_delete(thd, table_list, &lex->select_lex.where);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1105
    lex->unit.cleanup();
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1106
    DBUG_RETURN(res);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1107 1108
  }
  /* TODO: here we should send types of placeholders to the client. */ 
1109
  DBUG_RETURN(TRUE);
1110 1111
}

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

1113
/*
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1114
  Validate SELECT statement.
1115 1116
  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
1117

1118
  SYNOPSIS
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1119 1120 1121 1122
    mysql_test_select()
    stmt	prepared statemen handler
    tables	list of tables queries

1123
  RETURN VALUE
1124 1125
    FALSE success
    TRUE  error, sent to client
1126
*/
1127

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1128
static int mysql_test_select(Prepared_statement *stmt,
sergefp@mysql.com's avatar
sergefp@mysql.com committed
1129
			     TABLE_LIST *tables, bool text_protocol)
1130
{
1131
  THD *thd= stmt->thd;
1132
  LEX *lex= stmt->lex;
1133
  SELECT_LEX_UNIT *unit= &lex->unit;
1134
  bool result;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1135
  DBUG_ENTER("mysql_test_select");
1136

hf@deer.(none)'s avatar
hf@deer.(none) committed
1137
#ifndef NO_EMBEDDED_ACCESS_CHECKS
1138 1139 1140
  ulong privilege= lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL;
  if (tables)
  {
hf@deer.(none)'s avatar
hf@deer.(none) committed
1141
    if (check_table_access(thd, privilege, tables,0))
1142
      DBUG_RETURN(TRUE);
1143
  }
1144
  else if (check_access(thd, privilege, any_db,0,0,0))
1145
    DBUG_RETURN(TRUE);
hf@deer.(none)'s avatar
hf@deer.(none) committed
1146
#endif
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1147

1148
  result= TRUE;
1149
  if (!lex->result && !(lex->result= new (stmt->mem_root) select_send))
1150 1151
    goto err;

1152
  if (open_and_lock_tables(thd, tables))
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1153
    goto err;
1154

1155

1156 1157
  thd->used_tables= 0;                        // Updated by setup_fields

1158 1159 1160 1161 1162
  /*
    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
  */
1163
  if (unit->prepare(thd, 0, 0, ""))
1164 1165 1166
  {
    goto err_prep;
  }
1167
  if (!text_protocol)
1168
  {
1169 1170
    if (lex->describe)
    {
1171
      if (send_prep_stmt(stmt, 0) || thd->protocol->flush())
1172 1173 1174
        goto err_prep;
    }
    else
1175
    {
1176 1177 1178 1179 1180 1181 1182 1183
      /* 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;

1184 1185 1186 1187 1188
      /*
        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)) ||
1189
          lex->result->send_fields(fields, Protocol::SEND_EOF) ||
1190
          thd->protocol->flush())
sergefp@mysql.com's avatar
sergefp@mysql.com committed
1191 1192
        goto err_prep;
    }
1193
  }
1194
  result= FALSE;                                    // ok
1195 1196 1197 1198

err_prep:
  unit->cleanup();
err:
1199
  DBUG_RETURN(result);
1200 1201
}

1202

1203 1204 1205 1206 1207 1208 1209 1210 1211 1212
/*
  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
1213 1214
    FALSE success
    TRUE  error, sent to client
1215 1216
*/

1217
static bool mysql_test_do_fields(Prepared_statement *stmt,
1218 1219 1220 1221 1222
				TABLE_LIST *tables,
				List<Item> *values)
{
  DBUG_ENTER("mysql_test_do_fields");
  THD *thd= stmt->thd;
1223 1224 1225
  bool res;
  if (tables && check_table_access(thd, SELECT_ACL, tables, 0))
    DBUG_RETURN(TRUE);
1226

1227
  if (open_and_lock_tables(thd, tables))
1228
  {
1229
    DBUG_RETURN(TRUE);
1230 1231 1232
  }
  res= setup_fields(thd, 0, 0, *values, 0, 0, 0);
  stmt->lex->unit.cleanup();
1233
  DBUG_RETURN(res);
1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246
}


/*
  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
1247 1248
    FALSE success
    TRUE  error
1249
*/
1250 1251 1252
static bool mysql_test_set_fields(Prepared_statement *stmt,
                                  TABLE_LIST *tables,
                                  List<set_var_base> *var_list)
1253 1254 1255 1256 1257
{
  DBUG_ENTER("mysql_test_set_fields");
  List_iterator_fast<set_var_base> it(*var_list);
  THD *thd= stmt->thd;
  set_var_base *var;
1258
  bool res;
1259

1260 1261
  if (tables && check_table_access(thd, SELECT_ACL, tables, 0))
    DBUG_RETURN(TRUE);
1262

1263
  if ((res= open_and_lock_tables(thd, tables)))
1264 1265 1266 1267 1268 1269
    goto error;
  while ((var= it++))
  {
    if (var->light_check(thd))
    {
      stmt->lex->unit.cleanup();
1270
      res= TRUE;
1271 1272 1273 1274
      goto error;
    }
  }
error:
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1275
  stmt->lex->unit.cleanup();
1276 1277 1278 1279 1280 1281 1282 1283
  DBUG_RETURN(res);
}


/*
  Check internal SELECT of the prepared command

  SYNOPSIS
1284 1285 1286 1287 1288 1289 1290 1291 1292 1293
    select_like_stmt_test()
      stmt                      - prepared statement handler
      specific_prepare          - function of command specific prepare
      setup_tables_done_option  - options to be passed to LEX::unit.prepare()

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

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1295
  RETURN VALUE
1296 1297
    FALSE success
    TRUE  error
1298
*/
1299 1300 1301 1302

static bool select_like_stmt_test(Prepared_statement *stmt,
                                  bool (*specific_prepare)(THD *thd),
                                  ulong setup_tables_done_option)
1303
{
1304
  DBUG_ENTER("select_like_stmt_test");
1305 1306
  THD *thd= stmt->thd;
  LEX *lex= stmt->lex;
1307
  bool res= FALSE;
1308

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

1312 1313
  thd->used_tables= 0;                        // Updated by setup_fields

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1314
  // JOIN::prepare calls
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1315
  if (lex->unit.prepare(thd, 0, setup_tables_done_option, ""))
1316
  {
1317
    res= TRUE;
1318 1319 1320 1321 1322 1323 1324
  }
end:
  lex->unit.cleanup();
  DBUG_RETURN(res);
}


1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362
/*
  Check internal SELECT of the prepared command (with opening and
  locking tables used).

  SYNOPSIS
    select_like_stmt_test_with_open_n_lock()
      stmt                      - prepared statement handler
      tables                    - list of tables to be opened and locked
                                  before calling specific_prepare function
      specific_prepare          - function of command specific prepare
      setup_tables_done_option  - options to be passed to LEX::unit.prepare()

  RETURN VALUE
    FALSE success
    TRUE  error
*/

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

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

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


1363
/*
1364
  Validate and prepare for execution CREATE TABLE statement
1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375

  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
1376

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1377
static int mysql_test_create_table(Prepared_statement *stmt)
1378 1379 1380 1381
{
  DBUG_ENTER("mysql_test_create_table");
  THD *thd= stmt->thd;
  LEX *lex= stmt->lex;
1382
  SELECT_LEX *select_lex= &lex->select_lex;
1383 1384
  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
1385 1386 1387
  bool link_to_local;
  TABLE_LIST *create_table= lex->unlink_first_table(&link_to_local);
  TABLE_LIST *tables= lex->query_tables;
1388

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1389
  if (!(res= create_table_precheck(thd, tables, create_table)) &&
1390 1391 1392
      select_lex->item_list.elements)
  {
    select_lex->resolve_mode= SELECT_LEX::SELECT_MODE;
1393
    res= select_like_stmt_test_with_open_n_lock(stmt, tables, 0, 0);
1394 1395
    select_lex->resolve_mode= SELECT_LEX::NOMATTER_MODE;
  }
1396

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1397
  /* put tables back for PS rexecuting */
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1398
  lex->link_first_table_back(create_table, link_to_local);
1399 1400 1401
  DBUG_RETURN(res);
}

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

1403
/*
1404
  Validate and prepare for execution multi update statement
1405 1406 1407 1408 1409

  SYNOPSIS
    mysql_test_multiupdate()
    stmt	prepared statemen handler
    tables	list of tables queries
1410
    converted   converted to multi-update from usual update
1411 1412

  RETURN VALUE
1413 1414
    FALSE success
    TRUE error
1415
*/
1416 1417

static bool mysql_test_multiupdate(Prepared_statement *stmt,
1418 1419
				  TABLE_LIST *tables,
                                  bool converted)
1420
{
1421
  /* if we switched from normal update, rights are checked */
bell@sanja.is.com.ua's avatar
merge  
bell@sanja.is.com.ua committed
1422
  if (!converted && multi_update_precheck(stmt->thd, tables))
1423
    return TRUE;
1424 1425 1426

  return select_like_stmt_test(stmt, &mysql_multi_update_prepare,
                               OPTION_SETUP_TABLES_DONE);
1427 1428 1429 1430
}


/*
1431
  Validate and prepare for execution multi delete statement
1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450

  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;

1451
  if ((res= multi_delete_precheck(stmt->thd, tables)))
1452
    return res;
1453 1454 1455
  if ((res= select_like_stmt_test_with_open_n_lock(stmt, tables,
                                                   &mysql_multi_delete_prepare,
                                                   OPTION_SETUP_TABLES_DONE)))
1456 1457 1458 1459 1460 1461 1462 1463 1464
    return res;
  if (!tables->table)
  {
    my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
	     tables->view_db.str, tables->view_name.str);
    return -1;
  }
  return 0;

1465 1466 1467
}


1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490
/*
  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;
1491
  return mysql_insert_select_prepare(thd);
1492 1493 1494
}


1495 1496 1497 1498 1499 1500
/*
  Validate and prepare for execution INSERT ... SELECT statement

  SYNOPSIS
    mysql_test_insert_select()
    stmt	prepared statemen handler
1501
    tables	list of tables of query
1502 1503 1504 1505 1506 1507

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

1509 1510 1511 1512 1513
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
1514 1515
  TABLE_LIST *first_local_table;

1516 1517 1518 1519 1520
  if (tables->table)
  {
    // don't allocate insert_values
    tables->table->insert_values=(byte *)1;
  }
monty@mysql.com's avatar
monty@mysql.com committed
1521

1522 1523 1524 1525 1526 1527 1528
  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);

1529 1530 1531
  res= select_like_stmt_test_with_open_n_lock(stmt, tables,
                                              &mysql_insert_select_prepare_tester,
                                              OPTION_SETUP_TABLES_DONE);
1532
  /* revert changes  made by mysql_insert_select_prepare_tester */
miguel@hegel.local's avatar
miguel@hegel.local committed
1533
  lex->select_lex.table_list.first= (byte*) first_local_table;
1534 1535 1536 1537 1538
  lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE;
  return res;
}


1539
/*
1540 1541 1542
  Perform semantic analysis of the parsed tree and send a response packet
  to the client.

1543
  SYNOPSIS
1544 1545 1546 1547 1548 1549 1550 1551 1552
    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.

1553 1554 1555
  RETURN VALUE
    0   success
    1   error, sent to client
1556
*/
1557 1558 1559 1560

static int check_prepared_statement(Prepared_statement *stmt,
                                    bool text_protocol)
{
1561
  THD *thd= stmt->thd;
1562
  LEX *lex= stmt->lex;
1563
  SELECT_LEX *select_lex= &lex->select_lex;
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1564
  TABLE_LIST *tables;
1565
  enum enum_sql_command sql_command= lex->sql_command;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1566
  int res= 0;
1567
  DBUG_ENTER("check_prepared_statement");
1568
  DBUG_PRINT("enter",("command: %d, param_count: %ld",
1569
                      sql_command, stmt->param_count));
1570

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1571 1572
  lex->first_lists_tables_same();
  tables= lex->query_tables;
1573

1574
  switch (sql_command) {
1575
  case SQLCOM_REPLACE:
1576
  case SQLCOM_INSERT:
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1577 1578 1579
    res= mysql_test_insert(stmt, tables, lex->field_list,
			   lex->many_values,
			   select_lex->item_list, lex->value_list,
1580
			   lex->duplicates);
1581 1582 1583
    break;

  case SQLCOM_UPDATE:
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1584
    res= mysql_test_update(stmt, tables);
1585
    /* mysql_test_update return 2 if we need to switch to multi-update */
1586 1587 1588 1589 1590
    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
1591 1592
    break;

1593
  case SQLCOM_DELETE:
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1594
    res= mysql_test_delete(stmt, tables);
1595 1596 1597
    break;

  case SQLCOM_SELECT:
sergefp@mysql.com's avatar
sergefp@mysql.com committed
1598
    if ((res= mysql_test_select(stmt, tables, text_protocol)))
1599 1600 1601
      goto error;
    /* Statement and field info has already been sent */
    DBUG_RETURN(0);
1602

1603
  case SQLCOM_CREATE_TABLE:
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1604
    res= mysql_test_create_table(stmt);
1605 1606 1607
    break;
  
  case SQLCOM_DO:
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1608 1609
    res= mysql_test_do_fields(stmt, tables, lex->insert_list);
    break;
1610 1611

  case SQLCOM_SET_OPTION:
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1612
    res= mysql_test_set_fields(stmt, tables, &lex->var_list);
1613 1614 1615
    break;

  case SQLCOM_DELETE_MULTI:
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1616
    res= mysql_test_multidelete(stmt, tables);
1617 1618 1619
    break;

  case SQLCOM_INSERT_SELECT:
1620
  case SQLCOM_REPLACE_SELECT:
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1621
    res= mysql_test_insert_select(stmt, tables);
1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641
    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:
1642 1643 1644 1645 1646 1647
  case SQLCOM_ALTER_TABLE:
  case SQLCOM_COMMIT:
  case SQLCOM_CREATE_INDEX:
  case SQLCOM_DROP_INDEX:
  case SQLCOM_ROLLBACK:
  case SQLCOM_TRUNCATE:
1648
  case SQLCOM_CALL:
1649 1650
    break;

1651
  default:
1652 1653
    /*
      All other is not supported yet
1654
    */
1655
    res= -1;
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1656
    my_message(ER_UNSUPPORTED_PS, ER(ER_UNSUPPORTED_PS), MYF(0));
1657
    goto error;
1658
  }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
1659
  if (res == 0)
1660 1661
    DBUG_RETURN(text_protocol? 0 : (send_prep_stmt(stmt, 0) ||
                                    thd->protocol->flush()));
1662
error:
1663
  DBUG_RETURN(1);
1664 1665
}

venu@myvenu.com's avatar
venu@myvenu.com committed
1666
/*
1667 1668
  Initialize array of parameters in statement from LEX.
  (We need to have quick access to items by number in mysql_stmt_get_longdata).
1669
  This is to avoid using malloc/realloc in the parser.
venu@myvenu.com's avatar
venu@myvenu.com committed
1670
*/
1671

1672
static bool init_param_array(Prepared_statement *stmt)
venu@myvenu.com's avatar
venu@myvenu.com committed
1673
{
1674 1675 1676
  LEX *lex= stmt->lex;
  if ((stmt->param_count= lex->param_list.elements))
  {
1677 1678 1679
    if (stmt->param_count > (uint) UINT_MAX16)
    {
      /* Error code to be defined in 5.0 */
1680 1681
      my_message(ER_PS_MANY_PARAM, ER(ER_PS_MANY_PARAM), MYF(0));
      return TRUE;
1682
    }
1683 1684 1685 1686
    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 **)
1687
                       alloc_root(stmt->thd->mem_root,
1688 1689
                                  sizeof(Item_param*) * stmt->param_count);
    if (!stmt->param_array)
1690
      return TRUE;
1691 1692 1693 1694 1695 1696 1697
    for (to= stmt->param_array;
         to < stmt->param_array + stmt->param_count;
         ++to)
    {
      *to= param_iterator++;
    }
  }
1698
  return FALSE;
venu@myvenu.com's avatar
venu@myvenu.com committed
1699
}
1700

1701
/*
1702 1703 1704
  Given a query string with parameter markers, create a Prepared Statement
  from it and send PS info back to the client.
  
1705 1706
  SYNOPSIS
    mysql_stmt_prepare()
1707 1708 1709
      packet         query to be prepared 
      packet_length  query string length, including ignored trailing NULL or 
                     quote char.
1710
      name           NULL or statement name. For unnamed statements binary PS
1711
                     protocol is used, for named statements text protocol is 
1712
                     used.
1713 1714 1715 1716
  RETURN
    FALSE  OK, statement prepared successfully
    TRUE  Error

1717 1718 1719 1720 1721 1722 1723 1724 1725 1726
  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.
1727
   
1728 1729
*/

1730 1731
bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
                        LEX_STRING *name)
1732
{
1733 1734
  LEX *lex;
  Prepared_statement *stmt= new Prepared_statement(thd);
1735
  bool error;
1736
  DBUG_ENTER("mysql_stmt_prepare");
1737

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

1740
  if (stmt == 0)
1741
    DBUG_RETURN(TRUE);
1742 1743 1744 1745

  if (name)
  {
    stmt->name.length= name->length;
1746
    if (!(stmt->name.str= memdup_root(stmt->mem_root, (char*)name->str,
1747
                                      name->length)))
1748 1749
    {
      delete stmt;
1750
      DBUG_RETURN(TRUE);
1751
    }
1752
  }
1753

1754
  if (thd->stmt_map.insert(stmt))
1755 1756
  {
    delete stmt;
1757
    DBUG_RETURN(TRUE);
1758
  }
1759

1760 1761
  thd->set_n_backup_statement(stmt, &thd->stmt_backup);
  thd->set_n_backup_item_arena(stmt, &thd->stmt_backup);
1762

1763
  if (alloc_query(thd, packet, packet_length))
1764
  {
1765 1766
    thd->restore_backup_statement(stmt, &thd->stmt_backup);
    thd->restore_backup_item_arena(stmt, &thd->stmt_backup);
1767 1768
    /* Statement map deletes statement on erase */
    thd->stmt_map.erase(stmt);
1769
    DBUG_RETURN(TRUE);
1770
  }
1771

1772
  mysql_log.write(thd, COM_PREPARE, "[%lu] %s", stmt->id, packet);
1773

1774
  thd->current_arena= stmt;
1775
  mysql_init_query(thd, (uchar *) thd->query, thd->query_length);
1776
  /* Reset warnings from previous command */
monty@mysql.com's avatar
monty@mysql.com committed
1777
  mysql_reset_errors(thd, 0);
1778
  lex= thd->lex;
1779 1780
  lex->safe_to_cache_query= 0;

1781
  error= yyparse((void *)thd) || thd->is_fatal_error ||
1782
         thd->net.report_error || init_param_array(stmt);
1783
  /*
1784 1785
    While doing context analysis of the query (in check_prepared_statement)
    we allocate a lot of additional memory: for open tables, JOINs, derived
1786 1787 1788 1789 1790 1791 1792 1793
    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)
1794
    error= check_prepared_statement(stmt, test(name));
1795

1796
  /* restore to WAIT_PRIOR: QUERY_PRIOR is set inside alloc_query */
1797
  if (!(specialflag & SPECIAL_NO_PRIOR))
venu@myvenu.com's avatar
venu@myvenu.com committed
1798
    my_pthread_setprio(pthread_self(),WAIT_PRIOR);
pem@mysql.com's avatar
pem@mysql.com committed
1799
  if (error && thd->lex->sphead)
pem@mysql.comhem.se's avatar
pem@mysql.comhem.se committed
1800 1801 1802 1803
  {
    delete thd->lex->sphead;
    thd->lex->sphead= NULL;
  }
1804
  lex_end(lex);
1805
  close_thread_tables(thd);
1806 1807
  thd->restore_backup_statement(stmt, &thd->stmt_backup);
  cleanup_items(stmt->free_list);
1808
  thd->rollback_item_tree_changes();
1809
  thd->cleanup_after_query();
1810
  thd->current_arena= thd;
1811

1812
  if (error)
1813
  {
1814 1815
    /* Statement map deletes statement on erase */
    thd->stmt_map.erase(stmt);
sergefp@mysql.com's avatar
sergefp@mysql.com committed
1816
    stmt= NULL;
1817
  }
1818
  else
monty@mysql.com's avatar
monty@mysql.com committed
1819 1820
  {
    stmt->setup_set_params();
1821
    init_stmt_after_parse(thd, stmt->lex);
1822
    stmt->state= Item_arena::PREPARED;
monty@mysql.com's avatar
monty@mysql.com committed
1823
  }
1824
  DBUG_RETURN(!stmt);
1825 1826
}

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

1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847
/*
  Init PS/SP specific parse tree members.
*/

void init_stmt_after_parse(THD *thd, LEX *lex)
{
  SELECT_LEX *sl= 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;

  for (TABLE_LIST *table= lex->query_tables; table; table= table->next_global)
    table->prep_on_expr= table->on_expr;
}


/* Reinit prepared statement/stored procedure before execution */
1848

1849
void reset_stmt_for_execute(THD *thd, LEX *lex)
1850
{
1851
  SELECT_LEX *sl= lex->all_selects_list;
monty@mysql.com's avatar
monty@mysql.com committed
1852
  DBUG_ENTER("reset_stmt_for_execute");
1853

bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1854 1855 1856
  if (lex->empty_field_list_on_rset)
  {
    lex->empty_field_list_on_rset= 0;
1857
    lex->field_list.empty();
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1858
  }
1859
  for (; sl; sl= sl->next_select_in_list())
1860
  {
1861 1862
    if (!sl->first_execution)
    {
monty@mysql.com's avatar
monty@mysql.com committed
1863 1864 1865
      /* remove option which was put by mysql_explain_union() */
      sl->options&= ~SELECT_DESCRIBE;

1866 1867 1868
      /* see unique_table() */
      sl->exclude_from_table_unique_test= FALSE;

1869 1870 1871 1872
      /*
        Copy WHERE clause pointers to avoid damaging they by optimisation
      */
      if (sl->prep_where)
pem@mysql.com's avatar
pem@mysql.com committed
1873
      {
1874
        sl->where= sl->prep_where->copy_andor_structure(thd);
pem@mysql.com's avatar
pem@mysql.com committed
1875 1876
        sl->where->cleanup();
      }
1877 1878 1879 1880 1881 1882 1883 1884 1885
      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;
    }
1886 1887 1888 1889
    {
      SELECT_LEX_UNIT *unit= sl->master_unit();
      unit->unclean();
      unit->types.empty();
1890
      /* for derived tables & PS (which can't be reset by Item_subquery) */
1891 1892
      unit->reinit_exec_mechanism();
    }
1893
  }
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1894 1895 1896 1897 1898 1899

  /*
    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.
  */
1900 1901 1902 1903 1904
  /*
    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).
  */
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1905 1906 1907 1908 1909 1910 1911 1912 1913
  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;
1914 1915
    if (tables->nested_join)
      tables->nested_join->counter= 0;
1916 1917 1918 1919 1920 1921

    if (tables->prep_on_expr)
    {
      tables->on_expr= tables->prep_on_expr->copy_andor_structure(thd);
      tables->on_expr->cleanup();
    }
bell@sanja.is.com.ua's avatar
VIEW  
bell@sanja.is.com.ua committed
1922
  }
1923
  lex->current_select= &lex->select_lex;
1924 1925 1926 1927 1928

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

1929 1930
  if (lex->result)
    lex->result->cleanup();
monty@mysql.com's avatar
monty@mysql.com committed
1931 1932

  DBUG_VOID_RETURN;
1933 1934
}

1935

1936 1937
/*
  Clears parameters from data left from previous execution or long data
1938 1939 1940
    
  SYNOPSIS
    reset_stmt_params()
1941
    stmt	prepared statement for which parameters should be reset
1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952
*/

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


1953 1954 1955 1956
/*
  Executes previously prepared query.
  If there is any parameters, then replace markers with the data supplied
  from client, and then execute the query.
1957

1958
  SYNOPSIS
1959
    mysql_stmt_execute()
1960 1961 1962
      thd            Current thread
      packet         Query string
      packet_length  Query string length, including terminator character.
1963 1964
*/

1965
void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
1966
{
1967
  ulong stmt_id= uint4korr(packet);
1968
  ulong flags= (ulong) ((uchar) packet[4]);
1969
  Cursor *cursor;
1970 1971 1972 1973 1974
  /*
    Query text for binary log, or empty string if the query is not put into
    binary log.
  */
  String expanded_query;
1975
#ifndef EMBEDDED_LIBRARY
1976
  uchar *packet_end= (uchar *) packet + packet_length - 1;
1977
#endif
1978 1979
  Prepared_statement *stmt;
  DBUG_ENTER("mysql_stmt_execute");
1980 1981

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

1983
  if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_execute")))
1984 1985
    DBUG_VOID_RETURN;

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

1988
  /* Check if we got an error when sending long data */
1989
  if (stmt->state == Item_arena::ERROR)
1990
  {
1991
    my_message(stmt->last_errno, stmt->last_error, MYF(0));
1992 1993 1994
    DBUG_VOID_RETURN;
  }

1995 1996 1997 1998 1999 2000 2001
  cursor= stmt->cursor;
  if (cursor && cursor->is_open())
  {
    my_error(ER_EXEC_STMT_WITH_OPEN_CURSOR, MYF(0));
    DBUG_VOID_RETURN;
  }

2002 2003
  DBUG_ASSERT(thd->free_list == NULL);
  mysql_reset_thd_for_next_command(thd);
2004 2005
  if (flags & (ulong) CURSOR_TYPE_READ_ONLY)
  {
monty@mysql.com's avatar
monty@mysql.com committed
2006
    if (!stmt->lex->result || !stmt->lex->result->simple_select())
2007
    {
monty@mysql.com's avatar
monty@mysql.com committed
2008
      DBUG_PRINT("info",("Cursor asked for not SELECT stmt"));
2009 2010 2011 2012 2013
      /*
        If lex->result is set in the parser, this is not a SELECT
        statement: we can't open a cursor for it.
      */
      flags= 0;
2014 2015
      my_error(ER_SP_BAD_CURSOR_QUERY, MYF(0));
      goto err;
2016 2017 2018
    }
    else
    {
monty@mysql.com's avatar
monty@mysql.com committed
2019
      DBUG_PRINT("info",("Using READ_ONLY cursor"));
2020
      if (!cursor &&
2021
          !(cursor= stmt->cursor= new (&stmt->main_mem_root) Cursor()))
2022 2023
        DBUG_VOID_RETURN;
      /* If lex->result is set, mysql_execute_command will use it */
2024
      stmt->lex->result= &cursor->result;
2025 2026
    }
  }
hf@deer.(none)'s avatar
hf@deer.(none) committed
2027
#ifndef EMBEDDED_LIBRARY
2028
  if (stmt->param_count)
2029
  {
2030
    uchar *null_array= (uchar *) packet;
2031
    if (setup_conversion_functions(stmt, (uchar **) &packet, packet_end) ||
2032
        stmt->set_params(stmt, null_array, (uchar *) packet, packet_end,
2033
                         &expanded_query))
2034
      goto set_params_data_err;
2035
  }
hf@deer.(none)'s avatar
hf@deer.(none) committed
2036
#else
2037
  /*
2038 2039 2040
    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.
2041
  */
2042
  if (stmt->param_count && stmt->set_params_data(stmt, &expanded_query))
2043
    goto set_params_data_err;
hf@deer.(none)'s avatar
hf@deer.(none) committed
2044
#endif
2045 2046
  thd->stmt_backup.set_statement(thd);
  thd->set_statement(stmt);
2047
  thd->current_arena= stmt;
2048 2049 2050 2051 2052 2053 2054 2055 2056 2057
  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;
  }

2058 2059 2060
  mysql_log.write(thd, COM_EXECUTE, "[%lu] %s", stmt->id,
                  expanded_query.length() ? expanded_query.c_ptr() :
                                            stmt->query);
konstantin@mysql.com's avatar
konstantin@mysql.com committed
2061

2062
  thd->protocol= &thd->protocol_prep;           // Switch to binary protocol
2063 2064 2065 2066 2067
  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);
2068
  thd->protocol= &thd->protocol_simple;         // Use normal protocol
2069

2070
  if (cursor && cursor->is_open())
2071
  {
2072 2073
    cursor->init_from_thd(thd);
    cursor->state= stmt->state;
2074 2075 2076 2077 2078 2079 2080
  }
  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
2081
    thd->rollback_item_tree_changes();
2082
    thd->cleanup_after_query();
2083 2084 2085
  }

  thd->set_statement(&thd->stmt_backup);
2086
  thd->current_arena= thd;
2087
  DBUG_VOID_RETURN;
venu@myvenu.com's avatar
venu@myvenu.com committed
2088

2089
set_params_data_err:
2090
  reset_stmt_params(stmt);
2091
  my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_stmt_execute");
2092
err:
2093 2094 2095
  DBUG_VOID_RETURN;
}

2096

sergefp@mysql.com's avatar
sergefp@mysql.com committed
2097
/*
2098
  Execute prepared statement using parameter values from
sergefp@mysql.com's avatar
sergefp@mysql.com committed
2099 2100 2101
  lex->prepared_stmt_params and send result to the client using text protocol.
*/

2102
void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name)
sergefp@mysql.com's avatar
sergefp@mysql.com committed
2103
{
2104
  Prepared_statement *stmt;
2105
  /*
2106 2107
    Query text for binary log, or empty string if the query is not put into
    binary log.
2108
  */
2109
  String expanded_query;
2110
  DBUG_ENTER("mysql_sql_stmt_execute");
2111

2112 2113
  DBUG_ASSERT(thd->free_list == NULL);

2114 2115
  if (!(stmt= (Prepared_statement*)thd->stmt_map.find_by_name(stmt_name)))
  {
2116 2117 2118
    my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), stmt_name->length,
             stmt_name->str, "EXECUTE");
    DBUG_VOID_RETURN;
2119 2120
  }

sergefp@mysql.com's avatar
sergefp@mysql.com committed
2121 2122
  if (stmt->param_count != thd->lex->prepared_stmt_params.elements)
  {
2123
    my_error(ER_WRONG_ARGUMENTS, MYF(0), "EXECUTE");
sergefp@mysql.com's avatar
sergefp@mysql.com committed
2124 2125 2126
    DBUG_VOID_RETURN;
  }

2127 2128
  /* Must go before setting variables, as it clears thd->user_var_events */
  mysql_reset_thd_for_next_command(thd);
2129
  thd->set_n_backup_statement(stmt, &thd->stmt_backup);
2130
  thd->set_statement(stmt);
2131 2132
  if (stmt->set_params_from_vars(stmt,
                                 thd->stmt_backup.lex->prepared_stmt_params,
2133
                                 &expanded_query))
sergefp@mysql.com's avatar
sergefp@mysql.com committed
2134
  {
2135
    my_error(ER_WRONG_ARGUMENTS, MYF(0), "EXECUTE");
sergefp@mysql.com's avatar
sergefp@mysql.com committed
2136
  }
2137
  execute_stmt(thd, stmt, &expanded_query);
2138
  DBUG_VOID_RETURN;
2139
}
2140

2141

2142 2143
/*
  Execute prepared statement.
2144 2145 2146 2147
  SYNOPSIS
    execute_stmt()
      thd            Current thread
      stmt           Statement to execute
2148
      expanded_query If binary log is enabled, query string with parameter
2149 2150 2151
                     placeholders replaced with actual values. Otherwise empty
                     string.
  NOTES
2152
    Caller must set parameter values and thd::protocol.
2153
*/
2154

2155
static void execute_stmt(THD *thd, Prepared_statement *stmt,
2156
                         String *expanded_query)
2157 2158
{
  DBUG_ENTER("execute_stmt");
monty@mysql.com's avatar
monty@mysql.com committed
2159

monty@mysql.com's avatar
monty@mysql.com committed
2160
  reset_stmt_for_execute(thd, stmt->lex);
2161 2162 2163

  if (expanded_query->length() &&
      alloc_query(thd, (char *)expanded_query->ptr(),
2164 2165
                  expanded_query->length()+1))
  {
2166
    my_error(ER_OUTOFMEMORY, MYF(0), expanded_query->length());
2167 2168
    DBUG_VOID_RETURN;
  }
2169 2170 2171 2172 2173
  /*
    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.
  */
2174
  thd->current_arena= stmt;
2175

2176
  if (!(specialflag & SPECIAL_NO_PRIOR))
2177
    my_pthread_setprio(pthread_self(),QUERY_PRIOR);
2178
  mysql_execute_command(thd);
2179
  if (!(specialflag & SPECIAL_NO_PRIOR))
2180
    my_pthread_setprio(pthread_self(), WAIT_PRIOR);
2181

2182
  thd->lex->unit.cleanup();
2183
  thd->current_arena= thd;
hf@deer.(none)'s avatar
hf@deer.(none) committed
2184
  cleanup_items(stmt->free_list);
2185
  thd->rollback_item_tree_changes();
2186
  reset_stmt_params(stmt);
2187
  close_thread_tables(thd);                    // to close derived tables
2188
  thd->set_statement(&thd->stmt_backup);
2189 2190
  thd->cleanup_after_query();

2191 2192
  if (stmt->state == Item_arena::PREPARED)
    stmt->state= Item_arena::EXECUTED;
2193 2194 2195
  DBUG_VOID_RETURN;
}

2196

2197 2198
/*
  COM_FETCH handler: fetches requested amount of rows from cursor
monty@mysql.com's avatar
monty@mysql.com committed
2199

2200
  SYNOPSIS
monty@mysql.com's avatar
monty@mysql.com committed
2201 2202 2203 2204
    mysql_stmt_fetch()
    thd			Thread handler
    packet		Packet from client (with stmt_id & num_rows)
    packet_length	Length of packet
2205 2206 2207 2208 2209 2210
*/

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);
2211
  ulong num_rows= uint4korr(packet+4);
2212 2213 2214
  Statement *stmt;
  DBUG_ENTER("mysql_stmt_fetch");

2215 2216 2217 2218
  if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_fetch")))
    DBUG_VOID_RETURN;

  if (!stmt->cursor || !stmt->cursor->is_open())
2219
  {
2220
    my_error(ER_STMT_HAS_NO_OPEN_CURSOR, MYF(0));
2221 2222
    DBUG_VOID_RETURN;
  }
2223

monty@mysql.com's avatar
monty@mysql.com committed
2224
  thd->current_arena= stmt;
2225
  thd->set_n_backup_statement(stmt, &thd->stmt_backup);
2226 2227 2228 2229 2230 2231
  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
2232
  stmt->cursor->fetch(num_rows);
2233 2234 2235 2236 2237 2238 2239
  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);
2240 2241
  thd->restore_backup_statement(stmt, &thd->stmt_backup);
  thd->current_arena= thd;
2242 2243 2244 2245 2246

  DBUG_VOID_RETURN;
}


2247
/*
2248
  Reset a prepared statement in case there was a recoverable error.
2249 2250
  SYNOPSIS
    mysql_stmt_reset()
2251
      thd       Thread handle
2252
      packet	Packet with stmt id
2253 2254

  DESCRIPTION
2255 2256 2257 2258 2259 2260 2261
    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).
2262 2263
*/

2264
void mysql_stmt_reset(THD *thd, char *packet)
2265
{
2266
  /* There is always space for 4 bytes in buffer */
2267
  ulong stmt_id= uint4korr(packet);
2268
  Prepared_statement *stmt;
2269
  DBUG_ENTER("mysql_stmt_reset");
2270

2271
  if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_reset")))
2272 2273
    DBUG_VOID_RETURN;

2274 2275 2276
  if (stmt->cursor && stmt->cursor->is_open())
    stmt->cursor->close();

2277
  stmt->state= Item_arena::PREPARED;
2278

2279 2280 2281 2282 2283
  /* 
    Clear parameters from data which could be set by 
    mysql_stmt_send_long_data() call.
  */
  reset_stmt_params(stmt);
2284

2285
  mysql_reset_thd_for_next_command(thd);
2286
  send_ok(thd);
2287
  
2288 2289 2290 2291 2292
  DBUG_VOID_RETURN;
}


/*
2293 2294
  Delete a prepared statement from memory.
  Note: we don't send any reply to that command. 
2295 2296
*/

2297
void mysql_stmt_free(THD *thd, char *packet)
2298
{
2299
  /* There is always space for 4 bytes in packet buffer */
2300
  ulong stmt_id= uint4korr(packet);
2301 2302
  Prepared_statement *stmt;

2303
  DBUG_ENTER("mysql_stmt_free");
2304

2305
  if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_close")))
2306
    DBUG_VOID_RETURN;
2307 2308 2309

  /* Statement map deletes statement on erase */
  thd->stmt_map.erase(stmt);
2310 2311 2312
  DBUG_VOID_RETURN;
}

2313 2314

/*
2315
  Long data in pieces from client
2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332

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

2333
void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
2334
{
2335 2336
  ulong stmt_id;
  uint param_number;
2337
  Prepared_statement *stmt;
2338 2339
  Item_param *param;
  char *packet_end= packet + packet_length - 1;
2340
  
2341 2342
  DBUG_ENTER("mysql_stmt_get_longdata");

hf@deer.(none)'s avatar
hf@deer.(none) committed
2343
#ifndef EMBEDDED_LIBRARY
2344 2345
  /* Minimal size of long data packet is 6 bytes */
  if ((ulong) (packet_end - packet) < MYSQL_LONG_DATA_HEADER)
2346
  {
2347
    my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_stmt_send_long_data");
2348 2349
    DBUG_VOID_RETURN;
  }
hf@deer.(none)'s avatar
hf@deer.(none) committed
2350
#endif
2351

2352 2353
  stmt_id= uint4korr(packet);
  packet+= 4;
2354

2355 2356
  if (!(stmt=find_prepared_statement(thd, stmt_id,
                                     "mysql_stmt_send_long_data")))
2357 2358
    DBUG_VOID_RETURN;

2359 2360
  param_number= uint2korr(packet);
  packet+= 2;
hf@deer.(none)'s avatar
hf@deer.(none) committed
2361
#ifndef EMBEDDED_LIBRARY
2362 2363
  if (param_number >= stmt->param_count)
  {
venu@myvenu.com's avatar
venu@myvenu.com committed
2364
    /* Error will be sent in execute call */
2365
    stmt->state= Item_arena::ERROR;
venu@myvenu.com's avatar
venu@myvenu.com committed
2366
    stmt->last_errno= ER_WRONG_ARGUMENTS;
2367 2368
    sprintf(stmt->last_error, ER(ER_WRONG_ARGUMENTS),
            "mysql_stmt_send_long_data");
2369 2370
    DBUG_VOID_RETURN;
  }
hf@deer.(none)'s avatar
hf@deer.(none) committed
2371 2372
#endif

2373 2374
  param= stmt->param_array[param_number];

hf@deer.(none)'s avatar
hf@deer.(none) committed
2375
#ifndef EMBEDDED_LIBRARY
2376
  if (param->set_longdata(packet, (ulong) (packet_end - packet)))
hf@deer.(none)'s avatar
hf@deer.(none) committed
2377
#else
2378
  if (param->set_longdata(thd->extra_data, thd->extra_length))
hf@deer.(none)'s avatar
hf@deer.(none) committed
2379
#endif
2380
  {
2381
    stmt->state= Item_arena::ERROR;
2382 2383 2384
    stmt->last_errno= ER_OUTOFMEMORY;
    sprintf(stmt->last_error, ER(ER_OUTOFMEMORY), 0);
  }
2385 2386
  DBUG_VOID_RETURN;
}
venu@myvenu.com's avatar
venu@myvenu.com committed
2387

2388 2389 2390 2391

Prepared_statement::Prepared_statement(THD *thd_arg)
  :Statement(thd_arg),
  thd(thd_arg),
2392
  param_array(0),
2393
  param_count(0),
2394
  last_errno(0)
2395 2396 2397 2398
{
  *last_error= '\0';
}

2399 2400 2401 2402
void Prepared_statement::setup_set_params()
{
  /* Setup binary logging */
  if (mysql_bin_log.is_open() && is_update_query(lex->sql_command))
2403
  {
2404
    set_params_from_vars= insert_params_from_vars_with_log;
2405
#ifndef EMBEDDED_LIBRARY
2406
    set_params= insert_params_withlog;
2407
#else
2408
    set_params_data= emb_insert_params_withlog;
2409 2410 2411
#endif
  }
  else
2412 2413
  {
    set_params_from_vars= insert_params_from_vars;
2414
#ifndef EMBEDDED_LIBRARY
2415
    set_params= insert_params;
2416
#else
2417
    set_params_data= emb_insert_params;
2418
#endif
2419
  }
2420 2421
}

2422

2423 2424
Prepared_statement::~Prepared_statement()
{
2425 2426
  if (cursor)
    cursor->Cursor::~Cursor();
2427
  free_items(free_list);
2428
  delete lex->result;
2429 2430 2431
}


2432
Item_arena::Type Prepared_statement::type() const
2433 2434 2435
{
  return PREPARED_STATEMENT;
}