Skip to content

Commit 7321908

Browse files
ajitpratap0Ajit Pratap Singhclaude
authored
feat(dialect): add MariaDB SQL dialect with SEQUENCE, temporal tables, and CONNECT BY (#431)
* fix(playground): move useState/useCallback above early returns to fix React error #310 useState(copied) and useCallback(handleCopy) were declared after the if (loading) and if (error) early returns, violating the Rules of Hooks. When the WASM binary was a 404, the component always hit the error branch so both renders exited with the same hook count. After committing the WASM binary (#423), the component now successfully transitions loading→ready, causing React to see 11 hooks instead of 9 on the second render → #310. Fix: move both hooks above all conditional returns. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(dialect): add DialectMariaDB constant to keyword dialect system * fix(dialect): return MYSQL_SPECIFIC for DialectMariaDB and add to validDialects test * fix(dialect): wire DialectMariaDB into keywords.New() to load MYSQL_SPECIFIC keywords * test(dialect): add TestDialectMariaDB_InheritsMySQL to guard MySQL keyword inheritance * feat(dialect): add MARIADB_SPECIFIC keyword list extending MySQL dialect * feat(dialect): add MariaDB auto-detection hints (SEQUENCE, VERSIONING, CONNECT BY) * fix(dialect): remove over-broad START WITH hint and complete DetectDialect doc comment * fix(dialect): restore MariaDB CONNECT BY hint and add accumulation test * feat(ast): add CreateSequenceStatement, DropSequenceStatement, AlterSequenceStatement nodes Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(ast): nil guard in sequence ToSQL, split Restart field, add sequence tests - Guard s.Name nil dereference in CreateSequenceStatement.ToSQL, DropSequenceStatement.ToSQL, and AlterSequenceStatement.ToSQL - Split SequenceOptions.Restart (*LiteralValue) into two fields: Restart bool (bare RESTART) and RestartWith *LiteralValue (RESTART WITH n) - Update writeSequenceOptions to emit bare RESTART or RESTART WITH n accordingly - Add ast_sequence_test.go with full ToSQL table-driven tests and pool round-trip test Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(ast): add ForSystemTimeClause, PeriodDefinition, temporal table fields - Add SystemTimeClauseType enum with AS OF, BETWEEN, FROM/TO, ALL variants - Add ForSystemTimeClause struct for MariaDB FOR SYSTEM_TIME temporal queries - Add PeriodDefinition struct for PERIOD FOR clauses in CREATE TABLE - Extend TableReference with ForSystemTime field (MariaDB 10.3.4+) - Extend CreateTableStatement with WithSystemVersioning and PeriodDefinitions fields - Add ForSystemTimeClause.ToSQL() and tableRefSQL integration in sql.go Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(ast): add SQL() methods to temporal/CONNECT BY types and fix SelectStatement field order Add SQL() methods to ForSystemTimeClause, ConnectByClause, and PeriodDefinition (all implement expressionNode()) so they satisfy the Expression interface fully without silently degrading via the exprSQL() fallback. Move StartWith and ConnectBy fields in SelectStatement to directly follow Having, matching logical SQL clause ordering. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(parser): implement CREATE/DROP/ALTER SEQUENCE parsing for MariaDB dialect Add parseCreateSequenceStatement, parseDropSequenceStatement, and parseAlterSequenceStatement to mariadb.go with full option parsing (START WITH, INCREMENT BY, MINVALUE, MAXVALUE, CYCLE, CACHE, RESTART WITH). Wire dispatch into parseStatement() for DROP/ALTER and into parseCreateStatement() for CREATE. Gate all paths behind isMariaDB() so MySQL and other dialects are unaffected. Add six passing parser tests in mariadb_test.go. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(parser): implement temporal table parsing (FOR SYSTEM_TIME, WITH SYSTEM VERSIONING, PERIOD FOR) Add parseForSystemTimeClause and parseTemporalPointExpression to mariadb.go supporting AS OF, BETWEEN, FROM/TO, and ALL variants. Hook into parseFromTableReference in select_subquery.go (after alias, before SQL Server hints) with a peek-ahead guard so FOR is only consumed when followed by SYSTEM_TIME. Add WITH SYSTEM VERSIONING parsing to parseCreateTable (after closing paren, before PARTITION BY) and PERIOD FOR column parsing to the column loop in ddl.go. Add four passing tests for temporal queries and system versioning in mariadb_test.go. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(parser): implement CONNECT BY hierarchical query parsing for MariaDB dialect Add parseConnectByCondition to mariadb.go which handles the PRIOR prefix operator by wrapping the referenced column in a FunctionCall node and building a BinaryExpression for the full PRIOR col = parent_col pattern. Wire START WITH and CONNECT BY [NOCYCLE] parsing into parseSelectStatement in select.go after the HAVING clause. Guard CONNECT and START from being consumed as table aliases in parseFromTableReference via a peek-ahead check in select_subquery.go. Add three passing tests covering basic, NOCYCLE, and no-START-WITH variants in mariadb_test.go. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(parser): add bare RESTART test and nil guard for CONNECT BY condition * test(parser): add MariaDB SQL test data files and file-based integration test Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs: add MariaDB dialect to SQL_COMPATIBILITY.md and CHANGELOG.md Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(mariadb): address code review issues across AST, keywords, and parser AST layer: - Add `Prior` UnaryOperator constant for CONNECT BY PRIOR expressions - Add `NoCache bool` to SequenceOptions (NOCACHE was previously a silent no-op) - Add `Pos models.Location` to all 6 new MariaDB AST nodes (CreateSequence, DropSequence, AlterSequence, ForSystemTimeClause, ConnectByClause, PeriodDefinition) - Add `NewDropSequenceStatement()` / `ReleaseDropSequenceStatement()` pool funcs to match Create/Alter sequence pooling consistency - Emit NOCACHE in writeSequenceOptions when NoCache=true Keywords: - Remove duplicate MINVALUE, MAXVALUE, INCREMENT, RESTART, NOCACHE entries from MARIADB_SPECIFIC (already covered by base/Oracle keyword lists) Parser: - Fix PRIOR operator: switch from FunctionCall to UnaryExpression{Operator: Prior} - Fix PRIOR on RHS: CONNECT BY col = PRIOR col now parsed correctly - Fix parseJoinedTableRef: add isMariaDBClauseKeyword guard to prevent CONNECT/START from being consumed as table aliases (same guard already in parseFromTableReference) - Fix parseJoinedTableRef: add FOR SYSTEM_TIME temporal clause support on JOIN refs - Fix DROP SEQUENCE: support IF NOT EXISTS in addition to IF EXISTS - Fix DROP SEQUENCE: use NewDropSequenceStatement() for pool consistency - Fix parseSequenceOptions: set opts.NoCache=true for NOCACHE keyword - Add comment in parseTemporalPointExpression explaining quote-stripping behaviour Tests: - Add TestMariaDB_ConnectBy_PriorOnRight - Add TestMariaDB_DropSequence_IfNotExists - Add TestMariaDB_Sequence_NoCache - Expand testdata SQL files with NO MINVALUE/MAXVALUE forms, PRIOR-on-right cases, IF NOT EXISTS on DROP, and multi-table temporal JOIN query Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(mariadb): address second code review pass — Pos, NO CACHE, CONNECT BY, dedup Parser dispatch (parser.go, ddl.go, select.go): - Populate Pos on CreateSequenceStatement (at SEQUENCE token in ddl.go) - Populate Pos on DropSequenceStatement (at DROP token in parser.go) - Populate Pos on AlterSequenceStatement (at ALTER token in parser.go) - Populate Pos on ConnectByClause (at CONNECT token in select.go) - Populate Pos on PeriodDefinition (at PERIOD token in ddl.go) mariadb.go: - Fix NO CACHE (two-token) to also set opts.NoCache=true, matching NOCACHE - Fix parseConnectByCondition to handle complex AND/OR chains: CONNECT BY PRIOR id = parent_id AND active = 1 now fully parsed - Extract isMariaDBClauseStart() method (was duplicated closure in two functions) - Populate Pos on ForSystemTimeClause (at SYSTEM_TIME token) - Add comment clarifying IF NOT EXISTS is a non-standard permissive extension select_subquery.go: - Remove both isMariaDBClauseKeyword closures, replace with p.isMariaDBClauseStart() ast.go: - Update DropSequenceStatement doc to show [IF EXISTS | IF NOT EXISTS] Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(mariadb): correct START WITH/CONNECT BY SQL order and implement PeriodDefinition.SQL() - Move START WITH / CONNECT BY emission to after HAVING, before ORDER BY - Implement PeriodDefinition.SQL() — was silently returning empty string - Add round-trip tests for both fixes Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(mariadb): code review fixes — pool comments, expressionNode docs, PERIOD FOR SYSTEM_TIME test - Add '// zero all fields' comment to ReleaseCreateSequenceStatement and ReleaseAlterSequenceStatement - Add design-choice comments on expressionNode() for ForSystemTimeClause, ConnectByClause, PeriodDefinition - Add TestMariaDB_CreateTable_PeriodForSystemTime to cover PERIOD FOR SYSTEM_TIME parsing - Fix parsePeriodDefinition to use parseColumnName so SYSTEM_TIME (reserved keyword) is accepted as period name - Add GENERATED ALWAYS AS ROW START/END column constraint parsing in parseColumnConstraint (MariaDB system-versioned columns) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(dialect): reduce MariaDB CONNECT BY hint weight to 2 so Oracle wins pure CONNECT BY queries Oracle's CONNECT BY weight is 3; MariaDB's was also 3, causing a tie broken by non-deterministic map iteration. Reducing MariaDB to weight 2 ensures Oracle wins when CONNECT BY is the only hint. MariaDB is still correctly detected when its unique high-weight hints (NEXTVAL, FOR SYSTEM_TIME, etc.) are present. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(mariadb): address code review — CycleOption enum, CACHE validation, structured errors - Replace Cycle bool + NoCycle bool with CycleOption enum to prevent invalid state where both could be true simultaneously - Add validation in parseSequenceOptions for contradictory CACHE/NOCACHE - Replace fmt.Errorf with p.expectedError() for consistent error style Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * bench(mariadb): add MariaDB-specific parsing benchmarks 17 benchmarks across 4 groups: - BenchmarkMariaDB_Sequence: CREATE/ALTER/DROP SEQUENCE (5 cases) - BenchmarkMariaDB_ForSystemTime: temporal table queries (5 cases) - BenchmarkMariaDB_ConnectBy: hierarchical queries with PRIOR (4 cases) - BenchmarkMariaDB_Mixed: combined features — CTE+temporal, CTE+CONNECT BY, CREATE TABLE WITH SYSTEM VERSIONING (3 cases) Baseline (M2): 398–3001 ns/op, 984–6763 B/op --------- Co-authored-by: Ajit Pratap Singh <ajitpratapsingh@Ajits-Mac-mini-2655.local> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent cec5acc commit 7321908

26 files changed

Lines changed: 2225 additions & 16 deletions

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
- **MariaDB dialect** (`--dialect mariadb`): New SQL dialect extending MySQL with support for SEQUENCE DDL (`CREATE/DROP/ALTER SEQUENCE` with full option set), temporal tables (`FOR SYSTEM_TIME`, `WITH SYSTEM VERSIONING`, `PERIOD FOR`), and `CONNECT BY` hierarchical queries with `PRIOR`, `START WITH`, and `NOCYCLE`
12+
1013
## [1.13.0] - 2026-03-20
1114

1215
### Added

docs/SQL_COMPATIBILITY.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,27 @@ This matrix documents the comprehensive SQL feature support in GoSQLX across dif
317317
| **AUTO_INCREMENT** | ✅ Full | ✅ Full | 95% | Column property |
318318
| **Backtick identifiers** | ✅ Full | ✅ Full | 100% | `` `table`.`column` `` syntax |
319319

320+
### MariaDB-Specific Features (v1.14.0+)
321+
322+
MariaDB inherits all MySQL features (SHOW, DESCRIBE, REPLACE INTO, ON DUPLICATE KEY UPDATE, GROUP_CONCAT, MATCH/AGAINST, REGEXP/RLIKE, backtick identifiers, etc.) and adds the following extensions:
323+
324+
| Feature | Support Level | GoSQLX Parser | Test Coverage | Notes |
325+
|---------|---------------|---------------|---------------|-------|
326+
| **CREATE SEQUENCE** | ✅ Full | ✅ Full | 95% | Full DDL with all sequence options |
327+
| **DROP SEQUENCE** | ✅ Full | ✅ Full | 95% | DROP SEQUENCE [IF EXISTS] |
328+
| **ALTER SEQUENCE** | ✅ Full | ✅ Full | 90% | RESTART, RESTART WITH, and all options |
329+
| **Sequence options** | ✅ Full | ✅ Full | 95% | START WITH, INCREMENT BY, MINVALUE, MAXVALUE, CACHE, CYCLE, NOCACHE, NOCYCLE, RESTART, RESTART WITH |
330+
| **FOR SYSTEM_TIME AS OF** | ✅ Full | ✅ Full | 95% | Point-in-time query on system-versioned tables |
331+
| **FOR SYSTEM_TIME BETWEEN** | ✅ Full | ✅ Full | 95% | Range query on system-versioned tables |
332+
| **FOR SYSTEM_TIME FROM/TO** | ✅ Full | ✅ Full | 95% | Range query (inclusive/exclusive) |
333+
| **FOR SYSTEM_TIME ALL** | ✅ Full | ✅ Full | 95% | All rows including historical |
334+
| **WITH SYSTEM VERSIONING** | ✅ Full | ✅ Full | 90% | CREATE TABLE ... WITH SYSTEM VERSIONING |
335+
| **PERIOD FOR** | ✅ Full | ✅ Full | 85% | Application-time period definitions |
336+
| **CONNECT BY** | ✅ Full | ✅ Full | 90% | Hierarchical queries with PRIOR and NOCYCLE |
337+
| **START WITH (CONNECT BY)** | ✅ Full | ✅ Full | 90% | Root condition for hierarchical traversal |
338+
| **PRIOR operator** | ✅ Full | ✅ Full | 90% | Reference parent row in CONNECT BY |
339+
| **NOCYCLE** | ✅ Full | ✅ Full | 85% | Prevent infinite loops in cyclic graphs |
340+
320341
### SQL Server-Specific Features
321342

322343
| Feature | Support Level | GoSQLX Parser | Test Coverage | Notes |
@@ -549,6 +570,7 @@ GoSQLX v1.8.0 introduces a first-class dialect mode engine that threads the SQL
549570
| **SQLite** | `"sqlite"` | SQLite keywords | Flexible typing, simplified syntax | ⚠️ Keywords + basic parsing |
550571
| **Snowflake** | `"snowflake"` | Snowflake keywords | Stage operations, VARIANT type | ⚠️ Keyword detection only |
551572
| **ClickHouse** | `"clickhouse"` | ClickHouse keywords | PREWHERE, FINAL, GLOBAL IN/NOT IN, MergeTree keywords | ✅ v1.13.0 |
573+
| **MariaDB** | `"mariadb"` | MariaDB keywords (superset of MySQL) | All MySQL features + SEQUENCE DDL, FOR SYSTEM_TIME, WITH SYSTEM VERSIONING, PERIOD FOR, CONNECT BY | ✅ v1.14.0 |
552574

553575
### Usage
554576

@@ -597,6 +619,12 @@ gosqlx format --dialect mysql query.sql
597619
- No Snowflake-specific parsing (stages, COPY INTO, VARIANT operations)
598620
- QUALIFY clause not supported
599621

622+
#### MariaDB
623+
- Inherits all MySQL known gaps (stored procedures, HANDLER, XA transactions, CREATE EVENT)
624+
- JSON_TABLE not supported
625+
- Spider storage engine syntax not parsed
626+
- ColumnStore-specific syntax not supported
627+
600628
#### ClickHouse
601629
- PREWHERE clause for pre-filter optimization before primary key scan
602630
- FINAL modifier on table references (forces MergeTree part merge)
@@ -644,6 +672,7 @@ gosqlx format --dialect mysql query.sql
644672
| **SQL Server** | 85% | 65% | ⭐⭐⭐⭐ Very Good | Keywords + MERGE |
645673
| **Oracle** | 80% | 60% | ⭐⭐⭐⭐ Good | Keywords + basic features |
646674
| **SQLite** | 85% | 50% | ⭐⭐⭐⭐ Good | Keywords + basic features |
675+
| **MariaDB** | 95% | 90% | ⭐⭐⭐⭐⭐ Excellent | MySQL superset + SEQUENCE DDL, temporal tables, CONNECT BY (v1.14.0) |
647676
| **Snowflake** | 80% | 30% | ⭐⭐⭐ Good | Keyword detection only |
648677

649678
## Performance Characteristics by Feature

pkg/sql/ast/ast.go

Lines changed: 214 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,9 @@ type TableReference struct {
228228
Lateral bool // LATERAL keyword for correlated subqueries (PostgreSQL)
229229
TableHints []string // SQL Server table hints: WITH (NOLOCK), WITH (ROWLOCK, UPDLOCK), etc.
230230
Final bool // ClickHouse FINAL modifier: forces MergeTree part merge
231+
// ForSystemTime is the MariaDB temporal table clause (10.3.4+).
232+
// Example: SELECT * FROM t FOR SYSTEM_TIME AS OF '2024-01-01'
233+
ForSystemTime *ForSystemTimeClause // MariaDB temporal query
231234
}
232235

233236
func (t *TableReference) statementNode() {}
@@ -397,13 +400,19 @@ type SelectStatement struct {
397400
Where Expression
398401
GroupBy []Expression
399402
Having Expression
400-
Windows []WindowSpec
401-
OrderBy []OrderByExpression
402-
Limit *int
403-
Offset *int
404-
Fetch *FetchClause // SQL-99 FETCH FIRST/NEXT clause (F861, F862)
405-
For *ForClause // Row-level locking clause (SQL:2003, PostgreSQL, MySQL)
406-
Pos models.Location // Source position of the SELECT keyword (1-based line and column)
403+
// StartWith is the optional seed condition for CONNECT BY (MariaDB 10.2+).
404+
// Example: START WITH parent_id IS NULL
405+
StartWith Expression // MariaDB hierarchical query seed
406+
// ConnectBy holds the hierarchy traversal condition (MariaDB 10.2+).
407+
// Example: CONNECT BY PRIOR id = parent_id
408+
ConnectBy *ConnectByClause // MariaDB hierarchical query
409+
Windows []WindowSpec
410+
OrderBy []OrderByExpression
411+
Limit *int
412+
Offset *int
413+
Fetch *FetchClause // SQL-99 FETCH FIRST/NEXT clause (F861, F862)
414+
For *ForClause // Row-level locking clause (SQL:2003, PostgreSQL, MySQL)
415+
Pos models.Location // Source position of the SELECT keyword (1-based line and column)
407416
}
408417

409418
// TopClause represents SQL Server's TOP N [PERCENT] clause
@@ -518,6 +527,12 @@ func (s SelectStatement) Children() []Node {
518527
if s.For != nil {
519528
children = append(children, s.For)
520529
}
530+
if s.StartWith != nil {
531+
children = append(children, s.StartWith)
532+
}
533+
if s.ConnectBy != nil {
534+
children = append(children, s.ConnectBy)
535+
}
521536
return children
522537
}
523538

@@ -1275,6 +1290,14 @@ type CreateTableStatement struct {
12751290
Partitions []PartitionDefinition // Individual partition definitions
12761291
Options []TableOption
12771292
WithoutRowID bool // SQLite: CREATE TABLE ... WITHOUT ROWID
1293+
1294+
// WithSystemVersioning enables system-versioned temporal history (MariaDB 10.3.4+).
1295+
// Example: CREATE TABLE t (...) WITH SYSTEM VERSIONING
1296+
WithSystemVersioning bool
1297+
1298+
// PeriodDefinitions holds PERIOD FOR clauses for application-time or system-time periods.
1299+
// Example: PERIOD FOR app_time (start_col, end_col)
1300+
PeriodDefinitions []*PeriodDefinition
12781301
}
12791302

12801303
func (c *CreateTableStatement) statementNode() {}
@@ -1815,3 +1838,187 @@ func (r ReplaceStatement) Children() []Node {
18151838
}
18161839
return children
18171840
}
1841+
1842+
// ── MariaDB SEQUENCE DDL (10.3+) ───────────────────────────────────────────
1843+
1844+
// CycleOption represents the CYCLE behavior for a sequence.
1845+
type CycleOption int
1846+
1847+
const (
1848+
// CycleUnspecified means no CYCLE or NOCYCLE clause was given (database default applies).
1849+
CycleUnspecified CycleOption = iota
1850+
// CycleBehavior means CYCLE — sequence wraps around when it reaches min/max.
1851+
CycleBehavior
1852+
// NoCycleBehavior means NOCYCLE / NO CYCLE — sequence errors on overflow.
1853+
NoCycleBehavior
1854+
)
1855+
1856+
// SequenceOptions holds configuration for CREATE SEQUENCE and ALTER SEQUENCE.
1857+
// Fields are pointers so that unspecified options are distinguishable from zero values.
1858+
type SequenceOptions struct {
1859+
StartWith *LiteralValue // START WITH n
1860+
IncrementBy *LiteralValue // INCREMENT BY n (default 1)
1861+
MinValue *LiteralValue // MINVALUE n or nil when NO MINVALUE
1862+
MaxValue *LiteralValue // MAXVALUE n or nil when NO MAXVALUE
1863+
Cache *LiteralValue // CACHE n or nil when NO CACHE / NOCACHE
1864+
CycleMode CycleOption // CYCLE / NOCYCLE / NO CYCLE (CycleUnspecified if not specified)
1865+
NoCache bool // NOCACHE (explicit; Cache=nil alone is ambiguous)
1866+
Restart bool // bare RESTART (reset to start value)
1867+
RestartWith *LiteralValue // RESTART WITH n (explicit restart value)
1868+
}
1869+
1870+
// CreateSequenceStatement represents:
1871+
//
1872+
// CREATE [OR REPLACE] SEQUENCE [IF NOT EXISTS] name [options...]
1873+
type CreateSequenceStatement struct {
1874+
Name *Identifier
1875+
OrReplace bool
1876+
IfNotExists bool
1877+
Options SequenceOptions
1878+
Pos models.Location // Source position of the CREATE keyword (1-based line and column)
1879+
}
1880+
1881+
func (s *CreateSequenceStatement) statementNode() {}
1882+
func (s *CreateSequenceStatement) TokenLiteral() string { return "CREATE" }
1883+
func (s *CreateSequenceStatement) Children() []Node {
1884+
if s.Name != nil {
1885+
return []Node{s.Name}
1886+
}
1887+
return nil
1888+
}
1889+
1890+
// DropSequenceStatement represents:
1891+
//
1892+
// DROP SEQUENCE [IF EXISTS | IF NOT EXISTS] name
1893+
type DropSequenceStatement struct {
1894+
Name *Identifier
1895+
IfExists bool
1896+
Pos models.Location // Source position of the DROP keyword (1-based line and column)
1897+
}
1898+
1899+
func (s *DropSequenceStatement) statementNode() {}
1900+
func (s *DropSequenceStatement) TokenLiteral() string { return "DROP" }
1901+
func (s *DropSequenceStatement) Children() []Node {
1902+
if s.Name != nil {
1903+
return []Node{s.Name}
1904+
}
1905+
return nil
1906+
}
1907+
1908+
// AlterSequenceStatement represents:
1909+
//
1910+
// ALTER SEQUENCE [IF EXISTS] name [options...]
1911+
type AlterSequenceStatement struct {
1912+
Name *Identifier
1913+
IfExists bool
1914+
Options SequenceOptions
1915+
Pos models.Location // Source position of the ALTER keyword (1-based line and column)
1916+
}
1917+
1918+
func (s *AlterSequenceStatement) statementNode() {}
1919+
func (s *AlterSequenceStatement) TokenLiteral() string { return "ALTER" }
1920+
func (s *AlterSequenceStatement) Children() []Node {
1921+
if s.Name != nil {
1922+
return []Node{s.Name}
1923+
}
1924+
return nil
1925+
}
1926+
1927+
// ── MariaDB Temporal Table Types (10.3.4+) ────────────────────────────────
1928+
1929+
// SystemTimeClauseType identifies the kind of FOR SYSTEM_TIME clause.
1930+
type SystemTimeClauseType int
1931+
1932+
const (
1933+
SystemTimeAsOf SystemTimeClauseType = iota // FOR SYSTEM_TIME AS OF <point>
1934+
SystemTimeBetween // FOR SYSTEM_TIME BETWEEN <start> AND <end>
1935+
SystemTimeFromTo // FOR SYSTEM_TIME FROM <start> TO <end>
1936+
SystemTimeAll // FOR SYSTEM_TIME ALL
1937+
)
1938+
1939+
// ForSystemTimeClause represents a temporal query on a system-versioned table.
1940+
//
1941+
// SELECT * FROM t FOR SYSTEM_TIME AS OF TIMESTAMP '2024-01-01';
1942+
// SELECT * FROM t FOR SYSTEM_TIME BETWEEN '2020-01-01' AND '2024-01-01';
1943+
// SELECT * FROM t FOR SYSTEM_TIME ALL;
1944+
type ForSystemTimeClause struct {
1945+
Type SystemTimeClauseType
1946+
Point Expression // used for AS OF
1947+
Start Expression // used for BETWEEN, FROM
1948+
End Expression // used for BETWEEN (AND), TO
1949+
Pos models.Location // Source position of the FOR keyword (1-based line and column)
1950+
}
1951+
1952+
// expressionNode satisfies the Expression interface so ForSystemTimeClause can be
1953+
// stored in TableReference.ForSystemTime without a separate interface type.
1954+
// Semantically it is a table-level clause, not a scalar expression.
1955+
func (c *ForSystemTimeClause) expressionNode() {}
1956+
func (c ForSystemTimeClause) TokenLiteral() string { return "FOR SYSTEM_TIME" }
1957+
func (c ForSystemTimeClause) Children() []Node {
1958+
var nodes []Node
1959+
if c.Point != nil {
1960+
nodes = append(nodes, c.Point)
1961+
}
1962+
if c.Start != nil {
1963+
nodes = append(nodes, c.Start)
1964+
}
1965+
if c.End != nil {
1966+
nodes = append(nodes, c.End)
1967+
}
1968+
return nodes
1969+
}
1970+
1971+
// PeriodDefinition represents a PERIOD FOR clause in CREATE TABLE.
1972+
//
1973+
// PERIOD FOR app_time (start_col, end_col)
1974+
// PERIOD FOR SYSTEM_TIME (row_start, row_end)
1975+
type PeriodDefinition struct {
1976+
Name *Identifier // period name (e.g., "app_time") or SYSTEM_TIME
1977+
StartCol *Identifier
1978+
EndCol *Identifier
1979+
Pos models.Location // Source position of the PERIOD FOR keyword (1-based line and column)
1980+
}
1981+
1982+
// expressionNode satisfies the Expression interface so PeriodDefinition can be
1983+
// stored in CreateTableStatement.PeriodDefinitions without a separate interface type.
1984+
// Semantically it is a table column constraint, not a scalar expression.
1985+
func (p *PeriodDefinition) expressionNode() {}
1986+
func (p PeriodDefinition) TokenLiteral() string { return "PERIOD FOR" }
1987+
func (p PeriodDefinition) Children() []Node {
1988+
var nodes []Node
1989+
if p.Name != nil {
1990+
nodes = append(nodes, p.Name)
1991+
}
1992+
if p.StartCol != nil {
1993+
nodes = append(nodes, p.StartCol)
1994+
}
1995+
if p.EndCol != nil {
1996+
nodes = append(nodes, p.EndCol)
1997+
}
1998+
return nodes
1999+
}
2000+
2001+
// ── MariaDB Hierarchical Query / CONNECT BY (10.2+) ───────────────────────
2002+
2003+
// ConnectByClause represents the CONNECT BY hierarchical query clause (MariaDB 10.2+).
2004+
//
2005+
// SELECT id, name FROM t
2006+
// START WITH parent_id IS NULL
2007+
// CONNECT BY NOCYCLE PRIOR id = parent_id;
2008+
type ConnectByClause struct {
2009+
NoCycle bool // NOCYCLE modifier — prevents loops in cyclic graphs
2010+
Condition Expression // the PRIOR expression (e.g., PRIOR id = parent_id)
2011+
Pos models.Location // Source position of the CONNECT BY keyword (1-based line and column)
2012+
}
2013+
2014+
// expressionNode satisfies the Expression interface so ConnectByClause can be
2015+
// stored in SelectStatement.ConnectBy without a separate interface type.
2016+
// Semantically it is a query-level clause, not a scalar expression.
2017+
func (c *ConnectByClause) expressionNode() {}
2018+
func (c ConnectByClause) TokenLiteral() string { return "CONNECT BY" }
2019+
func (c ConnectByClause) Children() []Node {
2020+
if c.Condition != nil {
2021+
return []Node{c.Condition}
2022+
}
2023+
return nil
2024+
}

0 commit comments

Comments
 (0)