sql_prepare.cc 35.5 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
    [COM_LONG_DATA:1][STMT_ID:4][parameter_number:2][type:2][data]
61 62
  - Checks if the type is specified by client, and if yes reads the type, 
    and stores the data in that format.
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 71
***********************************************************************/

#include "mysql_priv.h"
#include "sql_acl.h"
72
#include "sql_select.h" // for JOIN
73
#include <m_ctype.h>  // for isspace()
74 75 76 77
#ifdef EMBEDDED_LIBRARY
/* include MYSQL_BIND headers */
#include <mysql.h>
#endif
78

79
const String my_null_string("NULL", 4, default_charset_info);
80

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

85 86 87 88
class Prepared_statement: public Statement
{
public:
  THD *thd;
89
  Item_param **param_array;
90 91 92
  uint param_count;
  uint last_errno;
  char last_error[MYSQL_ERRMSG_SIZE];
93 94
  bool get_longdata_error;
  bool long_data_used;
95 96
  bool log_full_query;
#ifndef EMBEDDED_LIBRARY
97 98
  bool (*set_params)(Prepared_statement *st, uchar *data, uchar *data_end,
                     uchar *read_pos);
hf@deer.(none)'s avatar
hf@deer.(none) committed
99
#else
100
  bool (*set_params_data)(Prepared_statement *st);
hf@deer.(none)'s avatar
hf@deer.(none) committed
101
#endif
102 103 104 105 106
public:
  Prepared_statement(THD *thd_arg);
  virtual ~Prepared_statement();
  virtual Statement::Type type() const;
};
hf@deer.(none)'s avatar
hf@deer.(none) committed
107

108

109 110 111
/******************************************************************************
  Implementation
******************************************************************************/
112 113


114
inline bool is_param_null(const uchar *pos, ulong param_no)
115
{
116
  return pos[param_no/8] & (1 << (param_no & 7));
117 118
}

119
enum { STMT_QUERY_LOG_LENGTH= 8192 };
120

121
enum enum_send_error { DONT_SEND_ERROR= 0, SEND_ERROR };
122 123

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

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

  if (stmt == 0 || stmt->type() != Statement::PREPARED_STATEMENT)
  {
    my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), id, where);
137 138
    if (se == SEND_ERROR)
      send_error(thd);
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
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;
153
  char buff[9];
154
  buff[0]= 0;                                   /* OK packet indicator */
155
  int4store(buff+1, stmt->id);
156 157
  int2store(buff+5, columns);
  int2store(buff+7, stmt->param_count);
158 159 160 161 162 163 164 165 166 167
  /*
    Send types and names of placeholders to the client
    XXX: fix this nasty upcast from List<Item_param> to List<Item>
  */
  return my_net_write(net, buff, sizeof(buff)) || 
         (stmt->param_count &&
          stmt->thd->protocol_simple.send_fields((List<Item> *)
                                                 &stmt->lex->param_list, 0)) ||
         net_flush(net);
  return 0;
hf@deer.(none)'s avatar
hf@deer.(none) committed
168
}
169
#else
170 171
static bool send_prep_stmt(Prepared_statement *stmt,
                           uint columns __attribute__((unused)))
hf@deer.(none)'s avatar
hf@deer.(none) committed
172
{
hf@deer.(none)'s avatar
SCRUM  
hf@deer.(none) committed
173 174
  THD *thd= stmt->thd;

175
  thd->client_stmt_id= stmt->id;
hf@deer.(none)'s avatar
SCRUM  
hf@deer.(none) committed
176
  thd->client_param_count= stmt->param_count;
hf@deer.(none)'s avatar
hf@deer.(none) committed
177
  thd->net.last_errno= 0;
hf@deer.(none)'s avatar
hf@deer.(none) committed
178

hf@deer.(none)'s avatar
SCRUM  
hf@deer.(none) committed
179
  return 0;
180
}
181
#endif /*!EMBEDDED_LIBRARY*/
182

183 184

/*
185 186
  Read the length of the parameter data and return back to
  caller by positing the pointer to param data.
187 188
*/

hf@deer.(none)'s avatar
hf@deer.(none) committed
189
#ifndef EMBEDDED_LIBRARY
190
static ulong get_param_length(uchar **packet, ulong len)
191 192
{
  reg1 uchar *pos= *packet;
193 194
  if (len < 1)
    return 0;
195 196 197 198 199
  if (*pos < 251)
  {
    (*packet)++;
    return (ulong) *pos;
  }
200 201
  if (len < 3)
    return 0;
202 203 204 205 206
  if (*pos == 252)
  {
    (*packet)+=3;
    return (ulong) uint2korr(pos+1);
  }
207 208
  if (len < 4)
    return 0;
209 210 211 212 213
  if (*pos == 253)
  {
    (*packet)+=4;
    return (ulong) uint3korr(pos+1);
  }
214 215
  if (len < 5)
    return 0;
216
  (*packet)+=9; // Must be 254 when here 
217
  /* TODO: why uint4korr here? (should be uint8korr) */
218 219
  return (ulong) uint4korr(pos+1);
}
hf@deer.(none)'s avatar
hf@deer.(none) committed
220
#else
221
#define get_param_length(packet, len) len
hf@deer.(none)'s avatar
hf@deer.(none) committed
222 223
#endif /*!EMBEDDED_LIBRARY*/

venu@myvenu.com's avatar
venu@myvenu.com committed
224
 /*
225 226 227 228 229 230
   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
231

232 233
  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
234 235 236 237 238

  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.

239 240
  RETURN VALUE
    none
241 242
*/

243
void set_param_tiny(Item_param *param, uchar **pos, ulong len)
244
{
245 246 247 248
#ifndef EMBEDDED_LIBRARY
  if (len < 1)
    return;
#endif
venu@myvenu.com's avatar
venu@myvenu.com committed
249 250 251 252
  param->set_int((longlong)(**pos));
  *pos+= 1;
}

