Commit 8b6c2d31 authored by unknown's avatar unknown
Browse files

bug #20318 (ctype_ucs2_def test fails with embedded)

there was two problems about charsets in embedded server
1. mysys/charset.c - defined there default_charset_info variable is
modified by both server and client code (particularly when
--default-charset option is handled)
In embedded server we get two codelines modifying one variable.
I created separate default_client_charset_info for client code

2. mysql->charset and mysql->options.charset initialization isn't
properly done for embedded server - necessary calls added


include/sql_common.h:
  client charset info default declared
libmysqld/lib_sql.cc:
  thd_init_client_charset calls added
libmysqld/libmysqld.c:
  check_embedded_connection moved to client.c to avoid code duplication
sql-common/client.c:
  charset initialization moved to mysql_init_character_set to
  be used in embedded server
sql/sql_parse.cc:
  thread client charset initialization moved to thd_init_client_charset
  to avoid code duplication
parent b10b25fb
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ extern const char *not_error_sqlstate;
extern "C" {
#endif

extern CHARSET_INFO *default_client_charset_info;
MYSQL_FIELD *unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields,
			   my_bool default_value, uint server_capabilities);
void free_rows(MYSQL_DATA *cur);
+7 −0
Original line number Diff line number Diff line
@@ -41,6 +41,8 @@ static const char *fake_groups[] = { "server", "embedded", 0 };
int check_user(THD *thd, enum enum_server_command command, 
	       const char *passwd, uint passwd_len, const char *db,
	       bool check_count);
void thd_init_client_charset(THD *thd, uint cs_number);

C_MODE_START
#include <mysql.h>
#undef ER
@@ -532,10 +534,13 @@ void *create_embedded_thd(int client_flag, char *db)
  return NULL;
}


#ifdef NO_EMBEDDED_ACCESS_CHECKS
int check_embedded_connection(MYSQL *mysql)
{
  THD *thd= (THD*)mysql->thd;
  thd_init_client_charset(thd, mysql->charset->number);
  thd->update_charset();
  thd->host= (char*)my_localhost;
  thd->host_or_ip= thd->host;
  thd->user= my_strdup(mysql->user, MYF(0));
@@ -551,6 +556,8 @@ int check_embedded_connection(MYSQL *mysql)
  char scramble_buff[SCRAMBLE_LENGTH];
  int passwd_len;

  thd_init_client_charset(thd, mysql->charset->number);
  thd->update_charset();
  if (mysql->options.client_ip)
  {
    thd->host= my_strdup(mysql->options.client_ip, MYF(0));
+3 −45
Original line number Diff line number Diff line
@@ -85,49 +85,7 @@ static void end_server(MYSQL *mysql)
}


static int mysql_init_charset(MYSQL *mysql)
{
  char charset_name_buff[16], *charset_name;

  if ((charset_name=mysql->options.charset_name))
  {
    const char *save=charsets_dir;
    if (mysql->options.charset_dir)
      charsets_dir=mysql->options.charset_dir;
    mysql->charset=get_charset_by_name(mysql->options.charset_name,
                                       MYF(MY_WME));
    charsets_dir=save;
  }
  else if (mysql->server_language)
  {
    charset_name=charset_name_buff;
    sprintf(charset_name,"%d",mysql->server_language);	/* In case of errors */
    mysql->charset=get_charset((uint8) mysql->server_language, MYF(MY_WME));
  }
  else
    mysql->charset=default_charset_info;

  if (!mysql->charset)
  {
    mysql->net.last_errno=CR_CANT_READ_CHARSET;
    strmov(mysql->net.sqlstate, "HY0000");
    if (mysql->options.charset_dir)
      sprintf(mysql->net.last_error,ER(mysql->net.last_errno),
              charset_name ? charset_name : "unknown",
              mysql->options.charset_dir);
    else
    {
      char cs_dir_name[FN_REFLEN];
      get_charsets_dir(cs_dir_name);
      sprintf(mysql->net.last_error,ER(mysql->net.last_errno),
              charset_name ? charset_name : "unknown",
              cs_dir_name);
    }
    return mysql->net.last_errno;
  }
  return 0;
}

int mysql_init_character_set(MYSQL *mysql);

MYSQL * STDCALL
mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
@@ -203,10 +161,10 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,

  init_embedded_mysql(mysql, client_flag, db_name);

  if (check_embedded_connection(mysql))
  if (mysql_init_character_set(mysql))
    goto error;

  if (mysql_init_charset(mysql))
  if (check_embedded_connection(mysql))
    goto error;

  /* Send client information for access check */
+48 −36
Original line number Diff line number Diff line
@@ -133,6 +133,8 @@ static void mysql_close_free(MYSQL *mysql);
static int wait_for_data(my_socket fd, uint timeout);
#endif

CHARSET_INFO *default_client_charset_info = &my_charset_latin1;


/****************************************************************************
  A modified version of connect().  my_connect() allows you to specify
@@ -1424,7 +1426,7 @@ mysql_init(MYSQL *mysql)
    bzero((char*) (mysql),sizeof(*(mysql)));
  mysql->options.connect_timeout= CONNECT_TIMEOUT;
  mysql->last_used_con= mysql->next_slave= mysql->master = mysql;
  mysql->charset=default_charset_info;
  mysql->charset=default_client_charset_info;
  strmov(mysql->net.sqlstate, not_error_sqlstate);
  /*
    By default, we are a replication pivot. The caller must reset it
@@ -1537,6 +1539,50 @@ static MYSQL_METHODS client_methods=
#endif
};

C_MODE_START
int mysql_init_character_set(MYSQL *mysql)
{
  NET		*net= &mysql->net;
  /* Set character set */
  if (!mysql->options.charset_name &&
      !(mysql->options.charset_name= 
       my_strdup(MYSQL_DEFAULT_CHARSET_NAME,MYF(MY_WME))))
    return 1;
  
  {
    const char *save= charsets_dir;
    if (mysql->options.charset_dir)
      charsets_dir=mysql->options.charset_dir;
    mysql->charset=get_charset_by_csname(mysql->options.charset_name,
                                         MY_CS_PRIMARY, MYF(MY_WME));
    charsets_dir= save;
  }
  
  if (!mysql->charset)
  {
    net->last_errno=CR_CANT_READ_CHARSET;
    strmov(net->sqlstate, unknown_sqlstate);
    if (mysql->options.charset_dir)
      my_snprintf(net->last_error, sizeof(net->last_error)-1,
                  ER(net->last_errno),
                  mysql->options.charset_name,
                  mysql->options.charset_dir);
    else
    {
      char cs_dir_name[FN_REFLEN];
      get_charsets_dir(cs_dir_name);
      my_snprintf(net->last_error, sizeof(net->last_error)-1,
                  ER(net->last_errno),
                  mysql->options.charset_name,
                  cs_dir_name);
    }
    return 1;
  }
  return 0;
}
C_MODE_END


