From: Date: December 11 2006 8:51pm Subject: bk commit into 5.0 tree (anozdrin:1.2318) BUG#16291 List-Archive: http://lists.mysql.com/commits/16793 X-Bug: 16291 Message-Id: <20061211195143.6A51C27057@booka.aliknet> Below is the list of changes that have just been committed into a local 5.0 repository of alik. When alik does a push these changes will be propagated to the main repository and, within 24 hours after the push, to the public repository. For information on how to access the public repository see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html ChangeSet@stripped, 2006-12-11 22:51:35+03:00, anozdrin@booka. +4 -0 This is a preliminary patch for BUG#16291: mysqldump corrupts string-constants with non-ascii-chars. The fix is: - to store view-query in the original character set; - to store additional attributes -- original character sets (client, connection, server); - to use original character sets when parsing the view; - to add charset-columns into SHOW CREATE VIEW output; - to add charset-columns into I_S.VIEWS pseudo-table; - to update mysqldump so that it puts charset-switching statements before CREATE VIEW statement. They are required because now CREATE VIEW is in the original charset (not the mysqldump-client's character set). client/mysqldump.c@stripped, 2006-12-11 22:51:32+03:00, anozdrin@booka. +24 -3 Switch charsets before CREATE VIEW statement. sql/sql_show.cc@stripped, 2006-12-11 22:51:32+03:00, anozdrin@booka. +145 -4 1. Add charset columns into SHOW CREATE VIEW output; 2. Add charset columns into I_S.VIEWS pseudo-table; sql/sql_view.cc@stripped, 2006-12-11 22:51:32+03:00, anozdrin@booka. +108 -6 1. Save 3 charsets (client, connection, server) in view-frm file; 2. Use view-charsets when parsing the view; 3. Store view-query in the original charset. sql/table.h@stripped, 2006-12-11 22:51:32+03:00, anozdrin@booka. +4 -0 Add attributes to store 3 view charsets (client, connection, server). # This is a BitKeeper patch. What follows are the unified diffs for the # set of deltas contained in the patch. The rest of the patch, the part # that BitKeeper cares about, is below these diffs. # User: anozdrin # Host: booka. # Root: /home/alik/Documents/MySQL/devel/5.0-rt-charsets --- 1.250/client/mysqldump.c 2006-12-11 22:51:43 +03:00 +++ 1.251/client/mysqldump.c 2006-12-11 22:51:43 +03:00 @@ -3573,8 +3573,9 @@ static my_bool get_view_structure(char * my_snprintf(query, sizeof(query), - "SELECT CHECK_OPTION, DEFINER, SECURITY_TYPE " \ - "FROM information_schema.views " \ + "SELECT CHECK_OPTION, DEFINER, SECURITY_TYPE, " + " CLIENT_CS, CONNECTION_CS, SERVER_CS " + "FROM information_schema.views " "WHERE table_name=\"%s\" AND table_schema=\"%s\"", table, db); if (mysql_query(mysql, query)) { @@ -3661,7 +3662,27 @@ static my_bool get_view_structure(char * } /* Dump view structure to file */ - fprintf(sql_file, "/*!50001 %s */;\n", ds_view.str); + + fprintf(sql_file, + "SET @saved_cs_client = @@character_set_client;\n" + "SET @saved_cs_results = @@character_set_results;\n" + "SET @saved_cs_connection = @@character_set_connection;\n" + "SET @saved_cs_server = @@character_set_server;\n" + "SET character_set_client = %s;\n" + "SET character_set_results = %s;\n" + "SET character_set_connection = %s;\n" + "SET character_set_server = %s;\n" + "/*!50001 %s */;\n" + "SET character_set_server = @saved_cs_client;\n" + "SET character_set_results = @saved_cs_results;\n" + "SET character_set_connection = @saved_cs_connection;\n" + "SET character_set_server = @saved_cs_server;\n", + (const char *) row[3], + (const char *) row[3], + (const char *) row[4], + (const char *) row[5], + (const char *) ds_view.str); + check_io(sql_file); mysql_free_result(table_res); dynstr_free(&ds_view); --- 1.332/sql/sql_show.cc 2006-12-11 22:51:43 +03:00 +++ 1.333/sql/sql_show.cc 2006-12-11 22:51:43 +03:00 @@ -418,6 +418,39 @@ mysqld_show_create(THD *thd, TABLE_LIST } buffer.length(0); + + if (table_list->view) + { + if (table_list->client_cs_name.str && + table_list->connection_cs_name.str && + table_list->server_cs_name.str) + { + CHARSET_INFO *client_cs= + get_charset_by_csname( + table_list->client_cs_name.str, + MY_CS_PRIMARY, + MYF(0)); + + if (client_cs) + { + buffer.set_charset(client_cs); + } + else + { + printf(">> Error: unknown client cs '%s'.\n", + (const char *) table_list->client_cs_name.str); + } + } + else + { + printf(">> Warning: no charset info.\n"); + } + } + else + { + printf(">> This is not a table.\n"); + } + if ((table_list->view ? view_store_create_info(thd, table_list, &buffer) : store_create_info(thd, table_list, &buffer))) @@ -429,6 +462,9 @@ mysqld_show_create(THD *thd, TABLE_LIST field_list.push_back(new Item_empty_string("View",NAME_LEN)); field_list.push_back(new Item_empty_string("Create View", max(buffer.length(),1024))); + field_list.push_back(new Item_empty_string("Client Charset", 255)); // FIXME + field_list.push_back(new Item_empty_string("Connection Charset", 255)); // FIXME + field_list.push_back(new Item_empty_string("Server Charset", 255)); // FIXME } else { @@ -452,7 +488,59 @@ mysqld_show_create(THD *thd, TABLE_LIST else protocol->store(table_list->table->alias, system_charset_info); } - protocol->store(buffer.ptr(), buffer.length(), buffer.charset()); + + if (table_list->view) + { + LEX_STRING client_cs_name; + LEX_STRING connection_cs_name; + LEX_STRING server_cs_name; + + if (table_list->client_cs_name.str) + { + client_cs_name= table_list->client_cs_name; + } + else + { + client_cs_name.str= (char *) system_charset_info->csname; + client_cs_name.length= strlen(client_cs_name.str); + } + + if (table_list->connection_cs_name.str) + { + connection_cs_name= table_list->connection_cs_name; + } + else + { + connection_cs_name.str= (char *) system_charset_info->csname; + connection_cs_name.length= strlen(connection_cs_name.str); + } + + if (table_list->server_cs_name.str) + { + server_cs_name= table_list->server_cs_name; + } + else + { + server_cs_name.str= (char *) system_charset_info->csname; + server_cs_name.length= strlen(server_cs_name.str); + } + + protocol->store(buffer.ptr(), buffer.length(), &my_charset_bin); + + protocol->store(client_cs_name.str, + client_cs_name.length, + system_charset_info); + + protocol->store(connection_cs_name.str, + connection_cs_name.length, + system_charset_info); + + protocol->store(server_cs_name.str, + server_cs_name.length, + system_charset_info); + } + else + protocol->store(buffer.ptr(), buffer.length(), buffer.charset()); if (protocol->write()) DBUG_RETURN(TRUE); @@ -692,7 +780,7 @@ append_identifier(THD *thd, String *pack if (q == EOF) { - packet->append(name, length, system_charset_info); + packet->append(name, length, packet->charset()); return; } @@ -710,7 +798,7 @@ append_identifier(THD *thd, String *pack uchar chr= (uchar) *name; length= my_mbcharlen(system_charset_info, chr); /* - my_mbcharlen can retur 0 on a wrong multibyte + my_mbcharlen can return 0 on a wrong multibyte sequence. It is possible when upgrading from 4.0, and identifier contains some accented characters. The manual says it does not work. So we'll just @@ -720,7 +808,7 @@ append_identifier(THD *thd, String *pack length= 1; if (length == 1 && chr == (uchar) quote_char) packet->append("e_char, 1, system_charset_info); - packet->append(name, length, packet->charset()); + packet->append(name, length, system_charset_info); } packet->append("e_char, 1, system_charset_info); } @@ -1235,6 +1323,10 @@ view_store_create_info(THD *thd, TABLE_L */ table->view->unit.print(buff); + /* XXX: alik + printf("--> buffer: '%s'\n", (const char *) buff->c_ptr()); + */ + if (table->with_check != VIEW_CHECK_NONE) { if (table->with_check == VIEW_CHECK_LOCAL) @@ -3184,6 +3276,52 @@ static int get_schema_views_record(THD * table->field[7]->store(STRING_WITH_LEN("DEFINER"), cs); else table->field[7]->store(STRING_WITH_LEN("INVOKER"), cs); + + { + LEX_STRING client_cs_name; + LEX_STRING connection_cs_name; + LEX_STRING server_cs_name; + + if (tables->client_cs_name.str) + { + client_cs_name= tables->client_cs_name; + } + else + { + client_cs_name.str= (char *) system_charset_info->csname; + client_cs_name.length= strlen(client_cs_name.str); + } + + if (tables->connection_cs_name.str) + { + connection_cs_name= tables->connection_cs_name; + } + else + { + connection_cs_name.str= (char *) system_charset_info->csname; + connection_cs_name.length= strlen(connection_cs_name.str); + } + + if (tables->server_cs_name.str) + { + server_cs_name= tables->server_cs_name; + } + else + { + server_cs_name.str= (char *) system_charset_info->csname; + server_cs_name.length= strlen(server_cs_name.str); + } + + table->field[8]->store( + client_cs_name.str, client_cs_name.length, cs); + + table->field[9]->store( + connection_cs_name.str, connection_cs_name.length, cs); + + table->field[10]->store( + server_cs_name.str, server_cs_name.length, cs); + } + if (schema_table_store_record(thd, table)) DBUG_RETURN(1); if (res) @@ -4151,6 +4289,9 @@ ST_FIELD_INFO view_fields_info[]= {"IS_UPDATABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0}, {"DEFINER", 77, MYSQL_TYPE_STRING, 0, 0, 0}, {"SECURITY_TYPE", 7, MYSQL_TYPE_STRING, 0, 0, 0}, + {"CLIENT_CS", 255, MYSQL_TYPE_STRING, 0, 0, 0}, // XXX + {"CONNECTION_CS", 255, MYSQL_TYPE_STRING, 0, 0, 0}, // XXX + {"SERVER_CS", 255, MYSQL_TYPE_STRING, 0, 0, 0}, // XXX {0, 0, MYSQL_TYPE_STRING, 0, 0, 0} }; --- 1.135/sql/table.h 2006-12-11 22:51:43 +03:00 +++ 1.136/sql/table.h 2006-12-11 22:51:43 +03:00 @@ -639,6 +639,10 @@ typedef struct st_table_list */ bool prelocking_placeholder; + LEX_STRING client_cs_name; + LEX_STRING connection_cs_name; + LEX_STRING server_cs_name; + void calc_md5(char *buffer); void set_underlying_merge(); int view_check_option(THD *thd, bool ignore_failure); --- 1.99/sql/sql_view.cc 2006-12-11 22:51:43 +03:00 +++ 1.100/sql/sql_view.cc 2006-12-11 22:51:43 +03:00 @@ -598,8 +598,8 @@ err: /* index of revision number in following table */ static const int revision_number_position= 8; -/* index of last required parameter for making view */ -static const int required_view_parameters= 10; +/* number of required parameters for making view */ +static const int required_view_parameters= 15; /* number of backups */ static const int num_view_backups= 3; @@ -646,6 +646,15 @@ static File_option view_parameters[]= {{(char*) STRING_WITH_LEN("source")}, my_offsetof(TABLE_LIST, source), FILE_OPTIONS_ESTRING}, + {{(char*) STRING_WITH_LEN("client_cs_name")}, + my_offsetof(TABLE_LIST, client_cs_name), + FILE_OPTIONS_STRING}, + {{(char*) STRING_WITH_LEN("connection_cs_name")}, + my_offsetof(TABLE_LIST, connection_cs_name), + FILE_OPTIONS_STRING}, + {{(char*) STRING_WITH_LEN("server_cs_name")}, + my_offsetof(TABLE_LIST, server_cs_name), + FILE_OPTIONS_STRING}, {{NullS, 0}, 0, FILE_OPTIONS_STRING} }; @@ -673,7 +682,7 @@ static int mysql_register_view(THD *thd, { LEX *lex= thd->lex; char buff[4096]; - String str(buff,(uint32) sizeof(buff), system_charset_info); + String str(buff,(uint32) sizeof(buff), thd->charset()); // system_charset_info); char md5[MD5_BUFF_LENGTH]; bool can_be_merged; char dir_buff[FN_REFLEN], file_buff[FN_REFLEN]; @@ -802,6 +811,23 @@ static int mysql_register_view(THD *thd, } } } + + view->client_cs_name.str= (char *) thd->charset()->csname; + view->client_cs_name.length= strlen(view->client_cs_name.str); + + view->connection_cs_name.str= (char *) thd->variables.collation_connection->csname; + view->connection_cs_name.length= strlen(view->connection_cs_name.str); + + view->server_cs_name.str= (char *) thd->variables.collation_server->csname; + view->server_cs_name.length= strlen(view->server_cs_name.str); + + /* XXX: alik + printf(">> client: '%s'; connection: '%s'; server: '%s'\n", + (const char *) view->client_cs_name.str, + (const char *) view->connection_cs_name.str, + (const char *) view->server_cs_name.str); + */ + loop_out: /* Check that table of main select do not used in subqueries. @@ -863,9 +889,14 @@ bool mysql_make_view(THD *thd, File_pars TABLE_LIST *top_view= table->top_table(); int res; bool result; + DBUG_ENTER("mysql_make_view"); DBUG_PRINT("info", ("table: 0x%lx (%s)", (ulong) table, table->table_name)); + /* XXX: alik + printf(">> Making '%s'...\n", (const char *) table->table_name); + */ + if (table->view) { /* @@ -973,6 +1004,14 @@ bool mysql_make_view(THD *thd, File_pars view_select= &lex->select_lex; view_select->select_number= ++thd->select_number; { + bool charset_changed= FALSE; + + CHARSET_INFO *saved_client_cs; + CHARSET_INFO *saved_connection_cs; + CHARSET_INFO *saved_server_cs; + + /* Change sql_mode. */ + ulong save_mode= thd->variables.sql_mode; /* switch off modes which can prevent normal parsing of VIEW - MODE_REAL_AS_FLOAT affect only CREATE TABLE parsing @@ -1000,12 +1039,75 @@ bool mysql_make_view(THD *thd, File_pars */ thd->variables.sql_mode&= ~(MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES | MODE_IGNORE_SPACE | MODE_NO_BACKSLASH_ESCAPES); - CHARSET_INFO *save_cs= thd->variables.character_set_client; - thd->variables.character_set_client= system_charset_info; + + /* Change charsets. */ + + if (table->client_cs_name.str && + table->connection_cs_name.str && + table->server_cs_name.str) + { + CHARSET_INFO *client_cs= + get_charset_by_csname( + table->client_cs_name.str, + MY_CS_PRIMARY, + MYF(0)); + + CHARSET_INFO *connection_cs= + get_charset_by_csname( + table->connection_cs_name.str, + MY_CS_PRIMARY, + MYF(0)); + + CHARSET_INFO *server_cs= + get_charset_by_csname( + table->server_cs_name.str, + MY_CS_PRIMARY, + MYF(0)); + + if (client_cs && connection_cs && server_cs) + { + saved_client_cs= thd->variables.character_set_client; + saved_connection_cs= thd->variables.collation_connection; + saved_server_cs= thd->variables.collation_server; + + thd->variables.character_set_client= client_cs; + thd->variables.collation_connection= connection_cs; + thd->variables.collation_server= server_cs; + thd->update_charset(); + + charset_changed= TRUE; + } + else + { + printf(">> Error: invalid charset specified.\n"); + } + } + else + { + printf(">> Warning: old version -- no charset info.\n"); + } + + /* Parse the query. */ + res= MYSQLparse((void *)thd); - thd->variables.character_set_client= save_cs; + + /* Restore environment. */ + + if (charset_changed) + { + DBUG_ASSERT(saved_client_cs); + DBUG_ASSERT(saved_connection_cs); + DBUG_ASSERT(saved_server_cs); + + thd->variables.character_set_client= saved_client_cs; + thd->variables.collation_connection= saved_connection_cs; + thd->variables.collation_server= saved_server_cs; + thd->update_charset(); + } + thd->variables.sql_mode= save_mode; } + if (!res && !thd->is_fatal_error) { TABLE_LIST *view_tables= lex->query_tables;