253
void set_param_short(Item_param *param, uchar **pos, ulong len)
venu@myvenu.com's avatar
venu@myvenu.com committed
254
{
255 256 257 258
#ifndef EMBEDDED_LIBRARY
  if (len < 2)
    return;
#endif
venu@myvenu.com's avatar
venu@myvenu.com committed
259 260 261 262
  param->set_int((longlong)sint2korr(*pos));
  *pos+= 2;
}

263
void set_param_int32(Item_param *param, uchar **pos, ulong len)
venu@myvenu.com's avatar
venu@myvenu.com committed
264
{
265 266 267 268
#ifndef EMBEDDED_LIBRARY
  if (len < 4)
    return;
#endif
venu@myvenu.com's avatar
venu@myvenu.com committed
269 270 271 272
  param->set_int((longlong)sint4korr(*pos));
  *pos+= 4;
}

273
void set_param_int64(Item_param *param, uchar **pos, ulong len)
venu@myvenu.com's avatar
venu@myvenu.com committed
274
{
275 276 277 278
#ifndef EMBEDDED_LIBRARY
  if (len < 8)
    return;
#endif
venu@myvenu.com's avatar
venu@myvenu.com committed
279 280 281 282
  param->set_int((longlong)sint8korr(*pos));
  *pos+= 8;
}

283
void set_param_float(Item_param *param, uchar **pos, ulong len)
venu@myvenu.com's avatar
venu@myvenu.com committed
284
{
285 286 287 288
#ifndef EMBEDDED_LIBRARY
  if (len < 4)
    return;
#endif
venu@myvenu.com's avatar
venu@myvenu.com committed
289 290 291 292 293 294
  float data;
  float4get(data,*pos);
  param->set_double((double) data);
  *pos+= 4;
}

295
void set_param_double(Item_param *param, uchar **pos, ulong len)
venu@myvenu.com's avatar
venu@myvenu.com committed
296
{
297 298 299 300
#ifndef EMBEDDED_LIBRARY
  if (len < 8)
    return;
#endif
venu@myvenu.com's avatar
venu@myvenu.com committed
301 302 303 304 305 306
  double data;
  float8get(data,*pos);
  param->set_double((double) data);
  *pos+= 8;
}

307
void set_param_time(Item_param *param, uchar **pos, ulong len)
308 309 310
{
  ulong length;

311
  if ((length= get_param_length(pos, len)) >= 8)
312 313
  {
    uchar *to= *pos;
314
    TIME  tm;
315
    
316
    /* TODO: why length is compared with 8 here? */
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
    tm.second_part= (length > 8 ) ? (ulong) sint4korr(to+7): 0;

    tm.day=    (ulong) sint4korr(to+1);
    tm.hour=   (uint) to[5];
    tm.minute= (uint) to[6];
    tm.second= (uint) to[7];

    tm.year= tm.month= 0;
    tm.neg= (bool)to[0];

    param->set_time(&tm, TIMESTAMP_TIME);
  }
  *pos+= length;
}

332
void set_param_datetime(Item_param *param, uchar **pos, ulong len)
333
{
334
  uint length;
335
 
336
  if ((length= get_param_length(pos, len)) >= 4)
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
  {
    uchar *to= *pos;
    TIME  tm;
    
    tm.second_part= (length > 7 ) ? (ulong) sint4korr(to+7): 0;
    
    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;
    
    tm.year=   (uint) sint2korr(to);
    tm.month=  (uint) to[2];
    tm.day=    (uint) to[3];
    tm.neg=    0;

357
    param->set_time(&tm, TIMESTAMP_DATETIME);
358 359 360 361
  }
  *pos+= length;
}

362
void set_param_date(Item_param *param, uchar **pos, ulong len)
363 364 365
{
  ulong length;
 
366
  if ((length= get_param_length(pos, len)) >= 4)
367 368 369 370
  {
    uchar *to= *pos;
    TIME tm;

371
    tm.year=  (uint) sint2korr(to);
372 373 374 375 376 377 378 379 380 381 382 383
    tm.month=  (uint) to[2];
    tm.day= (uint) to[3];

    tm.hour= tm.minute= tm.second= 0;
    tm.second_part= 0;
    tm.neg= 0;

    param->set_time(&tm, TIMESTAMP_DATE);
  }
  *pos+= length;
}

384
void set_param_str(Item_param *param, uchar **pos, ulong len)
venu@myvenu.com's avatar
venu@myvenu.com committed
385
{
386 387 388
  ulong length= get_param_length(pos, len);
  param->set_value((const char *)*pos, length);
  *pos+= length;
venu@myvenu.com's avatar
venu@myvenu.com committed
389 390
}

