MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
lib_sql.cc
1 /*
2  * Copyright (c) 2000
3  * SWsoft company
4  *
5  * This material is provided "as is", with absolutely no warranty expressed
6  * or implied. Any use is at your own risk.
7  *
8  * Permission to use or copy this software for any purpose is hereby granted
9  * without fee, provided the above notices are retained on all copies.
10  * Permission to modify the code and to distribute modified code is granted,
11  * provided the above notices are retained, and a notice that the code was
12  * modified is included with the above copyright notice.
13  *
14 
15  This code was modified by the MySQL team
16 */
17 
18 /*
19  The following is needed to not cause conflicts when we include mysqld.cc
20 */
21 
22 extern "C"
23 {
24  extern unsigned long max_allowed_packet, net_buffer_length;
25 }
26 
27 #include "../sql/mysqld.cc"
28 
29 extern "C" {
30 
31 #include <mysql.h>
32 #undef ER
33 #include "errmsg.h"
34 #include "embedded_priv.h"
35 
36 } // extern "C"
37 
38 #include <algorithm>
39 
40 using std::min;
41 using std::max;
42 
43 extern "C" {
44 
45 extern unsigned int mysql_server_last_errno;
46 extern char mysql_server_last_error[MYSQL_ERRMSG_SIZE];
47 static my_bool emb_read_query_result(MYSQL *mysql);
48 
49 
50 void unireg_clear(int exit_code)
51 {
52  DBUG_ENTER("unireg_clear");
53  clean_up(!opt_help && (exit_code || !opt_bootstrap)); /* purecov: inspected */
54  my_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
55  DBUG_VOID_RETURN;
56 }
57 
58 /*
59  Wrapper error handler for embedded server to call client/server error
60  handler based on whether thread is in client/server context
61 */
62 
63 static void embedded_error_handler(uint error, const char *str, myf MyFlags)
64 {
65  DBUG_ENTER("embedded_error_handler");
66 
67  /*
68  If current_thd is NULL, it means restore_global has been called and
69  thread is in client context, then call client error handler else call
70  server error handler.
71  */
72  DBUG_RETURN(current_thd ? my_message_sql(error, str, MyFlags):
73  my_message_stderr(error, str, MyFlags));
74 }
75 
76 
77 /*
78  Reads error information from the MYSQL_DATA and puts
79  it into proper MYSQL members
80 
81  SYNOPSIS
82  embedded_get_error()
83  mysql connection handler
84  data query result
85 
86  NOTES
87  after that function error information will be accessible
88  with usual functions like mysql_error()
89  data is my_free-d in this function
90  most of the data is stored in data->embedded_info structure
91 */
92 
93 void embedded_get_error(MYSQL *mysql, MYSQL_DATA *data)
94 {
95  NET *net= &mysql->net;
96  struct embedded_query_result *ei= data->embedded_info;
97  net->last_errno= ei->last_errno;
98  strmake(net->last_error, ei->info, sizeof(net->last_error)-1);
99  memcpy(net->sqlstate, ei->sqlstate, sizeof(net->sqlstate));
100  mysql->server_status= ei->server_status;
101  my_free(data);
102 }
103 
104 static my_bool
105 emb_advanced_command(MYSQL *mysql, enum enum_server_command command,
106  const uchar *header, ulong header_length,
107  const uchar *arg, ulong arg_length, my_bool skip_check,
108  MYSQL_STMT *stmt)
109 {
110  my_bool result= 1;
111  THD *thd=(THD *) mysql->thd;
112  NET *net= &mysql->net;
113  my_bool stmt_skip= stmt ? stmt->state != MYSQL_STMT_INIT_DONE : FALSE;
114 
115  if (!thd)
116  {
117  /* Do "reconnect" if possible */
118  if (mysql_reconnect(mysql) || stmt_skip)
119  return 1;
120  thd= (THD *) mysql->thd;
121  }
122 
123 #if defined(ENABLED_PROFILING)
124  thd->profiling.start_new_query();
125 #endif
126 
127  thd->clear_data_list();
128  /* Check that we are calling the client functions in right order */
129  if (mysql->status != MYSQL_STATUS_READY)
130  {
131  set_mysql_error(mysql, CR_COMMANDS_OUT_OF_SYNC, unknown_sqlstate);
132  result= 1;
133  goto end;
134  }
135 
136  /* Clear result variables */
137  thd->clear_error();
138  thd->get_stmt_da()->reset_diagnostics_area();
139  mysql->affected_rows= ~(my_ulonglong) 0;
140  mysql->field_count= 0;
141  net_clear_error(net);
142  thd->current_stmt= stmt;
143 
144  thd->thread_stack= (char*) &thd;
145  thd->store_globals(); // Fix if more than one connect
146  /*
147  We have to call free_old_query before we start to fill mysql->fields
148  for new query. In the case of embedded server we collect field data
149  during query execution (not during data retrieval as it is in remote
150  client). So we have to call free_old_query here
151  */
152  free_old_query(mysql);
153 
154  thd->extra_length= arg_length;
155  thd->extra_data= (char *)arg;
156  if (header)
157  {
158  arg= header;
159  arg_length= header_length;
160  }
161 
162  result= dispatch_command(command, thd, (char *) arg, arg_length);
163  thd->cur_data= 0;
164  thd->mysys_var= NULL;
165 
166  if (!skip_check)
167  result= thd->is_error() ? -1 : 0;
168 
169  thd->mysys_var= 0;
170 
171 #if defined(ENABLED_PROFILING)
172  thd->profiling.finish_current_query();
173 #endif
174 
175 end:
176  thd->restore_globals();
177  return result;
178 }
179 
180 static void emb_flush_use_result(MYSQL *mysql, my_bool)
181 {
182  THD *thd= (THD*) mysql->thd;
183  if (thd->cur_data)
184  {
185  free_rows(thd->cur_data);
186  thd->cur_data= 0;
187  }
188  else if (thd->first_data)
189  {
190  MYSQL_DATA *data= thd->first_data;
191  thd->first_data= data->embedded_info->next;
192  free_rows(data);
193  }
194 }
195 
196 
197 /*
198  reads dataset from the next query result
199 
200  SYNOPSIS
201  emb_read_rows()
202  mysql connection handle
203  other parameters are not used
204 
205  NOTES
206  It just gets next MYSQL_DATA from the result's queue
207 
208  RETURN
209  pointer to MYSQL_DATA with the coming recordset
210 */
211 
212 static MYSQL_DATA *
213 emb_read_rows(MYSQL *mysql, MYSQL_FIELD *mysql_fields __attribute__((unused)),
214  unsigned int fields __attribute__((unused)))
215 {
216  MYSQL_DATA *result= ((THD*)mysql->thd)->cur_data;
217  ((THD*)mysql->thd)->cur_data= 0;
218  if (result->embedded_info->last_errno)
219  {
220  embedded_get_error(mysql, result);
221  return NULL;
222  }
223  *result->embedded_info->prev_ptr= NULL;
224  return result;
225 }
226 
227 
228 static MYSQL_FIELD *emb_list_fields(MYSQL *mysql)
229 {
230  MYSQL_DATA *res;
231  if (emb_read_query_result(mysql))
232  return 0;
233  res= ((THD*) mysql->thd)->cur_data;
234  ((THD*) mysql->thd)->cur_data= 0;
235  mysql->field_alloc= res->alloc;
236  my_free(res);
237  mysql->status= MYSQL_STATUS_READY;
238  return mysql->fields;
239 }
240 
241 static my_bool emb_read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt)
242 {
243  THD *thd= (THD*) mysql->thd;
244  MYSQL_DATA *res;
245 
246  stmt->stmt_id= thd->client_stmt_id;
247  stmt->param_count= thd->client_param_count;
248  stmt->field_count= 0;
249  mysql->warning_count= thd->get_stmt_da()->current_statement_warn_count();
250 
251  if (thd->first_data)
252  {
253  if (emb_read_query_result(mysql))
254  return 1;
255  stmt->field_count= mysql->field_count;
256  mysql->status= MYSQL_STATUS_READY;
257  res= thd->cur_data;
258  thd->cur_data= NULL;
259  if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT))
260  mysql->server_status|= SERVER_STATUS_IN_TRANS;
261 
262  stmt->fields= mysql->fields;
263  stmt->mem_root= res->alloc;
264  mysql->fields= NULL;
265  my_free(res);
266  }
267 
268  return 0;
269 }
270 
271 /**************************************************************************
272  Get column lengths of the current row
273  If one uses mysql_use_result, res->lengths contains the length information,
274  else the lengths are calculated from the offset between pointers.
275 **************************************************************************/
276 
277 static void emb_fetch_lengths(ulong *to, MYSQL_ROW column,
278  unsigned int field_count)
279 {
280  MYSQL_ROW end;
281 
282  for (end=column + field_count; column != end ; column++,to++)
283  *to= *column ? *(uint *)((*column) - sizeof(uint)) : 0;
284 }
285 
286 static my_bool emb_read_query_result(MYSQL *mysql)
287 {
288  THD *thd= (THD*) mysql->thd;
289  MYSQL_DATA *res= thd->first_data;
290  DBUG_ASSERT(!thd->cur_data);
291  thd->first_data= res->embedded_info->next;
292  if (res->embedded_info->last_errno &&
293  !res->embedded_info->fields_list)
294  {
295  embedded_get_error(mysql, res);
296  return 1;
297  }
298 
299  mysql->warning_count= res->embedded_info->warning_count;
300  mysql->server_status= res->embedded_info->server_status;
301  mysql->field_count= res->fields;
302  if (!(mysql->fields= res->embedded_info->fields_list))
303  {
304  mysql->affected_rows= res->embedded_info->affected_rows;
305  mysql->insert_id= res->embedded_info->insert_id;
306  }
307  net_clear_error(&mysql->net);
308  mysql->info= 0;
309 
310  if (res->embedded_info->info[0])
311  {
312  strmake(mysql->info_buffer, res->embedded_info->info, MYSQL_ERRMSG_SIZE-1);
313  mysql->info= mysql->info_buffer;
314  }
315 
316  if (res->embedded_info->fields_list)
317  {
318  mysql->status=MYSQL_STATUS_GET_RESULT;
319  thd->cur_data= res;
320  }
321  else
322  my_free(res);
323 
324  return 0;
325 }
326 
327 static int emb_stmt_execute(MYSQL_STMT *stmt)
328 {
329  DBUG_ENTER("emb_stmt_execute");
330  uchar header[5];
331  THD *thd;
332  my_bool res;
333 
334  int4store(header, stmt->stmt_id);
335  header[4]= (uchar) stmt->flags;
336  thd= (THD*)stmt->mysql->thd;
337  thd->client_param_count= stmt->param_count;
338  thd->client_params= stmt->params;
339 
340  res= test(emb_advanced_command(stmt->mysql, COM_STMT_EXECUTE, 0, 0,
341  header, sizeof(header), 1, stmt) ||
342  emb_read_query_result(stmt->mysql));
343  stmt->affected_rows= stmt->mysql->affected_rows;
344  stmt->insert_id= stmt->mysql->insert_id;
345  stmt->server_status= stmt->mysql->server_status;
346  if (res)
347  {
348  NET *net= &stmt->mysql->net;
349  set_stmt_errmsg(stmt, net);
350  DBUG_RETURN(1);
351  }
352  else if (stmt->mysql->status == MYSQL_STATUS_GET_RESULT)
353  stmt->mysql->status= MYSQL_STATUS_STATEMENT_GET_RESULT;
354  DBUG_RETURN(0);
355 }
356 
357 int emb_read_binary_rows(MYSQL_STMT *stmt)
358 {
359  MYSQL_DATA *data;
360  if (!(data= emb_read_rows(stmt->mysql, 0, 0)))
361  {
362  set_stmt_errmsg(stmt, &stmt->mysql->net);
363  return 1;
364  }
365  stmt->result= *data;
366  my_free(data);
367  set_stmt_errmsg(stmt, &stmt->mysql->net);
368  return 0;
369 }
370 
371 int emb_read_rows_from_cursor(MYSQL_STMT *stmt)
372 {
373  MYSQL *mysql= stmt->mysql;
374  THD *thd= (THD*) mysql->thd;
375  MYSQL_DATA *res= thd->first_data;
376  DBUG_ASSERT(!thd->first_data->embedded_info->next);
377  thd->first_data= 0;
378  if (res->embedded_info->last_errno)
379  {
380  embedded_get_error(mysql, res);
381  set_stmt_errmsg(stmt, &mysql->net);
382  return 1;
383  }
384 
385  thd->cur_data= res;
386  mysql->warning_count= res->embedded_info->warning_count;
387  mysql->server_status= res->embedded_info->server_status;
388  net_clear_error(&mysql->net);
389 
390  return emb_read_binary_rows(stmt);
391 }
392 
393 int emb_unbuffered_fetch(MYSQL *mysql, char **row)
394 {
395  THD *thd= (THD*) mysql->thd;
396  MYSQL_DATA *data= thd->cur_data;
397  if (data && data->embedded_info->last_errno)
398  {
399  embedded_get_error(mysql, data);
400  thd->cur_data= 0;
401  return 1;
402  }
403  if (!data || !data->data)
404  {
405  *row= NULL;
406  if (data)
407  {
408  thd->cur_data= thd->first_data;
409  thd->first_data= data->embedded_info->next;
410  free_rows(data);
411  }
412  }
413  else
414  {
415  *row= (char *)data->data->data;
416  data->data= data->data->next;
417  }
418  return 0;
419 }
420 
421 static void emb_free_embedded_thd(MYSQL *mysql)
422 {
423  THD *thd= (THD*)mysql->thd;
424  thd->clear_data_list();
425  thd->store_globals();
426  thd->release_resources();
427 
428  mysql_mutex_lock(&LOCK_thread_count);
429  remove_global_thread(thd);
430  mysql_mutex_unlock(&LOCK_thread_count);
431 
432  delete thd;
433  my_pthread_setspecific_ptr(THR_THD, 0);
434  mysql->thd=0;
435 }
436 
437 static const char * emb_read_statistics(MYSQL *mysql)
438 {
439  THD *thd= (THD*)mysql->thd;
440  return thd->is_error() ? thd->get_stmt_da()->message() : "";
441 }
442 
443 
444 static MYSQL_RES * emb_store_result(MYSQL *mysql)
445 {
446  return mysql_store_result(mysql);
447 }
448 
449 int emb_read_change_user_result(MYSQL *mysql)
450 {
451  mysql->net.read_pos= (uchar*)""; // fake an OK packet
452  return mysql_errno(mysql) ? static_cast<int>packet_error :
453  1 /* length of the OK packet */;
454 }
455 
456 MYSQL_METHODS embedded_methods=
457 {
458  emb_read_query_result,
459  emb_advanced_command,
460  emb_read_rows,
461  emb_store_result,
462  emb_fetch_lengths,
463  emb_flush_use_result,
464  emb_read_change_user_result,
465  emb_list_fields,
466  emb_read_prepare_result,
467  emb_stmt_execute,
468  emb_read_binary_rows,
469  emb_unbuffered_fetch,
470  emb_free_embedded_thd,
471  emb_read_statistics,
472  emb_read_query_result,
473  emb_read_rows_from_cursor
474 };
475 
476 /*
477  Make a copy of array and the strings array points to
478 */
479 
480 char **copy_arguments(int argc, char **argv)
481 {
482  uint length= 0;
483  char **from, **res, **end= argv+argc;
484 
485  for (from=argv ; from != end ; from++)
486  length+= strlen(*from);
487 
488  if ((res= (char**) my_malloc(sizeof(argv)*(argc+1)+length+argc,
489  MYF(MY_WME))))
490  {
491  char **to= res, *to_str= (char*) (res+argc+1);
492  for (from=argv ; from != end ;)
493  {
494  *to++= to_str;
495  to_str= strmov(to_str, *from++)+1;
496  }
497  *to= 0; // Last ptr should be null
498  }
499  return res;
500 }
501 
502 char ** copy_arguments_ptr= 0;
503 
504 int init_embedded_server(int argc, char **argv, char **groups)
505 {
506  /*
507  This mess is to allow people to call the init function without
508  having to mess with a fake argv
509  */
510  int *argcp= NULL;
511  char ***argvp= NULL;
512  int fake_argc= 1;
513  char *fake_argv[2];
514  char **foo= &fake_argv[0];
515  char fake_server[]= "server";
516  char fake_embedded[]= "embedded";
517  char *fake_groups[]= { fake_server, fake_embedded, NULL };
518  char fake_name[]= "fake_name";
519  my_bool acl_error;
520 
521  if (my_thread_init())
522  return 1;
523 
524  if (argc)
525  {
526  argcp= &argc;
527  argvp= &argv;
528  }
529  else
530  {
531  fake_argv[0]= fake_name;
532  fake_argv[1]= NULL;
533 
534  argcp= &fake_argc;
535  argvp= &foo;
536  }
537  if (!groups)
538  groups= fake_groups;
539 
540  my_progname= "mysql_embedded";
541 
542  /*
543  Perform basic logger initialization logger. Should be called after
544  MY_INIT, as it initializes mutexes. Log tables are inited later.
545  */
546  logger.init_base();
547 
548  orig_argc= *argcp;
549  orig_argv= *argvp;
550  if (load_defaults("my", (const char **)groups, argcp, argvp))
551  return 1;
552  defaults_argc= *argcp;
553  defaults_argv= *argvp;
554  remaining_argc= *argcp;
555  remaining_argv= *argvp;
556 
557  /* Must be initialized early for comparison of options name */
558  system_charset_info= &my_charset_utf8_general_ci;
559  sys_var_init();
560 
561  int ho_error= handle_early_options();
562  if (ho_error != 0)
563  {
564  buffered_logs.print();
565  buffered_logs.cleanup();
566  return 1;
567  }
568 
569  ulong requested_open_files_dummy;
570  adjust_related_options(&requested_open_files_dummy);
571 
572  if (init_common_variables())
573  {
574  mysql_server_end();
575  return 1;
576  }
577 
578  mysql_data_home= mysql_real_data_home;
579  mysql_data_home_len= mysql_real_data_home_len;
580 
581  /* Get default temporary directory */
582  opt_mysql_tmpdir=getenv("TMPDIR"); /* Use this if possible */
583 #if defined(__WIN__)
584  if (!opt_mysql_tmpdir)
585  opt_mysql_tmpdir=getenv("TEMP");
586  if (!opt_mysql_tmpdir)
587  opt_mysql_tmpdir=getenv("TMP");
588 #endif
589  if (!opt_mysql_tmpdir || !opt_mysql_tmpdir[0])
590  opt_mysql_tmpdir=(char*) P_tmpdir; /* purecov: inspected */
591 
592  init_ssl();
593  umask(((~my_umask) & 0666));
594  if (init_server_components())
595  {
596  mysql_server_end();
597  return 1;
598  }
599 
600  /*
601  Each server should have one UUID. We will create it automatically, if it
602  does not exist.
603  */
604  if (!opt_bootstrap && init_server_auto_options())
605  {
606  mysql_server_end();
607  return 1;
608  }
609 
610  /*
611  set error_handler_hook to embedded_error_handler wrapper.
612  */
613  error_handler_hook= embedded_error_handler;
614 
615  acl_error= 0;
616 #ifndef NO_EMBEDDED_ACCESS_CHECKS
617  if (!(acl_error= acl_init(opt_noacl)) &&
618  !opt_noacl)
619  (void) grant_init();
620 #endif
621  if (acl_error || my_tz_init((THD *)0, default_tz_name, opt_bootstrap))
622  {
623  mysql_server_end();
624  return 1;
625  }
626 
627  init_max_user_conn();
628  init_update_queries();
629 
630  if (!opt_bootstrap)
631  servers_init(0);
632 
633 #ifdef HAVE_DLOPEN
634 #ifndef NO_EMBEDDED_ACCESS_CHECKS
635  if (!opt_noacl)
636 #endif
637  udf_init();
638 #endif
639 
640  (void) thr_setconcurrency(concurrency); // 10 by default
641 
642  start_handle_manager();
643 
644  // FIXME initialize binlog_filter and rpl_filter if not already done
645  // corresponding delete is in clean_up()
646  if(!binlog_filter) binlog_filter = new Rpl_filter;
647  if(!rpl_filter) rpl_filter = new Rpl_filter;
648 
649  if (opt_init_file)
650  {
651  if (read_init_file(opt_init_file))
652  {
653  mysql_server_end();
654  return 1;
655  }
656  }
657 
658  execute_ddl_log_recovery();
659 
660  /* Signal successful initialization */
661  mysql_mutex_lock(&LOCK_server_started);
662  mysqld_server_started= 1;
663  mysql_cond_broadcast(&COND_server_started);
664  mysql_mutex_unlock(&LOCK_server_started);
665 
666 #ifdef WITH_NDBCLUSTER_STORAGE_ENGINE
667  /* engine specific hook, to be made generic */
668  if (ndb_wait_setup_func && ndb_wait_setup_func(opt_ndb_wait_setup))
669  {
670  sql_print_warning("NDB : Tables not available after %lu seconds."
671  " Consider increasing --ndb-wait-setup value",
672  opt_ndb_wait_setup);
673  }
674 #endif
675 
676  return 0;
677 }
678 
679 void end_embedded_server()
680 {
681  my_free(copy_arguments_ptr);
682  copy_arguments_ptr=0;
683  clean_up(0);
684 }
685 
686 
687 void init_embedded_mysql(MYSQL *mysql, int client_flag)
688 {
689  THD *thd = (THD *)mysql->thd;
690  thd->mysql= mysql;
691  mysql->server_version= server_version;
692  mysql->client_flag= client_flag;
693  init_alloc_root(&mysql->field_alloc, 8192, 0);
694 }
695 
707 void *create_embedded_thd(int client_flag)
708 {
709  THD * thd= new THD;
710  thd->thread_id= thd->variables.pseudo_thread_id= thread_id++;
711 
712  thd->thread_stack= (char*) &thd;
713  if (thd->store_globals())
714  {
715  fprintf(stderr,"store_globals failed.\n");
716  goto err;
717  }
718  lex_start(thd);
719 
720  /* TODO - add init_connect command execution */
721 
722  if (thd->variables.max_join_size == HA_POS_ERROR)
723  thd->variables.option_bits |= OPTION_BIG_SELECTS;
724  thd->proc_info=0; // Remove 'login'
725  thd->set_command(COM_SLEEP);
726  thd->set_time();
727  thd->init_for_queries();
728  thd->client_capabilities= client_flag;
729  thd->real_id= pthread_self();
730 
731  thd->db= NULL;
732  thd->db_length= 0;
733 #ifndef NO_EMBEDDED_ACCESS_CHECKS
734  thd->security_ctx->db_access= DB_ACLS;
735  thd->security_ctx->master_access= ~NO_ACCESS;
736 #endif
737  thd->cur_data= 0;
738  thd->first_data= 0;
739  thd->data_tail= &thd->first_data;
740  memset(&thd->net, 0, sizeof(thd->net));
741 
742  mysql_mutex_lock(&LOCK_thread_count);
743  add_global_thread(thd);
744  mysql_mutex_unlock(&LOCK_thread_count);
745  thd->mysys_var= 0;
746  return thd;
747 err:
748  delete(thd);
749  return NULL;
750 }
751 
752 
753 static void
754 emb_transfer_connect_attrs(MYSQL *mysql)
755 {
756 #ifdef HAVE_PSI_THREAD_INTERFACE
757  if (mysql->options.extension &&
758  mysql->options.extension->connection_attributes_length)
759  {
760  uchar *buf, *ptr;
761  THD *thd= (THD*)mysql->thd;
762  size_t length= mysql->options.extension->connection_attributes_length;
763 
764  /* 9 = max length of the serialized length */
765  ptr= buf= (uchar *) my_alloca(length + 9);
766  send_client_connect_attrs(mysql, buf);
767  net_field_length_ll(&ptr);
768  PSI_THREAD_CALL(set_thread_connect_attrs)((char *) ptr, length, thd->charset());
769  my_afree(buf);
770  }
771 #endif
772 }
773 
774 
775 #ifdef NO_EMBEDDED_ACCESS_CHECKS
776 int check_embedded_connection(MYSQL *mysql, const char *db)
777 {
778  int result;
779  LEX_STRING db_str = { (char*)db, db ? strlen(db) : 0 };
780  THD *thd= (THD*)mysql->thd;
781 
782  /* the server does the same as the client */
783  mysql->server_capabilities= mysql->client_flag;
784 
785  thd_init_client_charset(thd, mysql->charset->number);
786  thd->update_charset();
787  Security_context *sctx= thd->security_ctx;
788  sctx->set_host(my_localhost);
789  sctx->host_or_ip= sctx->get_host()->ptr();
790  strmake(sctx->priv_host, (char*) my_localhost, MAX_HOSTNAME-1);
791  strmake(sctx->priv_user, mysql->user, USERNAME_LENGTH-1);
792  sctx->user= my_strdup(mysql->user, MYF(0));
793  sctx->proxy_user[0]= 0;
794  sctx->master_access= GLOBAL_ACLS; // Full rights
795  emb_transfer_connect_attrs(mysql);
796  /* Change database if necessary */
797  if (!(result= (db && db[0] && mysql_change_db(thd, &db_str, FALSE))))
798  my_ok(thd);
799  thd->protocol->end_statement();
800  emb_read_query_result(mysql);
801  return result;
802 }
803 
804 #else
805 int check_embedded_connection(MYSQL *mysql, const char *db)
806 {
807  /*
808  we emulate a COM_CHANGE_USER user here,
809  it's easier than to emulate the complete 3-way handshake
810  */
811  char *buf, *end;
812  NET *net= &mysql->net;
813  THD *thd= (THD*)mysql->thd;
814  Security_context *sctx= thd->security_ctx;
815  size_t connect_attrs_len=
816  (mysql->server_capabilities & CLIENT_CONNECT_ATTRS &&
817  mysql->options.extension) ?
818  mysql->options.extension->connection_attributes_length : 0;
819 
820  buf= my_alloca(USERNAME_LENGTH + SCRAMBLE_LENGTH + 1 + 2*NAME_LEN + 2 +
821  connect_attrs_len + 2);
822  if (mysql->options.client_ip)
823  {
824  sctx->set_host(my_strdup(mysql->options.client_ip, MYF(0)));
825  sctx->set_ip(my_strdup(sctx->get_host()->ptr(), MYF(0)));
826  }
827  else
828  sctx->set_host((char*)my_localhost);
829  sctx->host_or_ip= sctx->host->ptr();
830 
831  if (acl_check_host(sctx->get_host()->ptr(), sctx->get_ip()->ptr()))
832  goto err;
833 
834  /* construct a COM_CHANGE_USER packet */
835  end= strmake(buf, mysql->user, USERNAME_LENGTH) + 1;
836 
837  memset(thd->scramble, 55, SCRAMBLE_LENGTH); // dummy scramble
838  thd->scramble[SCRAMBLE_LENGTH]= 0;
839 
840  if (mysql->passwd && mysql->passwd[0])
841  {
842  *end++= SCRAMBLE_LENGTH;
843  scramble(end, thd->scramble, mysql->passwd);
844  end+= SCRAMBLE_LENGTH;
845  }
846  else
847  *end++= 0;
848 
849  end= strmake(end, db ? db : "", NAME_LEN) + 1;
850 
851  int2store(end, (ushort) mysql->charset->number);
852  end+= 2;
853 
854  end= strmake(end, "mysql_native_password", NAME_LEN) + 1;
855 
856  /* the server does the same as the client */
857  mysql->server_capabilities= mysql->client_flag;
858 
859  end= (char *) send_client_connect_attrs(mysql, (uchar *) end);
860 
861  /* acl_authenticate() takes the data from thd->net->read_pos */
862  thd->net.read_pos= (uchar*)buf;
863 
864  if (acl_authenticate(thd, 0, end - buf))
865  {
866  x_free(thd->security_ctx->user);
867  goto err;
868  }
869  my_afree(buf);
870  return 0;
871 err:
872  strmake(net->last_error, thd->main_da.message(), sizeof(net->last_error)-1);
873  memcpy(net->sqlstate,
874  mysql_errno_to_sqlstate(thd->main_da.sql_errno()),
875  sizeof(net->sqlstate)-1);
876  my_afree(buf);
877  return 1;
878 }
879 #endif
880 
881 } // extern "C"
882 
883 
884 void THD::clear_data_list()
885 {
886  while (first_data)
887  {
888  MYSQL_DATA *data= first_data;
889  first_data= data->embedded_info->next;
890  free_rows(data);
891  }
892  data_tail= &first_data;
893  free_rows(cur_data);
894  cur_data= 0;
895 }
896 
897 
898 static char *dup_str_aux(MEM_ROOT *root, const char *from, uint length,
899  const CHARSET_INFO *fromcs, const CHARSET_INFO *tocs)
900 {
901  uint32 dummy32;
902  uint dummy_err;
903  char *result;
904 
905  /* 'tocs' is set 0 when client issues SET character_set_results=NULL */
906  if (tocs && String::needs_conversion(0, fromcs, tocs, &dummy32))
907  {
908  uint new_len= (tocs->mbmaxlen * length) / fromcs->mbminlen + 1;
909  result= (char *)alloc_root(root, new_len);
910  length= copy_and_convert(result, new_len,
911  tocs, from, length, fromcs, &dummy_err);
912  }
913  else
914  {
915  result= (char *)alloc_root(root, length + 1);
916  memcpy(result, from, length);
917  }
918 
919  result[length]= 0;
920  return result;
921 }
922 
923 
924 /*
925  creates new result and hooks it to the list
926 
927  SYNOPSIS
928  alloc_new_dataset()
929 
930  NOTES
931  allocs the MYSQL_DATA + embedded_query_result couple
932  to store the next query result,
933  links these two and attach it to the THD::data_tail
934 
935  RETURN
936  pointer to the newly created query result
937 */
938 
939 MYSQL_DATA *THD::alloc_new_dataset()
940 {
941  MYSQL_DATA *data;
942  struct embedded_query_result *emb_data;
943  if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
944  &data, sizeof(*data),
945  &emb_data, sizeof(*emb_data),
946  NULL))
947  return NULL;
948 
949  emb_data->prev_ptr= &data->data;
950  cur_data= data;
951  *data_tail= data;
952  data_tail= &emb_data->next;
953  data->embedded_info= emb_data;
954  return data;
955 }
956 
957 
967 static
968 bool
969 write_eof_packet(THD *thd, uint server_status, uint statement_warn_count)
970 {
971  if (!thd->mysql) // bootstrap file handling
972  return FALSE;
973  /*
974  The following test should never be true, but it's better to do it
975  because if 'is_fatal_error' is set the server is not going to execute
976  other queries (see the if test in dispatch_command / COM_QUERY)
977  */
978  if (thd->is_fatal_error)
979  thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
980  thd->cur_data->embedded_info->server_status= server_status;
981  /*
982  Don't send warn count during SP execution, as the warn_list
983  is cleared between substatements, and mysqltest gets confused
984  */
985  thd->cur_data->embedded_info->warning_count=
986  (thd->sp_runtime_ctx ? 0 : min(statement_warn_count, 65535U));
987  return FALSE;
988 }
989 
990 
991 /*
992  allocs new query result and initialises Protocol::alloc
993 
994  SYNOPSIS
995  Protocol::begin_dataset()
996 
997  RETURN
998  0 if success
999  1 if memory allocation failed
1000 */
1001 
1002 int Protocol::begin_dataset()
1003 {
1004  MYSQL_DATA *data= thd->alloc_new_dataset();
1005  if (!data)
1006  return 1;
1007  alloc= &data->alloc;
1008  init_alloc_root(alloc,8192,0); /* Assume rowlength < 8192 */
1009  alloc->min_malloc=sizeof(MYSQL_ROWS);
1010  return 0;
1011 }
1012 
1013 
1014 /*
1015  remove last row of current recordset
1016 
1017  SYNOPSIS
1018  Protocol_text::remove_last_row()
1019 
1020  NOTES
1021  does the loop from the beginning of the current recordset to
1022  the last record and cuts it off.
1023  Not supposed to be frequently called.
1024 */
1025 
1026 void Protocol_text::remove_last_row()
1027 {
1028  MYSQL_DATA *data= thd->cur_data;
1029  MYSQL_ROWS **last_row_hook= &data->data;
1030  my_ulonglong count= data->rows;
1031  DBUG_ENTER("Protocol_text::remove_last_row");
1032  while (--count)
1033  last_row_hook= &(*last_row_hook)->next;
1034 
1035  *last_row_hook= 0;
1036  data->embedded_info->prev_ptr= last_row_hook;
1037  data->rows--;
1038 
1039  DBUG_VOID_RETURN;
1040 }
1041 
1042 
1044 {
1045  List_iterator_fast<Item> it(*list);
1046  Item *item;
1047  MYSQL_FIELD *client_field;
1048  MEM_ROOT *field_alloc;
1049  const CHARSET_INFO *thd_cs= thd->variables.character_set_results;
1050  const CHARSET_INFO *cs= system_charset_info;
1051  MYSQL_DATA *data;
1052  DBUG_ENTER("send_result_set_metadata");
1053 
1054  if (!thd->mysql) // bootstrap file handling
1055  DBUG_RETURN(0);
1056 
1057  if (begin_dataset())
1058  goto err;
1059 
1060  data= thd->cur_data;
1061  data->fields= field_count= list->elements;
1062  field_alloc= &data->alloc;
1063 
1064  if (!(client_field= data->embedded_info->fields_list=
1065  (MYSQL_FIELD*)alloc_root(field_alloc, sizeof(MYSQL_FIELD)*field_count)))
1066  goto err;
1067 
1068  while ((item= it++))
1069  {
1070  Send_field server_field;
1071  item->make_field(&server_field);
1072 
1073  /* Keep things compatible for old clients */
1074  if (server_field.type == MYSQL_TYPE_VARCHAR)
1075  server_field.type= MYSQL_TYPE_VAR_STRING;
1076 
1077  client_field->db= dup_str_aux(field_alloc, server_field.db_name,
1078  strlen(server_field.db_name), cs, thd_cs);
1079  client_field->table= dup_str_aux(field_alloc, server_field.table_name,
1080  strlen(server_field.table_name), cs, thd_cs);
1081  client_field->name= dup_str_aux(field_alloc, server_field.col_name,
1082  strlen(server_field.col_name), cs, thd_cs);
1083  client_field->org_table= dup_str_aux(field_alloc, server_field.org_table_name,
1084  strlen(server_field.org_table_name), cs, thd_cs);
1085  client_field->org_name= dup_str_aux(field_alloc, server_field.org_col_name,
1086  strlen(server_field.org_col_name), cs, thd_cs);
1087  if (item->charset_for_protocol() == &my_charset_bin || thd_cs == NULL)
1088  {
1089  /* No conversion */
1090  client_field->charsetnr= item->charset_for_protocol()->number;
1091  client_field->length= server_field.length;
1092  }
1093  else
1094  {
1095  uint max_char_len;
1096  /* With conversion */
1097  client_field->charsetnr= thd_cs->number;
1098  max_char_len= (server_field.type >= (int) MYSQL_TYPE_TINY_BLOB &&
1099  server_field.type <= (int) MYSQL_TYPE_BLOB) ?
1100  server_field.length / item->collation.collation->mbminlen :
1101  server_field.length / item->collation.collation->mbmaxlen;
1102  client_field->length= char_to_byte_length_safe(max_char_len,
1103  thd_cs->mbmaxlen);
1104  }
1105  client_field->type= server_field.type;
1106  client_field->flags= server_field.flags;
1107  client_field->decimals= server_field.decimals;
1108  client_field->db_length= strlen(client_field->db);
1109  client_field->table_length= strlen(client_field->table);
1110  client_field->name_length= strlen(client_field->name);
1111  client_field->org_name_length= strlen(client_field->org_name);
1112  client_field->org_table_length= strlen(client_field->org_table);
1113 
1114  client_field->catalog= dup_str_aux(field_alloc, "def", 3, cs, thd_cs);
1115  client_field->catalog_length= 3;
1116 
1117  if (IS_NUM(client_field->type))
1118  client_field->flags|= NUM_FLAG;
1119 
1120  if (flags & (int) Protocol::SEND_DEFAULTS)
1121  {
1122  char buff[80];
1123  String tmp(buff, sizeof(buff), default_charset_info), *res;
1124 
1125  if (!(res=item->val_str(&tmp)))
1126  {
1127  client_field->def_length= 0;
1128  client_field->def= strmake_root(field_alloc, "",0);
1129  }
1130  else
1131  {
1132  client_field->def_length= res->length();
1133  client_field->def= strmake_root(field_alloc, res->ptr(),
1134  client_field->def_length);
1135  }
1136  }
1137  else
1138  client_field->def=0;
1139  client_field->max_length= 0;
1140  ++client_field;
1141  }
1142 
1143  if (flags & SEND_EOF)
1144  write_eof_packet(thd, thd->server_status,
1145  thd->get_stmt_da()->current_statement_warn_count());
1146 
1147  DBUG_RETURN(prepare_for_send(list->elements));
1148  err:
1149  my_error(ER_OUT_OF_RESOURCES, MYF(0)); /* purecov: inspected */
1150  DBUG_RETURN(1); /* purecov: inspected */
1151 }
1152 
1153 bool Protocol::write()
1154 {
1155  if (!thd->mysql) // bootstrap file handling
1156  return false;
1157 
1158  *next_field= 0;
1159  return false;
1160 }
1161 
1162 bool Protocol_binary::write()
1163 {
1164  MYSQL_ROWS *cur;
1165  MYSQL_DATA *data= thd->cur_data;
1166 
1167  data->rows++;
1168  if (!(cur= (MYSQL_ROWS *)alloc_root(alloc,
1169  sizeof(MYSQL_ROWS)+packet->length())))
1170  {
1171  my_error(ER_OUT_OF_RESOURCES,MYF(0));
1172  return true;
1173  }
1174  cur->data= (MYSQL_ROW)(((char *)cur) + sizeof(MYSQL_ROWS));
1175  memcpy(cur->data, packet->ptr()+1, packet->length()-1);
1176  cur->length= packet->length(); /* To allow us to do sanity checks */
1177 
1178  *data->embedded_info->prev_ptr= cur;
1179  data->embedded_info->prev_ptr= &cur->next;
1180  cur->next= 0;
1181 
1182  return false;
1183 }
1184 
1185 
1205 bool
1206 net_send_ok(THD *thd,
1207  uint server_status, uint statement_warn_count,
1208  ulonglong affected_rows, ulonglong id, const char *message)
1209 {
1210  DBUG_ENTER("emb_net_send_ok");
1211  MYSQL_DATA *data;
1212  MYSQL *mysql= thd->mysql;
1213 
1214  if (!mysql) // bootstrap file handling
1215  DBUG_RETURN(FALSE);
1216  if (!(data= thd->alloc_new_dataset()))
1217  DBUG_RETURN(TRUE);
1218  data->embedded_info->affected_rows= affected_rows;
1219  data->embedded_info->insert_id= id;
1220  if (message)
1221  strmake(data->embedded_info->info, message,
1222  sizeof(data->embedded_info->info)-1);
1223 
1224  bool error= write_eof_packet(thd, server_status, statement_warn_count);
1225  thd->cur_data= 0;
1226  DBUG_RETURN(error);
1227 }
1228 
1229 
1240 bool
1241 net_send_eof(THD *thd, uint server_status, uint statement_warn_count)
1242 {
1243  bool error= write_eof_packet(thd, server_status, statement_warn_count);
1244  thd->cur_data= 0;
1245  return error;
1246 }
1247 
1248 
1249 bool net_send_error_packet(THD *thd, uint sql_errno, const char *err,
1250  const char *sqlstate)
1251 {
1252  uint error;
1253  char converted_err[MYSQL_ERRMSG_SIZE];
1254  MYSQL_DATA *data= thd->cur_data;
1255  struct embedded_query_result *ei;
1256 
1257  if (!thd->mysql) // bootstrap file handling
1258  {
1259  fprintf(stderr, "ERROR: %d %s\n", sql_errno, err);
1260  return TRUE;
1261  }
1262 
1263  if (!data)
1264  data= thd->alloc_new_dataset();
1265 
1266  ei= data->embedded_info;
1267  ei->last_errno= sql_errno;
1268  convert_error_message(converted_err, sizeof(converted_err),
1269  thd->variables.character_set_results,
1270  err, strlen(err),
1271  system_charset_info, &error);
1272  /* Converted error message is always null-terminated. */
1273  strmake(ei->info, converted_err, sizeof(ei->info)-1);
1274  strmov(ei->sqlstate, sqlstate);
1275  ei->server_status= thd->server_status;
1276  thd->cur_data= 0;
1277  return FALSE;
1278 }
1279 
1280 
1281 void Protocol_text::prepare_for_resend()
1282 {
1283  MYSQL_ROWS *cur;
1284  MYSQL_DATA *data= thd->cur_data;
1285  DBUG_ENTER("send_data");
1286 
1287  if (!thd->mysql) // bootstrap file handling
1288  DBUG_VOID_RETURN;
1289 
1290  data->rows++;
1291  if (!(cur= (MYSQL_ROWS *)alloc_root(alloc, sizeof(MYSQL_ROWS)+(field_count + 1) * sizeof(char *))))
1292  {
1293  my_error(ER_OUT_OF_RESOURCES,MYF(0));
1294  DBUG_VOID_RETURN;
1295  }
1296  cur->data= (MYSQL_ROW)(((char *)cur) + sizeof(MYSQL_ROWS));
1297 
1298  *data->embedded_info->prev_ptr= cur;
1299  data->embedded_info->prev_ptr= &cur->next;
1300  next_field=cur->data;
1301  next_mysql_field= data->embedded_info->fields_list;
1302 #ifndef DBUG_OFF
1303  field_pos= 0;
1304 #endif
1305 
1306  DBUG_VOID_RETURN;
1307 }
1308 
1309 bool Protocol_text::store_null()
1310 {
1311  *(next_field++)= NULL;
1312  ++next_mysql_field;
1313  return false;
1314 }
1315 
1316 bool Protocol::net_store_data(const uchar *from, size_t length)
1317 {
1318  char *field_buf;
1319  if (!thd->mysql) // bootstrap file handling
1320  return FALSE;
1321 
1322  if (!(field_buf= (char*) alloc_root(alloc, length + sizeof(uint) + 1)))
1323  return TRUE;
1324  *(uint *)field_buf= length;
1325  *next_field= field_buf + sizeof(uint);
1326  memcpy((uchar*) *next_field, from, length);
1327  (*next_field)[length]= 0;
1328  if (next_mysql_field->max_length < length)
1329  next_mysql_field->max_length=length;
1330  ++next_field;
1331  ++next_mysql_field;
1332  return FALSE;
1333 }
1334 
1335 #if defined(_MSC_VER) && _MSC_VER < 1400
1336 #define vsnprintf _vsnprintf
1337 #endif
1338 
1339 int vprint_msg_to_log(enum loglevel level __attribute__((unused)),
1340  const char *format, va_list argsi)
1341 {
1342  my_vsnprintf(mysql_server_last_error, sizeof(mysql_server_last_error),
1343  format, argsi);
1344  mysql_server_last_errno= CR_UNKNOWN_ERROR;
1345  return 0;
1346 }
1347 
1348 
1349 bool Protocol::net_store_data(const uchar *from, size_t length,
1350  const CHARSET_INFO *from_cs,
1351  const CHARSET_INFO *to_cs)
1352 {
1353  uint conv_length= to_cs->mbmaxlen * length / from_cs->mbminlen;
1354  uint dummy_error;
1355  char *field_buf;
1356  if (!thd->mysql) // bootstrap file handling
1357  return false;
1358 
1359  if (!(field_buf= (char*) alloc_root(alloc, conv_length + sizeof(uint) + 1)))
1360  return true;
1361  *next_field= field_buf + sizeof(uint);
1362  length= copy_and_convert(*next_field, conv_length, to_cs,
1363  (const char*) from, length, from_cs, &dummy_error);
1364  *(uint *) field_buf= length;
1365  (*next_field)[length]= 0;
1366  if (next_mysql_field->max_length < length)
1367  next_mysql_field->max_length= length;
1368  ++next_field;
1369  ++next_mysql_field;
1370  return false;
1371 }