lib_sql.cc 26.4 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

unknown's avatar
unknown committed
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
#if defined(__WIN__) && !defined(USING_CMAKE)
unknown's avatar
unknown committed
32 33
#include "../sql/mysqld.cpp"
#else
34
#include "../sql/mysqld.cc"
unknown's avatar
unknown committed
35
#endif
36

unknown's avatar
SCRUM:  
unknown committed
37 38 39
int check_user(THD *thd, enum enum_server_command command, 
	       const char *passwd, uint passwd_len, const char *db,
	       bool check_count);
40 41
void thd_init_client_charset(THD *thd, uint cs_number);

unknown's avatar
unknown committed
42
C_MODE_START
unknown's avatar
unknown committed
43

44
#include <mysql.h>
unknown's avatar
unknown committed
45
#undef ER
46
#include "errmsg.h"
unknown's avatar
SCRUM  
unknown committed
47
#include <sql_common.h>
48
#include "embedded_priv.h"
unknown's avatar
unknown committed
49

50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
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;
  net->last_errno= ei->last_errno;
  strmake(net->last_error, ei->info, sizeof(net->last_error));
  memcpy(net->sqlstate, ei->sqlstate, sizeof(net->sqlstate));
  my_free((gptr) data, MYF(0));
77 78
}

unknown's avatar
unknown committed
79
static my_bool
unknown's avatar
SCRUM  
unknown committed
80 81
emb_advanced_command(MYSQL *mysql, enum enum_server_command command,
		     const char *header, ulong header_length,
82 83
		     const char *arg, ulong arg_length, my_bool skip_check,
                     MYSQL_STMT *stmt)
