1
0
mirror of https://github.com/mariadb-corporation/mariadb-columnstore-engine.git synced 2025-06-07 19:22:02 +03:00
2025-05-30 03:27:04 +00:00

242 lines
5.6 KiB
C++

/* Copyright (C) 2022, 2023 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-1301, USA. */
// nullstring.h
//
// A class that can reprpesent string-with-NULL (special value not representable by a string value).
#pragma once
#include <algorithm>
#include <iostream>
#include <memory>
#include "exceptclasses.h"
#include "basic/conststring.h"
#include "mcs_datatype_basic.h"
namespace utils
{
// A class for striings that can hold NULL values - a value that is separate from all possible string.
class NullString
{
protected:
std::shared_ptr<std::string> mStrPtr;
public:
NullString() : mStrPtr(nullptr)
{
}
NullString(const char* str, size_t length)
{
idbassert(str != nullptr || length == 0);
if (str)
{
mStrPtr.reset(new std::string((const char*)str, length));
}
}
// XXX: this constructor is used to construct NullString from char*. Please be
// aware of that - std::string(nullptr) throws exception and you should check
// for nullptr.
explicit NullString(const std::string& str) : mStrPtr(new std::string(str))
{
}
explicit NullString(const ConstString& str) : mStrPtr()
{
assign((const uint8_t*)str.str(), str.length());
}
ConstString toConstString() const
{
if (isNull())
{
return ConstString(nullptr, 0);
}
return ConstString(mStrPtr->c_str(), mStrPtr->length());
}
uint64_t toMCSUInt64() const
{
if (isNull())
{
return 0;
}
const uint64_t val = static_cast<uint64_t>(strtoul(str(), 0, 0));
//@Bug 4632 and 4648: Don't return marker value for NULL, but allow return of marker value for EMPTYROW.
return val == joblist::UBIGINTNULL ? MAX_UBIGINT : val;
}
int64_t toMCSInt64() const
{
if (isNull())
{
return 0;
}
const int64_t val = static_cast<int64_t>(atoll(str()));
//@Bug 4632 and 4648: Don't return marker value for NULL, but allow return of marker value for EMPTYROW.
return std::max(val, static_cast<int64_t>(joblist::BIGINTEMPTYROW));
}
const char* str() const
{
if (!mStrPtr)
{
return nullptr;
}
return mStrPtr->c_str();
}
const char* end() const
{
if (!mStrPtr)
{
return nullptr;
}
return str() + length();
}
size_t length() const
{
if (!mStrPtr)
{
return 0;
}
return mStrPtr->length();
}
std::string toString() const
{
idbassert(mStrPtr);
return std::string(*mStrPtr);
}
// "unsafe" means we do not check for NULL.
// it should be used after we know there is data in NullString.
const std::string& unsafeStringRef() const
{
idbassert(mStrPtr);
return (*mStrPtr);
}
bool eq(char ch) const
{
return length() == 1 && str()[0] == ch;
}
// this is SQL-like NULL handling equality. NULL will not be equal to anything, including NULL.
bool eq(const NullString& rhs) const
{
if (!rhs.mStrPtr)
{
return false;
}
if (!mStrPtr)
{
return false;
}
return *mStrPtr == *(rhs.mStrPtr);
}
NullString& rtrimZero()
{
return *this; // TODO
}
// this can be used to safely get a string value, with default value for NULL substitution.
// it does not raise anything and provides some nonsensical default value for you that will be
// easy to find.
std::string safeString(const char* defaultValue = "<<<no default value for null provided>>>") const
{
if (!mStrPtr)
{
return std::string(defaultValue);
}
return std::string(*mStrPtr);
}
bool isNull() const
{
return !mStrPtr;
}
void resize(size_t newSize, char pad)
{
if (mStrPtr)
{
mStrPtr->resize(newSize, pad);
}
}
NullString& dropString()
{
mStrPtr.reset();
return (*this);
}
void assign(const uint8_t* p, size_t len)
{
if (!p)
{
mStrPtr.reset();
return;
}
mStrPtr.reset(new std::string((const char*)p, len));
}
void assign(const std::string& newVal)
{
mStrPtr.reset(new std::string(newVal));
}
// XXX: here we implement what Row::equals expects.
// It is not SQL-NULL-handling compatible, please beware.
bool operator==(const NullString& a) const
{
if (!mStrPtr && !a.mStrPtr)
{
return true;
}
if (!mStrPtr)
{
return false;
}
if (!a.mStrPtr)
{
return false;
}
// fall to std::string equality.
return (*mStrPtr) == (*a.mStrPtr);
}
bool operator==(const std::string& a) const
{
if (!mStrPtr)
{
return false;
}
// fall to std::string equality.
return (*mStrPtr) == a;
}
bool operator<(const NullString& a) const
{
// order NULLs first.
if (isNull() > a.isNull())
{
return true;
}
if (isNull() < a.isNull())
{
return false;
}
if (!isNull())
{
// fall to std::string equality.
return (*mStrPtr) < (*a.mStrPtr);
}
return false; // both are NULLs.
}
bool operator>(const NullString& a) const
{
return a < (*this);
}
};
} // namespace utils.