lib_sql.cc 28.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13
/*
 * Copyright (c)  2000
 * SWsoft  company
 *
 * This material is provided "as is", with absolutely no warranty expressed
 * or implied. Any use is at your own risk.
 *
 * Permission to use or copy this software for any purpose is hereby granted 
 * without fee, provided the above notices are retained on all copies.
 * Permission to modify the code and to distribute modified code is granted,
 * provided the above notices are retained, and a notice that the code was
 * modified is included with the above copyright notice.
 *
unknown's avatar
unknown committed
14 15 16

  This code was modified by the MySQL team
*/
17

18 19 20 21
/*
  The following is needed to not cause conflicts when we include mysqld.cc
*/

22 23 24 25
#define main main1
#define mysql_unix_port mysql_inix_port1
#define mysql_port mysql_port1

26 27
extern "C"
{
unknown's avatar
unknown committed
28
  extern unsigned long max_allowed_packet, net_buffer_length;
29 30
}

31
#include "../sql/mysqld.cc"
32

unknown's avatar
unknown committed
33
C_MODE_START
unknown's avatar
unknown committed
34

35
#include <mysql.h>
unknown's avatar
unknown committed
36
#undef ER
37
#include "errmsg.h"
unknown's avatar
SCRUM  
unknown committed
38
#include <sql_common.h>
39
#include "embedded_priv.h"
unknown's avatar
unknown committed
40

41 42
extern unsigned int mysql_server_last_errno;
extern char mysql_server_last_error[MYSQL_ERRMSG_SIZE];
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
static my_bool emb_read_query_result(MYSQL *mysql);


/*
  Reads error information from the MYSQL_DATA and puts
  it into proper MYSQL members

  SYNOPSIS
    embedded_get_error()
    mysql        connection handler
    data         query result

  NOTES
    after that function error information will be accessible
       with usual functions like mysql_error()
    data is my_free-d in this function
    most of the data is stored in data->embedded_info structure
*/

void embedded_get_error(MYSQL *mysql, MYSQL_DATA *data)
{
  NET *net= &mysql->net;
  struct embedded_query_result *ei= data->embedded_info;
unknown's avatar
unknown committed
66 67
  net->last_errno= ei->last_errno;
  strmake(net->last_error, ei->info, sizeof(net->last_error)-1);
68
  memcpy(net->sqlstate, ei->sqlstate, sizeof(net->sqlstate));
69
  mysql->server_status= ei->server_status;
70
  my_free(data, MYF(0));
71 72
}

unknown's avatar
unknown committed
73
static my_bool
unknown's avatar
SCRUM  
unknown committed
74
emb_advanced_command(MYSQL *mysql, enum enum_server_command command,
75 76
		     const uchar *header, ulong header_length,
		     const uchar *arg, ulong arg_length, my_bool skip_check,
77
                     MYSQL_STMT *stmt)
78
{
79
  my_bool result= 1;
80
  THD *thd=(THD *) mysql->thd;
unknown's avatar
unknown committed
81
  NET *net= &mysql->net;
82 83 84 85 86 87 88 89 90
  my_bool stmt_skip= stmt ? stmt->state != MYSQL_STMT_INIT_DONE : FALSE;

  if (!thd)
  {
    /* Do "reconnect" if possible */
    if (mysql_reconnect(mysql) || stmt_skip)
      return 1;
    thd= (THD *) mysql->thd;
  }
91

92 93 94 95
#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
  thd->profiling.start_new_query();
#endif

96
  thd->clear_data_list();
97 98 99
  /* Check that we are calling the client functions in right order */
  if (mysql->status != MYSQL_STATUS_READY)
  {
100
    set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
101 102 103 104
    return 1;
  }

  /* Clear result variables */
unknown's avatar
unknown committed
105
  thd->clear_error();
106
  thd->main_da.reset_diagnostics_area();
107
  mysql->affected_rows= ~(my_ulonglong) 0;
unknown's avatar
SCRUM  
unknown committed
108
  mysql->field_count= 0;
109
  net_clear_error(net);
110
  thd->current_stmt= stmt;
111

112
  thd->store_globals();				// Fix if more than one connect
113
  lex_start(thd);
unknown's avatar
unknown committed
114 115 116 117 118 119
  /* 
     We have to call free_old_query before we start to fill mysql->fields 
     for new query. In the case of embedded server we collect field data
     during query execution (not during data retrieval as it is in remote
     client). So we have to call free_old_query here
  */
unknown's avatar
SCRUM  
unknown committed
120
  free_old_query(mysql);
unknown's avatar
unknown committed
121 122 123 124

  thd->extra_length= arg_length;
  thd->extra_data= (char *)arg;
  if (header)
unknown's avatar
SCRUM  
unknown committed
125 126 127 128 129
  {
    arg= header;
    arg_length= header_length;
  }

130
  result= dispatch_command(command, thd, (char *) arg, arg_length);
131
  thd->cur_data= 0;
unknown's avatar
unknown committed
132

unknown's avatar
SCRUM  
unknown committed
133
  if (!skip_check)
134
    result= thd->is_error() ? -1 : 0;
135

136 137 138
#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
  thd->profiling.finish_current_query();
#endif
139
  return result;
140 141
}

142 143
static void emb_flush_use_result(MYSQL *mysql)
{
144 145
  THD *thd= (THD*) mysql->thd;
  if (thd->cur_data)
146
  {
147 148 149 150 151 152 153
    free_rows(thd->cur_data);
    thd->cur_data= 0;
  }
  else if (thd->first_data)
  {
    MYSQL_DATA *data= thd->first_data;
    thd->first_data= data->embedded_info->next;
154 155 156 157
    free_rows(data);
  }
}

158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173

/*
  reads dataset from the next query result

  SYNOPSIS
  emb_read_rows()
  mysql		connection handle
  other parameters are not used

  NOTES
    It just gets next MYSQL_DATA from the result's queue

  RETURN
    pointer to MYSQL_DATA with the coming recordset
*/

