Repository: duckdb/duckdb (language: python)

Issue:
DuckDB Segmentation Fault, with Assertion message:  "types.cpp" on line 1674: info
### What happens?

The latest version of the DuckDB (latest main: v1.1.4-dev3226 07e3b42f75 and released version: v1.1.3 19864453f7) triggers Assertion Failure or Segmentation Fault when running the following SQL statement: 

```sql
CREATE TABLE v00 (c01 INT);
PIVOT_WIDER v00 AS ta02 ON ROW ( ) [ 'string' IN CASE WHEN 'string' THEN c01 END ] IN ENUM;
```

On the latest main (v1.1.4-dev3226 07e3b42f75), getting crash stack trace: 

```
#0  duckdb::EnumType::GetSize (type=...) at /home/duckdb/duckdb/src/common/types.cpp:1675
#1  0x00000000027bd048 in duckdb::Binder::BindPivot (this=0x266133c0, ref=..., all_columns=...)
    at /home/duckdb/duckdb/src/planner/binder/tableref/bind_pivot.cpp:425
#2  0x00000000027dbc78 in duckdb::Binder::Bind (this=<optimized out>, ref=...) at /home/duckdb/duckdb/src/planner/binder/tableref/bind_pivot.cpp:724
#3  0x0000000002913e74 in duckdb::Binder::Bind (this=0x266133c0, ref=...) at /home/duckdb/duckdb/src/planner/binder.cpp:416
#4  0x0000000004b4d5dc in duckdb::Binder::BindNode (this=0x266133c0, statement=...)
    at /home/duckdb/duckdb/src/planner/binder/query_node/bind_select_node.cpp:371
#5  0x0000000002911978 in duckdb::Binder::BindNode (this=0x266133c0, node=...) at /home/duckdb/duckdb/src/planner/binder.cpp:328
#6  0x0000000002912250 in duckdb::Binder::Bind (this=0x266133c0, node=...) at /home/duckdb/duckdb/src/planner/binder.cpp:365
#7  0x000000000290cbc4 in duckdb::Binder::Bind (this=0x266133c0, statement=...) at /home/duckdb/duckdb/src/planner/binder.cpp:150
#8  0x000000000293f1dc in duckdb::Planner::CreatePlan (this=0xffffea3a1e50, statement=...) at /home/duckdb/duckdb/src/planner/planner.cpp:43
#9  0x000000000188a7dc in duckdb::ClientContext::CreatePreparedStatementInternal (this=0x2647c4a0, lock=..., Python Exception <class 'gdb.error'> There is no member named _M_dataplus.:
query=, statement=..., values=...)
    at /home/duckdb/duckdb/src/main/client_context.cpp:340
#10 0x000000000188ea4c in duckdb::ClientContext::CreatePreparedStatement (this=<optimized out>, lock=..., Python Exception <class 'gdb.error'> There is no member named _M_dataplus.:
query=, statement=..., values=...,
    mode=duckdb::PreparedStatementMode::PREPARE_AND_EXECUTE) at /home/duckdb/duckdb/src/main/client_context.cpp:426
#11 0x00000000018a502c in duckdb::ClientContext::PendingStatementInternal (this=0x2647c4a0, lock=..., Python Exception <class 'gdb.error'> There is no member named _M_dataplus.:
query=, statement=..., parameters=...)
    at /home/duckdb/duckdb/src/main/client_context.cpp:745
#12 0x00000000018ae9f8 in duckdb::ClientContext::PendingStatementOrPreparedStatement (this=<optimized out>, lock=..., Python Exception <class 'gdb.error'> There is no member named _M_dataplus.:
query=, statement=..., prepared=...,
    parameters=...) at /home/duckdb/duckdb/src/main/client_context.cpp:863
#13 0x00000000018a2bf0 in duckdb::ClientContext::PendingStatementOrPreparedStatementInternal (this=0x2647c4a0, lock=..., Python Exception <class 'gdb.error'> There is no member named _M_dataplus.:
query=, statement=...,
    prepared=..., parameters=...) at /home/duckdb/duckdb/src/main/client_context.cpp:837
#14 0x00000000018a7534 in duckdb::ClientContext::PendingQueryInternal (this=0x2647c4a0, lock=..., statement=..., parameters=..., verify=<optimized out>)
    at /home/duckdb/duckdb/src/main/client_context.cpp:1054
#15 0x00000000018b7a50 in duckdb::ClientContext::PendingQuery (this=0x2647c4a0, statement=..., values=..., allow_stream_result=<optimized out>)
    at /home/duckdb/duckdb/src/main/client_context.cpp:1041
#16 0x00000000018b17e8 in duckdb::ClientContext::PendingQuery (this=0x2048, statement=..., allow_stream_result=false)
    at /home/duckdb/duckdb/src/main/client_context.cpp:1001
#17 0x00000000018e622c in duckdb::Connection::PendingQuery (this=<optimized out>, statement=..., allow_stream_result=false)
    at /home/duckdb/duckdb/src/main/connection.cpp:140
#18 0x00000000004b3fe8 in duckdb_shell_sqlite3_prepare_v2 (db=0x263daa40, zSql=<optimized out>, nByte=<optimized out>, ppStmt=<optimized out>,
    pzTail=<optimized out>) at ../../tools/sqlite3_api_wrapper/sqlite3_api_wrapper.cpp:224
#19 0x000000000046f604 in duckdb_shell::ShellState::ExecuteSQL (this=<optimized out>,
    zSql=0x263b5830 "PIVOT_WIDER v00 AS ta02 ON ROW ( ) [ 'string' IN CASE WHEN 'string' THEN c01 END ] IN ENUM;", pzErrMsg=0xffffea3a2e68)
    at ../../tools/shell/shell.cpp:1762
#20 0x0000000000485874 in duckdb_shell::ShellState::RunOneSqlLine (this=0xffffea3a3098,
    zSql=0x263b5830 "PIVOT_WIDER v00 AS ta02 ON ROW ( ) [ 'string' IN CASE WHEN 'string' THEN c01 END ] IN ENUM;") at ../../tools/shell/shell.cpp:4353
#21 0x0000000000480098 in duckdb_shell::ShellState::ProcessInput (this=<optimized out>) at ../../tools/shell/shell.cpp:4468
#22 0x0000000000489b40 in main (argc=1, argv=0xffffea3a33e8) at ../../tools/shell/shell.cpp:5076
```

