1 | //===----------------------------------------------------------------------===// |
2 | // DuckDB |
3 | // |
4 | // duckdb/main/client_context.hpp |
5 | // |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #pragma once |
10 | |
11 | #include "duckdb/catalog/catalog_entry/schema_catalog_entry.hpp" |
12 | #include "duckdb/catalog/catalog_set.hpp" |
13 | #include "duckdb/common/enums/pending_execution_result.hpp" |
14 | #include "duckdb/common/deque.hpp" |
15 | #include "duckdb/common/pair.hpp" |
16 | #include "duckdb/common/unordered_set.hpp" |
17 | #include "duckdb/common/winapi.hpp" |
18 | #include "duckdb/main/prepared_statement.hpp" |
19 | #include "duckdb/main/stream_query_result.hpp" |
20 | #include "duckdb/main/table_description.hpp" |
21 | #include "duckdb/transaction/transaction_context.hpp" |
22 | #include "duckdb/main/pending_query_result.hpp" |
23 | #include "duckdb/common/atomic.hpp" |
24 | #include "duckdb/main/client_config.hpp" |
25 | #include "duckdb/main/external_dependencies.hpp" |
26 | #include "duckdb/common/preserved_error.hpp" |
27 | |
28 | namespace duckdb { |
29 | class Appender; |
30 | class Catalog; |
31 | class CatalogSearchPath; |
32 | class ColumnDataCollection; |
33 | class DatabaseInstance; |
34 | class FileOpener; |
35 | class LogicalOperator; |
36 | class PreparedStatementData; |
37 | class Relation; |
38 | class BufferedFileWriter; |
39 | class QueryProfiler; |
40 | class ClientContextLock; |
41 | struct CreateScalarFunctionInfo; |
42 | class ScalarFunctionCatalogEntry; |
43 | struct ActiveQueryContext; |
44 | struct ParserOptions; |
45 | struct ClientData; |
46 | |
47 | struct PendingQueryParameters { |
48 | //! Prepared statement parameters (if any) |
49 | vector<Value> *parameters = nullptr; |
50 | //! Whether or not a stream result should be allowed |
51 | bool allow_stream_result = false; |
52 | }; |
53 | |
54 | //! ClientContextState is virtual base class for ClientContext-local (or Query-Local, using QueryEnd callback) state |
55 | //! e.g. caches that need to live as long as a ClientContext or Query. |
56 | class ClientContextState { |
57 | public: |
58 | virtual ~ClientContextState() {}; |
59 | virtual void QueryEnd() = 0; |
60 | }; |
61 | |
62 | //! The ClientContext holds information relevant to the current client session |
63 | //! during execution |
64 | class ClientContext : public std::enable_shared_from_this<ClientContext> { |
65 | friend class PendingQueryResult; |
66 | friend class StreamQueryResult; |
67 | friend class DuckTransactionManager; |
68 | |
69 | public: |
70 | DUCKDB_API explicit ClientContext(shared_ptr<DatabaseInstance> db); |
71 | DUCKDB_API ~ClientContext(); |
72 | |
73 | //! The database that this client is connected to |
74 | shared_ptr<DatabaseInstance> db; |
75 | //! Whether or not the query is interrupted |
76 | atomic<bool> interrupted; |
77 | //! External Objects (e.g., Python objects) that views depend of |
78 | unordered_map<string, vector<shared_ptr<ExternalDependency>>> external_dependencies; |
79 | //! Set of optional states (e.g. Caches) that can be held by the ClientContext |
80 | unordered_map<string, shared_ptr<ClientContextState>> registered_state; |
81 | //! The client configuration |
82 | ClientConfig config; |
83 | //! The set of client-specific data |
84 | unique_ptr<ClientData> client_data; |
85 | //! Data for the currently running transaction |
86 | TransactionContext transaction; |
87 | |
88 | public: |
89 | MetaTransaction &ActiveTransaction() { |
90 | return transaction.ActiveTransaction(); |
91 | } |
92 | |
93 | //! Interrupt execution of a query |
94 | DUCKDB_API void Interrupt(); |
95 | //! Enable query profiling |
96 | DUCKDB_API void EnableProfiling(); |
97 | //! Disable query profiling |
98 | DUCKDB_API void DisableProfiling(); |
99 | |
100 | //! Issue a query, returning a QueryResult. The QueryResult can be either a StreamQueryResult or a |
101 | //! MaterializedQueryResult. The StreamQueryResult will only be returned in the case of a successful SELECT |
102 | //! statement. |
103 | DUCKDB_API unique_ptr<QueryResult> Query(const string &query, bool allow_stream_result); |
104 | DUCKDB_API unique_ptr<QueryResult> Query(unique_ptr<SQLStatement> statement, bool allow_stream_result); |
105 | |
106 | //! Issues a query to the database and returns a Pending Query Result. Note that "query" may only contain |
107 | //! a single statement. |
108 | DUCKDB_API unique_ptr<PendingQueryResult> PendingQuery(const string &query, bool allow_stream_result); |
109 | //! Issues a query to the database and returns a Pending Query Result |
110 | DUCKDB_API unique_ptr<PendingQueryResult> PendingQuery(unique_ptr<SQLStatement> statement, |
111 | bool allow_stream_result); |
112 | |
113 | //! Destroy the client context |
114 | DUCKDB_API void Destroy(); |
115 | |
116 | //! Get the table info of a specific table, or nullptr if it cannot be found |
117 | DUCKDB_API unique_ptr<TableDescription> TableInfo(const string &schema_name, const string &table_name); |
118 | //! Appends a DataChunk to the specified table. Returns whether or not the append was successful. |
119 | DUCKDB_API void Append(TableDescription &description, ColumnDataCollection &collection); |
120 | //! Try to bind a relation in the current client context; either throws an exception or fills the result_columns |
121 | //! list with the set of returned columns |
122 | DUCKDB_API void TryBindRelation(Relation &relation, vector<ColumnDefinition> &result_columns); |
123 | |
124 | //! Execute a relation |
125 | DUCKDB_API unique_ptr<PendingQueryResult> PendingQuery(const shared_ptr<Relation> &relation, |
126 | bool allow_stream_result); |
127 | DUCKDB_API unique_ptr<QueryResult> Execute(const shared_ptr<Relation> &relation); |
128 | |
129 | //! Prepare a query |
130 | DUCKDB_API unique_ptr<PreparedStatement> Prepare(const string &query); |
131 | //! Directly prepare a SQL statement |
132 | DUCKDB_API unique_ptr<PreparedStatement> Prepare(unique_ptr<SQLStatement> statement); |
133 | |
134 | //! Create a pending query result from a prepared statement with the given name and set of parameters |
135 | //! It is possible that the prepared statement will be re-bound. This will generally happen if the catalog is |
136 | //! modified in between the prepared statement being bound and the prepared statement being run. |
137 | DUCKDB_API unique_ptr<PendingQueryResult> |
138 | PendingQuery(const string &query, shared_ptr<PreparedStatementData> &prepared, PendingQueryParameters parameters); |
139 | |
140 | //! Execute a prepared statement with the given name and set of parameters |
141 | //! It is possible that the prepared statement will be re-bound. This will generally happen if the catalog is |
142 | //! modified in between the prepared statement being bound and the prepared statement being run. |
143 | DUCKDB_API unique_ptr<QueryResult> Execute(const string &query, shared_ptr<PreparedStatementData> &prepared, |
144 | vector<Value> &values, bool allow_stream_result = true); |
145 | DUCKDB_API unique_ptr<QueryResult> Execute(const string &query, shared_ptr<PreparedStatementData> &prepared, |
146 | PendingQueryParameters parameters); |
147 | |
148 | //! Gets current percentage of the query's progress, returns 0 in case the progress bar is disabled. |
149 | DUCKDB_API double GetProgress(); |
150 | |
151 | //! Register function in the temporary schema |
152 | DUCKDB_API void RegisterFunction(CreateFunctionInfo &info); |
153 | |
154 | //! Parse statements from a query |
155 | DUCKDB_API vector<unique_ptr<SQLStatement>> ParseStatements(const string &query); |
156 | |
157 | //! Extract the logical plan of a query |
158 | DUCKDB_API unique_ptr<LogicalOperator> (const string &query); |
159 | DUCKDB_API void HandlePragmaStatements(vector<unique_ptr<SQLStatement>> &statements); |
160 | |
161 | //! Runs a function with a valid transaction context, potentially starting a transaction if the context is in auto |
162 | //! commit mode. |
163 | DUCKDB_API void RunFunctionInTransaction(const std::function<void(void)> &fun, |
164 | bool requires_valid_transaction = true); |
165 | //! Same as RunFunctionInTransaction, but does not obtain a lock on the client context or check for validation |
166 | DUCKDB_API void RunFunctionInTransactionInternal(ClientContextLock &lock, const std::function<void(void)> &fun, |
167 | bool requires_valid_transaction = true); |
168 | |
169 | //! Equivalent to CURRENT_SETTING(key) SQL function. |
170 | DUCKDB_API bool TryGetCurrentSetting(const std::string &key, Value &result); |
171 | |
172 | //! Returns the parser options for this client context |
173 | DUCKDB_API ParserOptions GetParserOptions() const; |
174 | |
175 | DUCKDB_API unique_ptr<DataChunk> Fetch(ClientContextLock &lock, StreamQueryResult &result); |
176 | |
177 | //! Whether or not the given result object (streaming query result or pending query result) is active |
178 | DUCKDB_API bool IsActiveResult(ClientContextLock &lock, BaseQueryResult *result); |
179 | |
180 | //! Returns the current executor |
181 | Executor &GetExecutor(); |
182 | |
183 | //! Returns the current query string (if any) |
184 | const string &GetCurrentQuery(); |
185 | |
186 | //! Fetch a list of table names that are required for a given query |
187 | DUCKDB_API unordered_set<string> GetTableNames(const string &query); |
188 | |
189 | DUCKDB_API ClientProperties GetClientProperties() const; |
190 | |
191 | //! Returns true if execution of the current query is finished |
192 | DUCKDB_API bool ExecutionIsFinished(); |
193 | |
194 | private: |
195 | //! Parse statements and resolve pragmas from a query |
196 | bool ParseStatements(ClientContextLock &lock, const string &query, vector<unique_ptr<SQLStatement>> &result, |
197 | PreservedError &error); |
198 | //! Issues a query to the database and returns a Pending Query Result |
199 | unique_ptr<PendingQueryResult> PendingQueryInternal(ClientContextLock &lock, unique_ptr<SQLStatement> statement, |
200 | PendingQueryParameters parameters, bool verify = true); |
201 | unique_ptr<QueryResult> ExecutePendingQueryInternal(ClientContextLock &lock, PendingQueryResult &query); |
202 | |
203 | //! Parse statements from a query |
204 | vector<unique_ptr<SQLStatement>> ParseStatementsInternal(ClientContextLock &lock, const string &query); |
205 | //! Perform aggressive query verification of a SELECT statement. Only called when query_verification_enabled is |
206 | //! true. |
207 | PreservedError VerifyQuery(ClientContextLock &lock, const string &query, unique_ptr<SQLStatement> statement); |
208 | |
209 | void InitialCleanup(ClientContextLock &lock); |
210 | //! Internal clean up, does not lock. Caller must hold the context_lock. |
211 | void CleanupInternal(ClientContextLock &lock, BaseQueryResult *result = nullptr, |
212 | bool invalidate_transaction = false); |
213 | unique_ptr<PendingQueryResult> PendingStatementOrPreparedStatement(ClientContextLock &lock, const string &query, |
214 | unique_ptr<SQLStatement> statement, |
215 | shared_ptr<PreparedStatementData> &prepared, |
216 | PendingQueryParameters parameters); |
217 | unique_ptr<PendingQueryResult> PendingPreparedStatement(ClientContextLock &lock, |
218 | shared_ptr<PreparedStatementData> statement_p, |
219 | PendingQueryParameters parameters); |
220 | |
221 | //! Internally prepare a SQL statement. Caller must hold the context_lock. |
222 | shared_ptr<PreparedStatementData> CreatePreparedStatement(ClientContextLock &lock, const string &query, |
223 | unique_ptr<SQLStatement> statement, |
224 | vector<Value> *values = nullptr); |
225 | unique_ptr<PendingQueryResult> PendingStatementInternal(ClientContextLock &lock, const string &query, |
226 | unique_ptr<SQLStatement> statement, |
227 | PendingQueryParameters parameters); |
228 | unique_ptr<QueryResult> RunStatementInternal(ClientContextLock &lock, const string &query, |
229 | unique_ptr<SQLStatement> statement, bool allow_stream_result, |
230 | bool verify = true); |
231 | unique_ptr<PreparedStatement> PrepareInternal(ClientContextLock &lock, unique_ptr<SQLStatement> statement); |
232 | void LogQueryInternal(ClientContextLock &lock, const string &query); |
233 | |
234 | unique_ptr<QueryResult> FetchResultInternal(ClientContextLock &lock, PendingQueryResult &pending); |
235 | unique_ptr<DataChunk> FetchInternal(ClientContextLock &lock, Executor &executor, BaseQueryResult &result); |
236 | |
237 | unique_ptr<ClientContextLock> LockContext(); |
238 | |
239 | void BeginTransactionInternal(ClientContextLock &lock, bool requires_valid_transaction); |
240 | void BeginQueryInternal(ClientContextLock &lock, const string &query); |
241 | PreservedError EndQueryInternal(ClientContextLock &lock, bool success, bool invalidate_transaction); |
242 | |
243 | PendingExecutionResult ExecuteTaskInternal(ClientContextLock &lock, PendingQueryResult &result); |
244 | |
245 | unique_ptr<PendingQueryResult> PendingStatementOrPreparedStatementInternal( |
246 | ClientContextLock &lock, const string &query, unique_ptr<SQLStatement> statement, |
247 | shared_ptr<PreparedStatementData> &prepared, PendingQueryParameters parameters); |
248 | |
249 | unique_ptr<PendingQueryResult> PendingQueryPreparedInternal(ClientContextLock &lock, const string &query, |
250 | shared_ptr<PreparedStatementData> &prepared, |
251 | PendingQueryParameters parameters); |
252 | |
253 | unique_ptr<PendingQueryResult> PendingQueryInternal(ClientContextLock &, const shared_ptr<Relation> &relation, |
254 | bool allow_stream_result); |
255 | |
256 | private: |
257 | //! Lock on using the ClientContext in parallel |
258 | mutex context_lock; |
259 | //! The currently active query context |
260 | unique_ptr<ActiveQueryContext> active_query; |
261 | //! The current query progress |
262 | atomic<double> query_progress; |
263 | }; |
264 | |
265 | class ClientContextLock { |
266 | public: |
267 | explicit ClientContextLock(mutex &context_lock) : client_guard(context_lock) { |
268 | } |
269 | |
270 | ~ClientContextLock() { |
271 | } |
272 | |
273 | private: |
274 | lock_guard<mutex> client_guard; |
275 | }; |
276 | |
277 | class ClientContextWrapper { |
278 | public: |
279 | explicit ClientContextWrapper(const shared_ptr<ClientContext> &context) |
280 | : client_context(context) { |
281 | |
282 | }; |
283 | shared_ptr<ClientContext> GetContext() { |
284 | auto actual_context = client_context.lock(); |
285 | if (!actual_context) { |
286 | throw ConnectionException("Connection has already been closed" ); |
287 | } |
288 | return actual_context; |
289 | } |
290 | |
291 | private: |
292 | std::weak_ptr<ClientContext> client_context; |
293 | }; |
294 | |
295 | } // namespace duckdb |
296 | |