Skip to content

Commit 5d06c53

Browse files
committed
feat: add explain TableFunction for substrait
This adds a new table function, `explain_substrait`, as well as a new execution kernel for the function and binding kernel. This reuses the `FromSubstraitFunctionData` structure since it contains all the pieces we would need.
1 parent be71387 commit 5d06c53

File tree

1 file changed

+44
-0
lines changed

1 file changed

+44
-0
lines changed

src/substrait_extension.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,27 @@ static unique_ptr<FunctionData> FromSubstraitBindJSON(ClientContext &context, Ta
250250
return SubstraitBind(context, input, return_types, names, true);
251251
}
252252

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+
253274
static void FromSubFunction(ClientContext &context, TableFunctionInput &data_p, DataChunk &output) {
254275
auto &data = data_p.bind_data->CastNoConst<FromSubstraitFunctionData>();
255276
if (!data.res) {
@@ -262,6 +283,18 @@ static void FromSubFunction(ClientContext &context, TableFunctionInput &data_p,
262283
output.Move(*result_chunk);
263284
}
264285

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+
265298
void InitializeGetSubstrait(const Connection &con) {
266299
auto &catalog = Catalog::GetSystemCatalog(*con.context);
267300

@@ -296,6 +329,16 @@ void InitializeFromSubstrait(const Connection &con) {
296329
catalog.CreateTableFunction(*con.context, from_sub_info);
297330
}
298331

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+
299342
void InitializeFromSubstraitJSON(const Connection &con) {
300343
auto &catalog = Catalog::GetSystemCatalog(*con.context);
301344

@@ -316,6 +359,7 @@ void SubstraitExtension::Load(DuckDB &db) {
316359

317360
InitializeFromSubstrait(con);
318361
InitializeFromSubstraitJSON(con);
362+
InitializeExplainSubstrait(con);
319363

320364
con.Commit();
321365
}

0 commit comments

Comments
 (0)