unknown's avatar
unknown committed
174
static MYSQL_DATA *
unknown's avatar
SCRUM  
unknown committed
175
emb_read_rows(MYSQL *mysql, MYSQL_FIELD *mysql_fields __attribute__((unused)),
unknown's avatar
SCRUM  
unknown committed
176
	      unsigned int fields __attribute__((unused)))
unknown's avatar
SCRUM  
unknown committed
177
{
178 179 180
  MYSQL_DATA *result= ((THD*)mysql->thd)->cur_data;
  ((THD*)mysql->thd)->cur_data= 0;
  if (result->embedded_info->last_errno)
unknown's avatar
SCRUM  
unknown committed
181
  {
182 183 184 185
    embedded_get_error(mysql, result);
    return NULL;
  }
  *result->embedded_info->prev_ptr= NULL;
unknown's avatar
SCRUM  
unknown committed
186 187 188
  return result;
}

189

unknown's avatar
unknown committed
190
static MYSQL_FIELD *emb_list_fields(MYSQL *mysql)
unknown's avatar
SCRUM  
unknown committed
191
{
192 193 194 195 196 197
  MYSQL_DATA *res;
  if (emb_read_query_result(mysql))
    return 0;
  res= ((THD*) mysql->thd)->cur_data;
  ((THD*) mysql->thd)->cur_data= 0;
  mysql->field_alloc= res->alloc;
198
  my_free(res,MYF(0));
199
  mysql->status= MYSQL_STATUS_READY;
unknown's avatar
SCRUM  
unknown committed
200 201 202
  return mysql->fields;
}

unknown's avatar
unknown committed
203
static my_bool emb_read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt)
unknown's avatar
SCRUM  
unknown committed
204
{
205 206 207
  THD *thd= (THD*) mysql->thd;
  MYSQL_DATA *res;

unknown's avatar
SCRUM  
unknown committed
208 209
  stmt->stmt_id= thd->client_stmt_id;
  stmt->param_count= thd->client_param_count;
210
  stmt->field_count= 0;
211
  mysql->warning_count= thd->total_warn_count;
unknown's avatar
SCRUM  
unknown committed
212

213
  if (thd->first_data)
unknown's avatar
SCRUM  
unknown committed
214
  {
215 216 217 218 219 220
    if (emb_read_query_result(mysql))
      return 1;
    stmt->field_count= mysql->field_count;
    mysql->status= MYSQL_STATUS_READY;
    res= thd->cur_data;
    thd->cur_data= NULL;
unknown's avatar
SCRUM  
unknown committed
221 222 223 224
    if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT))
      mysql->server_status|= SERVER_STATUS_IN_TRANS;

    stmt->fields= mysql->fields;
225
    stmt->mem_root= res->alloc;
unknown's avatar
SCRUM  
unknown committed
226
    mysql->fields= NULL;
227
    my_free(res,MYF(0));
unknown's avatar
SCRUM  
unknown committed
228
  }
unknown's avatar
SCRUM  
unknown committed
229

unknown's avatar
SCRUM  
unknown committed
230 231 232 233 234 235 236 237 238
  return 0;
}

/**************************************************************************
  Get column lengths of the current row
  If one uses mysql_use_result, res->lengths contains the length information,
  else the lengths are calculated from the offset between pointers.
**************************************************************************/

unknown's avatar
unknown committed
239 240
static void emb_fetch_lengths(ulong *to, MYSQL_ROW column,
			      unsigned int field_count)
unknown's avatar
SCRUM  
unknown committed
241 242 243 244 245 246 247
{ 
  MYSQL_ROW end;

  for (end=column + field_count; column != end ; column++,to++)
    *to= *column ? *(uint *)((*column) - sizeof(uint)) : 0;
}

248
static my_bool emb_read_query_result(MYSQL *mysql)
unknown's avatar
SCRUM  
unknown committed
249
{
250 251 252 253 254 255 256 257 258 259 260 261 262 263
  THD *thd= (THD*) mysql->thd;
  MYSQL_DATA *res= thd->first_data;
  DBUG_ASSERT(!thd->cur_data);
  thd->first_data= res->embedded_info->next;
  if (res->embedded_info->last_errno &&
      !res->embedded_info->fields_list)
  {
    embedded_get_error(mysql, res);
    return 1;
  }

  mysql->warning_count= res->embedded_info->warning_count;
  mysql->server_status= res->embedded_info->server_status;
  mysql->field_count= res->fields;
264 265 266 267 268
  if (!(mysql->fields= res->embedded_info->fields_list))
  {
    mysql->affected_rows= res->embedded_info->affected_rows;
    mysql->insert_id= res->embedded_info->insert_id;
  }
269
  net_clear_error(&mysql->net);
270 271 272 273 274 275 276
  mysql->info= 0;

  if (res->embedded_info->info[0])
  {
    strmake(mysql->info_buffer, res->embedded_info->info, MYSQL_ERRMSG_SIZE-1);
    mysql->info= mysql->info_buffer;
  }
unknown's avatar
SCRUM  
unknown committed
277

278 279
  if (res->embedded_info->fields_list)
  {
unknown's avatar
SCRUM  
unknown committed
280
    mysql->status=MYSQL_STATUS_GET_RESULT;
281 282 283
    thd->cur_data= res;
  }
  else
284
    my_free(res, MYF(0));
unknown's avatar
SCRUM  
unknown committed
285 286 287 288

  return 0;
}