391
static void setup_one_conversion_function(Item_param *param, uchar param_type)
venu@myvenu.com's avatar
venu@myvenu.com committed
392
{
393
  switch (param_type) {
394
  case FIELD_TYPE_TINY:
395
    param->set_param_func= set_param_tiny;
396
    param->item_result_type= INT_RESULT;
397 398
    break;
  case FIELD_TYPE_SHORT:
399
    param->set_param_func= set_param_short;
400
    param->item_result_type= INT_RESULT;
401 402
    break;
  case FIELD_TYPE_LONG:
403
    param->set_param_func= set_param_int32;
404
    param->item_result_type= INT_RESULT;
405 406
    break;
  case FIELD_TYPE_LONGLONG:
407
    param->set_param_func= set_param_int64;
408
    param->item_result_type= INT_RESULT;
409 410
    break;
  case FIELD_TYPE_FLOAT:
411
    param->set_param_func= set_param_float;
412
    param->item_result_type= REAL_RESULT;
413 414
    break;
  case FIELD_TYPE_DOUBLE:
415
    param->set_param_func= set_param_double;
416
    param->item_result_type= REAL_RESULT;
417
    break;
418
  case FIELD_TYPE_TIME:
419
    param->set_param_func= set_param_time;
420
    param->item_result_type= STRING_RESULT;
421 422
    break;
  case FIELD_TYPE_DATE:
423
    param->set_param_func= set_param_date;
424
    param->item_result_type= STRING_RESULT;
425
    break;
426 427
  case MYSQL_TYPE_DATETIME:
  case MYSQL_TYPE_TIMESTAMP:
428
    param->set_param_func= set_param_datetime;
429
    param->item_result_type= STRING_RESULT;
430
    break;
431
  default:
432
    param->set_param_func= set_param_str;
433
    param->item_result_type= STRING_RESULT;
434 435 436
  }
}

hf@deer.(none)'s avatar
hf@deer.(none) committed
437
#ifndef EMBEDDED_LIBRARY
438
/*
439 440
  Update the parameter markers by reading data from client packet 
  and if binary/update log is set, generate the valid query.
441 442
*/

443 444
static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array,
                                  uchar *read_pos, uchar *data_end)
445
{
446 447 448 449 450
  THD  *thd= stmt->thd;
  Item_param **begin= stmt->param_array;
  Item_param **end= begin + stmt->param_count;
  uint32 length= 0;

451 452 453 454
  String str, query;
  const String *res;

  DBUG_ENTER("insert_params_withlog"); 
455

456
  if (query.copy(stmt->query, stmt->query_length, default_charset_info))
457
    DBUG_RETURN(1);
458
  
459
  for (Item_param **it= begin; it < end; ++it)
460
  {
461
    Item_param *param= *it;
462
    if (param->long_data_supplied)
463
      res= param->query_val_str(&str);
464 465
    else
    {
466
      if (is_param_null(null_array, it - begin))
467 468
      {
        param->maybe_null= param->null_value= 1;
hf@deer.(none)'s avatar
hf@deer.(none) committed
469
        res= &my_null_string;
470 471 472 473
      }
      else
      {
        param->maybe_null= param->null_value= 0;
474 475 476
        if (read_pos >= data_end)
          DBUG_RETURN(1);
        param->set_param_func(param, &read_pos, data_end - read_pos);
477 478 479
        res= param->query_val_str(&str);
      }
    }
480
    if (query.replace(param->pos_in_query+length, 1, *res))
481 482 483 484
      DBUG_RETURN(1);
    
    length+= res->length()-1;
  }
485
  if (alloc_query(thd, (char *)query.ptr(), query.length()+1))
486
    DBUG_RETURN(1);
487

488 489 490
  DBUG_RETURN(0);
}

491

492 493
static bool insert_params(Prepared_statement *stmt, uchar *null_array,
                          uchar *read_pos, uchar *data_end)
494
{
495 496
  Item_param **begin= stmt->param_array;
  Item_param **end= begin + stmt->param_count;
497 498 499

  DBUG_ENTER("insert_params"); 

500
  for (Item_param **it= begin; it < end; ++it)
501
  {
502 503
    Item_param *param= *it;
    if (!param->long_data_supplied)
504
    {
505
      if (is_param_null(null_array, it - begin))
506 507 508 509
        param->maybe_null= param->null_value= 1;
      else
      {
        param->maybe_null= param->null_value= 0;
510 511 512
        if (read_pos >= data_end)
          DBUG_RETURN(1);
        param->set_param_func(param, &read_pos, data_end - read_pos);
513 514 515 516 517 518
      }
    }
  }
  DBUG_RETURN(0);
}

519

520
static bool setup_conversion_functions(Prepared_statement *stmt,
521
                                       uchar **data, uchar *data_end)
522 523 524
{
  /* skip null bits */
  uchar *read_pos= *data + (stmt->param_count+7) / 8;
525

526
  DBUG_ENTER("setup_conversion_functions");
527

venu@myvenu.com's avatar
venu@myvenu.com committed
528
  if (*read_pos++) //types supplied / first execute
529
  {
venu@myvenu.com's avatar
venu@myvenu.com committed
530 531 532 533
    /*
      First execute or types altered by the client, setup the 
      conversion routines for all parameters (one time)
    */
534 535 536 537
    Item_param **it= stmt->param_array;
    Item_param **end= it + stmt->param_count;
    for (; it < end; ++it)
    {
538 539
      if (read_pos >= data_end)
        DBUG_RETURN(1);
540
      setup_one_conversion_function(*it, *read_pos);
venu@myvenu.com's avatar
venu@myvenu.com committed
541
      read_pos+= 2;
542
    }
543 544
  }
  *data= read_pos;
545 546 547
  DBUG_RETURN(0);
}

548 549
#else

550 551 552 553
static bool emb_insert_params(Prepared_statement *stmt)
{
  Item_param **it= stmt->param_array;
  Item_param **end= it + stmt->param_count;
554 555
  MYSQL_BIND *client_param= stmt->thd->client_params;

556
  DBUG_ENTER("emb_insert_params");
557

558 559 560 561
  for (; it < end; ++it, ++client_param)
  {
    Item_param *param= *it;
    setup_one_conversion_function(param, client_param->buffer_type);
562 563 564 565 566 567 568 569
    if (!param->long_data_supplied)
    {
      if (*client_param->is_null)
        param->maybe_null= param->null_value= 1;
      else
      {
	uchar *buff= (uchar*)client_param->buffer;
        param->maybe_null= param->null_value= 0;
570 571 572 573
        param->set_param_func(param, &buff,
                              client_param->length ? 
                              *client_param->length : 
                              client_param->buffer_length);
574 575 576 577 578 579
      }
    }
  }
  DBUG_RETURN(0);
}

