mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-04 04:46:15 +01:00 
			
		
		
		
	Under terms of MDEV 27490 we'll add support for non-BMP identifiers and upgrade casefolding information to Unicode version 14.0.0. In Unicode-14.0.0 conversion to lower and upper cases can increase octet length of the string, so conversion won't be possible in-place any more. This patch removes virtual functions performing in-place casefolding: - my_charset_handler_st::casedn_str() - my_charset_handler_st::caseup_str() and fixes the code to use the non-inplace functions instead: - my_charset_handler_st::casedn() - my_charset_handler_st::caseup()
		
			
				
	
	
		
			176 lines
		
	
	
	
		
			5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			176 lines
		
	
	
	
		
			5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#ifndef CHAR_BUFFER_INCLUDED
 | 
						|
#define CHAR_BUFFER_INCLUDED
 | 
						|
/*
 | 
						|
   Copyright (c) 2023, MariaDB
 | 
						|
 | 
						|
   This program is free software; you can redistribute it and/or
 | 
						|
   modify it under the terms of the GNU General Public License
 | 
						|
   as published by the Free Software Foundation; version 2 of
 | 
						|
   the License.
 | 
						|
 | 
						|
   This program is distributed in the hope that it will be useful,
 | 
						|
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | 
						|
   GNU General Public License for more details.
 | 
						|
 | 
						|
   You should have received a copy of the GNU General Public License
 | 
						|
   along with this program; if not, write to the Free Software
 | 
						|
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335  USA
 | 
						|
*/
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
  A string buffer with length.
 | 
						|
  This template class is useful to store things like database, table names,
 | 
						|
  whose maximum length a small fixed known value. Mainly to be used as
 | 
						|
  stack variables to store temporary values.
 | 
						|
 | 
						|
  Can store exact string copies or casefolded string copies.
 | 
						|
  The stored value is returned as a LEX_CSTRING.
 | 
						|
*/
 | 
						|
template<size_t buff_sz>
 | 
						|