unknown's avatar
unknown committed
289
static int emb_stmt_execute(MYSQL_STMT *stmt)
unknown's avatar
SCRUM  
unknown committed
290 291
{
  DBUG_ENTER("emb_stmt_execute");
292
  uchar header[5];
293
  THD *thd;
294
  my_bool res;
295

296
  int4store(header, stmt->stmt_id);
297
  header[4]= (uchar) stmt->flags;
298
  thd= (THD*)stmt->mysql->thd;
unknown's avatar
SCRUM  
unknown committed
299
  thd->client_param_count= stmt->param_count;
unknown's avatar
unknown committed
300
  thd->client_params= stmt->params;
301

302
  res= test(emb_advanced_command(stmt->mysql, COM_STMT_EXECUTE, 0, 0,
303
                                 header, sizeof(header), 1, stmt) ||
304
            emb_read_query_result(stmt->mysql));
305 306
  stmt->affected_rows= stmt->mysql->affected_rows;
  stmt->insert_id= stmt->mysql->insert_id;
307
  stmt->server_status= stmt->mysql->server_status;
308
  if (res)
unknown's avatar
SCRUM  
unknown committed
309 310
  {
    NET *net= &stmt->mysql->net;
311
    set_stmt_errmsg(stmt, net);
unknown's avatar
SCRUM  
unknown committed
312 313 314 315 316
    DBUG_RETURN(1);
  }
  DBUG_RETURN(0);
}

317
int emb_read_binary_rows(MYSQL_STMT *stmt)
unknown's avatar
unknown committed
318
{
319 320
  MYSQL_DATA *data;
  if (!(data= emb_read_rows(stmt->mysql, 0, 0)))
unknown's avatar
unknown committed
321
  {
322
    set_stmt_errmsg(stmt, &stmt->mysql->net);
323
    return 1;
unknown's avatar
unknown committed
324
  }
325 326
  stmt->result= *data;
  my_free((char *) data, MYF(0));
327
  set_stmt_errmsg(stmt, &stmt->mysql->net);
328
  return 0;
unknown's avatar
unknown committed
329 330
}

331 332 333 334 335 336 337 338 339 340
int emb_read_rows_from_cursor(MYSQL_STMT *stmt)
{
  MYSQL *mysql= stmt->mysql;
  THD *thd= (THD*) mysql->thd;
  MYSQL_DATA *res= thd->first_data;
  DBUG_ASSERT(!thd->first_data->embedded_info->next);
  thd->first_data= 0;
  if (res->embedded_info->last_errno)
  {
    embedded_get_error(mysql, res);
341
    set_stmt_errmsg(stmt, &mysql->net);
342 343 344 345 346 347
    return 1;
  }

  thd->cur_data= res;
  mysql->warning_count= res->embedded_info->warning_count;
  mysql->server_status= res->embedded_info->server_status;
348
  net_clear_error(&mysql->net);
349 350 351 352

  return emb_read_binary_rows(stmt);
}

unknown's avatar
unknown committed
353
int emb_unbuffered_fetch(MYSQL *mysql, char **row)
unknown's avatar
SCRUM  
unknown committed
354
{
355 356 357 358 359 360 361 362
  THD *thd= (THD*) mysql->thd;
  MYSQL_DATA *data= thd->cur_data;
  if (data && data->embedded_info->last_errno)
  {
    embedded_get_error(mysql, data);
    thd->cur_data= 0;
    return 1;
  }
unknown's avatar
SCRUM  
unknown committed
363 364 365 366 367
  if (!data || !data->data)
  {
    *row= NULL;
    if (data)
    {
368 369
      thd->cur_data= thd->first_data;
      thd->first_data= data->embedded_info->next;
unknown's avatar
SCRUM  
unknown committed
370 371 372 373 374 375 376 377 378 379 380
      free_rows(data);
    }
  }
  else
  {
    *row= (char *)data->data->data;
    data->data= data->data->next;
  }
  return 0;
}

unknown's avatar
unknown committed
381
static void emb_free_embedded_thd(MYSQL *mysql)
unknown's avatar
SCRUM  
unknown committed
382 383
{
  THD *thd= (THD*)mysql->thd;
384
  thd->clear_data_list();
unknown's avatar
unknown committed
385
  thread_count--;
386
  thd->store_globals();
unknown's avatar
SCRUM  
unknown committed
387
  delete thd;
388
  mysql->thd=0;
unknown's avatar
SCRUM  
unknown committed
389 390
}

unknown's avatar
unknown committed
391
static const char * emb_read_statistics(MYSQL *mysql)
unknown's avatar
unknown committed
392 393
{
  THD *thd= (THD*)mysql->thd;
394
  return thd->is_error() ? thd->main_da.message() : "";
unknown's avatar
unknown committed
395 396
}

unknown's avatar
unknown committed
397

398
static MYSQL_RES * emb_store_result(MYSQL *mysql)
unknown's avatar
unknown committed
399 400 401 402
{
  return mysql_store_result(mysql);
}

403 404 405 406 407 408 409
int emb_read_change_user_result(MYSQL *mysql, 
				char *buff __attribute__((unused)),
				const char *passwd __attribute__((unused)))
{
  return mysql_errno(mysql);
}

unknown's avatar
SCRUM  
unknown committed
410 411
MYSQL_METHODS embedded_methods= 
{
412
  emb_read_query_result,
unknown's avatar
SCRUM  
unknown committed
413 414
  emb_advanced_command,
  emb_read_rows,
415
  emb_store_result,
unknown's avatar
SCRUM  
unknown committed
416
  emb_fetch_lengths, 
417
  emb_flush_use_result,
unknown's avatar
SCRUM  
unknown committed
418
  emb_list_fields,
unknown's avatar
SCRUM  
unknown committed
419
  emb_read_prepare_result,
unknown's avatar
unknown committed
420
  emb_stmt_execute,
unknown's avatar
SCRUM  
unknown committed
421
  emb_read_binary_rows,
unknown's avatar
SCRUM  
unknown committed
422
  emb_unbuffered_fetch,
unknown's avatar
unknown committed
423
  emb_free_embedded_thd,
unknown's avatar
unknown committed
424
  emb_read_statistics,
425 426 427
  emb_read_query_result,
  emb_read_change_user_result,
  emb_read_rows_from_cursor
unknown's avatar
SCRUM  
unknown committed
428 429
};