580 581 582

static bool emb_insert_params_withlog(Prepared_statement *stmt)
{
583
  THD *thd= stmt->thd;
584 585
  Item_param **it= stmt->param_array;
  Item_param **end= it + stmt->param_count;
586 587 588 589
  MYSQL_BIND *client_param= thd->client_params;

  String str, query;
  const String *res;
590
  uint32 length= 0;
591

592
  DBUG_ENTER("emb_insert_params_withlog");
593 594 595 596

  if (query.copy(stmt->query, stmt->query_length, default_charset_info))
    DBUG_RETURN(1);
  
597 598 599 600
  for (; it < end; ++it, ++client_param)
  {
    Item_param *param= *it;
    setup_one_conversion_function(param, client_param->buffer_type);
601
    if (param->long_data_supplied)
602
      res= param->query_val_str(&str);
603 604 605 606 607 608 609 610 611 612 613
    else
    {
      if (*client_param->is_null)
      {
        param->maybe_null= param->null_value= 1;
        res= &my_null_string;
      }
      else
      {
	uchar *buff= (uchar*)client_param->buffer;
        param->maybe_null= param->null_value= 0;
614 615 616 617
        param->set_param_func(param, &buff,
                              client_param->length ? 
                              *client_param->length : 
                              client_param->buffer_length);
618 619 620 621 622 623 624 625 626 627 628 629 630 631
        res= param->query_val_str(&str);
      }
    }
    if (query.replace(param->pos_in_query+length, 1, *res))
      DBUG_RETURN(1);
    length+= res->length()-1;
  }
  
  if (alloc_query(thd, (char *) query.ptr(), query.length()+1))
    DBUG_RETURN(1);

  DBUG_RETURN(0);
}

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

634
/*
635 636 637 638 639 640 641 642 643
  Validate the following information for INSERT statement: 
    - field existence
    - fields count
  SYNOPSIS
    mysql_test_insert_fields()
  RETURN VALUE
    0   ok
    1   error, sent to the client
   -1   error, not sent to client
644 645
*/

646 647 648 649
static int mysql_test_insert_fields(Prepared_statement *stmt,
                                    TABLE_LIST *table_list,
                                    List<Item> &fields, 
                                    List<List_item> &values_list)
650
{
651
  THD *thd= stmt->thd;
652 653 654
  TABLE *table;
  List_iterator_fast<List_item> its(values_list);
  List_item *values;
655

656 657
  DBUG_ENTER("mysql_test_insert_fields");

hf@deer.(none)'s avatar
hf@deer.(none) committed
658
#ifndef NO_EMBEDDED_ACCESS_CHECKS
659 660
  my_bool update=(stmt->lex->value_list.elements ? UPDATE_ACL : 0);
  ulong privilege= (stmt->lex->duplicates == DUP_REPLACE ?
661 662
                    INSERT_ACL | DELETE_ACL : INSERT_ACL | update);
  if (check_access(thd,privilege,table_list->db,
hf@deer.(none)'s avatar
hf@deer.(none) committed
663
                   &table_list->grant.privilege,0,0) || 
monty@mysql.com's avatar
monty@mysql.com committed
664
      (grant_option && check_grant(thd,privilege,table_list,0,0)))
hf@deer.(none)'s avatar
hf@deer.(none) committed
665
    DBUG_RETURN(1); 
666
#endif
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
667 668 669 670 671

  /* 
     open temporary memory pool for temporary data allocated by derived
     tables & preparation procedure
  */
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
672
  thd->allocate_temporary_memory_pool_for_ps_preparing();
hf@deer.(none)'s avatar
hf@deer.(none) committed
673
  if (open_and_lock_tables(thd, table_list))
674
  {
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
675
    thd->free_temporary_memory_pool_for_ps_preparing();
676
    DBUG_RETURN(-1);
677 678
  }

679
  table= table_list->table;
680 681 682 683

  if ((values= its++))
  {
    uint value_count;
684
    ulong counter= 0;
685 686
    
    if (check_insert_fields(thd,table,fields,*values,1))
687
    {
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
688
      thd->free_temporary_memory_pool_for_ps_preparing();
689
      DBUG_RETURN(-1);
690
    }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
691
    thd->free_temporary_memory_pool_for_ps_preparing();
692 693 694 695

    value_count= values->elements;
    its.rewind();
   
696
    while ((values= its++))
697 698 699 700 701 702
    {
      counter++;
      if (values->elements != value_count)
      {
        my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW,
			ER(ER_WRONG_VALUE_COUNT_ON_ROW),
703
			MYF(0), counter);
704
        DBUG_RETURN(-1);
705 706 707
      }
    }
  }
708 709
  else
  {
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
710
    thd->free_temporary_memory_pool_for_ps_preparing();
711
  }
712 713 714 715 716
  DBUG_RETURN(0);
}


/*
717 718 719 720 721 722 723 724 725
  Validate the following information:
    UPDATE - set and where clause
    DELETE - where clause
  SYNOPSIS
    mysql_test_upd_fields()
  RETURN VALUE
    0   success
    1   error, sent to client
   -1   error, not sent to client
726 727
*/

728 729 730 731
static int mysql_test_upd_fields(Prepared_statement *stmt,
                                 TABLE_LIST *table_list,
                                 List<Item> &fields, List<Item> &values,
                                 COND *conds)
