Commit cf52dd17 authored by Oleksandr Byelkin's avatar Oleksandr Byelkin

MDEV-22545: my_vsnprintf behaves not as in C standard

Added parameter %T for string which should be visibly truncated.
parent d8e2fa0c
......@@ -787,6 +787,7 @@ static ha_checksum checksum_format_specifier(const char* msg)
case 'x':
case 's':
case 'M':
case 'T':
chksum= my_checksum(chksum, (uchar*) start, (uint) (p + 1 - start));
start= 0; /* Not in format specifier anymore */
break;
......
......@@ -55,7 +55,8 @@
Supported formats are 's' (null pointer is accepted, printed as
"(null)"), 'b' (extension, see below), 'c', 'd', 'i', 'u', 'x', 'o',
'X', 'p' (works as 0x%x), 'f', 'g', 'M' (extension, see below).
'X', 'p' (works as 0x%x), 'f', 'g', 'M' (extension, see below),
'T' (extension, see below).
Standard syntax for positional arguments $n is supported.
......@@ -69,6 +70,9 @@
Format 'M': takes one integer, prints this integer, space, double quote
error message, double quote. In other words
printf("%M", n) === printf("%d \"%s\"", n, strerror(n))
Format 'T': takes string and print it like s but if the strints should be
truncated puts "..." at the end.
*/
#ifdef __cplusplus
......
......@@ -2,6 +2,6 @@ MySQL error code 150: Foreign key constraint is incorrectly formed
Win32 error code 150: System trace information was not specified in your CONFIG.SYS file, or tracing is disallowed.
OS error code 23: Too many open files in system
Win32 error code 23: Data error (cyclic redundancy check).
MySQL error code 1062 (ER_DUP_ENTRY): Duplicate entry '%-.192s' for key %d
MySQL error code 1062 (ER_DUP_ENTRY): Duplicate entry '%-.192T' for key %d
Win32 error code 1062: The service has not been started.
Illegal error code: 30000
Illegal error code: 10000
MySQL error code 1062 (ER_DUP_ENTRY): Duplicate entry '%-.192s' for key %d
MySQL error code 1062 (ER_DUP_ENTRY): Duplicate entry '%-.192T' for key %d
MySQL error code 1408 (ER_STARTUP): %s: ready for connections.
Version: '%s' socket: '%s' port: %d %s
MySQL error code 1459 (ER_TABLE_NEEDS_UPGRADE): Upgrade required. Please do "REPAIR %s %`s" or dump/reload to fix it!
......
......@@ -11,7 +11,7 @@ drop table t1;
connection slave;
include/wait_for_slave_sql_to_stop.inc
call mtr.add_suppression("Slave SQL.*Query caused different errors on master and slave.*Error on master:.* error code=1062.*Error on slave:.* error.* 0");
Error: "Query caused different errors on master and slave. Error on master: message (format)='Duplicate entry '%-.192s' for key %d' error code=1062 ; Error on slave: actual message='no error', error code=0. Default database: 'test'. Query: 'insert into t1 values(1),(2)'" (expected different error codes on master and slave)
Error: "Query caused different errors on master and slave. Error on master: message (format)='Duplicate entry '%-.192T' for key %d' error code=1062 ; Error on slave: actual message='no error', error code=0. Default database: 'test'. Query: 'insert into t1 values(1),(2)'" (expected different error codes on master and slave)
Errno: "0" (expected 0)
drop table t1;
include/stop_slave.inc
......
......@@ -6661,7 +6661,7 @@ Item_float::Item_float(THD *thd, const char *str_arg, uint length):
&error);
if (error)
{
char tmp[NAME_LEN + 1];
char tmp[NAME_LEN + 2];
my_snprintf(tmp, sizeof(tmp), "%.*s", length, str_arg);
my_error(ER_ILLEGAL_VALUE_FOR_TYPE, MYF(0), "double", tmp);
}
......
......@@ -997,11 +997,16 @@ static Item *create_comparator(MY_XPATH *xpath,
b->type() == Item::XPATH_NODESET)
{
uint len= (uint)(xpath->query.end - context->beg);
set_if_smaller(len, 32);
my_printf_error(ER_UNKNOWN_ERROR,
"XPATH error: "
"comparison of two nodesets is not supported: '%.*s'",
MYF(0), len, context->beg);
if (len <= 32)
my_printf_error(ER_UNKNOWN_ERROR,
"XPATH error: "
"comparison of two nodesets is not supported: '%.*s'",
MYF(0), len, context->beg);
else
my_printf_error(ER_UNKNOWN_ERROR,
"XPATH error: "
"comparison of two nodesets is not supported: '%.32T'",
MYF(0), context->beg);
return 0; // TODO: Comparison of two nodesets
}
......@@ -2634,9 +2639,12 @@ my_xpath_parse_VariableReference(MY_XPATH *xpath)
xpath->item= NULL;
DBUG_ASSERT(xpath->query.end > dollar_pos);
uint len= (uint)(xpath->query.end - dollar_pos);
set_if_smaller(len, 32);
my_printf_error(ER_UNKNOWN_ERROR, "Unknown XPATH variable at: '%.*s'",
MYF(0), len, dollar_pos);
if (len <= 32)
my_printf_error(ER_UNKNOWN_ERROR, "Unknown XPATH variable at: '%.*s'",
MYF(0), len, dollar_pos);
else
my_printf_error(ER_UNKNOWN_ERROR, "Unknown XPATH variable at: '%.32T'",
MYF(0), dollar_pos);
}
}
return xpath->item ? 1 : 0;
......@@ -2767,9 +2775,13 @@ bool Item_xml_str_func::fix_fields(THD *thd, Item **ref)
if (!rc)
{
uint clen= (uint)(xpath.query.end - xpath.lasttok.beg);
set_if_smaller(clen, 32);
my_printf_error(ER_UNKNOWN_ERROR, "XPATH syntax error: '%.*s'",
MYF(0), clen, xpath.lasttok.beg);
if (clen <= 32)
my_printf_error(ER_UNKNOWN_ERROR, "XPATH syntax error: '%.*s'",
MYF(0), clen, xpath.lasttok.beg);
else
my_printf_error(ER_UNKNOWN_ERROR, "XPATH syntax error: '%.32T'",
MYF(0), xpath.lasttok.beg);
return true;
}
......
This diff is collapsed.
......@@ -224,7 +224,8 @@ static char *backtick_string(CHARSET_INFO *cs, char *to, const char *end,
*/
static char *process_str_arg(CHARSET_INFO *cs, char *to, const char *end,
size_t width, char *par, uint print_type)
size_t width, char *par, uint print_type,
my_bool nice_cut)
{
int well_formed_error;
uint dots= 0;
......@@ -232,24 +233,34 @@ static char *process_str_arg(CHARSET_INFO *cs, char *to, const char *end,
if (!par)
par = (char*) "(null)";
plen= slen= strnlen(par, width + 1);
if (plen > width)
plen= width;
if (left_len <= plen)
plen = left_len - 1;
if ((slen > plen))
if (nice_cut)
{
if (plen < 3)
plen= slen= strnlen(par, width + 1);
if (plen > width)
plen= width;
if (left_len <= plen)
plen = left_len - 1;
if ((slen > plen))
{
dots= (uint) plen;
plen= 0;
}
else
{
dots= 3;
plen-= 3;
if (plen < 3)
{
dots= (uint) plen;
plen= 0;
}
else
{
dots= 3;
plen-= 3;
}
}
}
else
{
plen= slen= strnlen(par, width);
dots= 0;
if (left_len <= plen)
plen = left_len - 1;
}
plen= my_well_formed_length(cs, par, par + plen, width, &well_formed_error);
if (print_type & ESCAPED_ARG)
......@@ -446,6 +457,7 @@ static char *process_args(CHARSET_INFO *cs, char *to, char *end,
switch (args_arr[i].arg_type) {
case 's':
case 'b':
case 'T':
args_arr[i].str_arg= va_arg(ap, char *);
break;
case 'f':
......@@ -480,12 +492,14 @@ static char *process_args(CHARSET_INFO *cs, char *to, char *end,
size_t width= 0, length= 0;
switch (print_arr[i].arg_type) {
case 's':
case 'T':
{
char *par= args_arr[print_arr[i].arg_idx].str_arg;
width= (print_arr[i].flags & WIDTH_ARG)
? (size_t)args_arr[print_arr[i].width].longlong_arg
: print_arr[i].width;
to= process_str_arg(cs, to, end, width, par, print_arr[i].flags);
to= process_str_arg(cs, to, end, width, par, print_arr[i].flags,
(print_arr[i].arg_type == 'T'));
break;
}
case 'b':
......@@ -552,7 +566,7 @@ static char *process_args(CHARSET_INFO *cs, char *to, char *end,
*to++= '"';
my_strerror(errmsg_buff, sizeof(errmsg_buff), (int) larg);
to= process_str_arg(cs, to, real_end, width, errmsg_buff,
print_arr[i].flags);
print_arr[i].flags, 1);
if (real_end > to) *to++= '"';
}
break;
......@@ -676,10 +690,10 @@ size_t my_vsnprintf_ex(CHARSET_INFO *cs, char *to, size_t n,
fmt= check_longlong(fmt, &have_longlong);
if (*fmt == 's') /* String parameter */
if (*fmt == 's' || *fmt == 'T') /* String parameter */
{
reg2 char *par= va_arg(ap, char *);
to= process_str_arg(cs, to, end, width, par, print_type);
to= process_str_arg(cs, to, end, width, par, print_type, (*fmt == 'T'));
continue;
}
else if (*fmt == 'b') /* Buffer parameter */
......@@ -731,7 +745,8 @@ size_t my_vsnprintf_ex(CHARSET_INFO *cs, char *to, size_t n,
*to++= ' ';
*to++= '"';
my_strerror(errmsg_buff, sizeof(errmsg_buff), (int) larg);
to= process_str_arg(cs, to, real_end, width, errmsg_buff, print_type);
to= process_str_arg(cs, to, real_end, width, errmsg_buff,
print_type, 1);
if (real_end > to) *to++= '"';
}
continue;
......
......@@ -61,7 +61,7 @@ static void test_many(const char **res, const char *fmt, ...)
int main(void)
{
plan(43);
plan(47);
test1("Constant string",
"Constant string");
......@@ -99,27 +99,33 @@ int main(void)
test1("Width is ignored for strings <x> <y>",
"Width is ignored for strings <%04s> <%5s>", "x", "y");
test1("Precision works for strings <ab...>",
test1("Precision works for strings <abcde>",
"Precision works for strings <%.5s>", "abcdef!");
test1("Precision works for strings <ab...>",
"Precision works for strings <%.5T>", "abcdef!");
test1("Flag '`' (backtick) works: `abcd` `op``q` (mysql extension)",
"Flag '`' (backtick) works: %`s %`.4s (mysql extension)",
"abcd", "op`qrst");
test1("Flag '`' (backtick) works: `abcd` `op``q...` (mysql extension)",
"Flag '`' (backtick) works: %`s %`.7s (mysql extension)",
"Flag '`' (backtick) works: %`T %`.7T (mysql extension)",
"abcd", "op`qrstuuuuuuuuu");
test1("Flag '`' (backtick) works: `abcd` `.` (mysql extension)",
"Flag '`' (backtick) works: %`s %`.1s (mysql extension)",
"Flag '`' (backtick) works: %`T %`.1T (mysql extension)",
"abcd", "op`qrstuuuuuuuuu");
test1("Flag '`' (backtick) works: `abcd` `...` (mysql extension)",
"Flag '`' (backtick) works: %`s %`.3s (mysql extension)",
"Flag '`' (backtick) works: %`T %`.3T (mysql extension)",
"abcd", "op`qrstuuuuuuuuu");
test1("Flag '`' (backtick) works: `abcd` `op...` (mysql extension)",
"Flag '`' (backtick) works: %`s %`.5s (mysql extension)",
"Flag '`' (backtick) works: %`T %`.5T (mysql extension)",
"abcd", "op`qrstuuuuuuuuu");
test1("Flag '`' (backtick) works: `abcd` `op``...` (mysql extension)",
"Flag '`' (backtick) works: %`s %`.6s (mysql extension)",
"Flag '`' (backtick) works: %`T %`.6T (mysql extension)",
"abcd", "op`qrstuuuuuuuuu");
test1("Length modifiers work: 1 * -1 * 2 * 3",
......@@ -141,15 +147,21 @@ int main(void)
test1("Asterisk '*' as a width works: < 4>",
"Asterisk '*' as a width works: <%*d>", 5, 4);
test1("Asterisk '*' as a precision works: <qwe...>",
test1("Asterisk '*' as a precision works: <qwerty>",
"Asterisk '*' as a precision works: <%.*s>", 6, "qwertyuiop");
test1("Asterisk '*' as a precision works: <qwe...>",
"Asterisk '*' as a precision works: <%.*T>", 6, "qwertyuiop");
test1("Positional arguments for a width: < 4>",
"Positional arguments for a width: <%1$*2$d>", 4, 5);
test1("Positional arguments for a precision: <qwe...>",
test1("Positional arguments for a precision: <qwerty>",
"Positional arguments for a precision: <%1$.*2$s>", "qwertyuiop", 6);
test1("Positional arguments for a precision: <qwe...>",
"Positional arguments for a precision: <%1$.*2$T>", "qwertyuiop", 6);
test1("Positional arguments and a width: <0000ab>",
"Positional arguments and a width: <%1$06x>", 0xab);
......
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