lib_sql.cc 26.1 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
}

unknown's avatar
unknown committed
31 32 33
#if defined (__WIN__)
#include "../sql/mysqld.cpp"
#else
34
#include "../sql/mysqld.cc"
unknown's avatar
unknown committed
35
#endif
36

unknown's avatar
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);
unknown's avatar
unknown committed
40
C_MODE_START
41
#include <mysql.h>
unknown's avatar
unknown committed
42
#undef ER
43
#include "errmsg.h"
unknown's avatar
SCRUM  
unknown committed
44
#include <sql_common.h>
45
#include "embedded_priv.h"
unknown's avatar
unknown committed
46

47 48
static my_bool emb_read_query_result(MYSQL *mysql);

unknown's avatar
unknown committed
49 50
C_MODE_END

51
void THD::clear_data_list()
52
{
53
  while (first_data)
54
  {
55 56 57
    MYSQL_DATA *data= first_data;
    first_data= data->embedded_info->next;
    free_rows(data);
58
  }
59 60 61 62 63
  data_tail= &first_data;
  free_rows(cur_data);
  cur_data= 0;
}

unknown's avatar
unknown committed
64
C_MODE_START
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89

/*
  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));
90 91
}

unknown's avatar
unknown committed
92
static my_bool
unknown's avatar
SCRUM  
unknown committed
93 94 95
emb_advanced_command(MYSQL *mysql, enum enum_server_command command,
		     const char *header, ulong header_length,
		     const char *arg, ulong arg_length, my_bool skip_check)
96
{
97
  my_bool result= 1;
98
  THD *thd=(THD *) mysql->thd;
unknown's avatar
unknown committed
99
  NET *net= &mysql->net;
100

101
  thd->clear_data_list();
102 103 104
  /* Check that we are calling the client functions in right order */
  if (mysql->status != MYSQL_STATUS_READY)
  {
unknown's avatar
unknown committed
105 106
    strmov(net->last_error,
	   ER(net->last_errno=CR_COMMANDS_OUT_OF_SYNC));
107 108 109 110
    return 1;
  }

  /* Clear result variables */
unknown's avatar
unknown committed
111
  thd->clear_error();
112
  mysql->affected_rows= ~(my_ulonglong) 0;
unknown's avatar
SCRUM  
unknown committed
113
  mysql->field_count= 0;
114
  net->last_errno= 0;
115

116
  thd->store_globals();				// Fix if more than one connect
unknown's avatar
unknown committed
117 118 119 120 121 122
  /* 
     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
123
  free_old_query(mysql);
unknown's avatar
unknown committed
124 125 126 127

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

133
  thd->net.no_send_error= 0;
unknown's avatar
SCRUM  
unknown committed
134
  result= dispatch_command(command, thd, (char *) arg, arg_length + 1);
135
  thd->cur_data= 0;
unknown's avatar
unknown committed
136

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

140
  return result;
141 142
}

143 144
static void emb_flush_use_result(MYSQL *mysql)
{
145 146
  THD *thd= (THD*) mysql->thd;
  if (thd->cur_data)
147
  {
148 149 150 151 152 153 154
    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;
155 156 157 158
    free_rows(data);
  }
}

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

/*
  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
175
static MYSQL_DATA *
unknown's avatar
SCRUM  
unknown committed
176
emb_read_rows(MYSQL *mysql, MYSQL_FIELD *mysql_fields __attribute__((unused)),
unknown's avatar
SCRUM  
unknown committed
177
	      unsigned int fields __attribute__((unused)))
unknown's avatar
SCRUM  
unknown committed
178
{
179 180 181
  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
182
  {
183 184 185 186
    embedded_get_error(mysql, result);
    return NULL;
  }
  *result->embedded_info->prev_ptr= NULL;
unknown's avatar
SCRUM  
unknown committed
187 188 189
  return result;
}

190

unknown's avatar
unknown committed
191
static MYSQL_FIELD *emb_list_fields(MYSQL *mysql)
unknown's avatar
SCRUM  
unknown committed
192
{
193 194 195 196 197 198 199 200
  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
201 202 203
  return mysql->fields;
}

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

unknown's avatar
SCRUM  
unknown committed
209 210
  stmt->stmt_id= thd->client_stmt_id;
  stmt->param_count= thd->client_param_count;
211
  stmt->field_count= 0;
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((gptr) 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 264 265 266 267 268 269 270 271 272 273 274 275
  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
276

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

  return 0;
}

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

295
  int4store(header, stmt->stmt_id);
296 297
  header[4]= stmt->flags;
  thd= (THD*)stmt->mysql->thd;
unknown's avatar
SCRUM  
unknown committed
298
  thd->client_param_count= stmt->param_count;
unknown's avatar
unknown committed
299
  thd->client_params= stmt->params;
300
  if (emb_advanced_command(stmt->mysql, COM_STMT_EXECUTE,0,0,
301
                           header, sizeof(header), 1) ||
302
      emb_read_query_result(stmt->mysql))
unknown's avatar
SCRUM  
unknown committed
303 304 305 306 307
  {
    NET *net= &stmt->mysql->net;
    set_stmt_errmsg(stmt, net->last_error, net->last_errno, net->sqlstate);
    DBUG_RETURN(1);
  }
308 309
  stmt->affected_rows= stmt->mysql->affected_rows;
  stmt->insert_id= stmt->mysql->insert_id;
310 311
  stmt->server_status= stmt->mysql->server_status;

unknown's avatar
SCRUM  
unknown committed
312 313 314
  DBUG_RETURN(0);
}

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

327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350
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
351
int emb_unbuffered_fetch(MYSQL *mysql, char **row)
unknown's avatar
SCRUM  
unknown committed
352
{
353 354 355 356 357 358 359 360
  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
361 362 363 364 365
  if (!data || !data->data)
  {
    *row= NULL;
    if (data)
    {
366 367
      thd->cur_data= thd->first_data;
      thd->first_data= data->embedded_info->next;
unknown's avatar
SCRUM  
unknown committed
368 369 370 371 372 373 374 375 376 377 378
      free_rows(data);
    }
  }
  else
  {
    *row= (char *)data->data->data;
    data->data= data->data->next;
  }
  return 0;
}

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

unknown's avatar
unknown committed
389
static const char * emb_read_statistics(MYSQL *mysql)
unknown's avatar
unknown committed
390 391 392 393 394
{
  THD *thd= (THD*)mysql->thd;
  return thd->net.last_error;
}

unknown's avatar
unknown committed
395

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


402 403 404 405 406 407 408
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
409 410
MYSQL_METHODS embedded_methods= 
{
411
  emb_read_query_result,
unknown's avatar
SCRUM  
unknown committed
412 413
  emb_advanced_command,
  emb_read_rows,
414
  emb_store_result,
unknown's avatar
SCRUM  
unknown committed
415
  emb_fetch_lengths, 
416
  emb_flush_use_result,
unknown's avatar
SCRUM  
unknown committed
417
  emb_list_fields,
unknown's avatar
SCRUM  
unknown committed
418
  emb_read_prepare_result,
unknown's avatar
unknown committed
419
  emb_stmt_execute,
unknown's avatar
SCRUM  
unknown committed
420
  emb_read_binary_rows,
unknown's avatar
SCRUM  
unknown committed
421
  emb_unbuffered_fetch,
unknown's avatar
unknown committed
422
  emb_free_embedded_thd,
unknown's avatar
unknown committed
423
  emb_read_statistics,
424 425 426
  emb_read_query_result,
  emb_read_change_user_result,
  emb_read_rows_from_cursor
unknown's avatar
SCRUM  
unknown committed
427 428
};

unknown's avatar
unknown committed
429
C_MODE_END
430

431
void THD::clear_error()
432
{
433 434 435
  net.last_error[0]= 0;
  net.last_errno= 0;
  net.report_error= 0;
436 437
}

438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
/*
  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
465 466 467
extern "C"
{

468
char **		copy_arguments_ptr= 0; 
unknown's avatar
unknown committed
469

470
int init_embedded_server(int argc, char **argv, char **groups)
unknown's avatar
unknown committed
471
{
unknown's avatar
unknown committed
472 473 474 475
  /*
    This mess is to allow people to call the init function without
    having to mess with a fake argv
   */