732
{
733
  THD *thd= stmt->thd;
734

735
  DBUG_ENTER("mysql_test_upd_fields");
hf@deer.(none)'s avatar
hf@deer.(none) committed
736
#ifndef NO_EMBEDDED_ACCESS_CHECKS
737
  if (check_access(thd,UPDATE_ACL,table_list->db,
hf@deer.(none)'s avatar
hf@deer.(none) committed
738
                   &table_list->grant.privilege,0,0) || 
monty@mysql.com's avatar
monty@mysql.com committed
739
      (grant_option && check_grant(thd,UPDATE_ACL,table_list,0,0)))
hf@deer.(none)'s avatar
hf@deer.(none) committed
740 741
    DBUG_RETURN(1);
#endif
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
742 743 744 745 746

  /* 
     open temporary memory pool for temporary data allocated by derived
     tables & preparation procedure
  */
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
747
  thd->allocate_temporary_memory_pool_for_ps_preparing();
748

bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
749 750
  if (open_and_lock_tables(thd, table_list))
    goto err;
751
  if (setup_tables(table_list) ||
752 753
      setup_fields(thd, 0, table_list, fields, 1, 0, 0) ||
      setup_conds(thd, table_list, &conds) || thd->net.report_error)
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
754 755 756
    goto err;

  thd->free_temporary_memory_pool_for_ps_preparing();
757

758
  /* TODO: here we should send types of placeholders to the client. */
759
  DBUG_RETURN(0);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
760 761
err:
  thd->free_temporary_memory_pool_for_ps_preparing();
762
  DBUG_RETURN(-1);
763 764 765
}

/*
766
  Validate the following information:
767 768
    SELECT - column list 
           - where clause
769
           - order clause
770 771 772
           - having clause
           - group by clause
           - if no column spec i.e. '*', then setup all fields
773 774 775 776 777 778 779 780
  In case of success, if this query is not EXPLAIN, send column list info
  back to client. 
  SYNOPSIS
    mysql_test_select_fields()
  RETURN VALUE
    0   success
    1   error, sent to client
   -1   error, not sent to client
781
*/
782

783 784 785 786 787 788 789 790 791
static int mysql_test_select_fields(Prepared_statement *stmt,
                                    TABLE_LIST *tables,
                                    uint wild_num,
                                    List<Item> &fields, COND *conds, 
                                    uint og_num, ORDER *order, ORDER *group,
                                    Item *having, ORDER *proc,
                                    ulong select_options, 
                                    SELECT_LEX_UNIT *unit,
                                    SELECT_LEX *select_lex)
792
{
793
  THD *thd= stmt->thd;
794 795
  LEX *lex= stmt->lex;

796 797
  DBUG_ENTER("mysql_test_select_fields");

hf@deer.(none)'s avatar
hf@deer.(none) committed
798
#ifndef NO_EMBEDDED_ACCESS_CHECKS
799 800 801
  ulong privilege= lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL;
  if (tables)
  {
hf@deer.(none)'s avatar
hf@deer.(none) committed
802
    if (check_table_access(thd, privilege, tables,0))
803 804
      DBUG_RETURN(1);
  }
hf@deer.(none)'s avatar
hf@deer.(none) committed
805
  else if (check_access(thd, privilege, "*any*",0,0,0))
806
    DBUG_RETURN(1);
hf@deer.(none)'s avatar
hf@deer.(none) committed
807
#endif
808
  if ((&lex->select_lex != lex->all_selects_list &&
809
       lex->unit.create_total_list(thd, lex, &tables)))
810
   DBUG_RETURN(1);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
811 812 813 814 815

  /* 
     open temporary memory pool for temporary data allocated by derived
     tables & preparation procedure
  */
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
816
  thd->allocate_temporary_memory_pool_for_ps_preparing();
817
  if (open_and_lock_tables(thd, tables))
818 819
  {
    send_error(thd);
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
820
    goto err;
821
  }
822

823
  if (lex->describe)
824
  {
825
    if (send_prep_stmt(stmt, 0))
826
      goto err;
827
  }
828 829
  else 
  {
830
    select_result *result= lex->result;
831 832 833
    if (!result && !(result= new select_send()))
    {
      send_error(thd, ER_OUT_OF_RESOURCES);
834
      goto err;
835
    }
836

837
    thd->used_tables= 0;                        // Updated by setup_fields
838

839
    if (unit->prepare(thd, result, 0))
840 841
    {
      send_error(thd);
842
      goto err_prep;
843
    }
844

845
    if (send_prep_stmt(stmt, fields.elements) ||
846
        thd->protocol_simple.send_fields(&fields, 0)
hf@deer.(none)'s avatar
SCRUM  
hf@deer.(none) committed
847
#ifndef EMBEDDED_LIBRARY
848
        || net_flush(&thd->net)
hf@deer.(none)'s avatar
SCRUM  
hf@deer.(none) committed
849
#endif
850
       )
851 852
      goto err_prep;

853
    unit->cleanup();
854
  }
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
855
  thd->free_temporary_memory_pool_for_ps_preparing();
856 857 858 859 860
  DBUG_RETURN(0);

err_prep:
  unit->cleanup();
err:
bell@sanja.is.com.ua's avatar
bell@sanja.is.com.ua committed
861
  thd->free_temporary_memory_pool_for_ps_preparing();
862
  DBUG_RETURN(1);
863 864
}

865

866
/*
867 868 869 870 871 872 873
  Send the prepare query results back to client
  SYNOPSIS
  send_prepare_results()
    stmt prepared statement
  RETURN VALUE
    0   success
    1   error, sent to client
874 875
*/
                     
