Repository: duckdb/duckdb (language: python)

Issue:
Unexpected implicit cast when using CASE WHEN
### What happens?

I am observing some unexpected type casting when using CASE WHEN in a query.

When using an ENUM-typed variable inside a CASE WHEN check, the resulting value will be of type VARCHAR instead of ENUM,  which is unnecessary and wrong in my opinion.

### To Reproduce

```sql
CREATE TYPE E1 AS ENUM ('v1', 'v2');
CREATE TABLE t1 (v E1);
INSERT INTO t1 VALUES ('v1');
INSERT INTO t1 VALUES ('v1');
INSERT INTO t1 VALUES ('v1');

-- This returns a result only if all elements in a column are equal (namely this value), otherwise it should return NULL.
DESCRIBE (SELECT CASE WHEN COUNT(DISTINCT v) == 1 THEN FIRST(v) END AS r FROM t1);
```
Output:
```
┌─────────────┬─────────────┬──────┬─────┬─────────┬───────┐
│ column_name ┆ column_type ┆ null ┆ key ┆ default ┆ extra │
╞═════════════╪═════════════╪══════╪═════╪═════════╪═══════╡
│ r           ┆ VARCHAR     ┆ YES  ┆     ┆         ┆       │
└─────────────┴─────────────┴──────┴─────┴─────────┴───────┘
```

I expect the column type to be of ENUM E1 type, not VARCHAR.

### OS:

MS Windows 10, x64

### DuckDB Version:

1.1.3

### DuckDB Client:

R, WASM

### Hardware:

_No response_

### Full Name:

Lukas Schneiderbauer

### Affiliation:

None

### 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
Unexpected implicit cast when using CASE WHEN
### What happens?

I am observing some unexpected type casting when using CASE WHEN in a query.

When using an ENUM-typed variable inside a CASE WHEN check, the resulting value will be of type VARCHAR instead of ENUM,  which is unnecessary and wrong in my opinion.

### To Reproduce

```sql
CREATE TYPE E1 AS ENUM ('v1', 'v2');
CREATE TABLE t1 (v E1);
INSERT INTO t1 VALUES ('v1');
INSERT INTO t1 VALUES ('v1');
INSERT INTO t1 VALUES ('v1');

-- This returns a result only if all elements in a column are equal (namely this value), otherwise it should return NULL.
DESCRIBE (SELECT CASE WHEN COUNT(DISTINCT v) == 1 THEN FIRST(v) END AS r FROM t1);
```
Output:
```
┌─────────────┬─────────────┬──────┬─────┬─────────┬───────┐
│ column_name ┆ column_type ┆ null ┆ key ┆ default ┆ extra │
╞═════════════╪═════════════╪══════╪═════╪═════════╪═══════╡
│ r           ┆ VARCHAR     ┆ YES  ┆     ┆         ┆       │
└─────────────┴─────────────┴──────┴─────┴─────────┴───────┘
```

I expect the column type to be of ENUM E1 type, not VARCHAR.

### OS:

MS Windows 10, x64

### DuckDB Version:

1.1.3

### DuckDB Client:

R, WASM

### Hardware:

_No response_

### Full Name:

Lukas Schneiderbauer

### Affiliation:

None

### 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:
duplicate of https://github.com/duckdb/duckdb/issues/14935
duplicate of https://github.com/duckdb/duckdb/issues/14935

Fix patch:
diff --git a/src/catalog/catalog.cpp b/src/catalog/catalog.cpp
index 6168967d764d..53a31ac389b5 100644
--- a/src/catalog/catalog.cpp
+++ b/src/catalog/catalog.cpp
@@ -862,7 +862,7 @@ CatalogEntryLookup Catalog::TryLookupEntry(CatalogEntryRetriever &retriever, Cat
 	// lookup
 	if (type == CatalogType::TABLE_ENTRY) {
 		auto lookup_result_default_table =
-		    TryLookupDefaultTable(retriever, type, catalog, schema, name, if_not_found, error_context);
+		    TryLookupDefaultTable(retriever, type, catalog, schema, name, OnEntryNotFound::RETURN_NULL, error_context);
 
 		if (lookup_result_default_table.Found() && lookup_result.Found()) {
 			ThrowDefaultTableAmbiguityException(lookup_result, lookup_result_default_table, name);
diff --git a/src/common/types.cpp b/src/common/types.cpp
index 7ec718928038..474fc2848cbe 100644
--- a/src/common/types.cpp
+++ b/src/common/types.cpp
@@ -887,14 +887,8 @@ LogicalType LogicalType::NormalizeType(const LogicalType &type) {
 template <class OP>
 static bool CombineUnequalTypes(const LogicalType &left, const LogicalType &right, LogicalType &result) {
 	// left and right are not equal
-	// for enums, match the varchar rules
-	if (left.id() == LogicalTypeId::ENUM) {
-		return OP::Operation(LogicalType::VARCHAR, right, result);
-	} else if (right.id() == LogicalTypeId::ENUM) {
-		return OP::Operation(left, LogicalType::VARCHAR, result);
-	}
-	// NULL/string literals/unknown (parameter) types always take the other type
-	LogicalTypeId other_types[] = {LogicalTypeId::SQLNULL, LogicalTypeId::UNKNOWN, LogicalTypeId::STRING_LITERAL};
+	// NULL/unknown (parameter) types always take the other type
+	LogicalTypeId other_types[] = {LogicalTypeId::SQLNULL, LogicalTypeId::UNKNOWN};
 	for (auto &other_type : other_types) {
 		if (left.id() == other_type) {
 			result = LogicalType::NormalizeType(right);
@@ -905,6 +899,22 @@ static bool CombineUnequalTypes(const LogicalType &left, const LogicalType &righ
 		}
 	}
 
+	// for enums, match the varchar rules
+	if (left.id() == LogicalTypeId::ENUM) {
+		return OP::Operation(LogicalType::VARCHAR, right, result);
+	} else if (right.id() == LogicalTypeId::ENUM) {
+		return OP::Operation(left, LogicalType::VARCHAR, result);
+	}
+
+	// for everything but enums - string literals also take the other type
+	if (left.id() == LogicalTypeId::STRING_LITERAL) {
+		result = LogicalType::NormalizeType(right);
+		return true;
+	} else if (right.id() == LogicalTypeId::STRING_LITERAL) {
+		result = LogicalType::NormalizeType(left);
+		return true;
+	}
+
 	// for other types - use implicit cast rules to check if we can combine the types
 	auto left_to_right_cost = CastRules::ImplicitCast(left, right);
 	auto right_to_left_cost = CastRules::ImplicitCast(right, left);


Test patch:
diff --git a/test/sql/types/enum/test_enum_case.test b/test/sql/types/enum/test_enum_case.test
new file mode 100644
index 000000000000..8c2da50c08a1
--- /dev/null
+++ b/test/sql/types/enum/test_enum_case.test
@@ -0,0 +1,20 @@
+# name: test/sql/types/enum/test_enum_case.test
+# description: Test enum in CASE expressions
+# group: [enum]
+
+statement ok
+PRAGMA enable_verification
+
+statement ok
+CREATE TYPE E1 AS ENUM ('v1', 'v2');
+
+statement ok
+CREATE TABLE t1 (v E1);
+
+statement ok
+INSERT INTO t1 VALUES ('v1');
+
+query I
+SELECT typeof(CASE WHEN 1 THEN v END) FROM t1;
+----
+ENUM('v1', 'v2')