Commit ced3ec4c authored by Marko Mäkelä's avatar Marko Mäkelä

Revert MDEV-20453 (string_view)

In fsp_path_to_space_name(), we would access a byte right before
the start of the string, tripping AddressSanitizer.

This reverts commit d87006a1
and commit a7634281.
parent 9936cfd5
/*****************************************************************************
Copyright (c) 2020 MariaDB Corporation.
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 Street, Fifth Floor, Boston, MA 02110-1335 USA
*****************************************************************************/
#ifndef STRING_VIEW_H
#define STRING_VIEW_H
#include <cassert>
#include <cstddef>
#include <algorithm>
#include <iosfwd>
#include <iterator>
#include <limits>
#include <memory>
#include <stdexcept>
#include <string>
#include "my_attribute.h"
class string_view
{
public:
using traits_type= std::char_traits<char>;
using value_type= char;
using pointer= char *;
using const_pointer= const char *;
using reference= char &;
using const_reference= const char &;
using const_iterator= const char *;
using iterator= const_iterator;
using const_reverse_iterator= std::reverse_iterator<const_iterator>;
using reverse_iterator= const_reverse_iterator;
using size_type= std::size_t;
using difference_type= std::ptrdiff_t;
static constexpr size_type npos= size_type(-1);
constexpr string_view() noexcept : str_(nullptr), size_(0) {}
constexpr string_view(const string_view &rhs) noexcept= default;
constexpr string_view(const char *s, size_type count) : str_(s), size_(count)
{
}
string_view(const char *s) : str_(s), size_(traits_type::length(s)) {}
// In C++20 it's different.
template <class It>
constexpr string_view(It first, It last) : str_(&*first), size_(last - first)
{
}
// Add such ctor because we can't add string_view operator to std::string
string_view(const std::string &s) noexcept : str_(s.data()), size_(s.size())
{
}
string_view &operator=(const string_view &rhs)
{
str_= rhs.str_;
size_= rhs.size_;
return *this;
}
constexpr const_iterator begin() const noexcept { return str_; }
constexpr const_iterator cbegin() const noexcept { return str_; }
constexpr const_iterator end() const noexcept { return str_ + size_; }
constexpr const_iterator cend() const noexcept { return str_ + size_; }
const_reverse_iterator rbegin() const noexcept
{
return const_reverse_iterator(end());
}
const_reverse_iterator crbegin() const noexcept
{
return const_reverse_iterator(end());
}
const_reverse_iterator rend() const noexcept
{
return const_reverse_iterator(begin());
}
const_reverse_iterator crend() const noexcept
{
return const_reverse_iterator(begin());
}
constexpr const_reference operator[](size_type pos) const noexcept
{
return str_[pos];
}
const_reference at(size_type pos) const
{
if (pos >= size())
throw std::out_of_range("string_view::at()");
return str_[pos];
}
constexpr const_reference front() const noexcept { return operator[](0); }
constexpr const_reference back() const noexcept
{
return operator[](size() - 1);
}
constexpr const_pointer data() const noexcept { return str_; }
constexpr size_type size() const noexcept { return size_; }
constexpr size_type length() const noexcept { return size_; }
constexpr size_type max_size() const noexcept
{
return std::numeric_limits<size_type>::max();
}
constexpr __attribute__((warn_unused_result)) bool empty() const noexcept
{
return size() == 0;
}
void remove_prefix(size_type n)
{
assert(n <= size());
str_+= n;
size_-= n;
}
void remove_suffix(size_type n)
{
assert(n <= size());
size_-= n;
}
void swap(string_view &rhs) noexcept
{
std::swap(str_, rhs.str_);
std::swap(size_, rhs.size_);
}
size_type copy(char *dest, size_type count, size_type pos= 0) const
{
if (pos > size())
throw std::out_of_range("string_view::copy()");
auto rcount= std::min(size() - pos, count);
traits_type::copy(dest, data() + pos, rcount);
return rcount;
}
string_view substr(size_type pos= 0, size_type count= npos) const
{
if (pos > size())
throw std::out_of_range("string_view::substr()");
auto rcount= std::min(size() - pos, count);
return {data() + pos, pos + rcount};
}
int compare(string_view v) const noexcept
{
auto rlen= std::min(size(), v.size());
return traits_type::compare(data(), v.data(), rlen);
}
int compare(size_type pos1, size_type count1, string_view v) const
{
return substr(pos1, count1).compare(v);
}
int compare(size_type pos1, size_type count1, string_view v, size_type pos2,
size_type count2) const
{
return substr(pos1, count1).compare(v.substr(pos2, count2));
}
int compare(const char *s) const { return compare(string_view(s)); }
int compare(size_type pos1, size_type count1, const char *s) const
{
return substr(pos1, count1).compare(string_view(s));
}
int compare(size_type pos1, size_type count1, const char *s,
size_type count2) const
{
return substr(pos1, count1).compare(string_view(s, count2));
}
bool starts_with(string_view sv) const noexcept
{
return substr(0, sv.size()) == sv;
}
constexpr bool starts_with(char c) const noexcept
{
return !empty() && traits_type::eq(front(), c);
}
bool starts_with(const char *s) const { return starts_with(string_view(s)); }
bool ends_with(string_view sv) const noexcept
{
return size() >= sv.size() && compare(size() - sv.size(), npos, sv) == 0;
}
constexpr bool ends_with(char c) const noexcept
{
return !empty() && traits_type::eq(back(), c);
}
bool ends_with(const char *s) const { return ends_with(string_view(s)); }
size_type find(string_view v, size_type pos= 0) const noexcept
{
// TODO: optimize with std::strstr()
auto it= std::search(begin() + pos, end(), v.begin(), v.end());
if (it == end())
return npos;
return it - begin();
}
size_type find(char ch, size_type pos= 0) const noexcept
{
return find(string_view(std::addressof(ch), 1));
}
size_type find(const char *s, size_type pos, size_type count) const
{
return find(string_view(s, count), pos);
}
size_type find(const char *s, size_type pos= 0) const
{
return find(string_view(s), pos);
}
size_type rfind(string_view v, size_type pos= npos) const noexcept
{
size_type result= npos;
for (;;)
{
auto where= find(v, pos);
if (where == npos)
break;
result= where;
pos= where + v.size();
}
return result;
}
size_type rfind(char c, size_type pos= npos) const noexcept
{
return rfind(string_view(std::addressof(c), 1), pos);
}
size_type rfind(const char *s, size_type pos, size_type count) const
{
return rfind(string_view(s, count), pos);
}
size_type rfind(const char *s, size_type pos= npos) const
{
return rfind(string_view(s), pos);
}
size_type find_first_of(string_view v, size_type pos= 0) const noexcept
{
// TODO: optimize with a lookup table.
auto it= std::find_if(begin() + pos, end(),
[v](char c) { return v.find(c) != npos; });
if (it == end())
return npos;
return it - begin();
}
size_type find_first_of(char c, size_type pos= 0) const noexcept
{
return find_first_of(string_view(std::addressof(c), 1), pos);
}
size_type find_first_of(const char *s, size_type pos, size_type count) const
{
return find_first_of(string_view(s, count), pos);
}
size_type find_first_of(const char *s, size_type pos= 0) const
{
return find_first_of(string_view(s), pos);
}
size_type find_last_of(string_view v, size_type pos= npos) const noexcept
{
// TODO: optimize with a lookup table.
auto it= std::find_if(reverse_iterator(begin() + pos), rend(),
[v](char c) { return v.find(c) != npos; });
if (it == rend())
return npos;
return it.base() - begin();
}
size_type find_last_of(char c, size_type pos= npos) const noexcept
{
return find_last_of(string_view(std::addressof(c), 1), pos);
}
size_type find_last_of(const char *s, size_type pos, size_type count) const
{
return find_last_of(string_view(s, count), pos);
}
size_type find_last_of(const char *s, size_type pos= npos) const
{
return find_last_of(string_view(s), pos);
}
size_type find_first_not_of(string_view v, size_type pos= 0) const noexcept
{
// TODO: optimize with a lookup table.
auto it= std::find_if(begin() + pos, end(),
[v](char c) { return v.find(c) == npos; });
if (it == end())
return npos;
return it - begin();
}
size_type find_first_not_of(char c, size_type pos= 0) const noexcept
{
return find_first_not_of(string_view(std::addressof(c), 1), pos);
}
size_type find_first_not_of(const char *s, size_type pos,
size_type count) const
{
return find_first_not_of(string_view(s, count), pos);
}
size_type find_first_not_of(const char *s, size_type pos= 0) const
{
return find_first_not_of(string_view(s), pos);
}
size_type find_last_not_of(string_view v, size_type pos= npos) const noexcept
{
// TODO: optimize with a lookup table.
auto it= std::find_if(reverse_iterator(begin() + pos), rend(),
[v](char c) { return v.find(c) == npos; });
if (it == rend())
return npos;
return it.base() - begin();
}
size_type find_last_not_of(char c, size_type pos= npos) const noexcept
{
return find_last_not_of(string_view(std::addressof(c), 1), pos);
}
size_type find_last_not_of(const char *s, size_type pos,
size_type count) const
{
return find_last_not_of(string_view(s, count), pos);
}
size_type find_last_not_of(const char *s, size_type pos= npos) const
{
return find_last_not_of(string_view(s), pos);
}
friend bool operator==(string_view lhs, string_view rhs) noexcept
{
return lhs.compare(rhs) == 0;
}
friend bool operator!=(string_view lhs, string_view rhs) noexcept
{
return lhs.compare(rhs) != 0;
}
friend bool operator<(string_view lhs, string_view rhs) noexcept
{
return lhs.compare(rhs) < 0;
}
friend bool operator<=(string_view lhs, string_view rhs) noexcept
{
return lhs.compare(rhs) <= 0;
}
friend bool operator>(string_view lhs, string_view rhs) noexcept
{
return lhs.compare(rhs) > 0;
}
friend bool operator>=(string_view lhs, string_view rhs) noexcept
{
return lhs.compare(rhs) >= 0;
}
private:
const_pointer str_= nullptr;
size_type size_= 0;
};
std::basic_ostream<char> &operator<<(std::basic_ostream<char> &os,
string_view v);
namespace std
{
template <> struct hash<string_view>
{
size_t operator()(string_view v)
{
uint32_t hash= 0;
for (char c : v)
hash= (hash * 2166136261u) ^ static_cast<uint32_t>(c);
return static_cast<size_t>(hash);
}
};
} // namespace std
#endif
......@@ -143,7 +143,7 @@ SET (SQL_SOURCE
opt_trace.cc
${WSREP_SOURCES}
table_cache.cc encryption.cc temporary_tables.cc
proxy_protocol.cc backup.cc xa.cc string_view.cc
proxy_protocol.cc backup.cc xa.cc
${CMAKE_CURRENT_BINARY_DIR}/sql_builtin.cc
${CMAKE_CURRENT_BINARY_DIR}/sql_yacc.cc
${CMAKE_CURRENT_BINARY_DIR}/sql_yacc_ora.cc
......
/*****************************************************************************
Copyright (c) 2020 MariaDB Corporation.
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 Street, Fifth Floor, Boston, MA 02110-1335 USA
*****************************************************************************/
#include "string_view.h"
#include <ostream>
std::basic_ostream<char> &operator<<(std::basic_ostream<char> &os,
string_view v)
{
// TODO standard requires a much more complicated code here.
auto size= static_cast<std::streamsize>(v.size());
os.write(v.data(), size);
return os;
}
......@@ -3487,6 +3487,53 @@ fil_space_read_name_and_filepath(
return(success);
}
/** Convert a file name to a tablespace name.
@param[in] filename directory/databasename/tablename.ibd
@return database/tablename string, to be freed with ut_free() */
char*
fil_path_to_space_name(
const char* filename)
{
/* Strip the file name prefix and suffix, leaving
only databasename/tablename. */
ulint filename_len = strlen(filename);
const char* end = filename + filename_len;
#ifdef HAVE_MEMRCHR
const char* tablename = 1 + static_cast<const char*>(
memrchr(filename, OS_PATH_SEPARATOR,
filename_len));
const char* dbname = 1 + static_cast<const char*>(
memrchr(filename, OS_PATH_SEPARATOR,
tablename - filename - 1));
#else /* HAVE_MEMRCHR */
const char* tablename = filename;
const char* dbname = NULL;
while (const char* t = static_cast<const char*>(
memchr(tablename, OS_PATH_SEPARATOR,
ulint(end - tablename)))) {
dbname = tablename;
tablename = t + 1;
}
#endif /* HAVE_MEMRCHR */
ut_ad(dbname != NULL);
ut_ad(tablename > dbname);
ut_ad(tablename < end);
ut_ad(end - tablename > 4);
ut_ad(memcmp(end - 4, DOT_IBD, 4) == 0);
char* name = mem_strdupl(dbname, ulint(end - dbname) - 4);
ut_ad(name[tablename - dbname - 1] == OS_PATH_SEPARATOR);
#if OS_PATH_SEPARATOR != '/'
/* space->name uses '/', not OS_PATH_SEPARATOR. */
name[tablename - dbname - 1] = '/';
#endif
return(name);
}
/** Discover the correct IBD file to open given a remote or missing
filepath from the REDO log. Administrators can move a crashed
database to another location on the same machine and try to recover it.
......
......@@ -30,7 +30,6 @@ Created 2013-7-26 by Kevin Lewis
#include "page0page.h"
#include "srv0start.h"
#include "string_view.h"
/** Initialize the name, size and order of this datafile
@param[in] name tablespace name, will be copied
@param[in] flags tablespace flags */
......@@ -259,28 +258,6 @@ Datafile::same_as(
#endif /* WIN32 */
}
/** Convert a file name to a tablespace name.
@param[in] filename directory/databasename/tablename.ibd
@return database/tablename string, to be freed with ut_free() */
static char *fsp_path_to_space_name(string_view filename)
{
auto last_slash= filename.rfind(OS_PATH_SEPARATOR);
auto prev_last_slash=
filename.substr(0, last_slash).rfind(OS_PATH_SEPARATOR);
filename.remove_prefix(prev_last_slash + 1);
ut_ad(filename.ends_with(DOT_IBD));
filename.remove_suffix(strlen(DOT_IBD));
char *name= mem_strdupl(filename.data(), filename.size());
#if OS_PATH_SEPARATOR != '/'
/* space->name uses '/', not OS_PATH_SEPARATOR. */
name[last_slash - prev_last_slash - 1]= '/';
#endif
return name;
}
/** Allocate and set the datafile or tablespace name in m_name.
If a name is provided, use it; else extract a file-per-table
tablespace name from m_filepath. The value of m_name
......@@ -294,7 +271,7 @@ Datafile::set_name(const char* name)
if (name != NULL) {
m_name = mem_strdup(name);
} else {
m_name = fsp_path_to_space_name(m_filepath);
m_name = fil_path_to_space_name(m_filepath);
}
}
......
......@@ -1495,6 +1495,13 @@ fil_space_read_name_and_filepath(
char** name,
char** filepath);
/** Convert a file name to a tablespace name.
@param[in] filename directory/databasename/tablename.ibd
@return database/tablename string, to be freed with ut_free() */
char*
fil_path_to_space_name(
const char* filename);
/** Generate redo log for swapping two .ibd files
@param[in] old_table old table
@param[in] new_table new table
......
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