876
static int send_prepare_results(Prepared_statement *stmt)
877
{   
878
  THD *thd= stmt->thd;
879
  LEX *lex= stmt->lex;
880 881
  SELECT_LEX *select_lex= &lex->select_lex;
  TABLE_LIST *tables=(TABLE_LIST*) select_lex->table_list.first;
882
  enum enum_sql_command sql_command= lex->sql_command;
883
  int res;
884

885 886
  DBUG_ENTER("send_prepare_results");
  DBUG_PRINT("enter",("command: %d, param_count: %ld",
887
                      sql_command, stmt->param_count));
888
  
889
  switch (sql_command) {
890 891

  case SQLCOM_INSERT:
892 893 894
    if ((res= mysql_test_insert_fields(stmt, tables, lex->field_list,
                                       lex->many_values)))
      goto error;
895 896 897
    break;

  case SQLCOM_UPDATE:
898
    /* XXX: fallthrough */
899
  case SQLCOM_DELETE:
900 901 902
    if ((res= mysql_test_upd_fields(stmt, tables, select_lex->item_list,
                                    lex->value_list, select_lex->where)))
      goto error;
903 904 905
    break;

  case SQLCOM_SELECT:
906 907 908 909 910 911 912 913 914 915 916 917 918 919
    if ((res= mysql_test_select_fields(stmt, tables, select_lex->with_wild,
                                       select_lex->item_list,
                                       select_lex->where,
                                       select_lex->order_list.elements +
                                       select_lex->group_list.elements,
                                       (ORDER*) select_lex->order_list.first,
                                       (ORDER*) select_lex->group_list.first, 
                                       select_lex->having,
                                       (ORDER*)lex->proc_list.first,
                                       select_lex->options | thd->options,
                                       &(lex->unit), select_lex)))
      goto error;
    /* Statement and field info has already been sent */
    DBUG_RETURN(0);
920 921

  default:
922 923 924 925 926
    /* 
      Rest fall through to default category, no parsing 
      for non-DML statements 
    */
    break;
927
  }
928
  DBUG_RETURN(send_prep_stmt(stmt, 0));
929

930 931 932
error:
  if (res < 0)
    send_error(thd, thd->killed ? ER_SERVER_SHUTDOWN : 0);
933
  DBUG_RETURN(1);
934 935
}

venu@myvenu.com's avatar
venu@myvenu.com committed
936
/*
937 938 939
  Initialize array of parametes in statement from LEX.
  (We need to have quick access to items by number in mysql_send_longdata).
  This is to avoid using malloc/realloc in the parser.
venu@myvenu.com's avatar
venu@myvenu.com committed
940
*/
941

942
static bool init_param_array(Prepared_statement *stmt)
venu@myvenu.com's avatar
venu@myvenu.com committed
943
{
944 945 946 947 948 949 950 951 952 953 954 955
  LEX *lex= stmt->lex;
  if ((stmt->param_count= lex->param_list.elements))
  {
    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 **)
                       alloc_root(&stmt->thd->mem_root,
                                  sizeof(Item_param*) * stmt->param_count);
    if (!stmt->param_array)
    {
      send_error(stmt->thd, ER_OUT_OF_RESOURCES);
956
      return 1;
957 958 959 960 961 962 963 964
    }
    for (to= stmt->param_array;
         to < stmt->param_array + stmt->param_count;
         ++to)
    {
      *to= param_iterator++;
    }
  }
965
  return 0;
venu@myvenu.com's avatar
venu@myvenu.com committed
966
}
967

968

969 970 971
/*
  Parse the query and send the total number of parameters 
  and resultset metadata information back to client (if any), 
972
  without executing the query i.e. without any log/disk 
973
  writes. This will allow the queries to be re-executed 
974 975 976 977 978 979 980
  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.
981 982
*/

983
void mysql_stmt_prepare(THD *thd, char *packet, uint packet_length)
984
{
985 986
  LEX *lex;
  Prepared_statement *stmt= new Prepared_statement(thd);
987
  int error;
988
  DBUG_ENTER("mysql_stmt_prepare");
989

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

992
  if (stmt == 0)
993 994 995 996
  {
    send_error(thd, ER_OUT_OF_RESOURCES);
    DBUG_VOID_RETURN;
  }
997 998

  if (thd->stmt_map.insert(stmt))
999 1000 1001 1002 1003
  {
    delete stmt;
    send_error(thd, ER_OUT_OF_RESOURCES);
    DBUG_VOID_RETURN;
  }
1004

1005
  thd->stmt_backup.set_statement(thd);
1006
  thd->stmt_backup.set_item_arena(thd);
1007
  thd->set_statement(stmt);
1008
  thd->set_item_arena(stmt);
1009

1010
  if (alloc_query(thd, packet, packet_length))
1011 1012 1013 1014 1015 1016 1017 1018 1019 1020
  {
    stmt->set_statement(thd);
    stmt->set_item_arena(thd);
    thd->set_statement(&thd->stmt_backup);
    thd->set_item_arena(&thd->stmt_backup);
    /* Statement map deletes statement on erase */
    thd->stmt_map.erase(stmt);
    send_error(thd, ER_OUT_OF_RESOURCES);
    DBUG_VOID_RETURN;
  }
1021

1022
  mysql_log.write(thd, COM_PREPARE, "%s", packet);
1023

1024
  thd->current_statement= stmt;
1025 1026 1027 1028
  lex= lex_start(thd, (uchar *) thd->query, thd->query_length);
  mysql_init_query(thd);
  lex->safe_to_cache_query= 0;

1029 1030 1031
  error= yyparse((void *)thd) || thd->is_fatal_error ||
         init_param_array(stmt) ||
         send_prepare_results(stmt);
1032

1033
  /* restore to WAIT_PRIOR: QUERY_PRIOR is set inside alloc_query */
1034
  if (!(specialflag & SPECIAL_NO_PRIOR))
venu@myvenu.com's avatar
venu@myvenu.com committed
1035
    my_pthread_setprio(pthread_self(),WAIT_PRIOR);
1036 1037
  lex_end(lex);
  stmt->set_statement(thd);
1038
  stmt->set_item_arena(thd);
1039
  thd->set_statement(&thd->stmt_backup);
1040
  thd->set_item_arena(&thd->stmt_backup);
1041
  thd->current_statement= 0;
1042

1043
  if (error)
1044
  {
1045 1046 1047
    /* Statement map deletes statement on erase */
    thd->stmt_map.erase(stmt);
    /* error is sent inside yyparse/send_prepare_results */
1048
  }
1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062
  else
  {
    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;
    }
  }
  DBUG_VOID_RETURN;
}
1063

