/* * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2.0, as * published by the Free Software Foundation. * * This program is also distributed with certain software (including * but not limited to OpenSSL) that is licensed under separate terms, * as designated in a particular file or component or in included license * documentation. The authors of MySQL hereby grant you an * additional permission to link the program and your derivative works * with the separately licensed software that they have included with * MySQL. * * Without limiting anything contained in the foregoing, this file, * which is part of MySQL Connector/C++, is also subject to the * Universal FOSS Exception, version 1.0, a copy of which can be found at * http://oss.oracle.com/licenses/universal-foss-exception. * * 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, version 2.0, 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-1301 USA */ #ifndef MYSQLX_COMMON_VALUE_H #define MYSQLX_COMMON_VALUE_H #include "api.h" #include "error.h" #include "util.h" PUSH_SYS_WARNINGS #include POP_SYS_WARNINGS namespace mysqlx { MYSQLX_ABI_BEGIN(2,0) namespace common { class Value_conv; /* Class representing a polymorphic value of one of the supported types. TODO: Extend it with array and document types (currently these are implemented in derived mysqlx::Value class of DevAPI). TODO: When storing raw bytes, currently they are copied inside the Value object. Consider if this can be avoided. */ class PUBLIC_API Value : public virtual Printable { public: enum Type { VNULL, ///< Null value UINT64, ///< Unsigned integer INT64, ///< Signed integer FLOAT, ///< Float number DOUBLE, ///< Double number BOOL, ///< Boolean STRING, ///< String (utf8) USTRING, ///< Wide string (utf16) RAW, ///< Raw bytes EXPR, ///< String to be interpreted as an expression JSON, ///< JSON string }; using string = std::string; protected: Type m_type; // TODO: Use std::variant to save space DLL_WARNINGS_PUSH std::string m_str; std::u16string m_ustr; DLL_WARNINGS_POP union { double v_double; float v_float; int64_t v_sint; uint64_t v_uint; bool v_bool; } m_val; void print(std::ostream&) const override; template Value(Type type, T &&init) : Value(std::forward(init)) { m_type = type; } public: // Construct a NULL item Value() : m_type(VNULL) {} // Construct an item from a string Value(const std::string& str) : m_type(STRING), m_str(str) { m_val.v_bool = false; } Value(const std::u16string &str) : m_type(USTRING), m_ustr(str) { m_val.v_bool = false; } // Construct an item from a signed 64-bit integer Value(int64_t v) : m_type(INT64) { m_val.v_sint = v; } // Construct an item from an unsigned 64-bit integer Value(uint64_t v) : m_type(UINT64) { m_val.v_uint = v; } // Construct an item from a float Value(float v) : m_type(FLOAT) { m_val.v_float = v; } // Construct an item from a double Value(double v) : m_type(DOUBLE) { m_val.v_double = v; } // Construct an item from a bool Value(bool v) : m_type(BOOL) { m_val.v_bool = v; } // Construct an item from bytes Value(const byte *ptr, size_t len) : m_type(RAW) { // Note: bytes are copied to m_str member. m_str.assign((const char*)ptr, len); } // Other numeric conversions template < typename T, typename std::enable_if::value>::type* = nullptr > Value(T val) : Value(uint64_t(val)) {} template < typename T, typename std::enable_if::value>::type* = nullptr, typename std::enable_if::value>::type* = nullptr > Value(T val) : Value(int64_t(val)) {} bool is_null() const { return VNULL == m_type; } bool get_bool() const { switch (m_type) { case BOOL: return m_val.v_bool; case UINT64: return 0 != m_val.v_uint; case INT64: return 0 != m_val.v_sint; default: throw Error("Can not convert to Boolean value"); } } uint64_t get_uint() const { if (UINT64 != m_type && INT64 != m_type && BOOL != m_type) throw Error("Can not convert to integer value"); if (BOOL == m_type) return m_val.v_bool ? 1 : 0; if (INT64 == m_type && 0 > m_val.v_sint) throw Error("Converting negative integer to unsigned value"); uint64_t val = (UINT64 == m_type ? m_val.v_uint : (uint64_t)m_val.v_sint); return val; } int64_t get_sint() const { if (INT64 == m_type) return m_val.v_sint; uint64_t val = get_uint(); if (!check_num_limits(val)) throw Error("Value cannot be converted to signed integer number"); return val; } float get_float() const { switch (m_type) { case INT64: return 1.0F*m_val.v_sint; case UINT64: return 1.0F*m_val.v_uint; case FLOAT: return m_val.v_float; default: throw Error("Value cannot be converted to float number"); } } double get_double() const { switch (m_type) { case INT64: return 1.0*m_val.v_sint; case UINT64: return 1.0*m_val.v_uint; case FLOAT: return m_val.v_float; case DOUBLE: return m_val.v_double; default: throw Error("Value can not be converted to double number"); } } /* Note: In general this method returns raw value representation as obtained from the server, which is stored in m_str member. If a non-string value was not obtained from the server, there is no raw representation for it and error is thrown. String values always have raw representation which is either utf8 or utf16 encoding. Strings obtained from the server use utf8 as raw representation. For strings created by user code this might be either utf8 or utf16, depending on how string was created. */ const byte* get_bytes(size_t *size) const { switch (m_type) { case USTRING: if (!m_ustr.empty()) { if (size) *size = m_ustr.size() * sizeof(char16_t); return (const byte*)m_ustr.data(); } FALLTHROUGH; default: if (m_str.empty()) throw Error("Value cannot be converted to raw bytes"); FALLTHROUGH; case RAW: case STRING: if (size) *size = m_str.length(); return (const byte*)m_str.data(); } } // Note: these methods perform utf8 conversions as necessary. const std::string& get_string() const; const std::u16string& get_ustring() const; Type get_type() const { return m_type; } private: /* Note: Avoid implicit conversion from pointer types to bool. Without this declaration, Value(bool) constructor is invoked for pointer types. Here we declare and hide an explicit constructor for pointer types which prevents compiler to pick Value(bool). */ template Value(const T*); public: friend Value_conv; struct Access; friend Access; }; } // common MYSQLX_ABI_END(2,0) } // mysqlx #endif