class CharBuffer
 | 
						|
{
 | 
						|
  char m_buff[buff_sz + 1 /* one extra byte for '\0' */];
 | 
						|
  size_t m_length;
 | 
						|
  bool is_sane() const
 | 
						|
  {
 | 
						|
    return m_length <= buff_sz; // One byte is still left for '\0'
 | 
						|
  }
 | 
						|
  bool buffer_overlaps(const LEX_CSTRING &str) const
 | 
						|
  {
 | 
						|
    return str.str + str.length >= m_buff && str.str <= m_buff + sizeof(m_buff);
 | 
						|
  }
 | 
						|
public:
 | 
						|
  constexpr size_t max_data_size() const
 | 
						|
  {
 | 
						|
    return buff_sz; // The maximum data size, without the trailing '\0' byte.
 | 
						|
  }
 | 
						|
  size_t available_size() const
 | 
						|
  {
 | 
						|
    DBUG_ASSERT(is_sane());
 | 
						|
    return buff_sz - m_length;
 | 
						|
  }
 | 
						|
  CharBuffer()
 | 
						|
   :m_length(0)
 | 
						|
  {
 | 
						|
    m_buff[0]= '\0';
 | 
						|
  }
 | 
						|
  CharBuffer<buff_sz> & copy(const LEX_CSTRING &str)
 | 
						|
  {
 | 
						|
    DBUG_ASSERT(!buffer_overlaps(str));
 | 
						|
    m_length= MY_MIN(buff_sz, str.length);
 | 
						|
    memcpy(m_buff, str.str, m_length);
 | 
						|
    m_buff[m_length]= '\0';
 | 
						|
    return *this;
 | 
						|
  }
 | 
						|
  CharBuffer<buff_sz> & copy_casedn(CHARSET_INFO *cs, const LEX_CSTRING &str)
 | 
						|
  {
 | 
						|
    DBUG_ASSERT(!buffer_overlaps(str));
 | 
						|
    m_length= cs->cset->casedn(cs, str.str, str.length, m_buff, buff_sz);
 | 
						|
    /*
 | 
						|
      casedn() never writes outsize of buff_sz (unless a bug in casedn()),
 | 
						|
      so it's safe to write '\0' at the position m_length:
 | 
						|
    */
 | 
						|
    DBUG_ASSERT(is_sane());
 | 
						|
    m_buff[m_length]= '\0';
 | 
						|
    return *this;
 | 
						|
  }
 | 
						|
  CharBuffer<buff_sz> & copy_caseup(CHARSET_INFO *cs, const LEX_CSTRING &str)
 | 
						|
  {
 | 
						|
    DBUG_ASSERT(!buffer_overlaps(str));
 | 
						|
    m_length= cs->cset->caseup(cs, str.str, str.length, m_buff, buff_sz);
 | 
						|
    DBUG_ASSERT(is_sane());
 | 
						|
    m_buff[m_length]= '\0'; // See comments in copy_casedn()
 | 
						|
    return *this;
 | 
						|
  }
 | 
						|
  CharBuffer<buff_sz> & copy_casedn(CHARSET_INFO *cs, const LEX_CSTRING &str,
 | 
						|
                                    bool casedn)
 | 
						|
  {
 | 
						|
    casedn ? copy_casedn(cs, str) : copy(str);
 | 
						|
    return *this;
 | 
						|
  }
 | 
						|
 | 
						|
  // Append one character
 | 
						|
  CharBuffer<buff_sz> & append_char(char ch)
 | 
						|
  {
 | 
						|
    DBUG_ASSERT(is_sane());
 | 
						|
    if (available_size())
 | 
						|
    {
 | 
						|
      m_buff[m_length++]= ch;
 | 
						|
      m_buff[m_length]= '\0';
 | 
						|
    }
 | 
						|
    DBUG_ASSERT(is_sane());
 | 
						|
    return *this;
 | 
						|
  }
 | 
						|
 | 
						|
  // Append a string
 | 
						|
  CharBuffer<buff_sz> & append(const LEX_CSTRING &str)
 | 
						|
  {
 | 
						|
    DBUG_ASSERT(is_sane());
 | 
						|
    DBUG_ASSERT(!buffer_overlaps(str));
 | 
						|
    size_t len= MY_MIN(available_size(), str.length);
 | 
						|
    memcpy(m_buff + m_length, str.str, len);
 | 
						|
    m_length+= len;
 | 
						|
    DBUG_ASSERT(is_sane());
 | 
						|
    m_buff[m_length]= '\0';
 | 
						|
    return *this;
 | 
						|
  }
 | 
						|
 | 
						|
  // Append a string with casedn conversion
 | 
						|
  CharBuffer<buff_sz> & append_casedn(CHARSET_INFO *cs, const LEX_CSTRING &str)
 | 
						|
  {
 | 
						|
    DBUG_ASSERT(is_sane());
 | 
						|
    DBUG_ASSERT(!buffer_overlaps(str));
 | 
						|
    size_t casedn_length= cs->casedn(str.str, str.length,
 | 
						|
                                     m_buff + m_length, available_size());
 | 
						|
    m_length+= casedn_length;
 | 
						|
    DBUG_ASSERT(is_sane());
 | 
						|
    m_buff[m_length]= '\0';
 | 
						|
    return *this;
 | 
						|
  }
 | 
						|
 | 
						|
  CharBuffer<buff_sz> & append_opt_casedn(CHARSET_INFO *cs,
 | 
						|
                                          const LEX_CSTRING &str,
 | 
						|
                                          bool casedn)
 | 
						|
  {
 | 
						|
    return casedn ? append_casedn(cs, str) : append(str);
 | 
						|
  }
 | 
						|
 | 
						|
  // Append a string with caseup conversion
 | 
						|
  CharBuffer<buff_sz> & append_caseup(CHARSET_INFO *cs, const LEX_CSTRING &str)
 | 
						|
  {
 | 
						|
    DBUG_ASSERT(is_sane());
 | 
						|
    DBUG_ASSERT(!buffer_overlaps(str));
 | 
						|
    size_t casedn_length= cs->caseup(str.str, str.length,
 | 
						|
                                     m_buff + m_length, available_size());
 | 
						|
    m_length+= casedn_length;
 | 
						|
    DBUG_ASSERT(is_sane());
 | 
						|
    m_buff[m_length]= '\0';
 | 
						|
    return *this;
 | 
						|
  }
 | 
						|
 | 
						|
  CharBuffer<buff_sz> & truncate(size_t length)
 | 
						|
  {
 | 
						|
    DBUG_ASSERT(is_sane());
 | 
						|
    if (m_length > length)
 | 
						|
    {
 | 
						|
      m_length= length;
 | 
						|
      m_buff[m_length]= '\0';
 | 
						|
      DBUG_ASSERT(is_sane());
 | 
						|
    }
 | 
						|
    return *this;
 | 
						|
  }
 | 
						|
 | 
						|
  LEX_CSTRING to_lex_cstring() const
 | 
						|
  {
 | 
						|
    return LEX_CSTRING{m_buff, m_length};
 | 
						|
  }
 | 
						|
 | 
						|
  const char *ptr() const { return m_buff; }
 | 
						|
  size_t length() const { return m_length; }
 | 
						|
  const char *end() const { return m_buff + m_length; }
 | 
						|
 | 
						|
};
 | 
						|
 | 
						|
#endif // CHAR_BUFFER_INCLUDED
 |