### To Reproduce

1. Clone the DuckDB Git from the official repo.
2. Checkout to the latest main (07e3b42f75).
3. Compile the DuckDB binary by using `make relassert`(assertion failure) or `make reldebug` (SEGV).
4. Run the compiled DuckDB and input the following SQL:

```sql
CREATE TABLE v00 (c01 INT);
PIVOT_WIDER v00 AS ta02 ON ROW ( ) [ 'string' IN CASE WHEN 'string' THEN c01 END ] IN ENUM;
```

### OS:

Ubuntu 24.04 LTS

### DuckDB Version:

07e3b42f75 and released version: v1.1.3 19864453f7

### DuckDB Client:

cli

### Hardware:

_No response_

### Full Name:

Yu Liang

### Affiliation:

The Pennsylvania State Univerity

### 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
DuckDB Segmentation Fault, with Assertion message:  "types.cpp" on line 1674: info
### What happens?

The latest version of the DuckDB (latest main: v1.1.4-dev3226 07e3b42f75 and released version: v1.1.3 19864453f7) triggers Assertion Failure or Segmentation Fault when running the following SQL statement: 

```sql
CREATE TABLE v00 (c01 INT);
PIVOT_WIDER v00 AS ta02 ON ROW ( ) [ 'string' IN CASE WHEN 'string' THEN c01 END ] IN ENUM;
```

On the latest main (v1.1.4-dev3226 07e3b42f75), getting crash stack trace: 