430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455
/*
  Make a copy of array and the strings array points to
*/

char **copy_arguments(int argc, char **argv)
{
  uint length= 0;
  char **from, **res, **end= argv+argc;

  for (from=argv ; from != end ; from++)
    length+= strlen(*from);

  if ((res= (char**) my_malloc(sizeof(argv)*(argc+1)+length+argc,
			       MYF(MY_WME))))
  {
    char **to= res, *to_str= (char*) (res+argc+1);
    for (from=argv ; from != end ;)
    {
      *to++= to_str;
      to_str= strmov(to_str, *from++)+1;
    }
    *to= 0;					// Last ptr should be null
  }
  return res;
}

unknown's avatar
unknown committed
456
char **		copy_arguments_ptr= 0;
unknown's avatar
unknown committed
457

458
int init_embedded_server(int argc, char **argv, char **groups)
unknown's avatar
unknown committed
459
{
unknown's avatar
unknown committed
460 461 462 463
  /*
    This mess is to allow people to call the init function without
    having to mess with a fake argv
   */
unknown's avatar
unknown committed
464 465 466 467 468
  int *argcp;
  char ***argvp;
  int fake_argc = 1;
  char *fake_argv[] = { (char *)"", 0 };
  const char *fake_groups[] = { "server", "embedded", 0 };
469
  my_bool acl_error;
unknown's avatar
unknown committed
470 471
  if (argc)
  {
unknown's avatar
unknown committed
472 473
    argcp= &argc;
    argvp= (char***) &argv;
unknown's avatar
unknown committed
474 475 476
  }
  else
  {
unknown's avatar
unknown committed
477 478
    argcp= &fake_argc;
    argvp= (char ***) &fake_argv;
unknown's avatar
unknown committed
479 480
  }
  if (!groups)
unknown's avatar
unknown committed
481
    groups= (char**) fake_groups;
unknown's avatar
unknown committed
482

483
  my_progname= (char *)"mysql_embedded";
unknown's avatar
unknown committed
484

485 486 487 488 489 490
  /*
    Perform basic logger initialization logger. Should be called after
    MY_INIT, as it initializes mutexes. Log tables are inited later.
  */
  logger.init_base();

unknown's avatar
unknown committed
491
  if (init_common_variables("my", *argcp, *argvp, (const char **)groups))
unknown's avatar
unknown committed
492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516
  {
    mysql_server_end();
    return 1;
  }
    
  /* Get default temporary directory */
  opt_mysql_tmpdir=getenv("TMPDIR");	/* Use this if possible */
#if defined( __WIN__) || defined(OS2)
  if (!opt_mysql_tmpdir)
    opt_mysql_tmpdir=getenv("TEMP");
  if (!opt_mysql_tmpdir)
    opt_mysql_tmpdir=getenv("TMP");
#endif
  if (!opt_mysql_tmpdir || !opt_mysql_tmpdir[0])
    opt_mysql_tmpdir=(char*) P_tmpdir;		/* purecov: inspected */

  umask(((~my_umask) & 0666));
  if (init_server_components())
  {
    mysql_server_end();
    return 1;
  }

  error_handler_hook = my_message_sql;

517
  acl_error= 0;
unknown's avatar
unknown committed
518
#ifndef NO_EMBEDDED_ACCESS_CHECKS
519
  if (!(acl_error= acl_init(opt_noacl)) &&
520
      !opt_noacl)
521
    (void) grant_init();
522 523
#endif
  if (acl_error || my_tz_init((THD *)0, default_tz_name, opt_bootstrap))
unknown's avatar
unknown committed
524 525 526 527
  {
    mysql_server_end();
    return 1;
  }
unknown's avatar
unknown committed
528

unknown's avatar
unknown committed
529 530 531 532
  init_max_user_conn();
  init_update_queries();

#ifdef HAVE_DLOPEN
unknown's avatar
unknown committed
533
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
534
  if (!opt_noacl)
unknown's avatar
unknown committed
535
#endif
unknown's avatar
unknown committed
536 537 538 539 540
    udf_init();
#endif

  (void) thr_setconcurrency(concurrency);	// 10 by default

unknown's avatar
unknown committed
541
  if (flush_time && flush_time != ~(ulong) 0L)
unknown's avatar
unknown committed
542 543 544 545 546 547
  {
    pthread_t hThread;
    if (pthread_create(&hThread,&connection_attrib,handle_manager,0))
      sql_print_error("Warning: Can't create thread to manage maintenance");
  }

548 549 550 551 552
  // FIXME initialize binlog_filter and rpl_filter if not already done
  //       corresponding delete is in clean_up()
  if(!binlog_filter) binlog_filter = new Rpl_filter;
  if(!rpl_filter) rpl_filter = new Rpl_filter;

unknown's avatar
unknown committed
553 554 555 556 557 558 559 560 561
  if (opt_init_file)
  {
    if (read_init_file(opt_init_file))
    {
      mysql_server_end();
      return 1;
    }
  }

562
  execute_ddl_log_recovery();
unknown's avatar
unknown committed
563 564 565
  return 0;
}

566
void end_embedded_server()
567
{
unknown's avatar
unknown committed
568 569
  my_free((char*) copy_arguments_ptr, MYF(MY_ALLOW_ZERO_PTR));
  copy_arguments_ptr=0;
unknown's avatar
unknown committed
570
  clean_up(0);
unknown's avatar
unknown committed
571 572
}

573

574
void init_embedded_mysql(MYSQL *mysql, int client_flag)
575
{
576
  THD *thd = (THD *)mysql->thd;
577
  thd->mysql= mysql;
unknown's avatar
unknown committed
578
  mysql->server_version= server_version;
579
  init_alloc_root(&mysql->field_alloc, 8192, 0);
580
}
581

