ulong myodbc_escape_string()

in driver/utility.cc [2469:2592]


ulong myodbc_escape_string(STMT *stmt,
                           char *to, ulong to_length,
                           const char *from, ulong length,
                           bool escape_id,
                           bool esc_wildcard)
{
  const char *to_start= to;
  const char *end, *to_end=to_start + (to_length ? to_length-1 : 2*length);

  my_bool overflow= FALSE;
  myodbc::CHARSET_INFO *charset_info= stmt->dbc->cxn_charset_info;

  /*
    The character to be escaped by doubling it -- for identifiers it is the backquote, for string
    literals it is the single quote.
  */

  char double_char = (escape_id ? '`' : '\'');

  /*
    Whether to use backslash escapes. Note that this is not the case when escaping an identifier.
  */

  bool use_backslash
    = (!escape_id &&
      !(stmt->dbc->mysql->server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES));

  my_bool use_mb_flag= use_mb(charset_info);

  for (end= from + length; from < end; ++from)
  {
    char escape= 0;
    int tmp_length;

    // Handle multi-byte sequences

    if (use_mb_flag && (tmp_length= my_ismbchar(charset_info, from, end)))
    {
      if (to + tmp_length > to_end)
      {
        overflow= TRUE;
        break;
      }
      while (tmp_length--)
        *to++= *from++;
      --from;
      continue;
    }

    if (double_char && *from == double_char)
      escape = double_char;

      /*
        If the next character appears to begin a multi-byte character, we
        escape that first byte of that apparent multi-byte character. (The
        character just looks like a multi-byte character -- if it were actually
        a multi-byte character, it would have been passed through in the test
        above.)

        Without this check, we can create a problem by converting an invalid
        multi-byte character into a valid one. For example, 0xbf27 is not
        a valid GBK character, but 0xbf5c is. (0x27 = ', 0x5c = \)
      */

    else if (use_mb_flag && (tmp_length= my_mbcharlen(charset_info, *from)) > 1)
      escape= *from;

      /*
        Note: If use_backslash is false then we will not set `escape` character and the logic
        below will copy input to output as is.
      */

    else if (use_backslash)
      switch (*from)
      {
      case 0:         // Must be escaped for 'mysql'
        escape= '0';
        break;
      case '\n':      // Must be escaped for logs
        escape= 'n';
        break;
      case '\r':
        escape= 'r';
        break;
      case '\\':
      case '\'':
      case '"':       // Better safe than sorry
        escape= *from;
        break;
      case '\032':    // This gives problems on Win32
        escape= 'Z';
        break;
      case '_':       // Escaping of the pattern characters
      case '%':
        if (esc_wildcard)
          escape = *from;
        break;
      }

    if (escape)
    {
      if (to + 2 > to_end)
      {
        overflow= TRUE;
        break;
      }
      *to++= (escape == double_char ? escape : '\\');
      *to++= escape;
    }
    else
    {
      if (to + 1 > to_end)
      {
        overflow= TRUE;
        break;
      }
      *to++= *from;
    }

  }  // for

  *to= 0;
  return overflow ? (ulong)~0 : (ulong) (to - to_start);
}