| 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 | |