11// SPDX-License-Identifier: Apache-2.0
22// SPDX-FileCopyrightText: Copyright the Vortex contributors
33
4+ #include " duckdb_vx/table_function.h"
45#include " duckdb_vx/duckdb_diagnostics.h"
56
67DUCKDB_INCLUDES_BEGIN
@@ -30,8 +31,10 @@ struct CTableFunctionInfo final : TableFunctionInfo {
3031};
3132
3233struct CTableBindData final : TableFunctionData {
33- CTableBindData (unique_ptr<CTableFunctionInfo> info_p, unique_ptr<vortex::CData> ffi_data_p)
34- : info(std::move(info_p)), ffi_data(std::move(ffi_data_p)) {
34+ CTableBindData (unique_ptr<CTableFunctionInfo> info_p,
35+ unique_ptr<vortex::CData> ffi_data_p,
36+ const vector<LogicalType> &types)
37+ : info(std::move(info_p)), ffi_data(std::move(ffi_data_p)), types(types) {
3538 }
3639
3740 unique_ptr<FunctionData> Copy () const override {
@@ -43,11 +46,13 @@ struct CTableBindData final : TableFunctionData {
4346 throw BinderException (IntoErrString (error_out));
4447 }
4548 return make_uniq<CTableBindData>(make_uniq<CTableFunctionInfo>(info->vtab ),
46- unique_ptr<CData>(reinterpret_cast <CData *>(copied_ffi_data)));
49+ unique_ptr<CData>(reinterpret_cast <CData *>(copied_ffi_data)),
50+ types);
4751 }
4852
4953 unique_ptr<CTableFunctionInfo> info;
5054 unique_ptr<CData> ffi_data;
55+ vector<LogicalType> types;
5156};
5257
5358struct CTableGlobalData final : GlobalTableFunctionState {
@@ -88,6 +93,79 @@ double c_table_scan_progress(ClientContext &context,
8893 return bind.info ->vtab .table_scan_progress (c_ctx, c_bind_data, c_global_state);
8994}
9095
96+ static Value &UnwrapValue (duckdb_value value) {
97+ return *(reinterpret_cast <Value *>(value));
98+ }
99+
100+ unique_ptr<BaseStatistics> numeric_stats (duckdb_column_statistics &stats, LogicalType type) {
101+ BaseStatistics out = StringStats::CreateUnknown (type);
102+ if (stats.min ) {
103+ NumericStats::SetMin (out, UnwrapValue (stats.min ));
104+ duckdb_destroy_value (&stats.min );
105+ }
106+ if (stats.max ) {
107+ NumericStats::SetMax (out, UnwrapValue (stats.max ));
108+ duckdb_destroy_value (&stats.max );
109+ }
110+ return out.ToUnique ();
111+ }
112+
113+ unique_ptr<BaseStatistics> string_stats (duckdb_column_statistics &stats, LogicalType type) {
114+ BaseStatistics out = StringStats::CreateUnknown (type);
115+ if (stats.min ) {
116+ StringStats::SetMin (out, StringValue::Get (UnwrapValue (stats.min )));
117+ duckdb_destroy_value (&stats.min );
118+ }
119+ if (stats.max ) {
120+ StringStats::SetMax (out, StringValue::Get (UnwrapValue (stats.max )));
121+ duckdb_destroy_value (&stats.max );
122+ }
123+ if (stats.max_string_length >> 63 ) {
124+ StringStats::SetMaxStringLength (out, uint32_t (stats.max_string_length ));
125+ }
126+ return out.ToUnique ();
127+ }
128+
129+ unique_ptr<BaseStatistics>
130+ c_statistics (ClientContext &context, const FunctionData *bind_data, column_t column_index) {
131+ if (column_index == COLUMN_IDENTIFIER_EMPTY) {
132+ return BaseStatistics::CreateUnknown (LogicalTypeId::INVALID).ToUnique ();
133+ }
134+
135+ const auto &bind = bind_data->Cast <CTableBindData>();
136+ void *const ffi_bind = bind.ffi_data ->DataPtr ();
137+
138+ duckdb_client_context c_ctx = reinterpret_cast <duckdb_client_context>(&context);
139+ duckdb_column_statistics statistics = {};
140+ const LogicalType type = bind.types [column_index];
141+
142+ switch (type.id ()) {
143+ case LogicalTypeId::BOOLEAN:
144+ case LogicalTypeId::TINYINT:
145+ case LogicalTypeId::SMALLINT:
146+ case LogicalTypeId::INTEGER:
147+ case LogicalTypeId::BIGINT:
148+ case LogicalTypeId::FLOAT:
149+ case LogicalTypeId::DOUBLE:
150+ case LogicalTypeId::UTINYINT:
151+ case LogicalTypeId::USMALLINT:
152+ case LogicalTypeId::UINTEGER:
153+ case LogicalTypeId::UBIGINT:
154+ case LogicalTypeId::UHUGEINT:
155+ case LogicalTypeId::HUGEINT: {
156+ bind.info ->vtab .statistics (c_ctx, ffi_bind, column_index, &statistics);
157+ return numeric_stats (statistics, type);
158+ }
159+ case LogicalTypeId::VARCHAR:
160+ case LogicalTypeId::BLOB: {
161+ bind.info ->vtab .statistics (c_ctx, ffi_bind, column_index, &statistics);
162+ return string_stats (statistics, type);
163+ }
164+ default :
165+ return BaseStatistics::CreateUnknown (type).ToUnique ();
166+ }
167+ }
168+
91169unique_ptr<FunctionData> c_bind (ClientContext &context,
92170 TableFunctionBindInput &input,
93171 vector<LogicalType> &return_types,
@@ -111,7 +189,8 @@ unique_ptr<FunctionData> c_bind(ClientContext &context,
111189 }
112190
113191 return make_uniq<CTableBindData>(make_uniq<CTableFunctionInfo>(info.vtab ),
114- unique_ptr<CData>(reinterpret_cast <CData *>(ffi_bind_data)));
192+ unique_ptr<CData>(reinterpret_cast <CData *>(ffi_bind_data)),
193+ return_types);
115194}
116195
117196unique_ptr<GlobalTableFunctionState> c_init_global (ClientContext &context, TableFunctionInitInput &input) {
@@ -363,6 +442,7 @@ extern "C" duckdb_state duckdb_vx_tfunc_register(duckdb_database ffi_db, const d
363442 tf.get_virtual_columns = c_get_virtual_columns;
364443 tf.to_string = c_to_string;
365444 tf.table_scan_progress = c_table_scan_progress;
445+ tf.statistics = c_statistics;
366446
367447 // Set up the parameters
368448 tf.arguments .reserve (vtab->parameter_count );
0 commit comments