Skip to content

Fix greedy comment regex and deallocate-all blast radius (stacked on #14) - #17

Merged
utkarash2991 merged 1 commit into
mainfrom
utkarashsingh/psqlext-1773-fix-comment-regex-and-deallocate
Oct 22, 2026
Merged

utkarash2991 merged 1 commit into
mainfrom
utkarashsingh/psqlext-1773-fix-comment-regex-and-deallocate

Conversation

@utkarash2991

@utkarash2991 utkarash2991 commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #14

Targets utkarashsingh/psqlext-1773-schema-qualify-hypopg-calls-v2 (#14) - merge #13 and #14 first.

Two issues found reviewing the function while working on PSQLEXT-1773, both silent (no error raised) and both verified before and after the fix:

1. Greedy block-comment regex deletes code between separate comments

The comment-stripping regex ('\/\*.+\*\/') is greedy across every /* */ pair in the query, not just the nearest one. A query with two separate block comments has everything between the first /* and the last */ deleted - including real code in between.

select regexp_replace('select /* c1 */ a /* c2 */ from t', '\/\*.+\*\/', '', 'g');
-- 'select  from t'  <- column "a" is gone

Fixed with a non-greedy quantifier (\/\*.+?\*\/).

2. deallocate all wipes every prepared statement in the session

The two bare deallocate all; calls clear every prepared statement in the calling session, not just index_advisor's own internal one. In a pooled or persistent connection (PostgREST, pgbouncer session mode) this silently breaks whatever else that connection had prepared.

Verified: preparing an unrelated statement, then calling index_advisor(), left pg_prepared_statements with 0 rows afterward.

Tracked in https://linear.app/supabase/issue/PSQLEXT-1773

Two issues found during review of the function, both silent and both
real:

1. The block-comment regex ('\/\*.+\*\/') is greedy across every /* */
   pair in the query, not just one. A query with two separate block
   comments had everything between the first "/*" and the last "*/"
   deleted - including real code in between - with no error raised.
   Fixed with a non-greedy quantifier.

2. The two bare "deallocate all;" calls wipe every prepared statement in
   the calling session, not just index_advisor's own internal one. In a
   pooled or persistent connection (PostgREST, pgbouncer session mode)
   this silently breaks whatever else that connection had prepared.
   Fixed by checking pg_prepared_statements for the specific name before
   deallocating it - DEALLOCATE has no IF EXISTS clause, so this needs an
   explicit existence check rather than DROP-style IF EXISTS syntax.

Edits the same 0.2.0--0.2.1.sql script from #14 rather than bumping to
0.2.2 - 0.2.1 hasn't shipped anywhere yet, so there's no reason for two
version bumps when both PRs land in the same release.
@utkarash2991

Copy link
Copy Markdown
Contributor Author

Closing and reopening to retry GitHub's stack detection.

@utkarash2991 utkarash2991 reopened this Oct 6, 2026
@utkarash2991

Copy link
Copy Markdown
Contributor Author

Closing in favor of reopening #15 instead - same branch, testing whether #15 retained stack tracking from when it was originally created.

regexp_replace(
regexp_replace(
regexp_replace(query,'\/\*.+\*\/', '', 'g'),
regexp_replace(query,'\/\*.+?\*\/', '', 'g'),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Regex based parsing of SQL code is bound to break in other unexpected ways as well. E.g. what happens if a /* and */ pair exists inside a string? That shouldn't be stripped, but the current regex will strip it. Ideally we should parse the SQL properly for such code transformations, but that's a bigger change, and ok for now to keep as is.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeah agreed, this is a real gap. Proper SQL parsing would be the correct fix. Proceeding with merging this one now and will handle it in a follow-up PR.

deallocate all;
if exists (select 1 from pg_prepared_statements where name = prepared_statement_name) then
execute format('deallocate %I', prepared_statement_name);
end if;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is there a failure mode here when two calls to the index_advisor function are made at the same time? Will they conflict with each other and corrupt each other's responses? If yes, worth making the prepare_statement_name value unique for each call.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@imor Locally verified it. Prepared statements are bachend local in postgres . So two different sessions can't collide on the same name . I tested it directly: ran two concurrent sessions both using index_advisor_working_statement, one sleeping mid-transaction while the other prepared/executed/deallocated its own version of the name, and the sleeping session's value came back untouched when it resumed. The only way this could actually conflict is if a single session called index_advisor() reentrantly. But I think we are covered there as a backend runs one statement at a time.

@imor imor left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Left a couple of comments, ok to merge for now, but we should consider those changes going forward.

Base automatically changed from utkarashsingh/psqlext-1773-schema-qualify-hypopg-calls-v2 to main October 8, 2026 14:56
@utkarash2991
utkarash2991 merged commit b41d1f5 into main Oct 22, 2026
8 checks passed
@utkarash2991
utkarash2991 deleted the utkarashsingh/psqlext-1773-fix-comment-regex-and-deallocate branch October 22, 2026 11:21
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.

2 participants