84
{
85
  my_bool result= 1;
86
  THD *thd=(THD *) mysql->thd;
unknown's avatar
unknown committed
87
  NET *net= &mysql->net;
88

89
  thd->clear_data_list();
90 91 92
  /* Check that we are calling the client functions in right order */
  if (mysql->status != MYSQL_STATUS_READY)
  {
unknown's avatar
unknown committed
93 94
    strmov(net->last_error,
	   ER(net->last_errno=CR_COMMANDS_OUT_OF_SYNC));
95 96 97 98
    return 1;
  }

  /* Clear result variables */
unknown's avatar
unknown committed
99
  thd->clear_error();
100
  mysql->affected_rows= ~(my_ulonglong) 0;
unknown's avatar
SCRUM  
unknown committed
101
  mysql->field_count= 0;
unknown's avatar
unknown committed
102
  net->last_errno= 0;
103

104
  thd->store_globals();				// Fix if more than one connect
unknown's avatar
unknown committed
105 106 107 108 109 110
  /* 
     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
111
  free_old_query(mysql);
unknown's avatar
unknown committed
112 113 114 115

  thd->extra_length= arg_length;
  thd->extra_data= (char *)arg;
  if (header)
unknown's avatar
SCRUM  
unknown committed
116 117 118 119 120
  {
    arg= header;
    arg_length= header_length;
  }

121
  thd->net.no_send_error= 0;
unknown's avatar
SCRUM  
unknown committed
122
  result= dispatch_command(command, thd, (char *) arg, arg_length + 1);
123
  thd->cur_data= 0;
unknown's avatar
unknown committed
124

unknown's avatar
SCRUM  
unknown committed
125
  if (!skip_check)
126
    result= thd->net.last_errno ? -1 : 0;
127

128
  return result;
129 130
}

unknown's avatar
unknown committed
131 132
static void emb_flush_use_result(MYSQL *mysql)
{
133 134
  THD *thd= (THD*) mysql->thd;
  if (thd->cur_data)
unknown's avatar
unknown committed
135
  {
136 137 138 139 140 141 142
    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;
unknown's avatar
unknown committed
143 144 145 146
    free_rows(data);
  }
}

147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162

/*
  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
163
static MYSQL_DATA *
unknown's avatar
SCRUM  
unknown committed
164
emb_read_rows(MYSQL *mysql, MYSQL_FIELD *mysql_fields __attribute__((unused)),
unknown's avatar
SCRUM  
unknown committed
165
	      unsigned int fields __attribute__((unused)))
unknown's avatar
SCRUM  
unknown committed
166
{
167 168 169
  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
170
  {
171 172 173 174
    embedded_get_error(mysql, result);
    return NULL;
  }
  *result->embedded_info->prev_ptr= NULL;
unknown's avatar
SCRUM  
unknown committed
175 176 177
  return result;
}

178

unknown's avatar
unknown committed
179
static MYSQL_FIELD *emb_list_fields(MYSQL *mysql)
unknown's avatar
SCRUM  
unknown committed
180
{
181 182 183 184 185 186 187 188
  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;
  my_free((gptr) res,MYF(0));
  mysql->status= MYSQL_STATUS_READY;
unknown's avatar
SCRUM  
unknown committed
189 190 191
  return mysql->fields;
}

unknown's avatar
unknown committed
192
static my_bool emb_read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt)
unknown's avatar
SCRUM  
unknown committed
193
{
194 195 196
  THD *thd= (THD*) mysql->thd;
  MYSQL_DATA *res;

unknown's avatar
SCRUM  
unknown committed
197 198
  stmt->stmt_id= thd->client_stmt_id;
  stmt->param_count= thd->client_param_count;
199
  stmt->field_count= 0;
unknown's avatar
SCRUM  
unknown committed
200

201
  if (thd->first_data)
unknown's avatar
SCRUM  
unknown committed
202
  {
203 204 205 206 207 208
    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
209 210 211 212
    if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT))
      mysql->server_status|= SERVER_STATUS_IN_TRANS;

    stmt->fields= mysql->fields;
213
    stmt->mem_root= res->alloc;
unknown's avatar
SCRUM  
unknown committed
214
    mysql->fields= NULL;
215
    my_free((gptr) res,MYF(0));
unknown's avatar
SCRUM  
unknown committed
216
  }
unknown's avatar
SCRUM  
unknown committed
217

unknown's avatar
SCRUM  
unknown committed
218 219 220 221 222 223 224 225 226
  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
227 228
static void emb_fetch_lengths(ulong *to, MYSQL_ROW column,
			      unsigned int field_count)
unknown's avatar
SCRUM  
unknown committed
229 230 231 232 233 234 235
{ 
  MYSQL_ROW end;

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

236
static my_bool emb_read_query_result(MYSQL *mysql)
unknown's avatar
SCRUM  
unknown committed
237
{
238 239 240 241 242 243 244 245 246 247 248 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;
  mysql->fields= res->embedded_info->fields_list;
  mysql->affected_rows= res->embedded_info->affected_rows;
  mysql->insert_id= res->embedded_info->insert_id;
  mysql->net.last_errno= 0;
  mysql->net.last_error[0]= 0;
  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
264

265 266
  if (res->embedded_info->fields_list)
  {
unknown's avatar
SCRUM  
unknown committed
267
    mysql->status=MYSQL_STATUS_GET_RESULT;
268 269 270 271
    thd->cur_data= res;
  }
  else
    my_free((gptr) res, MYF(0));
unknown's avatar
SCRUM  
unknown committed
272 273 274 275

  return 0;
}

unknown's avatar
unknown committed
276
static int emb_stmt_execute(MYSQL_STMT *stmt)
unknown's avatar
SCRUM  
unknown committed
277 278
{
  DBUG_ENTER("emb_stmt_execute");
279 280 281
  char header[5];
  THD *thd;

282
  int4store(header, stmt->stmt_id);
283 284
  header[4]= stmt->flags;
  thd= (THD*)stmt->mysql->thd;
unknown's avatar
SCRUM  
unknown committed
285
  thd->client_param_count= stmt->param_count;
unknown's avatar
SCRUM:  
unknown committed
286
  thd->client_params= stmt->params;
287
  if (emb_advanced_command(stmt->mysql, COM_STMT_EXECUTE,0,0,
288
                           header, sizeof(header), 1, stmt) ||
289
      emb_read_query_result(stmt->mysql))
unknown's avatar
SCRUM  
unknown committed
290 291 292 293 294
  {
    NET *net= &stmt->mysql->net;
    set_stmt_errmsg(stmt, net->last_error, net->last_errno, net->sqlstate);
    DBUG_RETURN(1);
  }
295 296
  stmt->affected_rows= stmt->mysql->affected_rows;
  stmt->insert_id= stmt->mysql->insert_id;
297 298
  stmt->server_status= stmt->mysql->server_status;

unknown's avatar
SCRUM  
unknown committed
299 300 301
  DBUG_RETURN(0);
}

302
int emb_read_binary_rows(MYSQL_STMT *stmt)
unknown's avatar
SCRUM:  
unknown committed
303
{
304 305 306 307 308
  MYSQL_DATA *data;
  if (!(data= emb_read_rows(stmt->mysql, 0, 0)))
    return 1;
  stmt->result= *data;
  my_free((char *) data, MYF(0));
309 310
  set_stmt_errmsg(stmt, stmt->mysql->net.last_error,
                  stmt->mysql->net.last_errno, stmt->mysql->net.sqlstate);
311
  return 0;
unknown's avatar
SCRUM:  
unknown committed
312 313
}

314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
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);
    set_stmt_errmsg(stmt, mysql->net.last_error,
                    mysql->net.last_errno, mysql->net.sqlstate);
    return 1;
  }

  thd->cur_data= res;
  mysql->warning_count= res->embedded_info->warning_count;
  mysql->server_status= res->embedded_info->server_status;
  mysql->net.last_errno= 0;
  mysql->net.last_error[0]= 0;

  return emb_read_binary_rows(stmt);
}

unknown's avatar
unknown committed
338
int emb_unbuffered_fetch(MYSQL *mysql, char **row)
unknown's avatar
SCRUM  
unknown committed
339
{
340 341 342 343 344 345 346 347
  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
348 349 350 351 352
  if (!data || !data->data)
  {
    *row= NULL;
    if (data)
    {
353 354
      thd->cur_data= thd->first_data;
      thd->first_data= data->embedded_info->next;
unknown's avatar
SCRUM  
unknown committed
355 356 357 358 359 360 361 362 363 364 365
      free_rows(data);
    }
  }
  else
  {
    *row= (char *)data->data->data;
    data->data= data->data->next;
  }
  return 0;
}

unknown's avatar
unknown committed
366
static void emb_free_embedded_thd(MYSQL *mysql)
unknown's avatar
SCRUM  
unknown committed
367 368
{
  THD *thd= (THD*)mysql->thd;
369
  thd->clear_data_list();
unknown's avatar
unknown committed
370
  thread_count--;
371
  thd->store_globals();
unknown's avatar
SCRUM  
unknown committed
372
  delete thd;
373
  mysql->thd=0;
unknown's avatar
SCRUM  
unknown committed
374 375
}

unknown's avatar
Rename:  
unknown committed
376
static const char * emb_read_statistics(MYSQL *mysql)
unknown's avatar
unknown committed
377 378 379 380 381
{
  THD *thd= (THD*)mysql->thd;
  return thd->net.last_error;
}

unknown's avatar
unknown committed
382

383
static MYSQL_RES * emb_store_result(MYSQL *mysql)
unknown's avatar
unknown committed
384 385 386 387
{
  return mysql_store_result(mysql);
}

388 389 390 391 392 393 394
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
395 396
MYSQL_METHODS embedded_methods= 
{
397
  emb_read_query_result,
unknown's avatar
SCRUM  
unknown committed
398 399
  emb_advanced_command,
  emb_read_rows,
400
  emb_store_result,
unknown's avatar
SCRUM  
unknown committed
401
  emb_fetch_lengths, 
unknown's avatar
unknown committed
402
  emb_flush_use_result,
unknown's avatar
SCRUM  
unknown committed
403
  emb_list_fields,
unknown's avatar
SCRUM  
unknown committed
404
  emb_read_prepare_result,
unknown's avatar
SCRUM:  
unknown committed
405
  emb_stmt_execute,
unknown's avatar
SCRUM  
unknown committed
406
  emb_read_binary_rows,
unknown's avatar
SCRUM  
unknown committed
407
  emb_unbuffered_fetch,
unknown's avatar
unknown committed
408
  emb_free_embedded_thd,
unknown's avatar
Rename:  
unknown committed
409
  emb_read_statistics,
410 411 412
  emb_read_query_result,
  emb_read_change_user_result,
  emb_read_rows_from_cursor
unknown's avatar
SCRUM  
unknown committed
413 414
};

415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440
/*
  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
441
char **		copy_arguments_ptr= 0;
unknown's avatar
unknown committed
442

443
int init_embedded_server(int argc, char **argv, char **groups)
unknown's avatar
unknown committed
444
{
unknown's avatar
unknown committed
445 446 447 448
  /*
    This mess is to allow people to call the init function without
    having to mess with a fake argv
   */
unknown's avatar
unknown committed
449 450 451 452 453
  int *argcp;
  char ***argvp;
  int fake_argc = 1;
  char *fake_argv[] = { (char *)"", 0 };
  const char *fake_groups[] = { "server", "embedded", 0 };
454
  my_bool acl_error;
unknown's avatar
unknown committed
455 456
  if (argc)
  {
unknown's avatar
unknown committed
457 458
    argcp= &argc;
    argvp= (char***) &argv;
unknown's avatar
unknown committed
459 460 461
  }
  else
  {
unknown's avatar
unknown committed
462 463
    argcp= &fake_argc;
    argvp= (char ***) &fake_argv;
unknown's avatar
unknown committed
464 465
  }
  if (!groups)
unknown's avatar
unknown committed
466
    groups= (char**) fake_groups;
unknown's avatar
unknown committed
467

468
  my_progname= (char *)"mysql_embedded";
unknown's avatar
unknown committed
469

470 471 472 473 474 475
  /*
    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
SCRUM:  
unknown committed
476
  if (init_common_variables("my", *argcp, *argvp, (const char **)groups))
unknown's avatar
unknown committed
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501
  {
    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;

502
  acl_error= 0;
unknown's avatar
SCRUM:  
unknown committed
503
#ifndef NO_EMBEDDED_ACCESS_CHECKS
504
  if (!(acl_error= acl_init(opt_noacl)) &&
505
      !opt_noacl)
506
    (void) grant_init();
507 508
#endif
  if (acl_error || my_tz_init((THD *)0, default_tz_name, opt_bootstrap))
unknown's avatar
unknown committed
509 510 511 512
  {
    mysql_server_end();
    return 1;
  }
unknown's avatar
SCRUM:  
unknown committed
513

unknown's avatar
unknown committed
514 515 516 517
  init_max_user_conn();
  init_update_queries();

#ifdef HAVE_DLOPEN
unknown's avatar
SCRUM:  
unknown committed
518
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
519
  if (!opt_noacl)
unknown's avatar
SCRUM:  
unknown committed
520
#endif
unknown's avatar
unknown committed
521 522 523 524 525
    udf_init();
#endif

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

unknown's avatar
unknown committed
526
  if (flush_time && flush_time != ~(ulong) 0L)
unknown's avatar
unknown committed
527 528 529 530 531 532
  {
    pthread_t hThread;
    if (pthread_create(&hThread,&connection_attrib,handle_manager,0))
      sql_print_error("Warning: Can't create thread to manage maintenance");
  }

unknown's avatar
unknown committed
533 534 535 536 537 538 539 540 541
  if (opt_init_file)
  {
    if (read_init_file(opt_init_file))
    {
      mysql_server_end();
      return 1;
    }
  }

unknown's avatar
unknown committed
542 543 544
  return 0;
}

545
void end_embedded_server()
546
{
unknown's avatar
unknown committed
547 548
  my_free((char*) copy_arguments_ptr, MYF(MY_ALLOW_ZERO_PTR));
  copy_arguments_ptr=0;
unknown's avatar
unknown committed
549
  clean_up(0);
unknown's avatar
unknown committed
550 551
}

552

553
void init_embedded_mysql(MYSQL *mysql, int client_flag)
554
{
555
  THD *thd = (THD *)mysql->thd;
556
  thd->mysql= mysql;
unknown's avatar
unknown committed
557
  mysql->server_version= server_version;
558
  init_alloc_root(&mysql->field_alloc, 8192, 0);
559
}
560

561
void *create_embedded_thd(int client_flag)
562 563 564 565
{
  THD * thd= new THD;
  thd->thread_id= thread_id++;

566
  thd->thread_stack= (char*) &thd;
567 568 569
  if (thd->store_globals())
  {
    fprintf(stderr,"store_globals failed.\n");
570
    goto err;
571 572 573 574 575
  }

  thd->mysys_var= my_thread_var;
  thd->dbug_thread_id= my_thread_id();

576 577
/* TODO - add init_connect command execution */

578 579
  if (thd->variables.max_join_size == HA_POS_ERROR)
    thd->options |= OPTION_BIG_SELECTS;
580 581 582 583
  thd->proc_info=0;				// Remove 'login'
  thd->command=COM_SLEEP;
  thd->version=refresh_version;
  thd->set_time();
584
  thd->init_for_queries();
585 586
  thd->client_capabilities= client_flag;

587 588
  thd->db= NULL;
  thd->db_length= 0;
unknown's avatar
SCRUM:  
unknown committed
589
#ifndef NO_EMBEDDED_ACCESS_CHECKS
590 591
  thd->security_ctx->db_access= DB_ACLS;
  thd->security_ctx->master_access= ~NO_ACCESS;
unknown's avatar
SCRUM:  
unknown committed
592
#endif
593 594 595 596
  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
597

unknown's avatar
unknown committed
598
  thread_count++;
599
  return thd;
600 601 602
err:
  delete(thd);
  return NULL;
603
}
604

