diff options
Diffstat (limited to 'sql/item_strfunc.cc')
-rw-r--r-- | sql/item_strfunc.cc | 93 |
1 files changed, 71 insertions, 22 deletions
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 7b28a9d4550..720313f4be7 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -2071,41 +2071,90 @@ String* Item_func_inet_ntoa::val_str(String* str) return str; } -#define get_esc_bit(mask, num) (1 & (*((mask) + ((num) >> 3))) >> ((num) & 7)) - /* - QUOTE() function returns argument string in single quotes, - also adds a \ before \, ' CHAR(0) and CHAR(24) + QUOTE() function returns argument string in single quotes suitable for + using in a SQL statement. + + DESCRIPTION + Adds a \ before all characters that needs to be escaped in a SQL string. + We also escape '^Z' (END-OF-FILE in windows) to avoid probelms when + running commands from a file in windows. + + This function is very useful when you want to generate SQL statements + + RETURN VALUES + str Quoted string + NULL Argument to QUOTE() was NULL or out of memory. */ + +#define get_esc_bit(mask, num) (1 & (*((mask) + ((num) >> 3))) >> ((num) & 7)) + String *Item_func_quote::val_str(String *str) { - static char escmask[32] = {0x01, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - String *arg= args[0]->val_str(str); - char *from, *to, *end; - uint delta= 2; /* for beginning and ending ' signs */ + /* + Bit mask that has 1 for set for the position of the following characters: + 0, \, ' and ^Z + */ + + static char escmask[32]= + { + 0x01, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; - if (!arg) + char *from, *to, *end, *start; + String *arg= args[0]->val_str(str); + uint arg_length, new_length; + if (!arg) // Null argument goto null; + arg_length= arg->length(); + new_length= arg_length+2; /* for beginning and ending ' signs */ - for (from= (char*) arg->ptr(), end= from + arg->length(); from < end; from++) - delta+= get_esc_bit(escmask, *from); + for (from= (char*) arg->ptr(), end= from + arg_length; from < end; from++) + new_length+= get_esc_bit(escmask, *from); - if (str->alloc(arg->length() + delta)) + /* + We have to use realloc() instead of alloc() as we want to keep the + old result in str + */ + if (str->realloc(new_length)) goto null; - to= (char*) str->ptr() + arg->length() + delta - 1; + + /* + As 'arg' and 'str' may be the same string, we must replace characters + from the end to the beginning + */ + to= (char*) str->ptr() + new_length - 1; *to--= '\''; - for (end= (char*) arg->ptr(), from= end + arg->length() - 1; from >= end; - from--, to--) + for (start= (char*) arg->ptr() ; end-- != start; to--) { - *to= *from; - if (get_esc_bit(escmask, *from)) - *--to= '\\'; + /* + We can't use the bitmask here as we want to replace \O and ^Z with 0 + and Z + */ + switch (*end) { + case 0: + *to--= '0'; + *to= '\\'; + break; + case '\032': + *to--= 'Z'; + *to= '\\'; + break; + case '\'': + case '\\': + *to--= *end; + *to= '\\'; + break; + default: + *to= *end; + break; + } } *to= '\''; - str->length(arg->length() + delta); + str->length(new_length); return str; null: |