Skip to content

Conversation

JelteF
Copy link
Collaborator

@JelteF JelteF commented Mar 11, 2025

With a specific query order it was possible that Postgres would cache the plan for the EXPLAINed version of a query instead of the plan for the actual query. This fixes that by only ever adding EXPLAIN to a query when actually executing the query, not also when only planning it. This way the plan that will be cached is always the actual query plan, but at execution time that might be changed in case the query is EXPLAINed.

This also fixes two bugs involving EXPLAIN ANALYZE:

  1. EXPLAIN ANALYZE + CTAS into a Postgres table is now disallowed when using DuckDB execution. Before it was putting the plan into the table... Not the result of the query.
  2. Don't execute the EXPLAIN ANALYZE twice in DuckDB. For read-only queries this would result in the query taking twice as long, while only reporting the runtime for one of the queries. When using EXPLAIN ANALYZE on DML statements this would actually matter a lot, because those would have the side-effect twice, i.e. data would be inserted twice.

Fixes #410

@JelteF JelteF force-pushed the fix-prepared-statement-crash branch from 58db8d3 to f1f3604 Compare March 11, 2025 15:18
Custom Scan (DuckDBScan) (cost=0.00..0.00 rows=0 width=0)
Output: duckdb_scan.explain_key, duckdb_scan.explain_value
Output: duckdb_scan."Count"
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is nice additional benefit of this change. The VERBOSE flag now actually lists the columns that the scan returns. For INSERT statements this isn't actually true though, because in postgres those don't return a column at all.

@JelteF JelteF requested a review from Y-- March 11, 2025 15:23
Query *copied_query = (Query *)copyObjectImpl(query);
const char *query_string = pgduckdb_get_querydef(copied_query);

if (ActivePortal && ActivePortal->commandTag == CMDTAG_EXPLAIN) {
if (allow_explain && ActivePortal && ActivePortal->commandTag == CMDTAG_EXPLAIN) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should't the condition be:

Suggested change
if (allow_explain && ActivePortal && ActivePortal->commandTag == CMDTAG_EXPLAIN) {
if (ActivePortal && ActivePortal->commandTag == CMDTAG_EXPLAIN) {
if (!allow_explain) {
elog(ERROR, ...);
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No it shouldn't, but I totally agree that the argument name suggested that. Instead of renaming it I moved the logic outside of DuckdbPrepare function now.

JelteF added 2 commits March 12, 2025 11:25
With a specific query order it was possible that Postgres would cache
the plan for the EXPLAINed version of a query instead of the plan for
the actual query. This fixes that by only ever adding EXPLAIN to a query
when actually executing the query, not also when only planning it. This
way the plan that will be cached is always the actual query plan, but
at execution time that might be changed in case the query is EXPLAINed.
@JelteF JelteF force-pushed the fix-prepared-statement-crash branch from f1f3604 to 305b227 Compare March 12, 2025 10:52
assert "Total Time:" in plan
# The insert should have been executed exactly once
assert cur.sql("SELECT * FROM test_table ORDER BY id") == [1, 2, 3, 4, 5]
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is currently failing on main...

@JelteF JelteF requested a review from Y-- March 12, 2025 13:04
Copy link
Collaborator

@Y-- Y-- left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neat! Thanks!

@JelteF JelteF merged commit d931980 into main Mar 12, 2025
5 checks passed
@JelteF JelteF deleted the fix-prepared-statement-crash branch March 12, 2025 15:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Server crashes involving plan_cache_mode
2 participants