```
#0  duckdb::EnumType::GetSize (type=...) at /home/duckdb/duckdb/src/common/types.cpp:1675
#1  0x00000000027bd048 in duckdb::Binder::BindPivot (this=0x266133c0, ref=..., all_columns=...)
    at /home/duckdb/duckdb/src/planner/binder/tableref/bind_pivot.cpp:425
#2  0x00000000027dbc78 in duckdb::Binder::Bind (this=<optimized out>, ref=...) at /home/duckdb/duckdb/src/planner/binder/tableref/bind_pivot.cpp:724
#3  0x0000000002913e74 in duckdb::Binder::Bind (this=0x266133c0, ref=...) at /home/duckdb/duckdb/src/planner/binder.cpp:416
#4  0x0000000004b4d5dc in duckdb::Binder::BindNode (this=0x266133c0, statement=...)
    at /home/duckdb/duckdb/src/planner/binder/query_node/bind_select_node.cpp:371
#5  0x0000000002911978 in duckdb::Binder::BindNode (this=0x266133c0, node=...) at /home/duckdb/duckdb/src/planner/binder.cpp:328
#6  0x0000000002912250 in duckdb::Binder::Bind (this=0x266133c0, node=...) at /home/duckdb/duckdb/src/planner/binder.cpp:365
#7  0x000000000290cbc4 in duckdb::Binder::Bind (this=0x266133c0, statement=...) at /home/duckdb/duckdb/src/planner/binder.cpp:150
#8  0x000000000293f1dc in duckdb::Planner::CreatePlan (this=0xffffea3a1e50, statement=...) at /home/duckdb/duckdb/src/planner/planner.cpp:43
#9  0x000000000188a7dc in duckdb::ClientContext::CreatePreparedStatementInternal (this=0x2647c4a0, lock=..., Python Exception <class 'gdb.error'> There is no member named _M_dataplus.:
query=, statement=..., values=...)
    at /home/duckdb/duckdb/src/main/client_context.cpp:340
#10 0x000000000188ea4c in duckdb::ClientContext::CreatePreparedStatement (this=<optimized out>, lock=..., Python Exception <class 'gdb.error'> There is no member named _M_dataplus.:
query=, statement=..., values=...,
    mode=duckdb::PreparedStatementMode::PREPARE_AND_EXECUTE) at /home/duckdb/duckdb/src/main/client_context.cpp:426
#11 0x00000000018a502c in duckdb::ClientContext::PendingStatementInternal (this=0x2647c4a0, lock=..., Python Exception <class 'gdb.error'> There is no member named _M_dataplus.:
query=, statement=..., parameters=...)
    at /home/duckdb/duckdb/src/main/client_context.cpp:745
#12 0x00000000018ae9f8 in duckdb::ClientContext::PendingStatementOrPreparedStatement (this=<optimized out>, lock=..., Python Exception <class 'gdb.error'> There is no member named _M_dataplus.:
query=, statement=..., prepared=...,
    parameters=...) at /home/duckdb/duckdb/src/main/client_context.cpp:863
#13 0x00000000018a2bf0 in duckdb::ClientContext::PendingStatementOrPreparedStatementInternal (this=0x2647c4a0, lock=..., Python Exception <class 'gdb.error'> There is no member named _M_dataplus.:
query=, statement=...,
    prepared=..., parameters=...) at /home/duckdb/duckdb/src/main/client_context.cpp:837
#14 0x00000000018a7534 in duckdb::ClientContext::PendingQueryInternal (this=0x2647c4a0, lock=..., statement=..., parameters=..., verify=<optimized out>)
    at /home/duckdb/duckdb/src/main/client_context.cpp:1054
#15 0x00000000018b7a50 in duckdb::ClientContext::PendingQuery (this=0x2647c4a0, statement=..., values=..., allow_stream_result=<optimized out>)
    at /home/duckdb/duckdb/src/main/client_context.cpp:1041
#16 0x00000000018b17e8 in duckdb::ClientContext::PendingQuery (this=0x2048, statement=..., allow_stream_result=false)
    at /home/duckdb/duckdb/src/main/client_context.cpp:1001
#17 0x00000000018e622c in duckdb::Connection::PendingQuery (this=<optimized out>, statement=..., allow_stream_result=false)
    at /home/duckdb/duckdb/src/main/connection.cpp:140
#18 0x00000000004b3fe8 in duckdb_shell_sqlite3_prepare_v2 (db=0x263daa40, zSql=<optimized out>, nByte=<optimized out>, ppStmt=<optimized out>,
    pzTail=<optimized out>) at ../../tools/sqlite3_api_wrapper/sqlite3_api_wrapper.cpp:224
#19 0x000000000046f604 in duckdb_shell::ShellState::ExecuteSQL (this=<optimized out>,
    zSql=0x263b5830 "PIVOT_WIDER v00 AS ta02 ON ROW ( ) [ 'string' IN CASE WHEN 'string' THEN c01 END ] IN ENUM;", pzErrMsg=0xffffea3a2e68)
    at ../../tools/shell/shell.cpp:1762
#20 0x0000000000485874 in duckdb_shell::ShellState::RunOneSqlLine (this=0xffffea3a3098,
    zSql=0x263b5830 "PIVOT_WIDER v00 AS ta02 ON ROW ( ) [ 'string' IN CASE WHEN 'string' THEN c01 END ] IN ENUM;") at ../../tools/shell/shell.cpp:4353
#21 0x0000000000480098 in duckdb_shell::ShellState::ProcessInput (this=<optimized out>) at ../../tools/shell/shell.cpp:4468
#22 0x0000000000489b40 in main (argc=1, argv=0xffffea3a33e8) at ../../tools/shell/shell.cpp:5076
```