unknown's avatar
unknown committed
476 477 478 479 480
  int *argcp;
  char ***argvp;
  int fake_argc = 1;
  char *fake_argv[] = { (char *)"", 0 };
  const char *fake_groups[] = { "server", "embedded", 0 };
481
  my_bool acl_error;
unknown's avatar
unknown committed
482 483
  if (argc)
  {
unknown's avatar
unknown committed
484 485
    argcp= &argc;
    argvp= (char***) &argv;
unknown's avatar
unknown committed
486 487 488
  }
  else
  {
unknown's avatar
unknown committed
489 490
    argcp= &fake_argc;
    argvp= (char ***) &fake_argv;
unknown's avatar
unknown committed
491 492
  }
  if (!groups)
unknown's avatar
unknown committed
493
    groups= (char**) fake_groups;
unknown's avatar
unknown committed
494

495
  my_progname= (char *)"mysql_embedded";
unknown's avatar
unknown committed
496

497 498 499 500 501 502
  /*
    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
503
  if (init_common_variables("my", *argcp, *argvp, (const char **)groups))
unknown's avatar
unknown committed
504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528
  {
    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;

529
  acl_error= 0;
unknown's avatar
unknown committed
530
#ifndef NO_EMBEDDED_ACCESS_CHECKS
531
  if (!(acl_error= acl_init(opt_noacl)) &&
532
      !opt_noacl)
533
    (void) grant_init();
534 535
#endif
  if (acl_error || my_tz_init((THD *)0, default_tz_name, opt_bootstrap))
unknown's avatar
unknown committed
536 537 538 539
  {
    mysql_server_end();
    return 1;
  }
unknown's avatar
unknown committed
540

unknown's avatar
unknown committed
541 542 543 544
  init_max_user_conn();
  init_update_queries();

#ifdef HAVE_DLOPEN
unknown's avatar
unknown committed
545
#ifndef NO_EMBEDDED_ACCESS_CHECKS
unknown's avatar
unknown committed
546
  if (!opt_noacl)
unknown's avatar
unknown committed
547
#endif
unknown's avatar
unknown committed
548 549 550 551 552 553 554
    udf_init();
#endif

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

  if (
#ifdef HAVE_BERKELEY_DB
555
      (have_berkeley_db == SHOW_OPTION_YES) ||
unknown's avatar
unknown committed
556 557 558 559 560 561 562 563
#endif
      (flush_time && flush_time != ~(ulong) 0L))
  {
    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
564 565 566 567 568 569 570 571 572
  if (opt_init_file)
  {
    if (read_init_file(opt_init_file))
    {
      mysql_server_end();
      return 1;
    }
  }

unknown's avatar
unknown committed
573 574 575
  return 0;
}

576
void end_embedded_server()
577
{
unknown's avatar
unknown committed
578 579
  my_free((char*) copy_arguments_ptr, MYF(MY_ALLOW_ZERO_PTR));
  copy_arguments_ptr=0;
unknown's avatar
unknown committed
580
  clean_up(0);
unknown's avatar
unknown committed
581 582
}

unknown's avatar
unknown committed
583
} /* extern "C" */
584