605

606
#ifdef NO_EMBEDDED_ACCESS_CHECKS
607
int check_embedded_connection(MYSQL *mysql, const char *db)
608
{
609
  int result;
610
  THD *thd= (THD*)mysql->thd;
611 612
  thd_init_client_charset(thd, mysql->charset->number);
  thd->update_charset();
unknown's avatar
unknown committed
613
  Security_context *sctx= thd->security_ctx;
614 615
  sctx->host_or_ip= sctx->host= (char*) my_localhost;
  strmake(sctx->priv_host, (char*) my_localhost,  MAX_HOSTNAME-1);
616
  sctx->priv_user= sctx->user= my_strdup(mysql->user, MYF(0));
617
  result= check_user(thd, COM_CONNECT, NULL, 0, db, true);
618 619
  emb_read_query_result(mysql);
  return result;
620 621 622
}

#else
623
int check_embedded_connection(MYSQL *mysql, const char *db)
unknown's avatar
SCRUM:  
unknown committed
624 625
{
  THD *thd= (THD*)mysql->thd;
626
  Security_context *sctx= thd->security_ctx;
unknown's avatar
SCRUM:  
unknown committed
627 628 629 630
  int result;
  char scramble_buff[SCRAMBLE_LENGTH];
  int passwd_len;

631 632
  thd_init_client_charset(thd, mysql->charset->number);
  thd->update_charset();
633 634
  if (mysql->options.client_ip)
  {
635 636
    sctx->host= my_strdup(mysql->options.client_ip, MYF(0));
    sctx->ip= my_strdup(sctx->host, MYF(0));
637 638
  }
  else
639 640
    sctx->host= (char*)my_localhost;
  sctx->host_or_ip= sctx->host;
unknown's avatar
SCRUM:  
unknown committed
641

642
  if (acl_check_host(sctx->host, sctx->ip))
unknown's avatar
SCRUM:  
unknown committed
643 644 645 646 647
  {
    result= ER_HOST_NOT_PRIVILEGED;
    goto err;
  }

648
  sctx->user= my_strdup(mysql->user, MYF(0));
unknown's avatar
SCRUM:  
unknown committed
649 650 651 652 653 654 655 656 657 658 659
  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, 
660
			 scramble_buff, passwd_len, db, true)))