582 583 584 585 586 587 588 589 590 591 592
/**
  @brief Initialize a new THD for a connection in the embedded server

  @param client_flag  Client capabilities which this thread supports
  @return pointer to the created THD object

  @todo
  This function copies code from several places in the server, including
  create_new_thread(), and prepare_new_connection_state().  This should
  be refactored to avoid code duplication.
*/
593
void *create_embedded_thd(int client_flag)
594 595
{
  THD * thd= new THD;
unknown's avatar
unknown committed
596
  thd->thread_id= thd->variables.pseudo_thread_id= thread_id++;
597

598
  thd->thread_stack= (char*) &thd;
599 600 601
  if (thd->store_globals())
  {
    fprintf(stderr,"store_globals failed.\n");
602
    goto err;
603
  }
604
  lex_start(thd);
605

unknown's avatar
unknown committed
606
  /* TODO - add init_connect command execution */
607

608 609
  if (thd->variables.max_join_size == HA_POS_ERROR)
    thd->options |= OPTION_BIG_SELECTS;
610 611 612 613
  thd->proc_info=0;				// Remove 'login'
  thd->command=COM_SLEEP;
  thd->version=refresh_version;
  thd->set_time();
614
  thd->init_for_queries();
615
  thd->client_capabilities= client_flag;
616
  thd->real_id= pthread_self();
617

618 619
  thd->db= NULL;
  thd->db_length= 0;
unknown's avatar
unknown committed
620
#ifndef NO_EMBEDDED_ACCESS_CHECKS
621 622
  thd->security_ctx->db_access= DB_ACLS;
  thd->security_ctx->master_access= ~NO_ACCESS;
unknown's avatar
unknown committed
623
#endif
624 625 626 627
  thd->cur_data= 0;
  thd->first_data= 0;
  thd->data_tail= &thd->first_data;
  bzero((char*) &thd->net, sizeof(thd->net));
unknown's avatar
SCRUM  
unknown committed
628

unknown's avatar
unknown committed
629
  thread_count++;
630
  return thd;
631 632 633
err:
  delete(thd);
  return NULL;
634
}
635

636

637
#ifdef NO_EMBEDDED_ACCESS_CHECKS
638
int check_embedded_connection(MYSQL *mysql, const char *db)
639
{
640
  int result;
641
  THD *thd= (THD*)mysql->thd;
642 643
  thd_init_client_charset(thd, mysql->charset->number);
  thd->update_charset();
unknown's avatar
unknown committed
644
  Security_context *sctx= thd->security_ctx;
645 646
  sctx->host_or_ip= sctx->host= (char*) my_localhost;
  strmake(sctx->priv_host, (char*) my_localhost,  MAX_HOSTNAME-1);
647
  sctx->priv_user= sctx->user= my_strdup(mysql->user, MYF(0));
648
  result= check_user(thd, COM_CONNECT, NULL, 0, db, true);
649
  net_end_statement(thd);
650 651
  emb_read_query_result(mysql);
  return result;
652 653 654
}

#else
655
int check_embedded_connection(MYSQL *mysql, const char *db)
unknown's avatar
unknown committed
656 657
{
  THD *thd= (THD*)mysql->thd;
658
  Security_context *sctx= thd->security_ctx;
unknown's avatar
unknown committed
659 660 661 662
  int result;
  char scramble_buff[SCRAMBLE_LENGTH];
  int passwd_len;

663 664
  thd_init_client_charset(thd, mysql->charset->number);
  thd->update_charset();
665 666
  if (mysql->options.client_ip)
  {
667 668
    sctx->host= my_strdup(mysql->options.client_ip, MYF(0));
    sctx->ip= my_strdup(sctx->host, MYF(0));
669 670
  }
  else
671 672
    sctx->host= (char*)my_localhost;
  sctx->host_or_ip= sctx->host;
unknown's avatar
unknown committed
673

674
  if (acl_check_host(sctx->host, sctx->ip))
unknown's avatar
unknown committed
675 676 677 678 679
  {
    result= ER_HOST_NOT_PRIVILEGED;
    goto err;
  }

680
  sctx->user= my_strdup(mysql->user, MYF(0));
unknown's avatar
unknown committed
681 682 683 684 685 686 687 688 689 690 691
  if (mysql->passwd && mysql->passwd[0])
  {
    memset(thd->scramble, 55, SCRAMBLE_LENGTH); // dummy scramble
    thd->scramble[SCRAMBLE_LENGTH]= 0;
    scramble(scramble_buff, thd->scramble, mysql->passwd);
    passwd_len= SCRAMBLE_LENGTH;
  }
  else
    passwd_len= 0;

  if((result= check_user(thd, COM_CONNECT, 
692
			 scramble_buff, passwd_len, db, true)))
unknown's avatar
unknown committed
693 694 695 696 697 698
     goto err;

  return 0;
err:
  {
    NET *net= &mysql->net;
unknown's avatar
unknown committed
699
    strmake(net->last_error, thd->main_da.message(), sizeof(net->last_error)-1);
700 701 702
    memcpy(net->sqlstate,
           mysql_errno_to_sqlstate(thd->main_da.sql_errno()),
           sizeof(net->sqlstate)-1);
unknown's avatar
unknown committed
703 704 705 706 707
  }
  return result;
}
#endif

708
C_MODE_END
709

unknown's avatar
unknown committed
710 711 712 713 714 715 716 717 718 719 720 721 722 723 724
void THD::clear_data_list()
{
  while (first_data)
  {
    MYSQL_DATA *data= first_data;
    first_data= data->embedded_info->next;
    free_rows(data);
  }
  data_tail= &first_data;
  free_rows(cur_data);
  cur_data= 0;
}

void THD::clear_error()
{
725 726
  if (main_da.is_error())
    main_da.reset_diagnostics_area();
unknown's avatar
unknown committed
727 728
}

