backend/plugin/parser/pg/SCENARIOS.md
Goal: Comprehensive test coverage for PostgreSQL autocompletion across all SQL contexts Verification:
go test -v -count=1 github.com/bytebase/bytebase/backend/plugin/parser/pg -run ^TestCompletion$Reference sources: PostgreSQL documentation, omni parser grammar rules, completion.go source code
Status: [ ] pending, [x] passing, [~] partial (needs upstream change)
Fill missing coverage for features already partially tested.
SELECT | FROM t1 RIGHT JOIN t2 ON t1.c1 = t2.c1 — columns from both tables visible in RIGHT JOINSELECT | FROM t1 FULL OUTER JOIN t2 ON t1.c1 = t2.c1 — columns from both tables visible in FULL OUTER JOINSELECT | FROM t1 CROSS JOIN t2 — columns from both tables visible in CROSS JOIN (no ON clause)SELECT | FROM t1 NATURAL JOIN t2 — columns from both tables visible in NATURAL JOINSELECT * FROM t1 RIGHT JOIN t2 ON t1.c1 = t2.| — qualified column in RIGHT JOIN ON conditionSELECT * FROM t1 FULL OUTER JOIN t2 ON t1.c1 = t2.| — qualified column in FULL OUTER JOIN ON conditionSELECT * FROM t1 CROSS JOIN t2 WHERE t1.| — qualified column in WHERE after CROSS JOINSELECT * FROM t1 JOIN t2 USING (|) — columns common to both tables in USING clauseSELECT | FROM t1 JOIN t2 ON t1.c1 = t2.c1 LEFT JOIN test.auto ON t2.c1 = test.auto.id — mixed join types with cross-schemaSELECT a.| FROM t1 a NATURAL JOIN t2 b — alias-qualified columns after NATURAL JOINSELECT * FROM t2 WHERE c1 BETWEEN | AND c2 — completion after BETWEENSELECT * FROM t2 WHERE c1 BETWEEN c2 AND | — completion after AND in BETWEENSELECT * FROM test.auto WHERE name LIKE | — completion after LIKESELECT * FROM t2 WHERE c1 IS NOT NULL AND | — completion after IS NOT NULL conditionSELECT * FROM t2 WHERE c1 IS NULL OR | — completion after IS NULL conditionSELECT * FROM t2 WHERE NOT | — completion after NOTSELECT * FROM t2 WHERE c1 > | — completion after comparison operatorSELECT * FROM t2 WHERE c1 + | > 0 — completion in arithmetic expressionSELECT * FROM t2 WHERE c1 IN (1, 2) AND | — completion after IN listSELECT * FROM t1 WHERE c1 = (SELECT MAX(|) FROM t2) — completion inside aggregate in scalar subquerySELECT * FROM t1 x WHERE x.c1 IN (SELECT c1 FROM t2 WHERE |) — completion in correlated subquery WHERESELECT * FROM t2 WHERE CASE WHEN c1 > 0 THEN | END = 1 — completion in CASE WHEN THENSELECT DISTINCT | FROM t2 — columns after DISTINCTSELECT DISTINCT ON (|) c1, c2 FROM t2 — columns in DISTINCT ONSELECT | FROM t2 LIMIT 10 — columns in SELECT with LIMIT presentSELECT * FROM t2 LIMIT | — completion in LIMIT expressionSELECT * FROM t2 OFFSET | — completion in OFFSET expressionSELECT * FROM t2 ORDER BY c1 LIMIT | — completion in LIMIT after ORDER BYSELECT c1, | FROM t2 — completion for second column in select listDELETE FROM t2 WHERE c1 > 0 RETURNING | — completion in RETURNING clause (DML)UPDATE t2 SET c1 = 1 RETURNING | — completion in UPDATE RETURNING clauseSELECT c1, SUM(c2) OVER (PARTITION BY |) FROM t2 — column in window PARTITION BYSELECT c1, SUM(c2) OVER (ORDER BY |) FROM t2 — column in window ORDER BYSELECT c1, ROW_NUMBER() OVER (PARTITION BY | ORDER BY c1) FROM t2 — column in window functionSELECT COALESCE(|, 0) FROM t2 — completion in COALESCE first argumentSELECT COALESCE(c1, |) FROM t2 — completion in COALESCE second argumentSELECT NULLIF(|, 0) FROM t2 — completion in NULLIFSELECT CAST(| AS int) FROM t2 — completion in CAST expressionSELECT | FROM t2 FOR UPDATE — columns with FOR UPDATE locking clauseSELECT * FROM | with foreign tables in metadata — foreign tables appear in FROM completionSELECT * FROM | with materialized views in metadata — materialized views appear in FROM completionSELECT * FROM public.| with foreign tables — foreign tables in schema-qualified FROMSELECT * FROM public.| with materialized views — materialized views in schema-qualified FROMSELECT mv1.| FROM mv1 — columns from materialized view (qualified)SELECT | FROM mv1 — columns from materialized view (unqualified)SELECT ft1.| FROM ft1 — columns from foreign table (qualified)SELECT | FROM ft1 — columns from foreign table (unqualified)INSERT INTO | with foreign tables — foreign tables in INSERT targetUPDATE | with materialized views — materialized views should NOT appear in UPDATE target (they are read-only; completion engine uses same relation_expr rule for SELECT/UPDATE/DELETE and doesn't distinguish context)Completion in DDL statements. Independent of Phase 1 — can run in parallel. Many scenarios likely need completion.go changes or omni parser grammar support; mark [~] if blocked.
CREATE TABLE test_tbl (id int, FOREIGN KEY (id) REFERENCES |) — table completion in FK referenceCREATE TABLE test_tbl (id int, FOREIGN KEY (id) REFERENCES public.|) — schema-qualified FK referenceCREATE TABLE test_tbl (id int REFERENCES |) — inline FK referenceCREATE TABLE test_tbl (id int REFERENCES t1(|)) — column completion in FK referenceCREATE INDEX idx ON | — table completion in CREATE INDEXCREATE INDEX idx ON public.| — schema-qualified table in CREATE INDEXCREATE INDEX idx ON t1 (|) — column completion in index expressionCREATE INDEX idx ON t2 (c1, |) — second column in composite indexCREATE VIEW v2 AS SELECT | FROM t1 — completion in CREATE VIEW bodyCREATE VIEW v2 AS SELECT * FROM | — FROM completion in CREATE VIEW bodyCREATE MATERIALIZED VIEW mv AS SELECT | FROM t1 — completion in CREATE MATERIALIZED VIEW bodyCREATE TABLE test_tbl AS SELECT | FROM t1 — completion in CREATE TABLE AS SELECTCREATE TABLE test_tbl (LIKE |) — table completion in LIKE clauseCREATE TRIGGER trig AFTER INSERT ON | — table completion in CREATE TRIGGERCREATE TRIGGER trig AFTER INSERT ON public.| — schema-qualified table in CREATE TRIGGERALTER TABLE | — table completion in ALTER TABLEALTER TABLE public.| — schema-qualified table in ALTER TABLEALTER TABLE t1 ADD COLUMN c2 int REFERENCES | — FK reference in ALTER ADD COLUMNALTER TABLE t1 DROP COLUMN | — column completion for existing columnsALTER TABLE t1 RENAME COLUMN | TO new_name — column completion in RENAMEALTER TABLE t1 ALTER COLUMN | — column completion in ALTER COLUMNALTER TABLE t1 ALTER COLUMN | SET NOT NULL — column completion with SET NOT NULLALTER TABLE t1 ADD CONSTRAINT fk FOREIGN KEY (|) REFERENCES t2 — column in FK constraintALTER TABLE t1 ADD CONSTRAINT fk FOREIGN KEY (c1) REFERENCES t2(|) — referenced columnALTER INDEX | RENAME TO new_name — index completion in ALTER INDEXALTER VIEW | — view completion in ALTER VIEWALTER VIEW public.| — schema-qualified view in ALTER VIEWALTER SEQUENCE | — sequence completion in ALTER SEQUENCEALTER SEQUENCE public.| — schema-qualified sequenceALTER MATERIALIZED VIEW | — materialized view completionDROP TABLE | — table completion in DROP TABLEDROP TABLE public.| — schema-qualified table in DROPDROP TABLE IF EXISTS | — table completion after IF EXISTSDROP VIEW | — view completion in DROP VIEWDROP VIEW public.| — schema-qualified view in DROP VIEWDROP INDEX | — index completion in DROP INDEXDROP SEQUENCE | — sequence completion in DROP SEQUENCEDROP MATERIALIZED VIEW | — materialized view in DROPTRUNCATE | — table completion in TRUNCATETRUNCATE public.| — schema-qualified table in TRUNCATECOMMENT ON TABLE | — table completion in COMMENT ONCOMMENT ON TABLE public.| — schema-qualified table in COMMENT ONCOMMENT ON COLUMN t1.| — column completion in COMMENT ON COLUMNCOMMENT ON COLUMN public.t1.| — schema-qualified column in COMMENT ON COLUMNGRANT SELECT ON | — table completion in GRANTGRANT SELECT ON public.| — schema-qualified table in GRANTGRANT ALL ON ALL TABLES IN SCHEMA | — schema completion in GRANTREVOKE SELECT ON | — table completion in REVOKEREVOKE SELECT ON public.| — schema-qualified table in REVOKEGRANT USAGE ON SEQUENCE | — sequence completion in GRANTComplex query structures and nesting. Independent of Phase 2. Sections 3.1 and 3.2 may need completion.go scope-tracking changes.
WITH RECURSIVE x AS (SELECT c1 FROM t1 UNION ALL SELECT | FROM x JOIN t1 ON x.c1 = t1.c1) SELECT * FROM x — completion in recursive branch (only t1 columns resolve; recursive self-reference x does not contribute its own columns)WITH RECURSIVE x AS (SELECT c1 FROM t1 UNION ALL SELECT x.| FROM x JOIN t1 ON x.c1 = t1.c1) SELECT * FROM x — qualified columns from recursive CTE reference (no candidates returned; recursive self-reference columns not resolvable)WITH x AS (SELECT * FROM t2) INSERT INTO t1 SELECT | FROM x — CTE used in INSERT...SELECTWITH x AS (SELECT c1, c2 FROM t2) UPDATE t1 SET c1 = (SELECT | FROM x) — CTE in UPDATE scalar subqueryWITH x AS (SELECT * FROM t2) DELETE FROM t1 WHERE c1 IN (SELECT | FROM x) — CTE in DELETE subqueryWITH a AS (SELECT c1 FROM t1), b AS (SELECT * FROM a) SELECT | FROM b — chained CTEs (CTE referencing another CTE) (b's columns not resolved; query span cannot resolve SELECT * FROM a where a is a CTE)WITH a AS (SELECT c1 FROM t1), b AS (SELECT a.| FROM a) SELECT * FROM b — qualified column in chained CTEWITH x AS (SELECT c1 FROM t1) SELECT | FROM x, t2 — CTE mixed with regular table in FROMWITH x AS (SELECT c1 FROM t1) SELECT x.| FROM x JOIN t2 ON x.c1 = t2.c1 — CTE qualified columns in JOINWITH x(a, b) AS (SELECT c1, c2 FROM t2) SELECT | FROM x JOIN t1 ON x.a = t1.c1 — named CTE columns in JOINSELECT * FROM t1, LATERAL (SELECT | FROM t2 WHERE t2.c1 = t1.c1) sub — LATERAL subquery referencing outer tableSELECT sub.| FROM t1, LATERAL (SELECT c1, c2 FROM t2 WHERE t2.c1 = t1.c1) sub — columns from LATERAL subquery aliasSELECT | FROM t1 LEFT JOIN LATERAL (SELECT * FROM t2 WHERE t2.c1 = t1.c1) sub ON true — LATERAL with LEFT JOINSELECT * FROM t1, LATERAL (SELECT t1.| FROM t2) sub — outer table column access in LATERALSELECT * FROM t2 x, LATERAL (SELECT x.| FROM t1) sub — alias-qualified outer reference in LATERALSELECT | FROM generate_series(1, 10) g — table function in FROM clauseSELECT g.| FROM generate_series(1, 10) g — qualified column from table function alias (no candidates returned; table functions have no column metadata in the completion engine)SELECT | FROM t1, generate_series(1, 10) g — table function with regular tableSELECT | FROM t2 x, LATERAL (SELECT * FROM t1 WHERE t1.c1 = x.c1) sub — complex LATERAL with aliasSELECT (SELECT | FROM t1) FROM t2 — scalar subquery in SELECT listSELECT (SELECT t1.| FROM t1) FROM t2 — qualified column in scalar subquerySELECT * FROM t1 WHERE c1 = ANY(SELECT | FROM t2) — ANY subquerySELECT * FROM t1 WHERE c1 = ALL(SELECT | FROM t2) — ALL subquerySELECT * FROM t1 WHERE c1 > (SELECT MAX(|) FROM t2) — aggregate in scalar subquerySELECT * FROM (SELECT * FROM (SELECT | FROM t1) a) b — triple-nested subquerySELECT b.| FROM (SELECT * FROM (SELECT c1 FROM t1) a) b — qualified column from triple-nestedSELECT * FROM t1 WHERE EXISTS (SELECT 1 FROM t2 WHERE t2.c1 = t1.|) — correlated subquery referencing outer columnSELECT | FROM (SELECT c1, c2 FROM t2 UNION SELECT c1, c2 FROM t2) sub — subquery with UNIONSELECT sub.| FROM (SELECT c1, c2 FROM t2 UNION SELECT c1, c2 FROM t2) sub — qualified columns from UNION subquerySELECT c1 FROM t1 INTERSECT SELECT | FROM t2 — SELECT list in INTERSECTSELECT c1 FROM t1 EXCEPT SELECT | FROM t2 — SELECT list in EXCEPTSELECT c1 FROM t1 UNION SELECT c1 FROM t1 UNION SELECT | FROM t2 — triple UNION(SELECT c1 FROM t1) UNION (SELECT | FROM t2) — parenthesized set operationSELECT c1 FROM t1 UNION ALL SELECT c1 FROM t2 ORDER BY | — ORDER BY on UNION resultSELECT * FROM (SELECT c1 FROM t1 UNION SELECT c1 FROM t2) x WHERE x.| — WHERE on UNION subqueryWITH x AS (SELECT c1 FROM t1 UNION SELECT c1 FROM t2) SELECT x.| FROM x — CTE with UNION bodySELECT c1 FROM t1 EXCEPT ALL SELECT | FROM t2 — EXCEPT ALL variantSELECT c1 FROM t1 INTERSECT ALL SELECT | FROM t2 — INTERSECT ALL variantSELECT | FROM t2 UNION SELECT * FROM t1 — first branch of UNIONIdentifier handling, error recovery, and special scenarios.
SELECT | FROM "t1" — quoted table name in FROM (should resolve t1 columns)SELECT "t1".| FROM t1 — quoted table qualifierSELECT * FROM "public".| — quoted schema nameSELECT * FROM | with table named using reserved keyword (metadata has table named "order") — reserved keyword table appears quotedSELECT | FROM "order" — columns from reserved-keyword-named tableSELECT "order".| FROM "order" — qualified columns from reserved-keyword tableSELECT * FROM | with mixed-case table name (metadata has "MyTable") — mixed-case name appears quotedSELECT | FROM "MyTable" — columns from mixed-case tableSELECT * FROM | with table containing special chars (metadata has "my-table") — special char name appears quotedSELECT * FROM public."t1" WHERE | — columns after quoted schema-qualified tableSELECT * FROM t| — partial table name prefix "t" matches t1, t2SELECT * FROM public.t| — partial schema-qualified prefixSELECT t1.c| — partial column name prefixSELECT * FROM test.a| — partial prefix in non-default schemaSELECT * FROM tes| — partial schema name prefixSELECT * FROM t1 WHERE t1.c| — partial column in WHEREINSERT INTO t| — partial table name in INSERTUPDATE t| — partial table name in UPDATEDELETE FROM t| — partial table name in DELETESELECT * FROM t1 JOIN t| — partial table name in JOINSELECT 1; INSERT INTO | — completion in second statement (INSERT)SELECT 1; UPDATE | — completion in second statement (UPDATE)SELECT 1; DELETE FROM | — completion in second statement (DELETE)INVALID SQL; SELECT * FROM | — recovery after invalid first statementSELECT * FROM t1; SELECT * FROM t2 WHERE | — columns from correct table in second statementSELECT; SELECT | FROM t1 — recovery after incomplete SELECTSELECT * FROM t1 WHERE; SELECT | FROM t2 — recovery after incomplete WHERECREATE TABLE x (id int); SELECT | FROM t1 — DDL then DML multi-statementSELECT\n |\nFROM t1 — completion works across line breaksSELECT *\nFROM\n | — FROM on separate lineSELECT\t|\tFROM t1 — tab characters in SQLSELECT * FROM | — multiple spaces between tokensSELECT * FROM t1 WHERE | — space after cursorSELECT * FROM /* comment */ | — completion after block commentSELECT * FROM t1 -- comment\nWHERE | — completion after line comment