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 | |
14 | namespace duckdb { |
15 | |
16 | enum 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. |
21 | class QueryResult { |
22 | public: |
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 | |
50 | public: |
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 | |
61 | private: |
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 | |
117 | public: |
118 | QueryResultIterator begin() { |
119 | return QueryResultIterator(this); |
120 | } |
121 | QueryResultIterator end() { |
122 | return QueryResultIterator(nullptr); |
123 | } |
124 | |
125 | protected: |
126 | string (); |
127 | |
128 | private: |
129 | QueryResult(const QueryResult &) = delete; |
130 | }; |
131 | |
132 | } // namespace duckdb |
133 | |