unknown's avatar
SCRUM:  
unknown committed
661 662 663 664 665 666 667 668 669 670 671 672 673
     goto err;

  return 0;
err:
  {
    NET *net= &mysql->net;
    memcpy(net->last_error, thd->net.last_error, sizeof(net->last_error));
    memcpy(net->sqlstate, thd->net.sqlstate, sizeof(net->sqlstate));
  }
  return result;
}
#endif

674
C_MODE_END
675

unknown's avatar
unknown committed
676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695
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()
{
  net.last_error[0]= 0;
  net.last_errno= 0;
  net.report_error= 0;
}

696 697 698 699 700 701 702 703 704 705 706 707 708
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
709
                             tocs, from, length, fromcs, &dummy_err);
710 711 712 713 714 715 716 717 718 719 720 721
  }
  else
  {
    result= (char *)alloc_root(root, length + 1);
    memcpy(result, from, length);
  }

  result[length]= 0;
  return result;
}


722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 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 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839
/*
  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;
}


/*
  stores server_status and warning_count in the current
  query result structures

  SYNOPSIS
  write_eof_packet()
  thd		current thread

  NOTES
    should be called to after we get the recordset-result

*/

static void write_eof_packet(THD *thd)
{
  /*
    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;
  thd->cur_data->embedded_info->server_status= thd->server_status;
  /*
    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=
    (thd->spcont ? 0 : min(thd->total_warn_count, 65535));
}


/*
  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
  Protocol_simple::remove_last_row()

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

void Protocol_simple::remove_last_row()
{
  MYSQL_DATA *data= thd->cur_data;
  MYSQL_ROWS **last_row_hook= &data->data;
  uint count= data->rows;
  DBUG_ENTER("Protocol_simple::remove_last_row");
  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
840
bool Protocol::send_fields(List<Item> *list, uint flags)
unknown's avatar
unknown committed
841 842 843
{
  List_iterator_fast<Item> it(*list);
  Item                     *item;
unknown's avatar
SCRUM  
unknown committed
844 845
  MYSQL_FIELD              *client_field;
  MEM_ROOT                 *field_alloc;
846 847
  CHARSET_INFO             *thd_cs= thd->variables.character_set_results;
  CHARSET_INFO             *cs= system_charset_info;
848
  MYSQL_DATA               *data;
unknown's avatar
SCRUM  
unknown committed
849
  DBUG_ENTER("send_fields");
unknown's avatar
unknown committed
850

851
  if (!thd->mysql)            // bootstrap file handling
unknown's avatar
unknown committed
852 853
    DBUG_RETURN(0);

854 855 856 857 858 859 860 861 862
  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
863 864 865 866 867 868 869
    goto err;

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

870 871 872 873
    /* Keep things compatible for old clients */
    if (server_field.type == MYSQL_TYPE_VARCHAR)
      server_field.type= MYSQL_TYPE_VAR_STRING;

874
    client_field->db= dup_str_aux(field_alloc, server_field.db_name,
unknown's avatar
unknown committed
875
                                  strlen(server_field.db_name), cs, thd_cs);
876
    client_field->table= dup_str_aux(field_alloc, server_field.table_name,
unknown's avatar
unknown committed
877
                                     strlen(server_field.table_name), cs, thd_cs);
878
    client_field->name= dup_str_aux(field_alloc, server_field.col_name,
unknown's avatar
unknown committed
879
                                    strlen(server_field.col_name), cs, thd_cs);
880
    client_field->org_table= dup_str_aux(field_alloc, server_field.org_table_name,
unknown's avatar
unknown committed
881
                                         strlen(server_field.org_table_name), cs, thd_cs);
882
    client_field->org_name= dup_str_aux(field_alloc, server_field.org_col_name,
unknown's avatar
unknown committed
883
                                        strlen(server_field.org_col_name), cs, thd_cs);
884 885 886 887 888 889 890 891
    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
    {
892
      uint max_char_len;
893 894
      /* With conversion */
      client_field->charsetnr= thd_cs->number;
895 896 897 898 899
      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;
900
    }
unknown's avatar
unknown committed
901 902 903
    client_field->type=   server_field.type;
    client_field->flags= server_field.flags;
    client_field->decimals= server_field.decimals;
904 905 906 907 908
    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
909

910
    client_field->catalog= dup_str_aux(field_alloc, "def", 3, cs, thd_cs);
unknown's avatar
SCRUM  
unknown committed
911
    client_field->catalog_length= 3;
unknown's avatar
unknown committed
912

unknown's avatar
unknown committed
913 914 915
    if (INTERNAL_NUM_FIELD(client_field))
      client_field->flags|= NUM_FLAG;

916
    if (flags & (int) Protocol::SEND_DEFAULTS)
unknown's avatar
unknown committed
917 918 919 920 921
    {
      char buff[80];
      String tmp(buff, sizeof(buff), default_charset_info), *res;

      if (!(res=item->val_str(&tmp)))
unknown's avatar
SCRUM  
unknown committed
922 923
      {
	client_field->def_length= 0;
924
	client_field->def= strmake_root(field_alloc, "",0);
unknown's avatar
SCRUM  
unknown committed
925
      }
unknown's avatar
unknown committed
926
      else
unknown's avatar
SCRUM  
unknown committed
927
      {
928
	client_field->def_length= res->length();
929 930
	client_field->def= strmake_root(field_alloc, res->ptr(),
					client_field->def_length);
unknown's avatar
SCRUM  
unknown committed
931
      }
unknown's avatar
unknown committed
932 933 934 935 936 937
    }
    else
      client_field->def=0;
    client_field->max_length= 0;
    ++client_field;
  }
