@@ -250,6 +250,27 @@ static unique_ptr<FunctionData> FromSubstraitBindJSON(ClientContext &context, Ta
250
250
return SubstraitBind (context, input, return_types, names, true );
251
251
}
252
252
253
+ static unique_ptr<FunctionData> ExplainSubstraitBind (ClientContext &context, TableFunctionBindInput &input,
254
+ vector<LogicalType> &return_types, vector<string> &names) {
255
+ if (input.inputs [0 ].IsNull ()) {
256
+ throw BinderException (" explain_substrait cannot be called with a NULL parameter" );
257
+ }
258
+
259
+ constexpr bool is_json = false ;
260
+ string serialized = input.inputs [0 ].GetValueUnsafe <string>();
261
+
262
+ // We can reuse the `FromSubstraitFunctionData` struct to return the explain plan
263
+ auto result = make_uniq<FromSubstraitFunctionData>();
264
+ result->conn = make_uniq<Connection>(*context.db );
265
+ result->plan = SubstraitPlanToDuckDBRel (*result->conn , serialized, is_json);
266
+
267
+ // But, we need to customize the return type to just be a string
268
+ return_types.emplace_back (LogicalType::VARCHAR);
269
+ names.emplace_back (" Explain Plan" );
270
+
271
+ return std::move (result);
272
+ }
273
+
253
274
static void FromSubFunction (ClientContext &context, TableFunctionInput &data_p, DataChunk &output) {
254
275
auto &data = data_p.bind_data ->CastNoConst <FromSubstraitFunctionData>();
255
276
if (!data.res ) {
@@ -262,6 +283,18 @@ static void FromSubFunction(ClientContext &context, TableFunctionInput &data_p,
262
283
output.Move (*result_chunk);
263
284
}
264
285
286
+ static void ExplainSubFunction (ClientContext &context, TableFunctionInput &data_p, DataChunk &output) {
287
+ auto &data = data_p.bind_data ->CastNoConst <FromSubstraitFunctionData>();
288
+ if (!data.res ) {
289
+ data.res = data.plan ->Explain ();
290
+ }
291
+ auto result_chunk = data.res ->Fetch ();
292
+ if (!result_chunk) {
293
+ return ;
294
+ }
295
+ output.Move (*result_chunk);
296
+ }
297
+
265
298
void InitializeGetSubstrait (const Connection &con) {
266
299
auto &catalog = Catalog::GetSystemCatalog (*con.context );
267
300
@@ -296,6 +329,16 @@ void InitializeFromSubstrait(const Connection &con) {
296
329
catalog.CreateTableFunction (*con.context , from_sub_info);
297
330
}
298
331
332
+ void InitializeExplainSubstrait (const Connection &con) {
333
+ auto &catalog = Catalog::GetSystemCatalog (*con.context );
334
+
335
+ // create the explain_substrait table function that returns a stringified query
336
+ // plan from a substrait plan
337
+ TableFunction explain_sub_func (" explain_substrait" , {LogicalType::BLOB}, ExplainSubFunction, ExplainSubstraitBind);
338
+ CreateTableFunctionInfo explain_sub_info (explain_sub_func);
339
+ catalog.CreateTableFunction (*con.context , explain_sub_info);
340
+ }
341
+
299
342
void InitializeFromSubstraitJSON (const Connection &con) {
300
343
auto &catalog = Catalog::GetSystemCatalog (*con.context );
301
344
@@ -316,6 +359,7 @@ void SubstraitExtension::Load(DuckDB &db) {
316
359
317
360
InitializeFromSubstrait (con);
318
361
InitializeFromSubstraitJSON (con);
362
+ InitializeExplainSubstrait (con);
319
363
320
364
con.Commit ();
321
365
}
0 commit comments