729 730 731 732 733 734 735 736 737 738 739 740 741
static char *dup_str_aux(MEM_ROOT *root, const char *from, uint length,
			 CHARSET_INFO *fromcs, CHARSET_INFO *tocs)
{
  uint32 dummy32;
  uint dummy_err;
  char *result;

  /* 'tocs' is set 0 when client issues SET character_set_results=NULL */
  if (tocs && String::needs_conversion(0, fromcs, tocs, &dummy32))
  {
    uint new_len= (tocs->mbmaxlen * length) / fromcs->mbminlen + 1;
    result= (char *)alloc_root(root, new_len);
    length= copy_and_convert(result, new_len,
unknown's avatar
unknown committed
742
                             tocs, from, length, fromcs, &dummy_err);
743 744 745 746 747 748 749 750 751 752 753 754
  }
  else
  {
    result= (char *)alloc_root(root, length + 1);
    memcpy(result, from, length);
  }

  result[length]= 0;
  return result;
}


755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788
/*
  creates new result and hooks it to the list

  SYNOPSIS
  alloc_new_dataset()

  NOTES
    allocs the MYSQL_DATA + embedded_query_result couple
    to store the next query result,
    links these two and attach it to the THD::data_tail

  RETURN
    pointer to the newly created query result
*/

MYSQL_DATA *THD::alloc_new_dataset()
{
  MYSQL_DATA *data;
  struct embedded_query_result *emb_data;
  if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
                       &data, sizeof(*data),
                       &emb_data, sizeof(*emb_data),
                       NULL))
    return NULL;

  emb_data->prev_ptr= &data->data;
  cur_data= data;
  *data_tail= data;
  data_tail= &emb_data->next;
  data->embedded_info= emb_data;
  return data;
}


789 790 791
/**
  Stores server_status and warning_count in the current
  query result structures.
792

793
  @param thd            current thread
794

795
  @note Should be called after we get the recordset-result.
796 797
*/

798 799 800
static
void
write_eof_packet(THD *thd, uint server_status, uint total_warn_count)
801
{
802 803
  if (!thd->mysql)            // bootstrap file handling
    return;
804 805 806 807 808 809 810
  /*
    The following test should never be true, but it's better to do it
    because if 'is_fatal_error' is set the server is not going to execute
    other queries (see the if test in dispatch_command / COM_QUERY)
  */
  if (thd->is_fatal_error)
    thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
811
  thd->cur_data->embedded_info->server_status= server_status;
812 813 814 815 816
  /*
    Don't send warn count during SP execution, as the warn_list
    is cleared between substatements, and mysqltest gets confused
  */
  thd->cur_data->embedded_info->warning_count=
817
    (thd->spcont ? 0 : min(total_warn_count, 65535));
818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847
}


/*
  allocs new query result and initialises Protocol::alloc

  SYNOPSIS
  Protocol::begin_dataset()

  RETURN
    0 if success
    1 if memory allocation failed
*/

int Protocol::begin_dataset()
{
  MYSQL_DATA *data= thd->alloc_new_dataset();
  if (!data)
    return 1;
  alloc= &data->alloc;
  init_alloc_root(alloc,8192,0);	/* Assume rowlength < 8192 */
  alloc->min_malloc=sizeof(MYSQL_ROWS);
  return 0;
}


/*
  remove last row of current recordset

  SYNOPSIS
unknown's avatar
unknown committed
848
  Protocol_text::remove_last_row()
849 850 851 852 853 854 855

  NOTES
    does the loop from the beginning of the current recordset to
    the last record and cuts it off.
    Not supposed to be frequently called.
*/

unknown's avatar
unknown committed
856
void Protocol_text::remove_last_row()
857 858 859
{
  MYSQL_DATA *data= thd->cur_data;
  MYSQL_ROWS **last_row_hook= &data->data;
860
  my_ulonglong count= data->rows;
unknown's avatar
unknown committed
861
  DBUG_ENTER("Protocol_text::remove_last_row");
862 863 864 865 866 867 868 869 870 871 872
  while (--count)
    last_row_hook= &(*last_row_hook)->next;

  *last_row_hook= 0;
  data->embedded_info->prev_ptr= last_row_hook;
  data->rows--;

  DBUG_VOID_RETURN;
}


