Consult PostgreSQL's parser and grammar (gram.y) to understand SQL syntax, DDL statement structure, and parsing rules when implementing pgschema features. Use this skill when generating DDL in internal/diff/*.go, validating SQL syntax, understanding keyword precedence, or learning how PostgreSQL handles specific constructs like triggers, indexes, generated columns, or constraint triggers.
Reference PostgreSQL's grammar to understand SQL syntax and generate correct DDL.
Local copies (preferred):
internal/gram.y - Yacc/Bison grammar defining all PostgreSQL SQL syntaxinternal/scan.l - Flex lexer for tokenizationSearching the grammar:
grep -n "CreateTrigStmt:" internal/gram.y # Find statement rule
grep -A 10 "TriggerWhen:" internal/gram.y # Understand an option
| Statement | Grammar Rule | Key Sub-rules |
|---|---|---|
| CREATE TABLE |
CreateStmtcolumnDef, TableConstraint, TableLikeClause |
| ALTER TABLE | AlterTableStmt | alter_table_cmd |
| CREATE INDEX | IndexStmt | index_elem (column, function, expression) |
| CREATE TRIGGER | CreateTrigStmt | TriggerActionTime, TriggerEvents, TriggerWhen |
| CREATE FUNCTION | CreateFunctionStmt | func_args, createfunc_opt_list |
| CREATE VIEW | ViewStmt | SelectStmt |
| CREATE SEQUENCE | CreateSeqStmt | OptSeqOptList |
| CREATE TYPE | CreateEnumStmt, CompositeTypeStmt, CreateDomainStmt |
| CREATE POLICY | CreatePolicyStmt | row_security_cmd |
gram.y uses Yacc/Bison notation:
CREATE, TRIGGER)|: Alternative syntax optionsopt_*: Optional elements (can be empty)*_list: Recursive list constructsExample:
CreateTrigStmt:
CREATE opt_or_replace TRIGGER name TriggerActionTime TriggerEvents ON
qualified_name TriggerReferencing TriggerForSpec TriggerWhen
EXECUTE FUNCTION_or_PROCEDURE func_name '(' TriggerFuncArgs ')'
column_name type [constraints]column_name type GENERATED ALWAYS AS (expr) STOREDcolumn_name type GENERATED {ALWAYS|BY DEFAULT} AS IDENTITYThree forms — note extra parens for arbitrary expressions:
CREATE INDEX idx ON t (col)CREATE INDEX idx ON t (lower(col))CREATE INDEX idx ON t ((col + 1))TriggerWhen:
WHEN '(' a_expr ')'
| /* EMPTY */
CREATE opt_or_replace CONSTRAINT TRIGGER name ...
-- Can be DEFERRABLE / NOT DEFERRABLE
-- Can be INITIALLY DEFERRED / INITIALLY IMMEDIATE
LIKE qualified_name [INCLUDING|EXCLUDING] {COMMENTS|CONSTRAINTS|DEFAULTS|IDENTITY|GENERATED|INDEXES|STATISTICS|STORAGE|ALL}
%left OR
%left AND
%right NOT
%nonassoc IS ISNULL NOTNULL
%nonassoc '<' '>' '=' LESS_EQUALS GREATER_EQUALS NOT_EQUALS
SELECT, TABLE, CREATE)ABORT, ACCESS, ACTION)When generating DDL, quote identifiers that match reserved keywords.
COMPRESSION clause for tablesUNIQUE NULLS NOT DISTINCTMERGE enhancementsCheck gram.y git history to see when features were added. Add version detection in pgschema if needed.
When generating DDL in internal/diff/*.go:
ir/quote.go