MYSQL * STDCALL 
CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
		       const char *passwd, const char *db,
@@ -1875,42 +1921,8 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
    goto error;
  }

  /* Set character set */
  if (!mysql->options.charset_name &&
      !(mysql->options.charset_name= 
       my_strdup(MYSQL_DEFAULT_CHARSET_NAME,MYF(MY_WME))))
    goto error;
  
  {
    const char *save= charsets_dir;
    if (mysql->options.charset_dir)
      charsets_dir=mysql->options.charset_dir;
    mysql->charset=get_charset_by_csname(mysql->options.charset_name,
                                         MY_CS_PRIMARY, MYF(MY_WME));
    charsets_dir= save;
  }
  
  if (!mysql->charset)
  {
    net->last_errno=CR_CANT_READ_CHARSET;
    strmov(net->sqlstate, unknown_sqlstate);
    if (mysql->options.charset_dir)
      my_snprintf(net->last_error, sizeof(net->last_error)-1,
                  ER(net->last_errno),
                  mysql->options.charset_name,
                  mysql->options.charset_dir);
    else
    {
      char cs_dir_name[FN_REFLEN];
      get_charsets_dir(cs_dir_name);
      my_snprintf(net->last_error, sizeof(net->last_error)-1,
                  ER(net->last_errno),
                  mysql->options.charset_name,
                  cs_dir_name);
    }
  if (mysql_init_character_set(mysql))
    goto error;
  }


  /* Save connection information */
  if (!my_multi_malloc(MYF(0),
+32 −27
Original line number Diff line number Diff line
@@ -667,6 +667,37 @@ static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them= 0)
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
}

void thd_init_client_charset(THD *thd, uint cs_number)
{
  /*
   Use server character set and collation if
   - opt_character_set_client_handshake is not set
   - client has not specified a character set
   - client character set is the same as the servers
   - client character set doesn't exists in server
  */
  if (!opt_character_set_client_handshake ||
      !(thd->variables.character_set_client= get_charset(cs_number, MYF(0))) ||
      !my_strcasecmp(&my_charset_latin1,
                     global_system_variables.character_set_client->name,
                     thd->variables.character_set_client->name))
  {
    thd->variables.character_set_client=
      global_system_variables.character_set_client;
    thd->variables.collation_connection=
      global_system_variables.collation_connection;
    thd->variables.character_set_results=
      global_system_variables.character_set_results;
  }
  else
  {
    thd->variables.character_set_results=
      thd->variables.collation_connection= 
      thd->variables.character_set_client;
  }
}


/*
    Perform handshake, authorize client and update thd ACL variables.
  SYNOPSIS
@@ -809,33 +840,7 @@ static int check_connection(THD *thd)
    thd->client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16;
    thd->max_client_packet_length= uint4korr(net->read_pos+4);
    DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8]));
    /*
      Use server character set and collation if
      - opt_character_set_client_handshake is not set
      - client has not specified a character set
      - client character set is the same as the servers
      - client character set doesn't exists in server
    */
    if (!opt_character_set_client_handshake ||
        !(thd->variables.character_set_client=
	  get_charset((uint) net->read_pos[8], MYF(0))) ||
	!my_strcasecmp(&my_charset_latin1,
		       global_system_variables.character_set_client->name,
		       thd->variables.character_set_client->name))
    {
      thd->variables.character_set_client=
	global_system_variables.character_set_client;
      thd->variables.collation_connection=
	global_system_variables.collation_connection;
      thd->variables.character_set_results=
	global_system_variables.character_set_results;
    }
    else
    {
      thd->variables.character_set_results=
      thd->variables.collation_connection= 
	thd->variables.character_set_client;
    }
    thd_init_client_charset(thd, (uint) net->read_pos[8]);
    thd->update_charset();
    end= (char*) net->read_pos+32;
  }