Commit 8476fe97 authored by tomas@poseidon.ndb.mysql.com's avatar tomas@poseidon.ndb.mysql.com

Merge tulin@bk-internal.mysql.com:/home/bk/mysql-4.1

into poseidon.ndb.mysql.com:/home/tomas/mysql-4.1-ndb-merge
parents 38afbaa4 2fd67321
...@@ -45,5 +45,5 @@ enum options_client ...@@ -45,5 +45,5 @@ enum options_client
OPT_COMPATIBLE, OPT_RECONNECT, OPT_DELIMITER, OPT_SECURE_AUTH, OPT_COMPATIBLE, OPT_RECONNECT, OPT_DELIMITER, OPT_SECURE_AUTH,
OPT_OPEN_FILES_LIMIT, OPT_SET_CHARSET, OPT_CREATE_OPTIONS, OPT_OPEN_FILES_LIMIT, OPT_SET_CHARSET, OPT_CREATE_OPTIONS,
OPT_START_POSITION, OPT_STOP_POSITION, OPT_START_DATETIME, OPT_STOP_DATETIME, OPT_START_POSITION, OPT_STOP_POSITION, OPT_START_DATETIME, OPT_STOP_DATETIME,
OPT_SIGINT_IGNORE OPT_SIGINT_IGNORE, OPT_HEXBLOB
}; };
...@@ -81,7 +81,8 @@ static my_bool verbose=0,tFlag=0,cFlag=0,dFlag=0,quick= 1, extended_insert= 1, ...@@ -81,7 +81,8 @@ static my_bool verbose=0,tFlag=0,cFlag=0,dFlag=0,quick= 1, extended_insert= 1,
opt_alldbs=0,opt_create_db=0,opt_first_slave=0,opt_set_charset, opt_alldbs=0,opt_create_db=0,opt_first_slave=0,opt_set_charset,
opt_autocommit=0,opt_master_data,opt_disable_keys=1,opt_xml=0, opt_autocommit=0,opt_master_data,opt_disable_keys=1,opt_xml=0,
opt_delete_master_logs=0, tty_password=0, opt_delete_master_logs=0, tty_password=0,
opt_single_transaction=0, opt_comments= 0, opt_compact= 0; opt_single_transaction=0, opt_comments= 0, opt_compact= 0,
opt_hex_blob=0;
static ulong opt_max_allowed_packet, opt_net_buffer_length; static ulong opt_max_allowed_packet, opt_net_buffer_length;
static MYSQL mysql_connection,*sock=0; static MYSQL mysql_connection,*sock=0;
static char insert_pat[12 * 1024],*opt_password=0,*current_user=0, static char insert_pat[12 * 1024],*opt_password=0,*current_user=0,
...@@ -316,6 +317,8 @@ static struct my_option my_long_options[] = ...@@ -316,6 +317,8 @@ static struct my_option my_long_options[] =
{"comments", 'i', "Write additional information.", {"comments", 'i', "Write additional information.",
(gptr*) &opt_comments, (gptr*) &opt_comments, 0, GET_BOOL, NO_ARG, (gptr*) &opt_comments, (gptr*) &opt_comments, 0, GET_BOOL, NO_ARG,
1, 0, 0, 0, 0, 0}, 1, 0, 0, 0, 0, 0},
{"hex-blob", OPT_HEXBLOB, "Dump BLOBs in HEX. this mode does not work with extended-insert",
(gptr*) &opt_hex_blob, (gptr*) &opt_hex_blob, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
}; };
...@@ -1507,6 +1510,7 @@ static void dumpTable(uint numFields, char *table) ...@@ -1507,6 +1510,7 @@ static void dumpTable(uint numFields, char *table)
for (i = 0; i < mysql_num_fields(res); i++) for (i = 0; i < mysql_num_fields(res); i++)
{ {
int is_blob;
if (!(field = mysql_fetch_field(res))) if (!(field = mysql_fetch_field(res)))
{ {
sprintf(query,"%s: Not enough fields from table %s! Aborting.\n", sprintf(query,"%s: Not enough fields from table %s! Aborting.\n",
...@@ -1515,6 +1519,17 @@ static void dumpTable(uint numFields, char *table) ...@@ -1515,6 +1519,17 @@ static void dumpTable(uint numFields, char *table)
error= EX_CONSCHECK; error= EX_CONSCHECK;
goto err; goto err;
} }
/*
63 is my_charset_bin. If charsetnr is not 63,
we have not a BLOB but a TEXT column.
we'll dump it in hex only BLOB columns.
*/
is_blob= (opt_hex_blob && field->charsetnr == 63 &&
(field->type == FIELD_TYPE_BLOB ||
field->type == FIELD_TYPE_LONG_BLOB ||
field->type == FIELD_TYPE_MEDIUM_BLOB ||
field->type == FIELD_TYPE_TINY_BLOB)) ? 1 : 0;
if (extended_insert) if (extended_insert)
{ {
ulong length = lengths[i]; ulong length = lengths[i];
...@@ -1535,13 +1550,29 @@ static void dumpTable(uint numFields, char *table) ...@@ -1535,13 +1550,29 @@ static void dumpTable(uint numFields, char *table)
error= EX_EOM; error= EX_EOM;
goto err; goto err;
} }
if (opt_hex_blob && is_blob)
{
ulong counter;
unsigned char *ptr= row[i];
dynstr_append(&extended_row, "0x");
for (counter = 0; counter < lengths[i]; counter++)
{
char xx[3];
sprintf(xx, "%02X", ptr[counter]);
dynstr_append(&extended_row, xx);
}
}
else
{
dynstr_append(&extended_row,"'"); dynstr_append(&extended_row,"'");
extended_row.length += extended_row.length +=
mysql_real_escape_string(&mysql_connection, mysql_real_escape_string(&mysql_connection,
&extended_row.str[extended_row.length],row[i],length); &extended_row.str[extended_row.length],
row[i],length);
extended_row.str[extended_row.length]='\0'; extended_row.str[extended_row.length]='\0';
dynstr_append(&extended_row,"'"); dynstr_append(&extended_row,"'");
} }
}
else else
{ {
/* change any strings ("inf", "-inf", "nan") into NULL */ /* change any strings ("inf", "-inf", "nan") into NULL */
...@@ -1591,6 +1622,18 @@ static void dumpTable(uint numFields, char *table) ...@@ -1591,6 +1622,18 @@ static void dumpTable(uint numFields, char *table)
print_quoted_xml(md_result_file, row[i], lengths[i]); print_quoted_xml(md_result_file, row[i], lengths[i]);
fputs("</field>\n", md_result_file); fputs("</field>\n", md_result_file);
} }
else if (opt_hex_blob && is_blob)
{ /* sakaik got this idea. */
ulong counter;
char xx[4];
unsigned char *ptr= row[i];
fputs("0x", md_result_file);
for (counter = 0; counter < lengths[i]; counter++)
{
sprintf(xx, "%02X", ptr[counter]);
fputs(xx, md_result_file);
}
}
else else
unescape(md_result_file, row[i], lengths[i]); unescape(md_result_file, row[i], lengths[i]);
} }
......
...@@ -53,6 +53,30 @@ rw_lock_t dict_operation_lock; /* table create, drop, etc. reserve ...@@ -53,6 +53,30 @@ rw_lock_t dict_operation_lock; /* table create, drop, etc. reserve
/* Identifies generated InnoDB foreign key names */ /* Identifies generated InnoDB foreign key names */
static char dict_ibfk[] = "_ibfk_"; static char dict_ibfk[] = "_ibfk_";
/**********************************************************************
Compares NUL-terminated UTF-8 strings case insensitively.
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
this function, you MUST change also the prototype here! */
extern
int
innobase_strcasecmp(
/*================*/
/* out: 0 if a=b, <0 if a<b, >1 if a>b */
const char* a, /* in: first string to compare */
const char* b); /* in: second string to compare */
/**********************************************************************
Makes all characters in a NUL-terminated UTF-8 string lower case.
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
this function, you MUST change also the prototype here! */
extern
void
innobase_casedn_str(
/*================*/
char* a); /* in/out: string to put in lower case */
/************************************************************************** /**************************************************************************
Adds a column to the data dictionary hash table. */ Adds a column to the data dictionary hash table. */
static static
...@@ -2066,7 +2090,7 @@ dict_foreign_find_index( ...@@ -2066,7 +2090,7 @@ dict_foreign_find_index(
break; break;
} }
if (0 != ut_cmp_in_lower_case(columns[i], if (0 != innobase_strcasecmp(columns[i],
col_name)) { col_name)) {
break; break;
} }
...@@ -2436,7 +2460,7 @@ dict_scan_col( ...@@ -2436,7 +2460,7 @@ dict_scan_col(
col = dict_table_get_nth_col(table, i); col = dict_table_get_nth_col(table, i);
if (0 == ut_cmp_in_lower_case(col->name, *name)) { if (0 == innobase_strcasecmp(col->name, *name)) {
/* Found */ /* Found */
*success = TRUE; *success = TRUE;
...@@ -2528,30 +2552,19 @@ dict_scan_table_name( ...@@ -2528,30 +2552,19 @@ dict_scan_table_name(
table_name_len = strlen(table_name); table_name_len = strlen(table_name);
/* Copy database_name, '/', table_name, '\0' */
ref = mem_heap_alloc(heap, database_name_len + table_name_len + 2); ref = mem_heap_alloc(heap, database_name_len + table_name_len + 2);
#ifdef __WIN__
ut_cpy_in_lower_case(ref, database_name, database_name_len);
#else
if (srv_lower_case_table_names) {
ut_cpy_in_lower_case(ref, database_name, database_name_len);
} else {
memcpy(ref, database_name, database_name_len); memcpy(ref, database_name, database_name_len);
} ref[database_name_len] = '/';
#endif memcpy(ref + database_name_len + 1, table_name, table_name_len + 1);
(ref)[database_name_len] = '/'; #ifndef __WIN__
#ifdef __WIN__
ut_cpy_in_lower_case(ref + database_name_len + 1,
table_name, table_name_len + 1);
#else
if (srv_lower_case_table_names) { if (srv_lower_case_table_names) {
ut_cpy_in_lower_case(ref + database_name_len + 1, #endif /* !__WIN__ */
table_name, table_name_len + 1); /* The table name is always put to lower case on Windows. */
} else { innobase_casedn_str(ref);
strcpy(ref + database_name_len + 1, table_name); #ifndef __WIN__
} }
#endif #endif /* !__WIN__ */
*success = TRUE; *success = TRUE;
*ref_name = ref; *ref_name = ref;
......
...@@ -229,25 +229,6 @@ ut_bit_set_nth( ...@@ -229,25 +229,6 @@ ut_bit_set_nth(
ulint a, /* in: ulint */ ulint a, /* in: ulint */
ulint n, /* in: nth bit requested */ ulint n, /* in: nth bit requested */
ibool val); /* in: value for the bit to set */ ibool val); /* in: value for the bit to set */
/****************************************************************
Copies a string to a memory location, setting characters to lower case. */
void
ut_cpy_in_lower_case(
/*=================*/
char* dest, /* in: destination */
const char* source, /* in: source */
ulint len); /* in: string length */
/****************************************************************
Compares two strings when converted to lower case. */
int
ut_cmp_in_lower_case(
/*=================*/
/* out: -1, 0, 1 if str1 < str2, str1 == str2,
str1 > str2, respectively */
const char* str1, /* in: string1 */
const char* str2); /* in: string2 */
#ifndef UNIV_NONINL #ifndef UNIV_NONINL
#include "ut0byte.ic" #include "ut0byte.ic"
......
...@@ -2010,6 +2010,11 @@ try_again: ...@@ -2010,6 +2010,11 @@ try_again:
return(TRUE); return(TRUE);
} }
fprintf(stderr,
"InnoDB: Error: tried to read %lu bytes at offset %lu %lu.\n"
"InnoDB: Was only able to read %ld.\n", (ulong)n, (ulong)offset_high,
(ulong)offset, (long)ret);
#endif #endif
#ifdef __WIN__ #ifdef __WIN__
error_handling: error_handling:
......
...@@ -951,7 +951,13 @@ retry: ...@@ -951,7 +951,13 @@ retry:
trx->op_info = "sleeping before joining InnoDB queue"; trx->op_info = "sleeping before joining InnoDB queue";
os_thread_sleep(50000); /* Peter Zaitsev suggested that we take the sleep away
altogether. But the sleep may be good in pathological
situations of lots of thread switches. Simply put some
threads aside for a while to reduce the number of thread
switches. */
os_thread_sleep(10000);
trx->op_info = ""; trx->op_info = "";
......
...@@ -29,51 +29,3 @@ ut_dulint_sort(dulint* arr, dulint* aux_arr, ulint low, ulint high) ...@@ -29,51 +29,3 @@ ut_dulint_sort(dulint* arr, dulint* aux_arr, ulint low, ulint high)
UT_SORT_FUNCTION_BODY(ut_dulint_sort, arr, aux_arr, low, high, UT_SORT_FUNCTION_BODY(ut_dulint_sort, arr, aux_arr, low, high,
ut_dulint_cmp); ut_dulint_cmp);
} }
/****************************************************************
Copies a string to a memory location, setting characters to lower case. */
void
ut_cpy_in_lower_case(
/*=================*/
char* dest, /* in: destination */
const char* source, /* in: source */
ulint len) /* in: string length */
{
ulint i;
for (i = 0; i < len; i++) {
dest[i] = tolower(source[i]);
}
}
/****************************************************************
Compares two strings when converted to lower case. */
int
ut_cmp_in_lower_case(
/*=================*/
/* out: -1, 0, 1 if str1 < str2, str1 == str2,
str1 > str2, respectively */
const char* str1, /* in: string1 */
const char* str2) /* in: string2 */
{
for (;;) {
int c1, c2;
if (!*str1) {
return(*str2 ? -1 : 0);
} else if (!*str2) {
return 1;
}
c1 = tolower(*str1++);
c2 = tolower(*str2++);
if (c1 < c2) {
return(-1);
}
if (c1 > c2) {
return(1);
}
}
return(0);
}
...@@ -1033,3 +1033,81 @@ a ...@@ -1033,3 +1033,81 @@ a
No No
aaa,bbb aaa,bbb
drop table t1,t2,t3,t4; drop table t1,t2,t3,t4;
create table t1 as
(select _latin1'test') union
(select _latin1'TEST') union
(select _latin1'TeST');
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`test` char(4) NOT NULL default ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1
select count(*) from t1;
count(*)
1
drop table t1;
create table t1 as
(select _latin1'test' collate latin1_bin) union
(select _latin1'TEST') union
(select _latin1'TeST');
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`_latin1'test' collate latin1_bin` char(4) character set latin1 collate latin1_bin NOT NULL default ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1
select count(*) from t1;
count(*)
3
drop table t1;
create table t1 as
(select _latin1'test') union
(select _latin1'TEST' collate latin1_bin) union
(select _latin1'TeST');
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`test` char(4) character set latin1 collate latin1_bin NOT NULL default ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1
select count(*) from t1;
count(*)
3
drop table t1;
create table t1 as
(select _latin1'test') union
(select _latin1'TEST') union
(select _latin1'TeST' collate latin1_bin);
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`test` char(4) character set latin1 collate latin1_bin NOT NULL default ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1
select count(*) from t1;
count(*)
3
drop table t1;
create table t2 (
a char character set latin1 collate latin1_swedish_ci,
b char character set latin1 collate latin1_bin);
create table t1 as
(select a from t2) union
(select b from t2);
ERROR HY000: Illegal mix of collations for operation 'UNION'
create table t1 as
(select a collate latin1_german1_ci from t2) union
(select b from t2);
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a collate latin1_german1_ci` char(1) character set latin1 collate latin1_german1_ci default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 as
(select a from t2) union
(select b collate latin1_german1_ci from t2);
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` char(1) character set latin1 collate latin1_german1_ci default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
drop table t2;
...@@ -595,3 +595,58 @@ select a as a from t3 union select "1"; ...@@ -595,3 +595,58 @@ select a as a from t3 union select "1";
select a as a from t4 union select a from t3; select a as a from t4 union select a from t3;
select a as a from t1 union select a from t4; select a as a from t1 union select a from t4;
drop table t1,t2,t3,t4; drop table t1,t2,t3,t4;
#
# Bug #6139 UNION doesn't understand collate in the column of second select
#
create table t1 as
(select _latin1'test') union
(select _latin1'TEST') union
(select _latin1'TeST');
show create table t1;
select count(*) from t1;
drop table t1;
create table t1 as
(select _latin1'test' collate latin1_bin) union
(select _latin1'TEST') union
(select _latin1'TeST');
show create table t1;
select count(*) from t1;
drop table t1;
create table t1 as
(select _latin1'test') union
(select _latin1'TEST' collate latin1_bin) union
(select _latin1'TeST');
show create table t1;
select count(*) from t1;
drop table t1;
create table t1 as
(select _latin1'test') union
(select _latin1'TEST') union
(select _latin1'TeST' collate latin1_bin);
show create table t1;
select count(*) from t1;
drop table t1;
create table t2 (
a char character set latin1 collate latin1_swedish_ci,
b char character set latin1 collate latin1_bin);
--error 1271
create table t1 as
(select a from t2) union
(select b from t2);
create table t1 as
(select a collate latin1_german1_ci from t2) union
(select b from t2);
show create table t1;
drop table t1;
create table t1 as
(select a from t2) union
(select b collate latin1_german1_ci from t2);
show create table t1;
drop table t1;
drop table t2;
...@@ -429,6 +429,36 @@ innobase_mysql_print_thd( ...@@ -429,6 +429,36 @@ innobase_mysql_print_thd(
putc('\n', f); putc('\n', f);
} }
/**********************************************************************
Compares NUL-terminated UTF-8 strings case insensitively.
NOTE that the exact prototype of this function has to be in
/innobase/dict/dict0dict.c! */
extern "C"
int
innobase_strcasecmp(
/*================*/
/* out: 0 if a=b, <0 if a<b, >1 if a>b */
const char* a, /* in: first string to compare */
const char* b) /* in: second string to compare */
{
return(my_strcasecmp(system_charset_info, a, b));
}
/**********************************************************************
Makes all characters in a NUL-terminated UTF-8 string lower case.
NOTE that the exact prototype of this function has to be in
/innobase/dict/dict0dict.c! */
extern "C"
void
innobase_casedn_str(
/*================*/
char* a) /* in/out: string to put in lower case */
{
my_casedn_str(system_charset_info, a);
}
/************************************************************************* /*************************************************************************
Creates a temporary file. */ Creates a temporary file. */
extern "C" extern "C"
...@@ -687,14 +717,7 @@ innobase_query_caching_of_table_permitted( ...@@ -687,14 +717,7 @@ innobase_query_caching_of_table_permitted(
separator between db and table */ separator between db and table */
norm_name[full_name_len] = '\0'; norm_name[full_name_len] = '\0';
#ifdef __WIN__ #ifdef __WIN__
/* Put to lower case */ innobase_casedn_str(norm_name);
char* ptr = norm_name;
while (*ptr != '\0') {
*ptr = tolower(*ptr);
ptr++;
}
#endif #endif
/* The call of row_search_.. will start a new transaction if it is /* The call of row_search_.. will start a new transaction if it is
not yet started */ not yet started */
...@@ -1539,14 +1562,7 @@ normalize_table_name( ...@@ -1539,14 +1562,7 @@ normalize_table_name(
norm_name[name_ptr - db_ptr - 1] = '/'; norm_name[name_ptr - db_ptr - 1] = '/';
#ifdef __WIN__ #ifdef __WIN__
/* Put to lower case */ innobase_casedn_str(norm_name);
ptr = norm_name;
while (*ptr != '\0') {
*ptr = tolower(*ptr);
ptr++;
}
#endif #endif
} }
...@@ -3559,9 +3575,9 @@ create_index( ...@@ -3559,9 +3575,9 @@ create_index(
field = form->field[j]; field = form->field[j];
if (0 == ut_cmp_in_lower_case( if (0 == innobase_strcasecmp(
(char*)field->field_name, field->field_name,
(char*)key_part->field->field_name)) { key_part->field->field_name)) {
/* Found the corresponding column */ /* Found the corresponding column */
break; break;
...@@ -4003,7 +4019,7 @@ innobase_drop_database( ...@@ -4003,7 +4019,7 @@ innobase_drop_database(
namebuf[len] = '/'; namebuf[len] = '/';
namebuf[len + 1] = '\0'; namebuf[len + 1] = '\0';
#ifdef __WIN__ #ifdef __WIN__
my_casedn_str(system_charset_info, namebuf); innobase_casedn_str(namebuf);
#endif #endif
trx = trx_allocate_for_mysql(); trx = trx_allocate_for_mysql();
trx->mysql_thd = current_thd; trx->mysql_thd = current_thd;
......
...@@ -2559,7 +2559,7 @@ bool Item_type_holder::join_types(THD *thd, Item *item) ...@@ -2559,7 +2559,7 @@ bool Item_type_holder::join_types(THD *thd, Item *item)
(new_result_type != item_type) || (new_length > max_length) || (new_result_type != item_type) || (new_length > max_length) ||
(!maybe_null && item->maybe_null) || (!maybe_null && item->maybe_null) ||
(item_type == STRING_RESULT && (item_type == STRING_RESULT &&
!my_charset_same(collation.collation, item->collation.collation))) collation.collation != item->collation.collation))
{ {
if (use_expression_type || item->type() != Item::FIELD_ITEM) if (use_expression_type || item->type() != Item::FIELD_ITEM)
field_example= 0; field_example= 0;
......
...@@ -264,9 +264,27 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, ...@@ -264,9 +264,27 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
} }
} }
// it is not single select
if (first_select->next_select()) if (first_select->next_select())
{ {
// it is not single select
/*
Check that it was possible to aggregate
all collations together for UNION.
*/
List_iterator_fast<Item> tp(types);
Item *type;
while ((type= tp++))
{
if (type->result_type() == STRING_RESULT &&
type->collation.derivation == DERIVATION_NONE)
{
my_error(ER_CANT_AGGREGATE_NCOLLATIONS, MYF(0), "UNION");
goto err;
}
}
union_result->tmp_table_param.field_count= types.elements; union_result->tmp_table_param.field_count= types.elements;
if (!(table= create_tmp_table(thd_arg, if (!(table= create_tmp_table(thd_arg,
&union_result->tmp_table_param, types, &union_result->tmp_table_param, types,
......
...@@ -58,8 +58,7 @@ using its non-default counterpart for the given character set. ...@@ -58,8 +58,7 @@ using its non-default counterpart for the given character set.
binary_numner - ID of a charset+collation pair, which consists binary_numner - ID of a charset+collation pair, which consists
of the same character set and the binary collation of this of the same character set and the binary collation of this
character set. Not really used now. Intended to optimize character set. Not really used now.
"SELECT BINARY x" in the future.
Names Names
----- -----
...@@ -121,7 +120,7 @@ Misc fields ...@@ -121,7 +120,7 @@ Misc fields
e.g. Letter 'A' with two dots above is e.g. Letter 'A' with two dots above is
substituted with 'AE'. substituted with 'AE'.
mbminlen - mininum multibyte sequence length. mbminlen - mininum multibyte sequence length.
Now always 1 accept ucs2. For ucs2 Now always 1 except ucs2. For ucs2
it is 2. it is 2.
mbmaxlen - maximum multibyte sequence length. mbmaxlen - maximum multibyte sequence length.
1 for 8bit charsets. Can be also 2 or 3. 1 for 8bit charsets. Can be also 2 or 3.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment