Coverage Report

Created: 2026-05-19 06:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/duckdb/src/function/scalar/struct/struct_pack.cpp
Line
Count
Source
1
#include "duckdb/common/vector/map_vector.hpp"
2
#include "duckdb/common/vector/struct_vector.hpp"
3
#include "duckdb/function/scalar/nested_functions.hpp"
4
#include "duckdb/function/scalar/struct_functions.hpp"
5
#include "duckdb/common/case_insensitive_map.hpp"
6
#include "duckdb/common/string_util.hpp"
7
#include "duckdb/parser/expression/bound_expression.hpp"
8
#include "duckdb/planner/expression/bound_function_expression.hpp"
9
#include "duckdb/planner/expression_binder.hpp"
10
#include "duckdb/storage/statistics/struct_stats.hpp"
11
12
namespace duckdb {
13
14
0
static void StructPackFunction(DataChunk &args, ExpressionState &state, Vector &result) {
15
#ifdef DEBUG
16
  auto &func_expr = state.expr.Cast<BoundFunctionExpression>();
17
  auto &info = func_expr.bind_info->Cast<VariableReturnBindData>();
18
  // this should never happen if the binder below is sane
19
  D_ASSERT(args.ColumnCount() == StructType::GetChildTypes(info.stype).size());
20
#endif
21
0
  bool all_const = true;
22
0
  auto &child_entries = StructVector::GetEntries(result);
23
0
  idx_t children_size = 0;
24
0
  for (idx_t i = 0; i < args.ColumnCount(); i++) {
25
0
    if (args.data[i].GetVectorType() != VectorType::CONSTANT_VECTOR) {
26
0
      all_const = false;
27
0
    }
28
    // same holds for this
29
0
    child_entries[i].Reference(args.data[i]);
30
0
    children_size = MaxValue<idx_t>(children_size, child_entries[i].size());
31
0
  }
32
  // set only the struct buffer's type/size - do not propagate to children
33
  // since children reference external vectors (args) that may have incompatible buffer types.
34
  // match the parent size to the (already-set) child vector size, not to the chunk cardinality - those can
35
  // differ when the caller is collapsing all-constant inputs to a single argument row.
36
0
  result.BufferMutable().SetVectorTypeOnly(all_const ? VectorType::CONSTANT_VECTOR : VectorType::FLAT_VECTOR);
37
0
  result.BufferMutable().SetVectorSizeOnly(children_size);
38
0
  result.Verify();
39
0
}
40
41
template <bool IS_STRUCT_PACK>
42
0
static unique_ptr<FunctionData> StructPackBind(BindScalarFunctionInput &input) {
43
0
  auto &bound_function = input.GetBoundFunction();
44
0
  auto &arguments = input.GetArguments();
45
0
  case_insensitive_set_t name_collision_set;
46
47
  // collect names and deconflict, construct return type
48
0
  if (arguments.empty()) {
49
0
    throw InvalidInputException("Can't pack nothing into a struct");
50
0
  }
51
0
  child_list_t<LogicalType> struct_children;
52
0
  for (idx_t i = 0; i < arguments.size(); i++) {
53
0
    auto &child = arguments[i];
54
0
    string alias;
55
0
    if (IS_STRUCT_PACK) {
56
0
      if (child->GetAlias().empty()) {
57
0
        throw BinderException("Need named argument for struct pack, e.g. STRUCT_PACK(a := b)");
58
0
      }
59
0
      alias = child->GetAlias();
60
0
      if (name_collision_set.find(alias) != name_collision_set.end()) {
61
0
        throw BinderException("Duplicate struct entry name \"%s\"", alias);
62
0
      }
63
0
      name_collision_set.insert(alias);
64
0
    }
65
0
    struct_children.push_back(make_pair(alias, arguments[i]->GetReturnType()));
66
0
  }
67
68
  // this is more for completeness reasons
69
0
  bound_function.SetReturnType(LogicalType::STRUCT(struct_children));
70
0
  return make_uniq<VariableReturnBindData>(bound_function.GetReturnType());
71
0
}
Unexecuted instantiation: ub_duckdb_func_struct_main.cpp:duckdb::unique_ptr<duckdb::FunctionData, std::__1::default_delete<duckdb::FunctionData>, true> duckdb::StructPackBind<true>(duckdb::BindScalarFunctionInput&)
Unexecuted instantiation: ub_duckdb_func_struct_main.cpp:duckdb::unique_ptr<duckdb::FunctionData, std::__1::default_delete<duckdb::FunctionData>, true> duckdb::StructPackBind<false>(duckdb::BindScalarFunctionInput&)
72
73
0
static unique_ptr<BaseStatistics> StructPackStats(ClientContext &context, FunctionStatisticsInput &input) {
74
0
  auto &child_stats = input.child_stats;
75
0
  auto &expr = input.expr;
76
0
  auto struct_stats = StructStats::CreateUnknown(expr.GetReturnType());
77
0
  for (idx_t i = 0; i < child_stats.size(); i++) {
78
0
    StructStats::SetChildStats(struct_stats, i, child_stats[i]);
79
0
  }
80
0
  return struct_stats.ToUnique();
81
0
}
82
83
template <bool IS_STRUCT_PACK>
84
1.27k
static ScalarFunction GetStructPackFunction() {
85
1.27k
  ScalarFunction fun(IS_STRUCT_PACK ? "struct_pack" : "row", {}, LogicalTypeId::STRUCT, StructPackFunction,
86
1.27k
                     StructPackBind<IS_STRUCT_PACK>, StructPackStats);
87
1.27k
  fun.SetVarArgs(LogicalType::ANY);
88
1.27k
  fun.SetNullHandling(FunctionNullHandling::SPECIAL_HANDLING);
89
1.27k
  fun.SetSerializeCallback(VariableReturnBindData::Serialize);
90
1.27k
  fun.SetDeserializeCallback(VariableReturnBindData::Deserialize);
91
1.27k
  return fun;
92
1.27k
}
ub_duckdb_func_struct_main.cpp:duckdb::ScalarFunction duckdb::GetStructPackFunction<true>()
Line
Count
Source
84
636
static ScalarFunction GetStructPackFunction() {
85
636
  ScalarFunction fun(IS_STRUCT_PACK ? "struct_pack" : "row", {}, LogicalTypeId::STRUCT, StructPackFunction,
86
636
                     StructPackBind<IS_STRUCT_PACK>, StructPackStats);
87
636
  fun.SetVarArgs(LogicalType::ANY);
88
636
  fun.SetNullHandling(FunctionNullHandling::SPECIAL_HANDLING);
89
636
  fun.SetSerializeCallback(VariableReturnBindData::Serialize);
90
636
  fun.SetDeserializeCallback(VariableReturnBindData::Deserialize);
91
636
  return fun;
92
636
}
ub_duckdb_func_struct_main.cpp:duckdb::ScalarFunction duckdb::GetStructPackFunction<false>()
Line
Count
Source
84
636
static ScalarFunction GetStructPackFunction() {
85
636
  ScalarFunction fun(IS_STRUCT_PACK ? "struct_pack" : "row", {}, LogicalTypeId::STRUCT, StructPackFunction,
86
636
                     StructPackBind<IS_STRUCT_PACK>, StructPackStats);
87
636
  fun.SetVarArgs(LogicalType::ANY);
88
636
  fun.SetNullHandling(FunctionNullHandling::SPECIAL_HANDLING);
89
636
  fun.SetSerializeCallback(VariableReturnBindData::Serialize);
90
636
  fun.SetDeserializeCallback(VariableReturnBindData::Deserialize);
91
636
  return fun;
92
636
}
93
94
636
ScalarFunction StructPackFun::GetFunction() {
95
636
  return GetStructPackFunction<true>();
96
636
}
97
98
636
ScalarFunction RowFun::GetFunction() {
99
636
  return GetStructPackFunction<false>();
100
636
}
101
102
} // namespace duckdb