BuildDarkFlame/_deps/mysql-src/include/mysqlx/devapi/result.h

909 lines
18 KiB
C
Raw Normal View History

2022-01-02 18:29:32 -06:00
/*
* 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_RESULT_H
#define MYSQLX_RESULT_H
/**
@file
Classes used to access query and command execution results.
*/
#include "common.h"
#include "document.h"
#include "row.h"
#include "collations.h"
#include "detail/result.h"
namespace mysqlx {
MYSQLX_ABI_BEGIN(2,0)
using std::ostream;
class Session;
class Schema;
class Collection;
class Result;
class Row;
class RowResult;
class SqlResult;
class DbDoc;
class DocResult;
template <class Res, class Op> class Executable;
namespace internal {
/*
A wrapper which adds methods common for all result classes.
*/
template <class Base>
class Result_common
: protected Base
{
using WarningList = internal::Result_detail::WarningList;
public:
/// Get the number of warnings stored in the result.
unsigned getWarningsCount() const
{
try {
return Base::get_warning_count();
}
CATCH_AND_WRAP
}
/// Get a list of warnings stored in the result.
WarningList getWarnings()
{
try {
return Base::get_warnings();
}
CATCH_AND_WRAP
}
/// Get the warning at the given, 0-based position.
// TODO: Change arg type to size_t?
Warning getWarning(unsigned pos)
{
try {
return Base::get_warning(pos);
}
CATCH_AND_WRAP
}
// TODO: expose this in the API?
//using WarningsIterator = Result_detail::iterator;
/**
Get the count of affected items (rows or doucuments) from manipulation statements.
*/
uint64_t getAffectedItemsCount() const
{
try {
return Result_detail::get_affected_rows();
} CATCH_AND_WRAP
}
protected:
// Wrap base ctors/assginment with catch handlers
Result_common()
try
: Base()
{}
CATCH_AND_WRAP
Result_common(Result_common &&other)
try
: Base(std::move(other))
{}
CATCH_AND_WRAP
Result_common& operator=(Result_common &&other)
try
{
Base::operator=(std::move(other));
return *this;
}
CATCH_AND_WRAP
Result_common(common::Result_init &init)
try
: Base(init)
{}
CATCH_AND_WRAP
};
} // internal namespace
/**
Represents a result of an operation that does not return data.
A generic result which can be returned by operations which only
modify data.
A `Result` instance can store the result of executing an operation:
~~~~~~
Result res = operation.execute();
~~~~~~
Storing another result in a `Result` instance overwrites
the previous result.
@note A `Result` object should be used by at most one thread at a time. It is
not safe to call its methods by several threads simultaneously. It is
responsibility of the user to ensure this using a synchronization mechanism
such as mutexes.
@ingroup devapi_res
*/
class Result
: public internal::Result_common<internal::Result_detail>
{
public:
Result() = default;
/**
Get the auto-increment value if one was generated by a table insert
statement.
*/
uint64_t getAutoIncrementValue() const
{
try {
return Result_detail::get_auto_increment();
} CATCH_AND_WRAP
}
/**
Return a list of identifiers of multiple documents added to a collection,
generated by the server.
*/
DocIdList getGeneratedIds() const
{
try {
return Result_detail::get_generated_ids();
} CATCH_AND_WRAP
}
private:
Result(common::Result_init &init)
: Result_common(init)
{}
template <class Res, class Op>
friend class Executable;
friend Collection;
};
// Row based results
// -----------------
/**
Types that can be reported in result meta-data.
These correspond to MySQL server datatypes described [here]
(https://dev.mysql.com/doc/refman/8.0/en/data-types.html).
@ingroup devapi_res
*/
enum class Type : unsigned short
{
#undef TYPE_ENUM
#define TYPE_ENUM(X,N) X=N,
RESULT_TYPE_LIST(TYPE_ENUM)
};
/*
Note: Normally we would put these docs in the RESULT_TYPE_LIST macro
but it would pollute documentation of methods like typeName() below
that also use this macro.
*/
/// @var mysqlx::Type::BIT
/// See <https://dev.mysql.com/doc/refman/8.0/en/bit-type.html>
/// @var Type::TINYINT
/// See <https://dev.mysql.com/doc/refman/8.0/en/integer-types.html>
/// @var Type::SMALLINT
/// See <https://dev.mysql.com/doc/refman/8.0/en/integer-types.html>
/// @var Type::MEDIUMINT
/// See <https://dev.mysql.com/doc/refman/8.0/en/integer-types.html>
/// @var Type::INT
/// See <https://dev.mysql.com/doc/refman/8.0/en/integer-types.html>
/// @var Type::BIGINT
/// See <https://dev.mysql.com/doc/refman/8.0/en/integer-types.html>
/// @var Type::FLOAT
/// See <https://dev.mysql.com/doc/refman/8.0/en/floating-point-types.html>
/// @var Type::DECIMAL
/// See <https://dev.mysql.com/doc/refman/8.0/en/fixed-point-types.html>
/// @var Type::DOUBLE
/// See <https://dev.mysql.com/doc/refman/8.0/en/floating-point-types.html>
/// @var Type::JSON
/// See <https://dev.mysql.com/doc/refman/8.0/en/json.html>
/// @var Type::STRING
/// See <https://dev.mysql.com/doc/refman/8.0/en/string-types.html>
/// @var Type::BYTES
/// See <https://dev.mysql.com/doc/refman/8.0/en/string-types.html>
/// @var Type::TIME
/// See <https://dev.mysql.com/doc/refman/8.0/en/date-and-time-types.html>
/// @var Type::DATE
/// See <https://dev.mysql.com/doc/refman/8.0/en/date-and-time-types.html>
/// @var Type::DATETIME
/// See <https://dev.mysql.com/doc/refman/8.0/en/date-and-time-types.html>
/// @var Type::TIMESTAMP
/// See <https://dev.mysql.com/doc/refman/8.0/en/date-and-time-types.html>
/// @var Type::SET
/// See <https://dev.mysql.com/doc/refman/8.0/en/set.html>
/// @var Type::ENUM
/// See <https://dev.mysql.com/doc/refman/8.0/en/enum.html>
/// @var Type::GEOMETRY
/// See <https://dev.mysql.com/doc/refman/8.0/en/spatial-types.html>
/**
Return name of a given type.
@ingroup devapi_res
*/
inline
const char* typeName(Type t)
{
#define TYPE_NAME(T,X) case Type::T: return #T;
switch (t)
{
RESULT_TYPE_LIST(TYPE_NAME)
default:
THROW("Unknown type");
}
}
inline
std::ostream& operator<<(std::ostream &out, Type t)
{
return out << typeName(t);
}
/**
Provides meta-data for a single result column.
@ingroup devapi_res
*/
class Column
: public virtual common::Printable
, private internal::Column_detail
{
public:
string getSchemaName() const ///< TODO
{
try {
return Column_detail::get_schema_name();
}
CATCH_AND_WRAP
}
string getTableName() const ///< TODO
{
try {
return Column_detail::get_table_name();
}
CATCH_AND_WRAP
}
string getTableLabel() const ///< TODO
{
try {
return Column_detail::get_table_label();
}
CATCH_AND_WRAP
}
string getColumnName() const ///< TODO
{
try {
return Column_detail::get_name();
}
CATCH_AND_WRAP
}
string getColumnLabel() const ///< TODO
{
try {
return Column_detail::get_label();
}
CATCH_AND_WRAP
}
Type getType() const ///< TODO
{
try {
return Type(Column_detail::get_type());
}
CATCH_AND_WRAP
}
/**
Get column length
@return The maximum length of data in the column in bytes, as reported
by the server.
@note Because the column length is returned as byte length, it could be
confusing with the multi-byte character sets. For instance, with UTF8MB4
the length of VARCHAR(100) column is reported as 400 because each character
is 4 bytes long.
*/
unsigned long getLength() const
{
try {
return Column_detail::get_length();
}
CATCH_AND_WRAP
}
unsigned short getFractionalDigits() const ///< TODO
{
try {
return Column_detail::get_decimals();
}
CATCH_AND_WRAP
}
bool isNumberSigned() const ///< TODO
{
try {
return Column_detail::is_signed();
}
CATCH_AND_WRAP
}
CharacterSet getCharacterSet() const ///< TODO
{
try {
return Column_detail::get_charset();
}
CATCH_AND_WRAP
}
/// TODO
std::string getCharacterSetName() const
{
try {
return characterSetName(getCharacterSet());
}
CATCH_AND_WRAP
}
const CollationInfo& getCollation() const ///< TODO
{
try {
return Column_detail::get_collation();
}
CATCH_AND_WRAP
}
/// TODO
std::string getCollationName() const
{
try {
return getCollation().getName();
}
CATCH_AND_WRAP
}
/// TODO
bool isPadded() const
{
try {
return Column_detail::is_padded();
}
CATCH_AND_WRAP
}
protected:
using Column_detail::Impl;
Column(const Impl *impl)
try
: Column_detail(impl)
{}
CATCH_AND_WRAP
Column() = default;
Column(const Column&) = default;
Column(Column&&) = default;
Column& operator=(const Column&) = default;
void print(std::ostream &out) const
{
// TODO: not sure if this code will be called by operator<<.
try {
Column_detail::print(out);
}
CATCH_AND_WRAP
}
public:
friend RowResult;
struct INTERNAL Access;
friend Access;
};
/*
Extern declarations for Columns_detail<Column> template specialization
elements that are defined in result.cc.
Note: "extern template" works with MSVC but not with GCC.
*/
namespace internal {
template<> PUBLIC_API
void Columns_detail<Column>::init(const Result_detail::Impl&);
} // internal
extern template PUBLIC_API
void internal::Columns_detail<Column>::init(
const internal::Result_detail::Impl &impl
);
class Columns
: private internal::Columns_detail<Column>
{
public:
using Columns_detail::operator[];
using Columns_detail::iterator;
using Columns_detail::begin;
using Columns_detail::end;
private:
using Columns_detail::init;
// note: Required by Row_result_detail
Columns() = default;
Columns(Columns&&) = default;
Columns& operator=(Columns&&) = default;
///@cond IGNORE
friend internal::Row_result_detail<Columns>;
///@endcond
};
/*
Extern declarations for Row_result_detail<Columns> template specialization
elements that are defined in result.cc.
*/
namespace internal {
template<> PUBLIC_API
bool Row_result_detail<Columns>::iterator_next();
template<> PUBLIC_API
col_count_t Row_result_detail<Columns>::col_count() const;
template<> PUBLIC_API
Row_result_detail<Columns>::Row_result_detail(
common::Result_init &init
);
template<> PUBLIC_API
auto Row_result_detail<Columns>::get_column(col_count_t pos) const
-> const Column&;
template<> PUBLIC_API
auto internal::Row_result_detail<Columns>::get_columns() const
-> const Columns&;
template<> PUBLIC_API
row_count_t internal::Row_result_detail<Columns>::row_count();
} // internal
/**
%Result of an operation that returns rows.
A `RowResult` object gives sequential access to the rows contained in
the result. It is possible to get the rows one-by-one, or fetch and store
all of them at once. One can iterate over the rows using range loop:
`for (Row r : result) ...`.
@ingroup devapi_res
*/
class RowResult
: public internal::Result_common<internal::Row_result_detail<Columns>>
{
public:
using Columns = mysqlx::Columns;
RowResult() = default;
/// Return the number of fields in each row.
col_count_t getColumnCount() const
{
try {
return Row_result_detail::col_count();
}
CATCH_AND_WRAP
}
/// Return `Column` object describing the given column of the result.
const Column& getColumn(col_count_t pos) const
{
try {
return Row_result_detail::get_column(pos);
}
CATCH_AND_WRAP
}
/**
Return meta-data for all result columns.
TODO: explain ownership
*/
const Columns& getColumns() const
{
try {
return Row_result_detail::get_columns();
}
CATCH_AND_WRAP
}
/**
Return the current row and move to the next one in the sequence.
If there are no more rows in this result, returns a null `Row` instance.
*/
Row fetchOne()
{
try {
return Row_result_detail::get_row();
}
CATCH_AND_WRAP
}
/**
Return all remaining rows
%Result of this method can be stored in a container such as
`std::list<Row>`. Rows that have already been fetched using `fetchOne()` are
not included in the result of `fetchAll()`.
*/
RowList fetchAll()
{
try {
return Row_result_detail::get_rows();
}
CATCH_AND_WRAP
}
/**
Returns the number of rows contained in the result.
The method counts only the rows that were not yet fetched and are still
available in the result.
*/
row_count_t count()
{
try {
return Row_result_detail::row_count();
}
CATCH_AND_WRAP
}
/*
Iterate over rows (range-for support).
Rows that have been fetched using iterator are not available when
calling fetchOne() or fetchAll()
*/
iterator begin()
{
try {
return Row_result_detail::begin();
}
CATCH_AND_WRAP
}
iterator end() const
{
try {
return Row_result_detail::end();
}
CATCH_AND_WRAP
}
private:
RowResult(common::Result_init &init)
: Result_common(init)
{}
public:
template <class Res, class Op> friend class Executable;
friend SqlResult;
friend DocResult;
};
/**
%Result of an SQL query or command.
In general, an SQL query or command can return multiple results (for example,
a call to a stored procedure). Additionally, each or only some of these
results can contain row data. A `SqlResult` object gives a sequential access
to all results of a multi-result. Method `nextResult()` moves to the next
result in the sequence, if present. Methods of `RowResult` are used to access
row data of the current result (if it contains data).
@note A `SqlResult` object should be used by at most one thread at a time.
It is not safe to call its methods by several threads simultaneously. It is
responsibility of the user to ensure this using a synchronization mechanism
such as mutexes.
@ingroup devapi_res
*/
class SqlResult
: public RowResult
{
public:
SqlResult() = default;
/**
Tell if the current result contains row data.
If this is the case, rows can be accessed using `RowResult` interface.
Otherwise calling `RowResult` methods throws an error.
*/
bool hasData() const
{
try {
return Result_detail::has_data();
}
CATCH_AND_WRAP
}
/**
Move to the next result, if there is one.
Returns true if the next result is available, false if there are no more
results in the reply. Calling `nextResult()` discards the current result.
If it has any rows that has not yet been fetched, these rows are also
discarded.
*/
bool nextResult()
{
try {
return Row_result_detail::next_result();
}
CATCH_AND_WRAP
}
/**
Get the auto-increment value if one was generated by a table insert
statement.
*/
uint64_t getAutoIncrementValue()
{
try {
return Result_detail::get_auto_increment();
}
CATCH_AND_WRAP
}
private:
SqlResult(common::Result_init &init)
: RowResult(init)
{}
template <class Res, class Op>
friend class Executable;
};
// Document based results
// ----------------------
/**
%Result of an operation that returns documents.
A `DocResult` object gives sequential access to the documents contained in
the result. It is possible to get the documents one-by-one, or fetch and store
all of them at once. One can iterate over the documents using range loop:
`for (DbDoc d : result) ...`.
@note A `DocResult` object should be used by at most one thread at a time.
It is not safe to call its methods by several threads simultaneously. It is
responsibility of the user to ensure this using a synchronization mechanism
such as mutexes.
@ingroup devapi_res
*/
class DocResult
: public internal::Result_common<internal::Doc_result_detail>
{
public:
DocResult() = default;
/**
Return the current document and move to the next one in the sequence.
If there are no more documents in this result, returns a null document.
*/
DbDoc fetchOne()
{
try {
return Doc_result_detail::get_doc();
}
CATCH_AND_WRAP
}
/**
Return all remaining documents.
%Result of this method can be stored in a container such as
`std::list<DbDoc>`. Documents that have already been fetched using
`fetchOne()` are not included in the result of `fetchAll()`.
*/
DocList fetchAll()
{
try {
return Doc_result_detail::get_docs();
}
CATCH_AND_WRAP
}
/**
Returns the number of documents contained in the result.
The method counts only the documents that were not yet fetched and are still
available in the result.
*/
uint64_t count()
{
try {
return Doc_result_detail::count();
}
CATCH_AND_WRAP
}
/*
Iterate over documents (range-for support).
Documents that have been fetched using iterator are not available when
calling fetchOne() or fetchAll()
*/
using iterator = Doc_result_detail::iterator;
iterator begin()
{
try {
return Doc_result_detail::begin();
}
CATCH_AND_WRAP
}
iterator end() const
{
try {
return Doc_result_detail::end();
}
CATCH_AND_WRAP
}
private:
DocResult(common::Result_init &init)
: Result_common(init)
{}
friend DbDoc;
template <class Res, class Op>
friend class Executable;
};
MYSQLX_ABI_END(2,0)
} // mysqlx
#endif