Repository: duckdb/duckdb (language: python)

Issue:
min() and max() do not respect default collation
### What happens?

The `min()` and `max()` aggregate functions in DuckDB do not respect the default collation set using the `set default_collation = 'EN_US'`; statement. This causes the results to be different from what one would expect based on the sort order.



### To Reproduce

1. Create a table with some sample data:

```sql
create table test(id int, name text);
insert into test values (1, 'a'), (2, 'b'), (3, 'c'), (4, 'A'), (5, 'G'), (6, 'd');
```
2. Observe the default sort order
```sql
select * from test order by name;
```
3. This returns the expected sorting:
```sql
┌───────┬─────────┐
│  id   │  name   │
│ int32 │ varchar │
├───────┼─────────┤
│     4 │ A       │
│     5 │ G       │
│     1 │ a       │
│     2 │ b       │
│     3 │ c       │
│     6 │ d       │
└───────┴─────────┘
```
3. Check the min() and max() functions:
```sql
select min(name) from test;
select max(name) from test;
```
This also returns the expected results:

```sql
┌─────────────┐
│ min("name") │
│   varchar   │
├─────────────┤
│ A           │
└─────────────┘

┌─────────────┐
│ max("name") │
│   varchar   │
├─────────────┤
│ d           │
└─────────────┘
```
4. Set the default collation to 'EN_US':

```sql
set default_collation = 'EN_US';

```
5. Observe the new sort order:

```sql
select * from test order by name;

```
This now returns a different sort order (which is expected):
```sql
┌───────┬─────────┐
│  id   │  name   │
│ int32 │ varchar │
├───────┼─────────┤
│     1 │ a       │
│     4 │ A       │
│     2 │ b       │
│     3 │ c       │
│     6 │ d       │
│     5 │ G       │
└───────┴─────────┘
```
6. Check the min() and max() functions again:
```sql
select min(name) from test;
select max(name) from test;
```
The results are not what one would expect based on the new sort order:
```sql
┌─────────────┐
│ min("name") │
│   varchar   │
├─────────────┤
│ A           │
└─────────────┘

┌─────────────┐
│ max("name") │
│   varchar   │
├─────────────┤
│ d           │
└─────────────┘
```
The `min()` should return 'a' and the `max()` should return 'G', but they are returning 'A' and 'd' respectively.


### OS:

Ubuntu 20.04.5 LTS

### DuckDB Version:

1.1

### DuckDB Client:

python

### Hardware:

_No response_

### Full Name:

Arif Aslam

### Affiliation:

Mammoth Analytics Inc.

### What is the latest build you tested with? If possible, we recommend testing with the latest nightly build.

I have tested with a stable release

### Did you include all relevant data sets for reproducing the issue?

Yes

### Did you include all code required to reproduce the issue?

- [X] Yes, I have

### Did you include all relevant configuration (e.g., CPU architecture, Python version, Linux distribution) to reproduce the issue?

- [X] Yes, I have
min() and max() do not respect default collation
### What happens?

The `min()` and `max()` aggregate functions in DuckDB do not respect the default collation set using the `set default_collation = 'EN_US'`; statement. This causes the results to be different from what one would expect based on the sort order.



### To Reproduce

1. Create a table with some sample data:

```sql
create table test(id int, name text);
insert into test values (1, 'a'), (2, 'b'), (3, 'c'), (4, 'A'), (5, 'G'), (6, 'd');
```
2. Observe the default sort order
```sql
select * from test order by name;
```
3. This returns the expected sorting:
```sql
┌───────┬─────────┐
│  id   │  name   │
│ int32 │ varchar │
├───────┼─────────┤
│     4 │ A       │
│     5 │ G       │
│     1 │ a       │
│     2 │ b       │
│     3 │ c       │
│     6 │ d       │
└───────┴─────────┘
```
3. Check the min() and max() functions:
```sql
select min(name) from test;
select max(name) from test;
```
This also returns the expected results:

```sql
┌─────────────┐
│ min("name") │
│   varchar   │
├─────────────┤
│ A           │
└─────────────┘

┌─────────────┐
│ max("name") │
│   varchar   │
├─────────────┤
│ d           │
└─────────────┘
```
4. Set the default collation to 'EN_US':