### To Reproduce

1. Clone the DuckDB Git from the official repo.
2. Checkout to the latest main (07e3b42f75).
3. Compile the DuckDB binary by using `make relassert`(assertion failure) or `make reldebug` (SEGV).
4. Run the compiled DuckDB and input the following SQL:

```sql
CREATE TABLE v00 (c01 INT);
PIVOT_WIDER v00 AS ta02 ON ROW ( ) [ 'string' IN CASE WHEN 'string' THEN c01 END ] IN ENUM;
```

### OS:

Ubuntu 24.04 LTS

### DuckDB Version:

07e3b42f75 and released version: v1.1.3 19864453f7

### DuckDB Client:

cli

### Hardware:

_No response_

### Full Name:

Yu Liang

### Affiliation:

The Pennsylvania State Univerity

### 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:
Thanks!
Thanks!

Fix patch:
diff --git a/src/common/types.cpp b/src/common/types.cpp
index 7ec718928038..5c01b2692338 100644
--- a/src/common/types.cpp
+++ b/src/common/types.cpp
@@ -711,6 +711,11 @@ bool LogicalType::IsComplete() const {
 				return true; // Missing or incorrect type info
 			}
 			break;
+		case LogicalTypeId::ENUM:
+			if (!type.AuxInfo() || type.AuxInfo()->type != ExtraTypeInfoType::ENUM_TYPE_INFO) {
+				return true; // Missing or incorrect type info
+			}
+			break;
 		default:
 			return false;
 		}