unknown's avatar
unknown committed
873
bool Protocol::send_fields(List<Item> *list, uint flags)
unknown's avatar
unknown committed
874 875 876
{
  List_iterator_fast<Item> it(*list);
  Item                     *item;
unknown's avatar
SCRUM  
unknown committed
877 878
  MYSQL_FIELD              *client_field;
  MEM_ROOT                 *field_alloc;
879 880
  CHARSET_INFO             *thd_cs= thd->variables.character_set_results;
  CHARSET_INFO             *cs= system_charset_info;
881
  MYSQL_DATA               *data;
unknown's avatar
SCRUM  
unknown committed
882
  DBUG_ENTER("send_fields");
unknown's avatar
unknown committed
883

884
  if (!thd->mysql)            // bootstrap file handling
unknown's avatar
unknown committed
885 886
    DBUG_RETURN(0);

887 888 889 890 891 892 893 894 895
  if (begin_dataset())
    goto err;

  data= thd->cur_data;
  data->fields= field_count= list->elements;
  field_alloc= &data->alloc;

  if (!(client_field= data->embedded_info->fields_list= 
	(MYSQL_FIELD*)alloc_root(field_alloc, sizeof(MYSQL_FIELD)*field_count)))
unknown's avatar
unknown committed
896 897 898 899 900 901 902
    goto err;

  while ((item= it++))
  {
    Send_field server_field;
    item->make_field(&server_field);

903 904 905 906
    /* Keep things compatible for old clients */
    if (server_field.type == MYSQL_TYPE_VARCHAR)
      server_field.type= MYSQL_TYPE_VAR_STRING;

907
    client_field->db= dup_str_aux(field_alloc, server_field.db_name,
unknown's avatar
unknown committed
908
                                  strlen(server_field.db_name), cs, thd_cs);
909
    client_field->table= dup_str_aux(field_alloc, server_field.table_name,
unknown's avatar
unknown committed
910
                                     strlen(server_field.table_name), cs, thd_cs);
911
    client_field->name= dup_str_aux(field_alloc, server_field.col_name,
unknown's avatar
unknown committed
912
                                    strlen(server_field.col_name), cs, thd_cs);
913
    client_field->org_table= dup_str_aux(field_alloc, server_field.org_table_name,
unknown's avatar
unknown committed
914
                                         strlen(server_field.org_table_name), cs, thd_cs);
915
    client_field->org_name= dup_str_aux(field_alloc, server_field.org_col_name,
unknown's avatar
unknown committed
916
                                        strlen(server_field.org_col_name), cs, thd_cs);
917 918 919 920 921 922 923 924
    if (item->collation.collation == &my_charset_bin || thd_cs == NULL)
    {
      /* No conversion */
      client_field->charsetnr= server_field.charsetnr;
      client_field->length= server_field.length;
    }
    else
    {
925
      uint max_char_len;
926 927
      /* With conversion */
      client_field->charsetnr= thd_cs->number;
928 929 930 931 932
      max_char_len= (server_field.type >= (int) MYSQL_TYPE_TINY_BLOB &&
                     server_field.type <= (int) MYSQL_TYPE_BLOB) ?
                     server_field.length / item->collation.collation->mbminlen :
                     server_field.length / item->collation.collation->mbmaxlen;
      client_field->length= max_char_len * thd_cs->mbmaxlen;
933
    }
unknown's avatar
unknown committed
934 935 936
    client_field->type=   server_field.type;
    client_field->flags= server_field.flags;
    client_field->decimals= server_field.decimals;
937 938 939 940 941
    client_field->db_length=		strlen(client_field->db);
    client_field->table_length=		strlen(client_field->table);
    client_field->name_length=		strlen(client_field->name);
    client_field->org_name_length=	strlen(client_field->org_name);
    client_field->org_table_length=	strlen(client_field->org_table);
unknown's avatar
SCRUM  
unknown committed
942

943
    client_field->catalog= dup_str_aux(field_alloc, "def", 3, cs, thd_cs);
unknown's avatar
SCRUM  
unknown committed
944
    client_field->catalog_length= 3;
unknown's avatar
unknown committed
945

unknown's avatar
unknown committed
946 947 948
    if (INTERNAL_NUM_FIELD(client_field))
      client_field->flags|= NUM_FLAG;

949
    if (flags & (int) Protocol::SEND_DEFAULTS)
unknown's avatar
unknown committed
950 951 952 953 954
    {
      char buff[80];
      String tmp(buff, sizeof(buff), default_charset_info), *res;

      if (!(res=item->val_str(&tmp)))
unknown's avatar
SCRUM  
unknown committed
955 956
      {
	client_field->def_length= 0;
957
	client_field->def= strmake_root(field_alloc, "",0);
unknown's avatar
SCRUM  
unknown committed
958
      }
unknown's avatar
unknown committed
959
      else
unknown's avatar
SCRUM  
unknown committed
960
      {
961
	client_field->def_length= res->length();
962 963
	client_field->def= strmake_root(field_alloc, res->ptr(),
					client_field->def_length);
unknown's avatar
SCRUM  
unknown committed
964
      }
unknown's avatar
unknown committed
965 966 967 968 969 970
    }
    else
      client_field->def=0;
    client_field->max_length= 0;
    ++client_field;
  }
971 972

  if (flags & SEND_EOF)
973
    write_eof_packet(thd, thd->server_status, thd->total_warn_count);
unknown's avatar
unknown committed
974

unknown's avatar
SCRUM  
unknown committed
975
  DBUG_RETURN(prepare_for_send(list));
unknown's avatar
unknown committed
976
 err:
unknown's avatar
unknown committed
977
  my_error(ER_OUT_OF_RESOURCES, MYF(0));        /* purecov: inspected */
unknown's avatar
SCRUM  
unknown committed
978
  DBUG_RETURN(1);				/* purecov: inspected */
unknown's avatar
unknown committed
979 980
}

unknown's avatar
SCRUM  
unknown committed
981
bool Protocol::write()
unknown's avatar
unknown committed
982
{
unknown's avatar
unknown committed
983 984 985
  if (!thd->mysql)            // bootstrap file handling
    return false;

unknown's avatar
SCRUM  
unknown committed
986 987
  *next_field= 0;
  return false;
unknown's avatar
unknown committed
988
}
989

unknown's avatar
unknown committed
990
bool Protocol_binary::write()
unknown's avatar
unknown committed
991 992
{
  MYSQL_ROWS *cur;
993
  MYSQL_DATA *data= thd->cur_data;
unknown's avatar
unknown committed
994 995

  data->rows++;
996 997
  if (!(cur= (MYSQL_ROWS *)alloc_root(alloc,
                                      sizeof(MYSQL_ROWS)+packet->length())))
unknown's avatar
unknown committed
998 999 1000 1001 1002
  {
    my_error(ER_OUT_OF_RESOURCES,MYF(0));
    return true;
  }
  cur->data= (MYSQL_ROW)(((char *)cur) + sizeof(MYSQL_ROWS));
unknown's avatar
SCRUM  
unknown committed
1003
  memcpy(cur->data, packet->ptr()+1, packet->length()-1);
1004
  cur->length= packet->length();       /* To allow us to do sanity checks */
unknown's avatar
unknown committed
1005

1006 1007
  *data->embedded_info->prev_ptr= cur;
  data->embedded_info->prev_ptr= &cur->next;
unknown's avatar
SCRUM  
unknown committed
1008 1009
  cur->next= 0;
  
unknown's avatar
unknown committed
1010 1011 1012
  return false;
}

1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030

/**
  Embedded library implementation of OK response.

  This function is used by the server to write 'OK' packet to
  the "network" when the server is compiled as an embedded library.
  Since there is no network in the embedded configuration,
  a different implementation is necessary.
  Instead of marshalling response parameters to a network representation
  and then writing it to the socket, here we simply copy the data to the
  corresponding client-side connection structures. 

  @sa Server implementation of net_send_ok in protocol.cc for
  description of the arguments.

  @return The function does not return errors.
*/

