22
22
23
23
namespace duckdb {
24
24
25
- void do_nothing (ClientContext *) {
26
- }
25
+ // ! This is a no-op deleter for creating a shared pointer to a reference.
26
+ void deleter_noop (ClientContext *) { }
27
27
28
28
struct ToSubstraitFunctionData : public TableFunctionData {
29
29
ToSubstraitFunctionData () = default ;
@@ -264,7 +264,7 @@ static unique_ptr<TableRef> SubstraitBind(ClientContext &context, TableFunctionB
264
264
throw BinderException (" from_substrait cannot be called with a NULL parameter" );
265
265
}
266
266
string serialized = input.inputs [0 ].GetValueUnsafe <string>();
267
- shared_ptr<ClientContext> c_ptr (&context, do_nothing );
267
+ shared_ptr<ClientContext> c_ptr (&context, deleter_noop );
268
268
auto plan = SubstraitPlanToDuckDBRel (c_ptr, serialized, is_json);
269
269
return plan->GetTableRef ();
270
270
}
@@ -275,6 +275,45 @@ static unique_ptr<TableRef> FromSubstraitBind(ClientContext &context, TableFunct
275
275
276
276
static unique_ptr<TableRef> FromSubstraitBindJSON (ClientContext &context, TableFunctionBindInput &input) {
277
277
return SubstraitBind (context, input, true );
278
+
279
+ // ! Container for TableFnExplainSubstrait to get data from BindFnExplainSubstrait
280
+ struct FromSubstraitFunctionData : public TableFunctionData {
281
+ FromSubstraitFunctionData () = default ;
282
+ shared_ptr<Relation> plan;
283
+ unique_ptr<QueryResult> res;
284
+ unique_ptr<Connection> conn;
285
+ };
286
+
287
+ static unique_ptr<TableRef> BindFnExplainSubstrait (ClientContext &context, TableFunctionBindInput &input
288
+ vector<LogicalType> &return_types, vector<string> &names) {
289
+ if (input.inputs [0 ].IsNull ()) {
290
+ throw BinderException (" explain_substrait cannot be called with a NULL parameter" );
291
+ }
292
+
293
+ // Prep args to `SubstraitPlanToDuckDBRel`
294
+ constexpr bool is_json = false ;
295
+ string serialized = input.inputs [0 ].GetValueUnsafe <string>();
296
+ shared_ptr<ClientContext> c_ptr (&context, deleter_noop);
297
+
298
+ auto result = make_uniq<FromSubstraitFunctionData>();
299
+ result->conn = make_uniq<Connection>(*context.db );
300
+ result->plan = SubstraitPlanToDuckDBRel (c_ptr, serialized, is_json);
301
+
302
+ // return schema is a single string attribute (column)
303
+ return_types.emplace_back (LogicalType::VARCHAR);
304
+ names.emplace_back (" Explain Plan" );
305
+
306
+ return std::move (result);
307
+ }
308
+
309
+ static void TableFnExplainSubstrait (ClientContext &context, TableFunctionInput &data_p, DataChunk &output) {
310
+ auto &data = data_p.bind_data ->CastNoConst <FromSubstraitFunctionData>();
311
+ if (!data.res ) { data.res = data.plan ->Explain (); }
312
+
313
+ auto result_chunk = data.res ->Fetch ();
314
+ if (!result_chunk) { return ; }
315
+
316
+ output.Move (*result_chunk);
278
317
}
279
318
280
319
void InitializeGetSubstrait (const Connection &con) {
@@ -299,22 +338,39 @@ void InitializeGetSubstraitJSON(const Connection &con) {
299
338
catalog.CreateTableFunction (*con.context , get_substrait_json_info);
300
339
}
301
340
341
+ // ! Define and register a TableFunction ("from_substrait") that returns a TableRef
302
342
void InitializeFromSubstrait (const Connection &con) {
303
- auto &catalog = Catalog::GetSystemCatalog (*con.context );
304
-
305
- // create the from_substrait table function that allows us to get a query
306
- // result from a substrait plan
307
- TableFunction from_sub_func (" from_substrait" , {LogicalType::BLOB}, nullptr , nullptr );
343
+ // `FromSubstraitBind` translates a substrait plan and returns a `TableRef`
344
+ // to return a `TableRef` we use `bind_replace` instead of `bind`
345
+ TableFunction from_sub_func (" from_substrait" , {LogicalType::BLOB}, nullptr );
308
346
from_sub_func.bind_replace = FromSubstraitBind;
347
+
348
+ // register the TableFunction in the system catalog
349
+ auto &catalog = Catalog::GetSystemCatalog (*con.context );
309
350
CreateTableFunctionInfo from_sub_info (from_sub_func);
310
351
catalog.CreateTableFunction (*con.context , from_sub_info);
311
352
}
312
353
354
+ // ! Define and register a TableFunction ("explain_substrait") that returns a QueryResult
355
+ void InitializeExplainSubstrait (const Connection &con) {
356
+ TableFunction explain_sub_func (
357
+ " explain_substrait"
358
+ ,{LogicalType::BLOB}
359
+ ,/* function=*/ TableFnExplainSubstrait // Translates the plan then converts to a string
360
+ ,/* bind=*/ BindFnExplainSubstrait // Sets return schema to a single string
361
+ );
362
+
363
+ // register the TableFunction in the system catalog
364
+ auto &catalog = Catalog::GetSystemCatalog (*con.context );
365
+ CreateTableFunctionInfo explain_sub_info (explain_sub_func);
366
+ catalog.CreateTableFunction (*con.context , explain_sub_info);
367
+ }
368
+
313
369
void InitializeFromSubstraitJSON (const Connection &con) {
314
370
auto &catalog = Catalog::GetSystemCatalog (*con.context );
315
371
// create the from_substrait table function that allows us to get a query
316
372
// result from a substrait plan
317
- TableFunction from_sub_func_json (" from_substrait_json" , {LogicalType::VARCHAR}, nullptr , nullptr );
373
+ TableFunction from_sub_func_json (" from_substrait_json" , {LogicalType::VARCHAR}, nullptr );
318
374
from_sub_func_json.bind_replace = FromSubstraitBindJSON;
319
375
CreateTableFunctionInfo from_sub_info_json (from_sub_func_json);
320
376
catalog.CreateTableFunction (*con.context , from_sub_info_json);
@@ -329,6 +385,7 @@ void SubstraitExtension::Load(DuckDB &db) {
329
385
330
386
InitializeFromSubstrait (con);
331
387
InitializeFromSubstraitJSON (con);
388
+ InitializeExplainSubstrait (con);
332
389
333
390
con.Commit ();
334
391
}
0 commit comments