@@ -33,6 +33,7 @@ static CustomExecMethods duckdb_scan_exec_methods;
33
33
34
34
typedef struct DuckdbScanState {
35
35
CustomScanState css; /* must be first field */
36
+ const CustomScan *custom_scan;
36
37
const Query *query;
37
38
ParamListInfo params;
38
39
duckdb::Connection *duckdb_connection;
@@ -72,6 +73,7 @@ static Node *
72
73
Duckdb_CreateCustomScanState (CustomScan *cscan) {
73
74
DuckdbScanState *duckdb_scan_state = (DuckdbScanState *)newNode (sizeof (DuckdbScanState), T_CustomScanState);
74
75
CustomScanState *custom_scan_state = &duckdb_scan_state->css ;
76
+ duckdb_scan_state->custom_scan = cscan;
75
77
76
78
duckdb_scan_state->query = (const Query *)linitial (cscan->custom_private );
77
79
custom_scan_state->methods = &duckdb_scan_exec_methods;
@@ -84,7 +86,9 @@ Duckdb_BeginCustomScan_Cpp(CustomScanState *cscanstate, EState *estate, int /*ef
84
86
85
87
StringInfo explain_prefix = makeStringInfo ();
86
88
87
- if (ActivePortal && ActivePortal->commandTag == CMDTAG_EXPLAIN) {
89
+ bool is_explain_query = ActivePortal && ActivePortal->commandTag == CMDTAG_EXPLAIN;
90
+
91
+ if (is_explain_query) {
88
92
appendStringInfoString (explain_prefix, " EXPLAIN " );
89
93
90
94
if (NEED_JSON_PLAN (duckdb_explain_format))
@@ -114,6 +118,33 @@ Duckdb_BeginCustomScan_Cpp(CustomScanState *cscanstate, EState *estate, int /*ef
114
118
" DuckDB re-planning failed: " + prepared_query->GetError ());
115
119
}
116
120
121
+ if (!is_explain_query) {
122
+ auto &prepared_result_types = prepared_query->GetTypes ();
123
+
124
+ size_t target_list_length = static_cast <size_t >(list_length (duckdb_scan_state->custom_scan ->custom_scan_tlist ));
125
+
126
+ if (prepared_result_types.size () != target_list_length) {
127
+ elog (ERROR,
128
+ " (PGDuckDB/CreatePlan) Number of columns returned by DuckDB query changed between planning and "
129
+ " execution, expected %zu got %zu" ,
130
+ target_list_length, prepared_result_types.size ());
131
+ }
132
+
133
+ for (size_t i = 0 ; i < prepared_result_types.size (); i++) {
134
+ Oid postgres_column_oid = pgduckdb::GetPostgresDuckDBType (prepared_result_types[i]);
135
+ if (!OidIsValid (postgres_column_oid)) {
136
+ elog (ERROR, " (PGDuckDB/CreatePlan) Cache lookup failed for type %u" , postgres_column_oid);
137
+ }
138
+ TargetEntry *target_entry =
139
+ list_nth_node (TargetEntry, duckdb_scan_state->custom_scan ->custom_scan_tlist , i);
140
+ Var *var = castNode (Var, target_entry->expr );
141
+ if (var->vartype != postgres_column_oid) {
142
+ elog (ERROR, " Types returned by duckdb query changed between planning and execution, expected %d got %d" ,
143
+ var->vartype , postgres_column_oid);
144
+ }
145
+ }
146
+ }
147
+
117
148
duckdb_scan_state->duckdb_connection = pgduckdb::DuckDBManager::GetConnection ();
118
149
duckdb_scan_state->prepared_statement = prepared_query.release ();
119
150
duckdb_scan_state->params = estate->es_param_list_info ;
0 commit comments