1064
/* Reinit statement before execution */
1065

1066 1067 1068 1069
static void reset_stmt_for_execute(Prepared_statement *stmt)
{
  THD *thd= stmt->thd;
  SELECT_LEX *sl= stmt->lex->all_selects_list;
1070

1071
  for (; sl; sl= sl->next_select_in_list())
1072
  {
1073 1074 1075
    /*
      Copy WHERE clause pointers to avoid damaging they by optimisation
    */
1076 1077
    if (sl->prep_where)
      sl->where= sl->prep_where->copy_andor_structure(thd);
1078
    DBUG_ASSERT(sl->join == 0);
hf@deer.(none)'s avatar
hf@deer.(none) committed
1079
    ORDER *order;
1080
    /* Fix GROUP list */
1081 1082
    for (order= (ORDER *)sl->group_list.first; order; order= order->next)
      order->item= &order->item_ptr;
1083
    /* Fix ORDER list */
1084 1085
    for (order= (ORDER *)sl->order_list.first; order; order= order->next)
      order->item= &order->item_ptr;
1086 1087 1088 1089 1090 1091 1092 1093 1094 1095

    /*
      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= (TABLE_LIST*) sl->table_list.first;
	 tables;
	 tables= tables->next)
    {
konstantin@oak.local's avatar
konstantin@oak.local committed
1096 1097 1098 1099 1100
      /*
        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;
1101 1102
      tables->table_list= 0;
    }
1103 1104 1105 1106 1107
    
    {
      SELECT_LEX_UNIT *unit= sl->master_unit();
      unit->unclean();
      unit->types.empty();
1108
      /* for derived tables & PS (which can't be reset by Item_subquery) */
1109 1110
      unit->reinit_exec_mechanism();
    }
1111
  }
1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122
}

/*
  Executes previously prepared query.
  If there is any parameters, then replace markers with the data supplied
  from client, and then execute the query.
  SYNOPSYS
    mysql_stmt_execute()
*/


1123
void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
1124 1125
{
  ulong stmt_id= uint4korr(packet);
1126
  uchar *packet_end= (uchar *) packet + packet_length - 1;
1127 1128 1129
  Prepared_statement *stmt;

  DBUG_ENTER("mysql_stmt_execute");
1130 1131

  packet+= 9;                               /* stmt_id + 5 bytes of flags */
1132 1133 1134 1135
  
  if (!(stmt= find_prepared_statement(thd, stmt_id, "execute", SEND_ERROR)))
    DBUG_VOID_RETURN;

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

1138 1139 1140 1141 1142 1143 1144 1145 1146
  /* Check if we got an error when sending long data */
  if (stmt->get_longdata_error)
  {
    send_error(thd, stmt->last_errno, stmt->last_error);
    DBUG_VOID_RETURN;
  }

  thd->stmt_backup.set_statement(thd);
  thd->set_statement(stmt);
1147

1148
  reset_stmt_for_execute(stmt);
1149

hf@deer.(none)'s avatar
hf@deer.(none) committed
1150
#ifndef EMBEDDED_LIBRARY
1151 1152 1153
  if (stmt->param_count)
  {
    uchar *null_array= (uchar *) packet;
1154 1155
    if (setup_conversion_functions(stmt, (uchar **) &packet, packet_end) ||
        stmt->set_params(stmt, null_array, (uchar *) packet, packet_end)) 
1156 1157
      goto set_params_data_err;
  }
hf@deer.(none)'s avatar
hf@deer.(none) committed
1158
#else
1159 1160 1161 1162 1163 1164 1165
  /*
    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.
  */
  if (stmt->param_count && stmt->set_params_data(stmt))
    goto set_params_data_err;
hf@deer.(none)'s avatar
hf@deer.(none) committed
1166
#endif
1167

1168
  if (!(specialflag & SPECIAL_NO_PRIOR))
1169
    my_pthread_setprio(pthread_self(),QUERY_PRIOR);
1170
 
1171 1172
  /*
    TODO:
1173 1174 1175
    Also, have checks on basic executions such as mysql_insert(), 
    mysql_delete(), mysql_update() and mysql_select() to not to 
    have re-check on setup_* and other things ..
1176 1177
  */
  thd->protocol= &thd->protocol_prep;           // Switch to binary protocol
1178
  mysql_execute_command(thd);
1179
  thd->protocol= &thd->protocol_simple;         // Use normal protocol
venu@myvenu.com's avatar
venu@myvenu.com committed
1180

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

hf@deer.(none)'s avatar
hf@deer.(none) committed
1184
  cleanup_items(stmt->free_list);
1185
  close_thread_tables(thd); // to close derived tables
1186
  thd->set_statement(&thd->stmt_backup);
1187 1188 1189 1190 1191 1192
  DBUG_VOID_RETURN;

set_params_data_err:
  thd->set_statement(&thd->stmt_backup);
  my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_execute");
  send_error(thd);
1193 1194 1195
  DBUG_VOID_RETURN;
}

1196

1197
/*
1198 1199
    Reset a prepared statement, in case there was an error in send_longdata.
    Note: we don't send any reply to that command.
1200 1201 1202
  SYNOPSIS
    mysql_stmt_reset()
    thd		Thread handle
1203
    packet	Packet with stmt id 
1204 1205 1206

  DESCRIPTION
    This function is useful when one gets an error after calling
1207
    mysql_stmt_getlongdata() and wants to reset the handle
1208
    so that one can call execute again.
1209
    See also bug #1664
1210 1211
*/