938 939 940

  if (flags & SEND_EOF)
    write_eof_packet(thd);
unknown's avatar
unknown committed
941

unknown's avatar
SCRUM  
unknown committed
942
  DBUG_RETURN(prepare_for_send(list));
unknown's avatar
unknown committed
943
 err:
unknown's avatar
unknown committed
944
  my_error(ER_OUT_OF_RESOURCES, MYF(0));        /* purecov: inspected */
unknown's avatar
SCRUM  
unknown committed
945
  DBUG_RETURN(1);				/* purecov: inspected */
unknown's avatar
unknown committed
946 947
}

unknown's avatar
SCRUM  
unknown committed
948
bool Protocol::write()
unknown's avatar
unknown committed
949
{
unknown's avatar
unknown committed
950 951 952
  if (!thd->mysql)            // bootstrap file handling
    return false;

unknown's avatar
SCRUM  
unknown committed
953 954
  *next_field= 0;
  return false;
unknown's avatar
unknown committed
955
}
956

unknown's avatar
SCRUM:  
unknown committed
957 958 959
bool Protocol_prep::write()
{
  MYSQL_ROWS *cur;
960
  MYSQL_DATA *data= thd->cur_data;
unknown's avatar
SCRUM:  
unknown committed
961 962

  data->rows++;
963 964
  if (!(cur= (MYSQL_ROWS *)alloc_root(alloc,
                                      sizeof(MYSQL_ROWS)+packet->length())))
unknown's avatar
SCRUM:  
unknown committed
965 966 967 968 969
  {
    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
970
  memcpy(cur->data, packet->ptr()+1, packet->length()-1);
971
  cur->length= packet->length();       /* To allow us to do sanity checks */
unknown's avatar
SCRUM:  
unknown committed
972

973 974
  *data->embedded_info->prev_ptr= cur;
  data->embedded_info->prev_ptr= &cur->next;
unknown's avatar
SCRUM  
unknown committed
975 976
  cur->next= 0;
  
unknown's avatar
SCRUM:  
unknown committed
977 978 979
  return false;
}

980
void
981
send_ok(THD *thd,ha_rows affected_rows,ulonglong id,const char *message)
982 983
{
  DBUG_ENTER("send_ok");
984 985 986
  MYSQL_DATA *data;
  MYSQL *mysql= thd->mysql;
  
unknown's avatar
unknown committed
987 988
  if (!mysql)            // bootstrap file handling
    DBUG_VOID_RETURN;
989 990 991 992 993 994
  if (thd->net.no_send_ok)	// hack for re-parsing queries
    DBUG_VOID_RETURN;
  if (!(data= thd->alloc_new_dataset()))
    return;
  data->embedded_info->affected_rows= affected_rows;
  data->embedded_info->insert_id= id;
995
  if (message)
996 997 998 999 1000
    strmake(data->embedded_info->info, message,
            sizeof(data->embedded_info->info)-1);

  write_eof_packet(thd);
  thd->cur_data= 0;
1001 1002 1003
  DBUG_VOID_RETURN;
}

1004
void
1005
send_eof(THD *thd)
1006
{
1007 1008
  write_eof_packet(thd);
  thd->cur_data= 0;
1009 1010
}

1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023

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));
  thd->cur_data= 0;
}