585
C_MODE_START
586 587
void init_embedded_mysql(MYSQL *mysql, int client_flag, char *db)
{
588
  THD *thd = (THD *)mysql->thd;
589
  thd->mysql= mysql;
unknown's avatar
unknown committed
590
  mysql->server_version= server_version;
591
  init_alloc_root(&mysql->field_alloc, 8192, 0);
592
}
593

594
void *create_embedded_thd(int client_flag, char *db)
595 596 597 598
{
  THD * thd= new THD;
  thd->thread_id= thread_id++;

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

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

609 610
/* TODO - add init_connect command execution */

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

  thd->db= db;
unknown's avatar
unknown committed
621
  thd->db_length= db ? strip_sp(db) : 0;
unknown's avatar
unknown committed
622
#ifndef NO_EMBEDDED_ACCESS_CHECKS
623 624
  thd->security_ctx->db_access= DB_ACLS;
  thd->security_ctx->master_access= ~NO_ACCESS;
unknown's avatar
unknown committed
625
#endif
626 627 628 629
  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
630

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

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

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

661 662
  if (mysql->options.client_ip)
  {
663 664
    sctx->host= my_strdup(mysql->options.client_ip, MYF(0));
    sctx->ip= my_strdup(sctx->host, MYF(0));
665 666
  }
  else
667 668
    sctx->host= (char*)my_localhost;
  sctx->host_or_ip= sctx->host;
unknown's avatar
unknown committed
669

670
  if (acl_check_host(sctx->host, sctx->ip))
unknown's avatar
unknown committed
671 672 673 674 675
  {
    result= ER_HOST_NOT_PRIVILEGED;
    goto err;
  }

676
  sctx->user= my_strdup(mysql->user, MYF(0));
unknown's avatar
unknown committed
677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701
  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, 
			 scramble_buff, passwd_len, thd->db, true)))
     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

702
C_MODE_END
703

704 705 706 707 708 709 710 711 712 713 714 715 716
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
717
                             tocs, from, length, fromcs, &dummy_err);
718 719 720 721 722 723 724 725 726 727 728 729
  }
  else
  {
    result= (char *)alloc_root(root, length + 1);
    memcpy(result, from, length);
  }

  result[length]= 0;
  return result;
}


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 840 841 842 843 844 845 846 847
/*
  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
848
bool Protocol::send_fields(List<Item> *list, uint flags)
unknown's avatar
unknown committed
849 850 851
{
  List_iterator_fast<Item> it(*list);
  Item                     *item;
unknown's avatar
SCRUM  
unknown committed
852 853
  MYSQL_FIELD              *client_field;
  MEM_ROOT                 *field_alloc;
854 855
  CHARSET_INFO             *thd_cs= thd->variables.character_set_results;
  CHARSET_INFO             *cs= system_charset_info;
856
  MYSQL_DATA               *data;
unknown's avatar
SCRUM  
unknown committed
857
  DBUG_ENTER("send_fields");
unknown's avatar
unknown committed
858

859
  if (!thd->mysql)            // bootstrap file handling
unknown's avatar
unknown committed
860 861
    DBUG_RETURN(0);

862 863 864 865 866 867 868 869 870
  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
871 872 873 874 875 876 877
    goto err;

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

878 879 880 881
    /* Keep things compatible for old clients */
    if (server_field.type == MYSQL_TYPE_VARCHAR)
      server_field.type= MYSQL_TYPE_VAR_STRING;

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

914
    client_field->catalog= dup_str_aux(field_alloc, "def", 3, cs, thd_cs);
unknown's avatar
SCRUM  
unknown committed
915
    client_field->catalog_length= 3;
unknown's avatar
unknown committed
916

unknown's avatar
unknown committed
917 918 919
    if (INTERNAL_NUM_FIELD(client_field))
      client_field->flags|= NUM_FLAG;

920
    if (flags & (int) Protocol::SEND_DEFAULTS)
