@@ -721,6 +721,16 @@ Field *Item_sum::create_tmp_field(bool, TABLE *table) {
721721 return field;
722722}
723723
724+ Field *Item_sum::make_string_field (TABLE *table) const {
725+ Field *field = Item::make_string_field (table);
726+ // VillageSQL: Propagate TypeContext from aggregated argument to result field.
727+ // This allows GROUP_CONCAT to decode custom type values when building output.
728+ if (field && arg_count > 0 && args[0 ]->has_type_context ()) {
729+ field->set_type_context (args[0 ]->get_type_context ());
730+ }
731+ return field;
732+ }
733+
724734bool Item_sum::collect_grouped_aggregates (uchar *arg) {
725735 auto *info = pointer_cast<Collect_grouped_aggregate_info *>(arg);
726736
@@ -4170,17 +4180,20 @@ int dump_leaf_key(void *key_arg, element_count count [[maybe_unused]],
41704180 We also can't use table->field array to access the fields
41714181 because it contains both order and arg list fields.
41724182 */
4173- if ((*arg)->const_item ())
4174- res = (*arg)->val_str (&tmp);
4175- else {
4183+ // VillageSQL: Use val_custom_str throughout to decode custom types.
4184+ // Const items can have custom types (e.g., const-folded function calls).
4185+ if ((*arg)->const_item ()) {
4186+ res = (*arg)->val_custom_str (&tmp);
4187+ } else {
41764188 Field *field = (*arg)->get_tmp_table_field ();
41774189 if (field) {
41784190 const uint offset =
41794191 (field->offset (field->table ->record [0 ]) - table->s ->null_bytes );
41804192 assert (offset < table->s ->reclength );
4181- res = field->val_str (&tmp, key + offset);
4182- } else
4183- res = (*arg)->val_str (&tmp);
4193+ res = field->val_custom_str (&tmp, key + offset);
4194+ } else {
4195+ res = (*arg)->val_custom_str (&tmp);
4196+ }
41844197 }
41854198 if (res) result->append (*res);
41864199 }
0 commit comments