Skip to content

Latest commit

 

History

History
116 lines (91 loc) · 3.8 KB

File metadata and controls

116 lines (91 loc) · 3.8 KB

AST Package - Claude Code Guide

This package defines the Abstract Syntax Tree (AST) nodes used by sqlc to represent SQL statements across all supported databases (PostgreSQL, MySQL, SQLite).

Key Concepts

Node Interface

All AST nodes implement the Node interface with:

  • Pos() int - returns the source position
  • Format(buf *TrackedBuffer) - formats the node back to SQL

TrackedBuffer

The TrackedBuffer type (pg_query.go) handles SQL formatting with dialect-specific behavior:

  • astFormat(node Node) - formats any AST node
  • join(list *List, sep string) - joins list items with separator
  • WriteString(s string) - writes raw SQL
  • QuoteIdent(name string) - quotes identifiers (dialect-specific)
  • TypeName(ns, name string) - formats type names (dialect-specific)

Dialect Interface

Dialect-specific formatting is handled via the Dialect interface:

type Dialect interface {
    QuoteIdent(string) string
    TypeName(ns, name string) string
    Param(int) string      // $1 for PostgreSQL, ? for MySQL
    NamedParam(string) string // @name for PostgreSQL, :name for SQLite
    Cast(string) string
}

Adding New AST Nodes

When adding a new AST node type:

  1. Create the node file (e.g., variable_expr.go):
package ast

type VariableExpr struct {
    Name     string
    Location int
}

func (n *VariableExpr) Pos() int {
    return n.Location
}

func (n *VariableExpr) Format(buf *TrackedBuffer) {
    if n == nil {
        return
    }
    buf.WriteString("@")
    buf.WriteString(n.Name)
}
  1. Add to astutils/walk.go - Add a case in the Walk function:
case *ast.VariableExpr:
    // Leaf node - no children to traverse
  1. Add to astutils/rewrite.go - Add a case in the Apply function:
case *ast.VariableExpr:
    // Leaf node - no children to traverse
  1. Update the parser/converter - In the relevant engine (e.g., dolphin/convert.go for MySQL)

Helper Functions for Format Methods

  • set(node Node) bool - returns true if node is non-nil and not an empty List
  • items(list *List) bool - returns true if list has items
  • todo(node) Node - placeholder for unimplemented conversions (returns nil)

Common Node Types

Statements

  • SelectStmt - SELECT queries with FromClause, WhereClause, etc.
  • InsertStmt - INSERT with Relation, Cols, SelectStmt, OnConflictClause
  • UpdateStmt - UPDATE with Relations, TargetList, WhereClause
  • DeleteStmt - DELETE with Relations, FromClause (for JOINs), Targets

Expressions

  • A_Expr - General expression with operator (e.g., a + b, @param)
  • ColumnRef - Column reference with Fields list
  • FuncCall - Function call with Func, Args, aggregation options
  • TypeCast - Type cast with Arg and TypeName
  • ParenExpr - Parenthesized expression
  • VariableExpr - MySQL user variable (e.g., @user_id)

Table References

  • RangeVar - Table reference with schema, name, alias
  • JoinExpr - JOIN with Larg, Rarg, Jointype, Quals/UsingClause

MySQL-Specific Nodes

  • VariableExpr - User variables (@var), distinct from sqlc's @param syntax
  • IntervalExpr - INTERVAL expressions
  • OnDuplicateKeyUpdate - MySQL's ON DUPLICATE KEY UPDATE clause
  • ParenExpr - Explicit parentheses (TiDB parser wraps expressions)

Important Distinctions

MySQL @variable vs sqlc @param

  • MySQL user variables (@user_id) use VariableExpr - preserved as-is in output
  • sqlc named parameters (@param) use A_Expr with @ operator - replaced with ?
  • The named.IsParamSign() function checks for A_Expr with @ operator

Type Modifiers

  • TypeName.Typmods holds type modifiers like varchar(255)
  • For MySQL, only populate Typmods for types where length is user-specified:
    • VARCHAR, CHAR, VARBINARY, BINARY - need length
    • DATETIME, TIMESTAMP, DATE - internal flen should NOT be output