1031
void
1032 1033 1034
net_send_ok(THD *thd,
            uint server_status, uint total_warn_count,
            ha_rows affected_rows, ulonglong id, const char *message)
1035
{
1036
  DBUG_ENTER("emb_net_send_ok");
1037 1038
  MYSQL_DATA *data;
  MYSQL *mysql= thd->mysql;
1039

unknown's avatar
unknown committed
1040 1041
  if (!mysql)            // bootstrap file handling
    DBUG_VOID_RETURN;
1042 1043 1044 1045
  if (!(data= thd->alloc_new_dataset()))
    return;
  data->embedded_info->affected_rows= affected_rows;
  data->embedded_info->insert_id= id;
1046
  if (message)
1047 1048 1049
    strmake(data->embedded_info->info, message,
            sizeof(data->embedded_info->info)-1);

1050
  write_eof_packet(thd, server_status, total_warn_count);
1051
  thd->cur_data= 0;
1052 1053 1054
  DBUG_VOID_RETURN;
}

1055 1056 1057 1058 1059 1060 1061 1062 1063

/**
  Embedded library implementation of EOF response.

  @sa net_send_ok

  @return This function does not return errors.
*/

1064
void
1065
net_send_eof(THD *thd, uint server_status, uint total_warn_count)
1066
{
1067
  write_eof_packet(thd, server_status, total_warn_count);
1068
  thd->cur_data= 0;
1069 1070
}

1071 1072 1073 1074 1075 1076 1077 1078 1079

void net_send_error_packet(THD *thd, uint sql_errno, const char *err)
{
  MYSQL_DATA *data= thd->cur_data ? thd->cur_data : thd->alloc_new_dataset();
  struct embedded_query_result *ei= data->embedded_info;

  ei->last_errno= sql_errno;
  strmake(ei->info, err, sizeof(ei->info)-1);
  strmov(ei->sqlstate, mysql_errno_to_sqlstate(sql_errno));
1080
  ei->server_status= thd->server_status;
1081 1082 1083 1084
  thd->cur_data= 0;
}


unknown's avatar
unknown committed
1085
void Protocol_text::prepare_for_resend()
unknown's avatar
SCRUM  
unknown committed
1086
{
unknown's avatar
SCRUM  
unknown committed
1087
  MYSQL_ROWS *cur;
1088
  MYSQL_DATA *data= thd->cur_data;
unknown's avatar
SCRUM  
unknown committed
1089 1090
  DBUG_ENTER("send_data");

unknown's avatar
unknown committed
1091 1092 1093
  if (!thd->mysql)            // bootstrap file handling
    DBUG_VOID_RETURN;

unknown's avatar
SCRUM  
unknown committed
1094
  data->rows++;
unknown's avatar
SCRUM  
unknown committed
1095 1096 1097 1098 1099 1100 1101
  if (!(cur= (MYSQL_ROWS *)alloc_root(alloc, sizeof(MYSQL_ROWS)+(field_count + 1) * sizeof(char *))))
  {
    my_error(ER_OUT_OF_RESOURCES,MYF(0));
    DBUG_VOID_RETURN;
  }
  cur->data= (MYSQL_ROW)(((char *)cur) + sizeof(MYSQL_ROWS));

1102 1103
  *data->embedded_info->prev_ptr= cur;
  data->embedded_info->prev_ptr= &cur->next;
unknown's avatar
SCRUM  
unknown committed
1104
  next_field=cur->data;
1105
  next_mysql_field= data->embedded_info->fields_list;
1106 1107 1108
#ifndef DBUG_OFF
  field_pos= 0;
#endif
1109

unknown's avatar
SCRUM  
unknown committed
1110 1111 1112
  DBUG_VOID_RETURN;
}

unknown's avatar
unknown committed
1113
bool Protocol_text::store_null()
unknown's avatar
SCRUM  
unknown committed
1114 1115 1116 1117 1118 1119
{
  *(next_field++)= NULL;
  ++next_mysql_field;
  return false;
}

1120
bool Protocol::net_store_data(const uchar *from, size_t length)
unknown's avatar
SCRUM  
unknown committed
1121
{
unknown's avatar
unknown committed
1122
  char *field_buf;
unknown's avatar
unknown committed
1123
  if (!thd->mysql)            // bootstrap file handling
1124
    return FALSE;
unknown's avatar
unknown committed
1125

1126 1127
  if (!(field_buf= (char*) alloc_root(alloc, length + sizeof(uint) + 1)))
    return TRUE;
unknown's avatar
unknown committed
1128 1129
  *(uint *)field_buf= length;
  *next_field= field_buf + sizeof(uint);
1130
  memcpy((uchar*) *next_field, from, length);
unknown's avatar
SCRUM  
unknown committed
1131
  (*next_field)[length]= 0;
unknown's avatar
SCRUM  
unknown committed
1132 1133 1134 1135
  if (next_mysql_field->max_length < length)
    next_mysql_field->max_length=length;
  ++next_field;
  ++next_mysql_field;
1136
  return FALSE;
unknown's avatar
SCRUM  
unknown committed
1137 1138
}

unknown's avatar
unknown committed
1139 1140 1141
#if defined(_MSC_VER) && _MSC_VER < 1400
#define vsnprintf _vsnprintf
#endif
1142

unknown's avatar
unknown committed
1143
int vprint_msg_to_log(enum loglevel level __attribute__((unused)),
1144 1145 1146 1147 1148
                       const char *format, va_list argsi)
{
  vsnprintf(mysql_server_last_error, sizeof(mysql_server_last_error),
           format, argsi);
  mysql_server_last_errno= CR_UNKNOWN_ERROR;
unknown's avatar
unknown committed
1149
  return 0;
1150
}