1//===----------------------------------------------------------------------===//
2// DuckDB
3//
4// duckdb/main/query_result.hpp
5//
6//
7//===----------------------------------------------------------------------===//
8
9#pragma once
10
11#include "duckdb/common/types/data_chunk.hpp"
12#include "duckdb/common/enums/statement_type.hpp"
13
14namespace duckdb {
15
16enum class QueryResultType : uint8_t { MATERIALIZED_RESULT, STREAM_RESULT };
17
18//! The QueryResult object holds the result of a query. It can either be a MaterializedQueryResult, in which case the
19//! result contains the entire result set, or a StreamQueryResult in which case the Fetch method can be called to
20//! incrementally fetch data from the database.
21class QueryResult {
22public:
23 //! Creates an successful empty query result
24 QueryResult(QueryResultType type, StatementType statement_type);
25 //! Creates a successful query result with the specified names and types
26 QueryResult(QueryResultType type, StatementType statement_type, vector<SQLType> sql_types, vector<TypeId> types,
27 vector<string> names);
28 //! Creates an unsuccessful query result with error condition
29 QueryResult(QueryResultType type, string error);
30 virtual ~QueryResult() {
31 }
32
33 //! The type of the result (MATERIALIZED or STREAMING)
34 QueryResultType type;
35 //! The type of the statement that created this result
36 StatementType statement_type;
37 //! The SQL types of the result
38 vector<SQLType> sql_types;
39 //! The types of the result
40 vector<TypeId> types;
41 //! The names of the result
42 vector<string> names;
43 //! Whether or not execution was successful
44 bool success;
45 //! The error string (in case execution was not successful)
46 string error;
47 //! The next result (if any)
48 unique_ptr<QueryResult> next;
49
50public:
51 //! Fetches a DataChunk from the query result. Returns an empty chunk if the result is empty, or nullptr on failure.
52 virtual unique_ptr<DataChunk> Fetch() = 0;
53 // Converts the QueryResult to a string
54 virtual string ToString() = 0;
55 //! Prints the QueryResult to the console
56 void Print();
57 //! Returns true if the two results are identical; false otherwise. Note that this method is destructive; it calls
58 //! Fetch() until both results are exhausted. The data in the results will be lost.
59 bool Equals(QueryResult &other);
60
61private:
62 //! The current chunk used by the iterator
63 unique_ptr<DataChunk> iterator_chunk;
64
65 class QueryResultIterator;
66
67 class QueryResultRow {
68 public:
69 QueryResultRow(QueryResultIterator &iterator) : iterator(iterator), row(0) {
70 }
71
72 QueryResultIterator &iterator;
73 idx_t row;
74
75 template <class T> T GetValue(idx_t col_idx) const {
76 return iterator.result->iterator_chunk->GetValue(col_idx, iterator.row_idx).GetValue<T>();
77 }
78 };
79 //! The row-based query result iterator. Invoking the
80 class QueryResultIterator {
81 public:
82 QueryResultIterator(QueryResult *result) : current_row(*this), result(result), row_idx(0) {
83 if (result) {
84 result->iterator_chunk = result->Fetch();
85 }
86 }
87
88 QueryResultRow current_row;
89 QueryResult *result;
90 idx_t row_idx;
91
92 public:
93 void Next() {
94 if (!result->iterator_chunk) {
95 return;
96 }
97 current_row.row++;
98 row_idx++;
99 if (row_idx >= result->iterator_chunk->size()) {
100 result->iterator_chunk = result->Fetch();
101 row_idx = 0;
102 }
103 }
104
105 QueryResultIterator &operator++() {
106 Next();
107 return *this;
108 }
109 bool operator!=(const QueryResultIterator &other) const {
110 return result->iterator_chunk && result->iterator_chunk->column_count() > 0;
111 }
112 const QueryResultRow &operator*() const {
113 return current_row;
114 }
115 };
116
117public:
118 QueryResultIterator begin() {
119 return QueryResultIterator(this);
120 }
121 QueryResultIterator end() {
122 return QueryResultIterator(nullptr);
123 }
124
125protected:
126 string HeaderToString();
127
128private:
129 QueryResult(const QueryResult &) = delete;
130};
131
132} // namespace duckdb
133