Repository: duckdb/duckdb
File: extension/core_functions/scalar/struct/struct_values.cpp (C++)

Code before:
		// Make result validity to mirror input's nulls
		UnifiedVectorFormat input_data;
		input.ToUnifiedFormat(count, input_data);
		auto &validity = FlatVector::Validity(result);

		validity.EnsureWritable();
		for (idx_t i = 0; i < count; i++) {
			auto idx = input_data.sel->get_index(i);
			if (!input_data.validity.RowIsValid(idx)) {
				validity.SetInvalid(i);
			}
		}
	}
}

// Ensure input is a STRUCT, set return type to an unnamed STRUCT with same child types
static unique_ptr<FunctionData> StructValuesBind(ClientContext &context, ScalarFunction &bound_function,
                                                 vector<unique_ptr<Expression>> &arguments) {
	if (arguments[0]->return_type.id() != LogicalTypeId::STRUCT) {
		throw InvalidInputException("struct_values() expects a STRUCT argument");
	}

	// Build unnamed children list using only types, with empty names
	child_list_t<LogicalType> unnamed_children;
	auto &children = StructType::GetChildTypes(arguments[0]->return_type);
	unnamed_children.reserve(children.size());
	for (auto &child : children) {
		unnamed_children.emplace_back("", child.second);
	}
	bound_function.SetReturnType(LogicalType::STRUCT(unnamed_children));
	return nullptr;
}

ScalarFunction StructValuesFun::GetFunction() {
	ScalarFunction func({LogicalType::ANY}, LogicalTypeId::STRUCT, StructValuesFunction, StructValuesBind);
	func.SetNullHandling(FunctionNullHandling::SPECIAL_HANDLING);
	return func;
}

} // namespace duckdb


Review comment (suggestion):
Is there a test with a prepared parameter? If there isn't, can we add one? I suspect there's logic missing here to handle that (checking for UNKNOWN type in the input - see other bind methods)

Code after:
		result.SetVectorType(VectorType::CONSTANT_VECTOR);
		const bool is_null = ConstantVector::IsNull(input);
		ConstantVector::SetNull(result, is_null);
	} else {
		result.SetVectorType(VectorType::FLAT_VECTOR);

		// Make result validity to mirror input's nulls
		UnifiedVectorFormat input_data;
		input.ToUnifiedFormat(count, input_data);

		if (!input_data.validity.AllValid()) {
			auto &validity = FlatVector::Validity(result);

			for (idx_t i = 0; i < count; i++) {
				auto idx = input_data.sel->get_index(i);
				if (!input_data.validity.RowIsValid(idx)) {
					validity.SetInvalid(i);
				}
			}
		}
	}
}

// Ensure input is a STRUCT, set return type to an unnamed STRUCT with same child types
static unique_ptr<FunctionData> StructValuesBind(ClientContext &context, ScalarFunction &bound_function,
                                                 vector<unique_ptr<Expression>> &arguments) {
	const auto arg_type = arguments[0]->return_type;
	if (arg_type == LogicalTypeId::UNKNOWN) {
		throw ParameterNotResolvedException();
	}

	// Since the type of the argument we declared of in `GetFunction` doesn't contain the inner STRUCT type,
	// we should take it from the arguments
	bound_function.arguments[0] = arg_type;

	// Build unnamed children list using only types, with empty names
	child_list_t<LogicalType> unnamed_children;
	auto &children = StructType::GetChildTypes(arguments[0]->return_type);
	unnamed_children.reserve(children.size());
	for (auto &child : children) {
		unnamed_children.emplace_back("", child.second);
	}
	bound_function.SetReturnType(LogicalType::STRUCT(unnamed_children));
	return nullptr;
}

ScalarFunction StructValuesFun::GetFunction() {
	ScalarFunction func({LogicalTypeId::STRUCT}, LogicalTypeId::STRUCT, StructValuesFunction, StructValuesBind);
	return func;
}