unknown's avatar
SCRUM  
unknown committed
1024 1025
void Protocol_simple::prepare_for_resend()
{
unknown's avatar
SCRUM  
unknown committed
1026
  MYSQL_ROWS *cur;
1027
  MYSQL_DATA *data= thd->cur_data;
unknown's avatar
SCRUM  
unknown committed
1028 1029
  DBUG_ENTER("send_data");

unknown's avatar
SCRUM  
unknown committed
1030
  data->rows++;
unknown's avatar
SCRUM  
unknown committed
1031 1032 1033 1034 1035 1036 1037
  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));

1038 1039
  *data->embedded_info->prev_ptr= cur;
  data->embedded_info->prev_ptr= &cur->next;
unknown's avatar
SCRUM  
unknown committed
1040
  next_field=cur->data;
1041
  next_mysql_field= data->embedded_info->fields_list;
unknown's avatar
SCRUM  
unknown committed
1042 1043 1044
  DBUG_VOID_RETURN;
}

unknown's avatar
SCRUM  
unknown committed
1045 1046 1047 1048 1049 1050 1051
bool Protocol_simple::store_null()
{
  *(next_field++)= NULL;
  ++next_mysql_field;
  return false;
}

unknown's avatar
SCRUM  
unknown committed
1052 1053
bool Protocol::net_store_data(const char *from, uint length)
{
unknown's avatar
unknown committed
1054
  char *field_buf;
unknown's avatar
unknown committed
1055 1056 1057
  if (!thd->mysql)            // bootstrap file handling
    return false;

unknown's avatar
SCRUM  
unknown committed
1058
  if (!(field_buf=alloc_root(alloc, length + sizeof(uint) + 1)))
unknown's avatar
SCRUM  
unknown committed
1059
    return true;
unknown's avatar
unknown committed
1060 1061
  *(uint *)field_buf= length;
  *next_field= field_buf + sizeof(uint);
unknown's avatar
SCRUM  
unknown committed
1062
  memcpy(*next_field, from, length);
unknown's avatar
SCRUM  
unknown committed
1063
  (*next_field)[length]= 0;
unknown's avatar
SCRUM  
unknown committed
1064 1065 1066 1067 1068 1069 1070
  if (next_mysql_field->max_length < length)
    next_mysql_field->max_length=length;
  ++next_field;
  ++next_mysql_field;
  return false;
}