The version `void getAsArray(I insert_iter, NullHandling nullhandling = NullHandling::Throw) const` used the nullhandling param to also throw an error when the whole array is NULL however as empty arrays are often saved as NULL values and the distinction is often not important I decided that behaviour was more annoying then useful. You can easily use null() if the distinction is important. getAsArrayOfOptional and getAsVector completely forgot to check for NULL value getAsVector also didn't test for empty strings which appears to be possible
192 lines
4.8 KiB
C++
192 lines
4.8 KiB
C++
#ifndef PGSQL_VALUE_H
|
|
#define PGSQL_VALUE_H
|
|
|
|
#include "Pgsql_declare.h"
|
|
#include "Pgsql_oids.h"
|
|
#include "ArrayParser.h"
|
|
#include <sstream>
|
|
#include <vector>
|
|
#include <QString>
|
|
#include <QDateTime>
|
|
#include <optional>
|
|
|
|
namespace Pgsql {
|
|
|
|
|
|
/** \brief Class that is returned as value of a cell to facilitate auto conversion.
|
|
*/
|
|
class Value {
|
|
public:
|
|
const char *empty_str = "";
|
|
Value(const char *val, Oid typ);
|
|
QString asQString() const;
|
|
|
|
bool null() const { return m_val == nullptr; }
|
|
const char* c_str() const { return m_val == nullptr ? empty_str : m_val; }
|
|
|
|
operator QString() const;
|
|
operator QDateTime() const;
|
|
operator QDate() const;
|
|
operator QTime() const;
|
|
operator std::string() const;
|
|
operator int16_t() const;
|
|
operator int32_t() const;
|
|
operator Oid() const;
|
|
operator int64_t() const;
|
|
operator bool() const;
|
|
operator float() const;
|
|
operator double() const;
|
|
operator char() const;
|
|
|
|
bool isString() const;
|
|
|
|
/// Retrieves an array type value and passes them to an insert iterator.
|
|
///
|
|
/// When the array it self is NULL this function behaves the same as for an empty array. No
|
|
/// elements are given to the insert iterator and the function returns. Use the null() function
|
|
/// to check for NULL values.
|
|
///
|
|
/// \param insert_iter An insert_iterator which is used to add the elements of the array to a container.
|
|
/// \param nullhandling This only affects how NULL elements within the array are handled.
|
|
template <typename E, typename I>
|
|
void getAsArray(I insert_iter, NullHandling nullhandling = NullHandling::Throw) const
|
|
{
|
|
if (m_val == nullptr) {
|
|
return;
|
|
}
|
|
else {
|
|
using value_type = E;
|
|
ArrayParser parser(m_val);
|
|
for (;;) {
|
|
auto res = parser.GetNextElem();
|
|
if (res.ok) {
|
|
if (res.value) {
|
|
std::string str(res.value->data(), res.value->length());
|
|
Value val(str.c_str(), OidFor<E>::elem());
|
|
value_type v;
|
|
v << val;
|
|
insert_iter = v;
|
|
}
|
|
else {
|
|
if (nullhandling == NullHandling::Throw)
|
|
throw std::runtime_error("Unexpected NULL value in array");
|
|
}
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Retrieves an array typed value, and passes the element to the insert iterator
|
|
///
|
|
/// \param value_for_nulls Each time it encounters a NULL element in the array it
|
|
/// will instead pass this value to the insert iterator.
|
|
template <typename E, typename I>
|
|
void getAsArray(I insert_iter, const E &value_for_nulls) const
|
|
{
|
|
if (m_val == nullptr) return;
|
|
|
|
using value_type = E;
|
|
ArrayParser parser(m_val);
|
|
for (;;) {
|
|
auto res = parser.GetNextElem();
|
|
if (res.ok) {
|
|
if (res.value) {
|
|
std::string str(res.value->data(), res.value->length());
|
|
Value val(str.c_str(), OidFor<E>::elem());
|
|
value_type v;
|
|
v << val;
|
|
insert_iter = v;
|
|
}
|
|
else {
|
|
insert_iter = value_for_nulls;
|
|
}
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
|
|
/// Retrieves an array typed value, and passes the elements to the insert iterator
|
|
template <typename E, typename I>
|
|
void getAsArrayOfOptional(I insert_iter) const
|
|
{
|
|
if (m_val == nullptr) return;
|
|
|
|
using value_type = E;
|
|
ArrayParser parser(m_val);
|
|
for (;;) {
|
|
auto res = parser.GetNextElem();
|
|
if (res.ok) {
|
|
if (res.value) {
|
|
std::string str(res.value->data(), res.value->length());
|
|
Value val(str.c_str(), OidFor<E>::elem());
|
|
value_type v;
|
|
v << val;
|
|
insert_iter = v;
|
|
}
|
|
else {
|
|
insert_iter = std::nullopt;
|
|
}
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
|
|
/// De catalog uses vector types which are similar to array
|
|
/// but uses spaces as seperators. AFAIK there are only integral
|
|
/// vector types so this implementation is only tested for those
|
|
template <typename E, typename I>
|
|
void getAsVector(I insert_iter) const
|
|
{
|
|
if (m_val == nullptr || *m_val == '\0') return;
|
|
|
|
const char * pos = m_val;
|
|
const char * start = pos;
|
|
for (;;) {
|
|
while (*pos != 0 && *pos != ' ') ++pos;
|
|
// The cast (to prevent warning) should be save as start should always be <= pos
|
|
std::string str(start, static_cast<size_t>(pos-start));
|
|
Value val(str.c_str(), OidFor<E>::elem());
|
|
E v;
|
|
v << val;
|
|
insert_iter = v;
|
|
if (*pos == 0)
|
|
break;
|
|
start = ++pos; // skip space and set new start to match
|
|
}
|
|
}
|
|
|
|
inline Oid getOid() const { return m_typ; }
|
|
private:
|
|
const char *m_val;
|
|
Oid m_typ;
|
|
};
|
|
|
|
template <typename T>
|
|
void operator<<(std::optional<T> &s, const Value &v)
|
|
{
|
|
if (v.null())
|
|
s = std::optional<T>();
|
|
else
|
|
*s << v;
|
|
}
|
|
|
|
template <typename T>
|
|
void operator<<(std::vector<T> &s, const Value &v)
|
|
{
|
|
v.getAsArray(std::back_inserter(s));
|
|
}
|
|
|
|
template <typename T>
|
|
void operator<<(T &s, const Value &v)
|
|
{
|
|
s = v.operator T();
|
|
}
|
|
|
|
|
|
} // end namespace Pgsql
|
|
|
|
#endif // PGSQL_VALUE_H
|