unknown's avatar
unknown committed
921 922 923 924 925
    {
      char buff[80];
      String tmp(buff, sizeof(buff), default_charset_info), *res;

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

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

unknown's avatar
SCRUM  
unknown committed
946
  DBUG_RETURN(prepare_for_send(list));
unknown's avatar
unknown committed
947
 err:
unknown's avatar
unknown committed
948
  my_error(ER_OUT_OF_RESOURCES, MYF(0));        /* purecov: inspected */
unknown's avatar
SCRUM  
unknown committed
949
  DBUG_RETURN(1);				/* purecov: inspected */
unknown's avatar
unknown committed
950 951
}

unknown's avatar
SCRUM  
unknown committed
952
bool Protocol::write()
unknown's avatar
unknown committed
953
{
unknown's avatar
unknown committed
954 955 956
  if (!thd->mysql)            // bootstrap file handling
    return false;

unknown's avatar
SCRUM  
unknown committed
957 958
  *next_field= 0;
  return false;
unknown's avatar
unknown committed
959
}
960

unknown's avatar
unknown committed
961 962 963
bool Protocol_prep::write()
{
  MYSQL_ROWS *cur;
964
  MYSQL_DATA *data= thd->cur_data;
unknown's avatar
unknown committed
965 966

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

977 978
  *data->embedded_info->prev_ptr= cur;
  data->embedded_info->prev_ptr= &cur->next;
unknown's avatar
SCRUM  
unknown committed
979 980
  cur->next= 0;
  
unknown's avatar
unknown committed
981 982 983
  return false;
}

984
void
985
send_ok(THD *thd,ha_rows affected_rows,ulonglong id,const char *message)
986 987
{
  DBUG_ENTER("send_ok");
988 989 990
  MYSQL_DATA *data;
  MYSQL *mysql= thd->mysql;
  
unknown's avatar
unknown committed
991 992
  if (!mysql)            // bootstrap file handling
    DBUG_VOID_RETURN;
993 994 995 996 997 998
  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;
999
  if (message)
1000 1001 1002 1003 1004
    strmake(data->embedded_info->info, message,
            sizeof(data->embedded_info->info)-1);

  write_eof_packet(thd);
  thd->cur_data= 0;
1005 1006 1007
  DBUG_VOID_RETURN;
}

1008
void
1009
send_eof(THD *thd)
1010
{
1011 1012
  write_eof_packet(thd);
  thd->cur_data= 0;
1013 1014
}

1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027

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
1028 1029
void Protocol_simple::prepare_for_resend()
{
unknown's avatar
SCRUM  
unknown committed
1030
  MYSQL_ROWS *cur;
1031
  MYSQL_DATA *data= thd->cur_data;
unknown's avatar
SCRUM  
unknown committed
1032 1033
  DBUG_ENTER("send_data");

unknown's avatar
SCRUM  
unknown committed
1034
  data->rows++;
unknown's avatar
SCRUM  
unknown committed
1035 1036 1037 1038 1039 1040 1041
  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));

1042 1043
  *data->embedded_info->prev_ptr= cur;
  data->embedded_info->prev_ptr= &cur->next;
unknown's avatar
SCRUM  
unknown committed
1044
  next_field=cur->data;
1045
  next_mysql_field= data->embedded_info->fields_list;
unknown's avatar
SCRUM  
unknown committed
1046
err:
unknown's avatar
SCRUM  
unknown committed
1047 1048 1049
  DBUG_VOID_RETURN;
}

unknown's avatar
SCRUM  
unknown committed
1050 1051 1052 1053 1054 1055 1056
bool Protocol_simple::store_null()
{
  *(next_field++)= NULL;
  ++next_mysql_field;
  return false;
}

unknown's avatar
SCRUM  
unknown committed
1057 1058
bool Protocol::net_store_data(const char *from, uint length)
{
unknown's avatar
unknown committed
1059
  char *field_buf;
unknown's avatar
unknown committed
1060 1061 1062
  if (!thd->mysql)            // bootstrap file handling
    return false;

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