```sql
set default_collation = 'EN_US';

```
5. Observe the new sort order:

```sql
select * from test order by name;

```
This now returns a different sort order (which is expected):
```sql
┌───────┬─────────┐
│  id   │  name   │
│ int32 │ varchar │
├───────┼─────────┤
│     1 │ a       │
│     4 │ A       │
│     2 │ b       │
│     3 │ c       │
│     6 │ d       │
│     5 │ G       │
└───────┴─────────┘
```
6. Check the min() and max() functions again:
```sql
select min(name) from test;
select max(name) from test;
```
The results are not what one would expect based on the new sort order:
```sql
┌─────────────┐
│ min("name") │
│   varchar   │
├─────────────┤
│ A           │
└─────────────┘

┌─────────────┐
│ max("name") │
│   varchar   │
├─────────────┤
│ d           │
└─────────────┘
```
The `min()` should return 'a' and the `max()` should return 'G', but they are returning 'A' and 'd' respectively.


### OS:

Ubuntu 20.04.5 LTS

### DuckDB Version:

1.1

### DuckDB Client:

python

### Hardware:

_No response_

### Full Name:

Arif Aslam

### Affiliation:

Mammoth Analytics Inc.

### What is the latest build you tested with? If possible, we recommend testing with the latest nightly build.

I have tested with a stable release

### Did you include all relevant data sets for reproducing the issue?

Yes

### Did you include all code required to reproduce the issue?

- [X] Yes, I have

### Did you include all relevant configuration (e.g., CPU architecture, Python version, Linux distribution) to reproduce the issue?

- [X] Yes, I have


Discussion / hints:

Fix patch:
diff --git a/src/core_functions/aggregate/distributive/minmax.cpp b/src/core_functions/aggregate/distributive/minmax.cpp
index 9c8db50bb5e3..dba09e5aa0a8 100644
--- a/src/core_functions/aggregate/distributive/minmax.cpp
+++ b/src/core_functions/aggregate/distributive/minmax.cpp
@@ -4,6 +4,7 @@
 #include "duckdb/common/vector_operations/vector_operations.hpp"
 #include "duckdb/common/operator/comparison_operators.hpp"
 #include "duckdb/common/types/null_value.hpp"
+#include "duckdb/main/config.hpp"
 #include "duckdb/planner/expression.hpp"
 #include "duckdb/planner/expression/bound_comparison_expression.hpp"
 #include "duckdb/planner/expression_binder.hpp"
@@ -330,7 +331,7 @@ unique_ptr<FunctionData> BindMinMax(ClientContext &context, AggregateFunction &f
                                     vector<unique_ptr<Expression>> &arguments) {
 	if (arguments[0]->return_type.id() == LogicalTypeId::VARCHAR) {
 		auto str_collation = StringType::GetCollation(arguments[0]->return_type);
-		if (!str_collation.empty()) {
+		if (!str_collation.empty() || !DBConfig::GetConfig(context).options.collation.empty()) {
 			// If aggr function is min/max and uses collations, replace bound_function with arg_min/arg_max
 			// to make sure the result's correctness.
 			string function_name = function.name == "min" ? "arg_min" : "arg_max";


Test patch:
diff --git a/test/issues/general/test_13824.test b/test/issues/general/test_13824.test
new file mode 100644
index 000000000000..abaa64c43ce2
--- /dev/null
+++ b/test/issues/general/test_13824.test
@@ -0,0 +1,37 @@
+# name: test/issues/general/test_13824.test
+# description: min() and max() should use default collation
+# group: [general]
+
+require icu
+
+statement ok
+PRAGMA enable_verification
+
+statement ok
+create table test(id int, name text)
+
+statement ok
+insert into test values (1, 'a'), (2, 'b'), (3, 'c'), (4, 'A'), (5, 'G'), (6, 'd')
+
+query I
+select min(name) from test
+----
+A
+
+query I
+select max(name) from test
+----
+d
+
+statement ok
+set default_collation = 'EN_US';
+
+query I
+select min(name) from test
+----
+a
+
+query I
+select max(name) from test
+----
+G
\ No newline at end of file