1212
void mysql_stmt_reset(THD *thd, char *packet)
1213
{
1214
  /* There is always space for 4 bytes in buffer */
1215
  ulong stmt_id= uint4korr(packet);
1216 1217
  Prepared_statement *stmt;
  
1218
  DBUG_ENTER("mysql_stmt_reset");
1219

1220
  if (!(stmt= find_prepared_statement(thd, stmt_id, "reset", DONT_SEND_ERROR)))
1221 1222
    DBUG_VOID_RETURN;

1223
  stmt->get_longdata_error= 0;
1224 1225 1226 1227

  /* Free long data if used */
  if (stmt->long_data_used)
  {
1228 1229
    Item_param **item= stmt->param_array;
    Item_param **end= item + stmt->param_count;
1230 1231
    stmt->long_data_used= 0;
    for (; item < end ; item++)
1232
      (**item).reset();
1233 1234 1235 1236 1237 1238
  }
  DBUG_VOID_RETURN;
}


/*
1239 1240
  Delete a prepared statement from memory.
  Note: we don't send any reply to that command. 
1241 1242
*/

1243
void mysql_stmt_free(THD *thd, char *packet)
1244
{
1245
  /* There is always space for 4 bytes in packet buffer */
1246
  ulong stmt_id= uint4korr(packet);
1247 1248
  Prepared_statement *stmt;

1249
  DBUG_ENTER("mysql_stmt_free");
1250

1251
  if (!(stmt= find_prepared_statement(thd, stmt_id, "close", DONT_SEND_ERROR)))
1252
    DBUG_VOID_RETURN;
1253 1254 1255

  /* Statement map deletes statement on erase */
  thd->stmt_map.erase(stmt);
1256 1257 1258
  DBUG_VOID_RETURN;
}

1259 1260

/*
1261
  Long data in pieces from client
1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280

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

void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length)
{
1281 1282
  Prepared_statement *stmt;
  
1283 1284
  DBUG_ENTER("mysql_stmt_get_longdata");

hf@deer.(none)'s avatar
hf@deer.(none) committed
1285
#ifndef EMBEDDED_LIBRARY
1286
  /* The following should never happen */
venu@myvenu.com's avatar
venu@myvenu.com committed
1287
  if (packet_length < MYSQL_LONG_DATA_HEADER+1)
1288 1289 1290 1291
  {
    my_error(ER_WRONG_ARGUMENTS, MYF(0), "get_longdata");
    DBUG_VOID_RETURN;
  }
hf@deer.(none)'s avatar
hf@deer.(none) committed
1292
#endif
1293 1294 1295 1296

  ulong stmt_id=     uint4korr(pos);
  uint param_number= uint2korr(pos+4);

1297 1298
  if (!(stmt=find_prepared_statement(thd, stmt_id, "get_longdata",
                                     DONT_SEND_ERROR)))
1299 1300
    DBUG_VOID_RETURN;

hf@deer.(none)'s avatar
hf@deer.(none) committed
1301
#ifndef EMBEDDED_LIBRARY
1302 1303
  if (param_number >= stmt->param_count)
  {
venu@myvenu.com's avatar
venu@myvenu.com committed
1304
    /* Error will be sent in execute call */
1305
    stmt->get_longdata_error= 1;
venu@myvenu.com's avatar
venu@myvenu.com committed
1306
    stmt->last_errno= ER_WRONG_ARGUMENTS;
1307 1308 1309
    sprintf(stmt->last_error, ER(ER_WRONG_ARGUMENTS), "get_longdata");
    DBUG_VOID_RETURN;
  }
hf@deer.(none)'s avatar
hf@deer.(none) committed
1310 1311 1312
  pos+= MYSQL_LONG_DATA_HEADER;	// Point to data
#endif

1313
  Item_param *param= stmt->param_array[param_number];
hf@deer.(none)'s avatar
hf@deer.(none) committed
1314
#ifndef EMBEDDED_LIBRARY
venu@myvenu.com's avatar
venu@myvenu.com committed
1315
  param->set_longdata(pos, packet_length-MYSQL_LONG_DATA_HEADER-1);
hf@deer.(none)'s avatar
hf@deer.(none) committed
1316 1317 1318
#else
  param->set_longdata(thd->extra_data, thd->extra_length);
#endif
1319 1320 1321
  stmt->long_data_used= 1;
  DBUG_VOID_RETURN;
}
venu@myvenu.com's avatar
venu@myvenu.com committed
1322

1323 1324 1325 1326

Prepared_statement::Prepared_statement(THD *thd_arg)
  :Statement(thd_arg),
  thd(thd_arg),
1327
  param_array(0),
1328 1329
  param_count(0),
  last_errno(0),
1330
  get_longdata_error(0),
1331 1332 1333 1334 1335 1336 1337 1338
  long_data_used(0),
  log_full_query(0)
{
  *last_error= '\0';
  if (mysql_bin_log.is_open())
  {
    log_full_query= 1;
#ifndef EMBEDDED_LIBRARY
1339
    set_params= insert_params_withlog;
1340
#else
1341
    set_params_data= emb_insert_params_withlog;
1342 1343 1344 1345
#endif
  }
  else
#ifndef EMBEDDED_LIBRARY
1346
    set_params= insert_params;
1347
#else
1348
    set_params_data= emb_insert_params;
1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363
#endif
}


Prepared_statement::~Prepared_statement()
{
  free_items(free_list);
}


Statement::Type Prepared_statement::type() const
{
  return PREPARED_STATEMENT;
}