@@ -1596,35 +1601,30 @@ const child_list_t<LogicalType> UnionType::CopyMemberTypes(const LogicalType &ty
 const string &UserType::GetCatalog(const LogicalType &type) {
 	D_ASSERT(type.id() == LogicalTypeId::USER);
 	auto info = type.AuxInfo();
-	D_ASSERT(info);
 	return info->Cast<UserTypeInfo>().catalog;
 }
 
 const string &UserType::GetSchema(const LogicalType &type) {
 	D_ASSERT(type.id() == LogicalTypeId::USER);
 	auto info = type.AuxInfo();
-	D_ASSERT(info);
 	return info->Cast<UserTypeInfo>().schema;
 }
 
 const string &UserType::GetTypeName(const LogicalType &type) {
 	D_ASSERT(type.id() == LogicalTypeId::USER);
 	auto info = type.AuxInfo();
-	D_ASSERT(info);
 	return info->Cast<UserTypeInfo>().user_type_name;
 }
 
 const vector<Value> &UserType::GetTypeModifiers(const LogicalType &type) {
 	D_ASSERT(type.id() == LogicalTypeId::USER);
 	auto info = type.AuxInfo();
-	D_ASSERT(info);
 	return info->Cast<UserTypeInfo>().user_type_modifiers;
 }
 
 vector<Value> &UserType::GetTypeModifiers(LogicalType &type) {
 	D_ASSERT(type.id() == LogicalTypeId::USER);
 	auto info = type.GetAuxInfoShrPtr();
-	D_ASSERT(info);
 	return info->Cast<UserTypeInfo>().user_type_modifiers;
 }
 
@@ -1664,21 +1664,18 @@ const string EnumType::GetValue(const Value &val) {
 const Vector &EnumType::GetValuesInsertOrder(const LogicalType &type) {
 	D_ASSERT(type.id() == LogicalTypeId::ENUM);
 	auto info = type.AuxInfo();
-	D_ASSERT(info);
 	return info->Cast<EnumTypeInfo>().GetValuesInsertOrder();
 }
 
 idx_t EnumType::GetSize(const LogicalType &type) {
 	D_ASSERT(type.id() == LogicalTypeId::ENUM);
 	auto info = type.AuxInfo();
-	D_ASSERT(info);
 	return info->Cast<EnumTypeInfo>().GetDictSize();
 }
 
 PhysicalType EnumType::GetPhysicalType(const LogicalType &type) {
 	D_ASSERT(type.id() == LogicalTypeId::ENUM);
 	auto aux_info = type.AuxInfo();
-	D_ASSERT(aux_info);
 	auto &info = aux_info->Cast<EnumTypeInfo>();
 	D_ASSERT(info.GetEnumDictType() == EnumDictType::VECTOR_DICT);
 	return EnumTypeInfo::DictType(info.GetDictSize());
@@ -1704,21 +1701,18 @@ bool LogicalType::IsJSONType() const {
 const LogicalType &ArrayType::GetChildType(const LogicalType &type) {
 	D_ASSERT(type.id() == LogicalTypeId::ARRAY);
 	auto info = type.AuxInfo();
-	D_ASSERT(info);
 	return info->Cast<ArrayTypeInfo>().child_type;
 }
 
 idx_t ArrayType::GetSize(const LogicalType &type) {
 	D_ASSERT(type.id() == LogicalTypeId::ARRAY);
 	auto info = type.AuxInfo();
-	D_ASSERT(info);
 	return info->Cast<ArrayTypeInfo>().size;
 }
 
 bool ArrayType::IsAnySize(const LogicalType &type) {
 	D_ASSERT(type.id() == LogicalTypeId::ARRAY);
 	auto info = type.AuxInfo();
-	D_ASSERT(info);
 	return info->Cast<ArrayTypeInfo>().size == 0;
 }
 
@@ -1799,7 +1793,7 @@ idx_t AnyType::GetCastScore(const LogicalType &type) {
 LogicalType IntegerLiteral::GetType(const LogicalType &type) {
 	D_ASSERT(type.id() == LogicalTypeId::INTEGER_LITERAL);
 	auto info = type.AuxInfo();
-	D_ASSERT(info && info->type == ExtraTypeInfoType::INTEGER_LITERAL_TYPE_INFO);
+	D_ASSERT(info->type == ExtraTypeInfoType::INTEGER_LITERAL_TYPE_INFO);
 	return info->Cast<IntegerLiteralTypeInfo>().constant_value.type();
 }
 
@@ -1814,7 +1808,7 @@ bool IntegerLiteral::FitsInType(const LogicalType &type, const LogicalType &targ
 	}
 	// we can cast to integral types if the constant value fits within that type
 	auto info = type.AuxInfo();
-	D_ASSERT(info && info->type == ExtraTypeInfoType::INTEGER_LITERAL_TYPE_INFO);
+	D_ASSERT(info->type == ExtraTypeInfoType::INTEGER_LITERAL_TYPE_INFO);
 	auto &literal_info = info->Cast<IntegerLiteralTypeInfo>();
 	Value copy = literal_info.constant_value;
 	return copy.DefaultTryCastAs(target);
diff --git a/src/include/duckdb/common/types.hpp b/src/include/duckdb/common/types.hpp
index 72a9150150b7..5c2492f83969 100644
--- a/src/include/duckdb/common/types.hpp
+++ b/src/include/duckdb/common/types.hpp
@@ -252,7 +252,7 @@ struct LogicalType {
 	inline PhysicalType InternalType() const {
 		return physical_type_;
 	}
-	inline const ExtraTypeInfo *AuxInfo() const {
+	inline const optional_ptr<ExtraTypeInfo> AuxInfo() const {
 		return type_info_.get();
 	}
 	inline bool IsNested() const {
diff --git a/src/planner/binder/tableref/bind_pivot.cpp b/src/planner/binder/tableref/bind_pivot.cpp
index a1b9789adf26..f81c09d3a24f 100644
--- a/src/planner/binder/tableref/bind_pivot.cpp
+++ b/src/planner/binder/tableref/bind_pivot.cpp
@@ -422,6 +422,9 @@ unique_ptr<SelectNode> Binder::BindPivot(PivotRef &ref, vector<unique_ptr<Parsed
 				throw BinderException(ref, "Pivot must reference an ENUM type: \"%s\" is of type \"%s\"",
 				                      pivot.pivot_enum, type.ToString());
 			}
+			if (!type.IsComplete()) {
+				throw BinderException("ENUM type is incomplete");
+			}
 			auto enum_size = EnumType::GetSize(type);
 			for (idx_t i = 0; i < enum_size; i++) {
 				auto enum_value = EnumType::GetValue(Value::ENUM(i, type));


Test patch:
diff --git a/test/fuzzer/public/pivot_empty_enum.test b/test/fuzzer/public/pivot_empty_enum.test
new file mode 100644
index 000000000000..89caa26ba7b7
--- /dev/null
+++ b/test/fuzzer/public/pivot_empty_enum.test
@@ -0,0 +1,13 @@
+# name: test/fuzzer/public/pivot_empty_enum.test
+# description: Test pivot with an empty enum
+# group: [public]
+
+statement ok
+pragma enable_verification
+
+statement ok
+CREATE TABLE t1 (c01 INT);
+
+statement error
+PIVOT_WIDER t1 ON c01 IN ENUM;
+----