summaryrefslogtreecommitdiff
path: root/sql/sql_string.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_string.cc')
-rw-r--r--sql/sql_string.cc73
1 files changed, 73 insertions, 0 deletions
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index 7759985ba85..7c9793b273b 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -1119,3 +1119,76 @@ void String::swap(String &s)
swap_variables(bool, alloced, s.alloced);
swap_variables(CHARSET_INFO*, str_charset, s.str_charset);
}
+
+
+/**
+ Convert string to printable ASCII string
+
+ @details This function converts input string "from" replacing non-ASCII bytes
+ with hexadecimal sequences ("\xXX") optionally appending "..." to the end of
+ the resulting string.
+ This function used in the ER_TRUNCATED_WRONG_VALUE_FOR_FIELD error messages,
+ e.g. when a string cannot be converted to a result charset.
+
+
+ @param to output buffer
+ @param to_len size of the output buffer (8 bytes or greater)
+ @param from input string
+ @param from_len size of the input string
+ @param from_cs input charset
+ @param nbytes maximal number of bytes to convert (from_len if 0)
+
+ @return number of bytes in the output string
+*/
+
+uint convert_to_printable(char *to, size_t to_len,
+ const char *from, size_t from_len,
+ CHARSET_INFO *from_cs, size_t nbytes /*= 0*/)
+{
+ /* needs at least 8 bytes for '\xXX...' and zero byte */
+ DBUG_ASSERT(to_len >= 8);
+
+ char *t= to;
+ char *t_end= to + to_len - 1; // '- 1' is for the '\0' at the end
+ const char *f= from;
+ const char *f_end= from + (nbytes ? min(from_len, nbytes) : from_len);
+ char *dots= to; // last safe place to append '...'
+
+ if (!f || t == t_end)
+ return 0;
+
+ for (; t < t_end && f < f_end; f++)
+ {
+ /*
+ If the source string is ASCII compatible (mbminlen==1)
+ and the source character is in ASCII printable range (0x20..0x7F),
+ then display the character as is.
+
+ Otherwise, if the source string is not ASCII compatible (e.g. UCS2),
+ or the source character is not in the printable range,
+ then print the character using HEX notation.
+ */
+ if (((unsigned char) *f) >= 0x20 &&
+ ((unsigned char) *f) <= 0x7F &&
+ from_cs->mbminlen == 1)
+ {
+ *t++= *f;
+ }
+ else
+ {
+ if (t_end - t < 4) // \xXX
+ break;
+ *t++= '\\';
+ *t++= 'x';
+ *t++= _dig_vec_upper[((unsigned char) *f) >> 4];
+ *t++= _dig_vec_upper[((unsigned char) *f) & 0x0F];
+ }
+ if (t_end - t >= 3) // '...'
+ dots= t;
+ }
+ if (f < from + from_len)
+ memcpy(dots, STRING_WITH_LEN("...\0"));
+ else
+ *t= '\0';
+ return t - to;
+}