HORIZON HASKELLDocslts/ghc-9.10.xc74966e2026-09-27Search names, modules, packages, or :: a typeCtrl K

GHC 9.10.3 · lts/ghc-9.10.x · c74966e · 2026-09-27

Modulepostgresql-syntax-0.4.1.1Haskell2010

PostgresqlSyntax.Parsing

Our parsing strategy is to port the original Postgres parser as closely as possible.

We're using the gram.y Postgres source file, which is the closest thing we have to a Postgres syntax spec. Here's a link to it: https://github.com/postgres/postgres/blob/master/src/backend/parser/gram.y.

Here's the essence of how the original parser is implemented, citing from PostgreSQL Wiki:

scan.l defines the lexer, i.e. the algorithm that splits a string (containing an SQL statement) into a stream of tokens. A token is usually a single word (i.e., doesn't contain spaces but is delimited by spaces), but can also be a whole single or double-quoted string for example. The lexer is basically defined in terms of regular expressions which describe the different token types.

gram.y defines the grammar (the syntactical structure) of SQL statements, using the tokens generated by the lexer as basic building blocks. The grammar is defined in BNF notation. BNF resembles regular expressions but works on the level of tokens, not characters. Also, patterns (called rules or productions in BNF) are named, and may be recursive, i.e. use themselves as sub-patterns.

  • 1 type
  • 211 values
Example1 expression
testParser parser = either putStr print . run parser

Executors

1 declaration

Helpers

11 declarations

PreparableStmt

1 declaration

Call

1 declaration

Insert

10 declarations

Update

5 declarations

Delete

2 declarations

Select

19 declarations
Example1 expression
test = testParser selectStmt
Example1 expression
test "select id from as"...  |1 | select id from as  |                  ^Reserved keyword "as" used as an identifier. If that's what you intend, you have to wrap it in double quotes.

The one that doesn't start with "WITH".

References
  | simple_select
  | select_clause sort_clause
  | select_clause opt_sort_clause for_locking_clause opt_select_limit
  | select_clause opt_sort_clause select_limit opt_for_locking_clause
Example1 expression
testParser targetEl "a.b as c"AliasedExprTargetEl (CExprAExpr (ColumnrefCExpr (Columnref (UnquotedIdent "a") (Just (AttrNameIndirectionEl (UnquotedIdent "b") :| []))))) (UnquotedIdent "c")

Into clause details

1 declaration
References
OptTempTableName:
  | TEMPORARY opt_table qualified_name
  | TEMP opt_table qualified_name
  | LOCAL TEMPORARY opt_table qualified_name
  | LOCAL TEMP opt_table qualified_name
  | GLOBAL TEMPORARY opt_table qualified_name
  | GLOBAL TEMP opt_table qualified_name
  | UNLOGGED opt_table qualified_name
  | TABLE qualified_name
  | qualified_name

Group by details

1 declaration

Window clause details

8 declarations
References
opt_frame_clause:
  |  RANGE frame_extent opt_window_exclusion_clause
  |  ROWS frame_extent opt_window_exclusion_clause
  |  GROUPS frame_extent opt_window_exclusion_clause
  |  EMPTY

Table refs

24 declarations

Where

2 declarations

Sorting

2 declarations

Expressions

48 declarations
valueaExpr :: Parser AExpr
#

Notice that the tree constructed by this parser does not reflect the precedence order of Postgres. For the purposes of this library it simply doesn't matter, so we're not bothering with that.

Composite on the right:
Example1 expression
testParser aExpr "a = b :: int4"SymbolicBinOpAExpr (CExprAExpr (ColumnrefCExpr (Columnref (UnquotedIdent "a") Nothing))) (MathSymbolicExprBinOp EqualsMathOp) (TypecastAExpr (CExprAExpr (ColumnrefCExpr (Columnref (UnquotedIdent "b") Nothing))) (Typename False (GenericTypeSimpleTypename (GenericType (UnquotedIdent "int4") Nothing Nothing)) False Nothing))
Composite on the left:
Example1 expression
testParser aExpr "a = b :: int4 and c"SymbolicBinOpAExpr (CExprAExpr (ColumnrefCExpr (Columnref (UnquotedIdent "a") Nothing))) (MathSymbolicExprBinOp EqualsMathOp) (AndAExpr (TypecastAExpr (CExprAExpr (ColumnrefCExpr (Columnref (UnquotedIdent "b") Nothing))) (Typename False (GenericTypeSimpleTypename (GenericType (UnquotedIdent "int4") Nothing Nothing)) False Nothing)) (CExprAExpr (ColumnrefCExpr (Columnref (UnquotedIdent "c") Nothing))))

Ops

8 declarations

Constants

15 declarations
Example1 expression
testParser aexprConst "32948023849023"IAexprConst 32948023849023
Example1 expression
testParser aexprConst "'abc''de'"SAexprConst "abc'de"
Example1 expression
testParser aexprConst "23.43234"FAexprConst 23.43234
Example1 expression
testParser aexprConst "32423423.324324872"FAexprConst 3.2423423324324872e7
Example1 expression
testParser aexprConst "NULL"NullAexprConst
References
AexprConst: Iconst
      | FCONST
      | Sconst
      | BCONST
      | XCONST
      | func_name Sconst
      | func_name '(' func_arg_list opt_sort_clause ')' Sconst
      | ConstTypename Sconst
      | ConstInterval Sconst opt_interval
      | ConstInterval '(' Iconst ')' Sconst
      | TRUE_P
      | FALSE_P
      | NULL_P

Clauses

9 declarations
References
limit_clause:
  | LIMIT select_limit_value
  | LIMIT select_limit_value ',' select_offset_value
  | FETCH first_or_next select_fetch_first_value row_or_rows ONLY
  | FETCH first_or_next row_or_rows ONLY

For Locking

4 declarations
References
for_locking_item:
  | for_locking_strength locked_rels_list opt_nowait_or_skip
locked_rels_list:
  | OF qualified_name_list
  | EMPTY
opt_nowait_or_skip:
  | NOWAIT
  | SKIP LOCKED
  | EMPTY

References & Names

25 declarations
References
ident_start   [A-Za-z200-377_]
ident_cont    [A-Za-z200-377_0-9$]
identifier    {ident_start}{ident_cont}*
Example1 expression
testParser qualifiedName "a.b"IndirectedQualifiedName (UnquotedIdent "a") (AttrNameIndirectionEl (UnquotedIdent "b") :| [])
Example1 expression
testParser qualifiedName "a.-"...expecting '*', column label, or white space
References
qualified_name:
  | ColId
  | ColId indirection

Typename

7 declarations

Indexes

7 declarations