Documentation
¶
Overview ¶
Package statement is a wrapper around the parser with some added functionality.
Index ¶
- Variables
- func ByName[T HasName](slice []T, name string) *T
- func DefaultCollationForCharset(name string) (cs, collation string, ok bool)
- func DiffCreateTables(table, wantCreate, gotCreate string, opts *DiffOptions) (string, error)
- func GetMissingSecondaryIndexes(sourceCreateTable, targetCreateTable, tableName string) (string, error)
- func ModifyColumnIsMetadataOnly(spec *ast.AlterTableSpec) bool
- func RemoveSecondaryIndexes(createStmt string) (string, error)
- func SpecOnlyChangesComment(spec *ast.AlterTableSpec) bool
- type AbstractStatement
- func DeclarativeToImperative(current, desired []table.TableSchema, opts *DiffOptions) ([]*AbstractStatement, error)
- func MustNew(statement string) []*AbstractStatement
- func New(statement string) ([]*AbstractStatement, error)
- func NewWithOptions(statement string, opts Options) ([]*AbstractStatement, error)
- func (a *AbstractStatement) AlgorithmInplaceConsideredSafe() error
- func (a *AbstractStatement) AlterContainsAddUnique() error
- func (a *AbstractStatement) AlterContainsUnsupportedClause() error
- func (a *AbstractStatement) AlterWithRenamedCheckConstraints(renames map[string]string) (string, []string, error)
- func (a *AbstractStatement) AsAlterTable() (*ast.AlterTableStmt, bool)
- func (a *AbstractStatement) CheckConstraintsReferenced() []string
- func (a *AbstractStatement) ColumnRenameMap() map[string]string
- func (a *AbstractStatement) GenericConstraintDrops() []string
- func (a *AbstractStatement) IsAlterTable() bool
- func (a *AbstractStatement) IsCreateTable() bool
- func (a *AbstractStatement) IsDropTable() bool
- func (a *AbstractStatement) IsRenameTable() bool
- func (a *AbstractStatement) ParseCreateTable() (*CreateTable, error)
- func (a *AbstractStatement) TrimAlter() string
- type Classification
- type Column
- type Columns
- type Constraint
- type Constraints
- type CreateTable
- func (ct *CreateTable) Diff(target *CreateTable, opts *DiffOptions) ([]*AbstractStatement, error)
- func (ct *CreateTable) GetColumns() Columns
- func (ct *CreateTable) GetConstraints() Constraints
- func (ct *CreateTable) GetCreateTable() *CreateTable
- func (ct *CreateTable) GetIndexes() Indexes
- func (ct *CreateTable) GetPartition() *PartitionOptions
- func (ct *CreateTable) GetTableName() string
- func (ct *CreateTable) GetTableOptions() map[string]any
- func (ct *CreateTable) ToTableInfo(schemaName string) (*table.TableInfo, error)
- func (ct *CreateTable) ToTableSchema() (table.TableSchema, error)
- type DiffOptions
- type ForeignKeyReference
- type HasName
- type Index
- type IndexColumn
- type Indexes
- type Normalizer
- type Options
- type PartitionDefinition
- type PartitionOptions
- type PartitionValues
- type StatementType
- type SubPartitionDefinition
- type SubPartitionOptions
- type TableOptions
Constants ¶
This section is empty.
Variables ¶
var ( ErrNotSupportedStatement = errors.New("not a supported statement type") ErrNotAlterTable = errors.New("not an ALTER TABLE statement") ErrMultipleSchemas = errors.New("statement attempts to modify tables across multiple schemas") ErrNoStatements = errors.New("could not find any compatible statements to execute") ErrMixMatchMultiStatements = errors.New("when performing atomic schema changes, all statements must be of type ALTER TABLE") ErrUnsafeForInplace = errors.New("statement contains operations that are not safe for INPLACE algorithm") ErrAlterNoSpecs = errors.New("ALTER TABLE does not specify any changes to make") ErrMultipleAlterClauses = errors.New("ALTER contains multiple clauses. Combinations of INSTANT and INPLACE operations cannot be detected safely. Consider executing these as separate ALTER statements") ErrAlterContainsUnique = errors.New("ALTER contains adding a unique index") )
Functions ¶
func ByName ¶
ByName is a generic function that finds an element by name in any slice of types with Name field NOTE: This function assumes that names are unique within the slice! That will be true for "canonical" CREATE TABLE statements as returned by SHOW CREATE TABLE, but may not be true for arbitrary input.
func DefaultCollationForCharset ¶ added in v0.17.0
DefaultCollationForCharset returns the charset and the collation MySQL applies to it when no COLLATE is written, and whether cs names a charset the parser knows. Both are spelled the way EffectiveCharsetCollation spells them, so values from the two can be compared directly — callers that need to supply a default for DDL which declares no charset at all should come through here rather than reading the parser's registry themselves.
func DiffCreateTables ¶ added in v0.17.0
func DiffCreateTables(table, wantCreate, gotCreate string, opts *DiffOptions) (string, error)
DiffCreateTables compares two CREATE TABLE statements and returns a runnable ALTER TABLE statement describing how they differ, or an empty string if they are equivalent under opts.
The comparison is performed by parsing both statements and diffing the structured form via CreateTable.Diff, so it is insensitive to the textual noise two servers can put in SHOW CREATE TABLE output. What is and isn't compared is controlled by opts; with NewDiffOptions the comparison:
- ignores AUTO_INCREMENT counter values (instance-specific noise),
- ignores ENGINE and ROW_FORMAT cosmetic defaults,
- DOES compare column types, nullability, defaults, and per-column / per-table CHARACTER SET and COLLATE,
- DOES compare indexes (including the primary key) and constraints.
"want" is the schema treated as the source of truth; "got" is the schema being validated against it. The returned statement describes the transformation that would turn "got" into "want", which is what makes the message actionable. "table" is the real (logical) table name used to build the runnable "ALTER TABLE <table>" prefix, escaped so identifiers containing backticks remain valid — the two CREATE TABLE statements themselves may name tables on different instances, so their names are normalized away before the diff and never compared.
CreateTable.Diff deliberately splits some reconciliations across more than one ALTER — a partition-type change, or an option-only index change that MySQL would no-op if its DROP and ADD shared a statement. Those are emitted as separate semicolon-separated ALTERs, in order, rather than merged into one (which would produce SQL that silently does the wrong thing).
If opts is nil, NewDiffOptions() defaults are used.
func GetMissingSecondaryIndexes ¶ added in v0.10.1
func GetMissingSecondaryIndexes(sourceCreateTable, targetCreateTable, tableName string) (string, error)
GetMissingSecondaryIndexes compares two CREATE TABLE statements (source and target) and returns an ALTER TABLE statement that adds any missing secondary indexes. Returns an empty string if no indexes need to be added. Considers UNIQUE, FULLTEXT, SPATIAL, and regular INDEX types. PRIMARY KEY is excluded as it's fundamental to table structure.
func ModifyColumnIsMetadataOnly ¶ added in v0.16.0
func ModifyColumnIsMetadataOnly(spec *ast.AlterTableSpec) bool
ModifyColumnIsMetadataOnly returns true if a MODIFY/CHANGE COLUMN spec only changes metadata: a VARCHAR redeclaration that neither reorders the column nor declares NOT NULL. Both of those are accepted by MySQL under ALGORITHM=INPLACE but performed with a full table rebuild.
This is a statement-level judgement: without the current column definition we can't tell a VARCHAR length change from an INT-to-VARCHAR conversion, so a true result means "not provably a rebuild" rather than "provably not".
func RemoveSecondaryIndexes ¶ added in v0.10.1
RemoveSecondaryIndexes takes a CREATE TABLE statement and returns a modified version without secondary indexes (regular INDEX only). PRIMARY KEY, UNIQUE, and FULLTEXT indexes are preserved.
func SpecOnlyChangesComment ¶ added in v0.16.0
func SpecOnlyChangesComment(spec *ast.AlterTableSpec) bool
SpecOnlyChangesComment returns true if every table option in an AlterTableOption spec is a COMMENT change. A table comment change is in-place and metadata-only, but other table options (ENGINE=, ROW_FORMAT=, AUTO_INCREMENT=, ...) can force a table rebuild, so a spec that mixes any of them in is not safe for INPLACE.
Types ¶
type AbstractStatement ¶
type AbstractStatement struct {
Schema string // this will be empty unless the table name is fully qualified (ALTER TABLE test.t1 ...)
Table string // for statements that affect multiple tables (DROP TABLE t1, t2), only the first is set here!
Alter string // may be empty.
Statement string
StmtNode *ast.StmtNode
}
func DeclarativeToImperative ¶ added in v0.11.3
func DeclarativeToImperative(current, desired []table.TableSchema, opts *DiffOptions) ([]*AbstractStatement, error)
DeclarativeToImperative compares current and desired schemas and returns the imperative DDL statements (ALTER, CREATE, DROP) needed to transform current into desired.
This is the core of declarative schema management: given two sets of table definitions, compute the minimal set of changes. It is used by spirit's diff subcommand, strata, and GAP.
The returned statements are ordered as CREATE → ALTER → DROP (within each group, tables are sorted alphabetically). This ordering is a correctness property: it ensures the output is safe to execute sequentially (e.g. an ALTER that adds a foreign key referencing a newly-created table will run after the CREATE, and a table referenced by a FK won't be dropped before the referencing ALTER runs).
If opts is nil, NewDiffOptions() defaults are used for table diffs.
func MustNew ¶
func MustNew(statement string) []*AbstractStatement
MustNew is like New but panics if the statement cannot be parsed. It is used by tests.
func New ¶
func New(statement string) ([]*AbstractStatement, error)
func NewWithOptions ¶ added in v0.12.0
func NewWithOptions(statement string, opts Options) ([]*AbstractStatement, error)
func (*AbstractStatement) AlgorithmInplaceConsideredSafe ¶
func (a *AbstractStatement) AlgorithmInplaceConsideredSafe() error
AlgorithmInplaceConsideredSafe checks to see if all clauses of an ALTER statement are "safe". We consider an operation to be "safe" if it is "In Place" and "Only Modifies Metadata". See https://dev.mysql.com/doc/refman/8.0/en/innodb-online-ddl-operations.html for details. INPLACE DDL is not generally safe for online use in MySQL 8.0, because ADD INDEX can block replicas.
func (*AbstractStatement) AlterContainsAddUnique ¶
func (a *AbstractStatement) AlterContainsAddUnique() error
AlterContainsAddUnique checks to see if any clauses of an ALTER contains add UNIQUE index. We use this to customize the error returned from checksum fails.
func (*AbstractStatement) AlterContainsUnsupportedClause ¶
func (a *AbstractStatement) AlterContainsUnsupportedClause() error
AlterContainsUnsupportedClause checks to see if any clauses of an ALTER statement are unsupported by Spirit. These include clauses like ALGORITHM and LOCK, because they step on the toes of Spirit's own locking and algorithm selection.
func (*AbstractStatement) AlterWithRenamedCheckConstraints ¶ added in v0.17.0
func (a *AbstractStatement) AlterWithRenamedCheckConstraints(renames map[string]string) (string, []string, error)
AlterWithRenamedCheckConstraints returns this ALTER's clauses with its check constraint symbols rewritten for a table other than the one the user named: the copy algorithm's _new table, which holds the same check constraints under different names because check constraint names are unique per schema rather than per table.
renames maps a lower-cased check constraint name on the user's table to the name the same constraint has on the table the ALTER will be applied to. Names in DROP CHECK / DROP CONSTRAINT and ALTER CHECK clauses are translated through it; a name that is not in the map is left alone, so MySQL still reports it as missing rather than spirit guessing at what was meant.
A named check constraint being added by this same ALTER under a name it also drops (the "widen this constraint" idiom: DROP CHECK c, ADD CONSTRAINT c CHECK (...)) has its symbol removed, because the user's table still owns that name for as long as it exists, and adding it to a second table in the schema is an error. MySQL generates a name instead - the same outcome the copy algorithm already produces for every check constraint it copies, and the resolution recommended in issue #418. Those names are returned so the caller can report them.
func (*AbstractStatement) AsAlterTable ¶
func (a *AbstractStatement) AsAlterTable() (*ast.AlterTableStmt, bool)
AsAlterTable is a helper function that simply wraps the type case so the caller doesn't have to import the ast package and use the cast syntax
func (*AbstractStatement) CheckConstraintsReferenced ¶ added in v0.17.0
func (a *AbstractStatement) CheckConstraintsReferenced() []string
CheckConstraintsReferenced returns the check constraint names this ALTER refers to by name, i.e. the names in its DROP CHECK / DROP CONSTRAINT and ALTER CHECK clauses. It returns nil for a statement that is not an ALTER TABLE, or one that names no check constraints.
Note that MySQL's DROP CONSTRAINT is not specific to check constraints - it also drops a foreign key or a unique constraint of that name - so a name it contributes here is only a candidate. Callers match it against the check constraints that the table actually has.
func (*AbstractStatement) ColumnRenameMap ¶ added in v0.13.0
func (a *AbstractStatement) ColumnRenameMap() map[string]string
ColumnRenameMap returns a mapping of old column name → new column name for any RENAME COLUMN or CHANGE COLUMN (with a different name) specs in this ALTER TABLE statement. Returns nil if there are no renames or if this is not an ALTER TABLE statement. MySQL column identifiers are case-insensitive, so a case-only change (e.g. foo → FOO) is not considered a rename: the data mapping is unaffected and case-insensitive identity matching handles it. The map keys and values keep the case as typed in the ALTER; consumers must match them against declared column names case-insensitively.
func (*AbstractStatement) GenericConstraintDrops ¶ added in v0.17.0
func (a *AbstractStatement) GenericConstraintDrops() []string
GenericConstraintDrops returns the names in this ALTER's DROP CONSTRAINT clauses - the subset of CheckConstraintsReferenced that does not say which kind of constraint it means. DROP CHECK and ALTER CHECK do say, so they are not returned.
MySQL resolves such a name against the table's CHECK, FOREIGN KEY, UNIQUE and PRIMARY KEY constraints, which are separate namespaces, and refuses the ALTER when more than one of them holds it: "Table has multiple constraints with the name 'x'. Please use constraint specific 'DROP' clause" (error 3939). A caller that resolves the name itself has to reproduce that rather than pick one.
func (*AbstractStatement) IsAlterTable ¶
func (a *AbstractStatement) IsAlterTable() bool
func (*AbstractStatement) IsCreateTable ¶
func (a *AbstractStatement) IsCreateTable() bool
func (*AbstractStatement) IsDropTable ¶ added in v0.11.1
func (a *AbstractStatement) IsDropTable() bool
func (*AbstractStatement) IsRenameTable ¶ added in v0.11.1
func (a *AbstractStatement) IsRenameTable() bool
func (*AbstractStatement) ParseCreateTable ¶
func (a *AbstractStatement) ParseCreateTable() (*CreateTable, error)
func (*AbstractStatement) TrimAlter ¶
func (a *AbstractStatement) TrimAlter() string
type Classification ¶ added in v0.11.1
type Classification struct {
Type StatementType
Table string // First table referenced (empty for unparseable statements)
Schema string // Schema if fully qualified (e.g. "test" from "test.t1")
}
Classification holds the result of classifying a single SQL statement.
func Classify ¶ added in v0.11.1
func Classify(sql string) ([]Classification, error)
Classify parses one or more SQL statements and returns their classifications. Unlike New(), this accepts any statement type including DML and TRUNCATE.
type Column ¶
type Column struct {
Raw *ast.ColumnDef `json:"-"`
Name string `json:"name"`
Type string `json:"type"`
Length *int `json:"length,omitempty"`
Precision *int `json:"precision,omitempty"`
Scale *int `json:"scale,omitempty"`
Unsigned *bool `json:"unsigned,omitempty"`
Zerofill *bool `json:"zerofill,omitempty"` // ZEROFILL display attribute (implies unsigned)
EnumValues []string `json:"enum_values,omitempty"` // Permitted values for ENUM type
SetValues []string `json:"set_values,omitempty"` // Permitted values for SET type
Nullable bool `json:"nullable"`
Default *string `json:"default,omitempty"`
DefaultIsExpr bool `json:"default_is_expr,omitempty"` // true when default is an expression (needs parens), e.g. DEFAULT (json_object())
DefaultIsString bool `json:"default_is_string,omitempty"` // true when the default is a quoted string literal (so it must be re-quoted on emission, even if it looks like a keyword/number)
OnUpdate *string `json:"on_update,omitempty"` // ON UPDATE expression for TIMESTAMP/DATETIME, e.g. "current_timestamp"
GeneratedExpr *string `json:"generated_expr,omitempty"` // Expression for GENERATED ALWAYS AS (...) columns
GeneratedStored bool `json:"generated_stored,omitempty"` // true = STORED, false = VIRTUAL (only meaningful when GeneratedExpr is set)
Check *string `json:"check,omitempty"` // Column-level CHECK (...) constraint expression
SRID *uint32 `json:"srid,omitempty"` // SRID attribute for spatial columns
AutoInc bool `json:"auto_increment"`
PrimaryKey bool `json:"primary_key"`
Unique bool `json:"unique"`
Comment *string `json:"comment,omitempty"`
Charset *string `json:"charset,omitempty"`
Collation *string `json:"collation,omitempty"`
Options map[string]string `json:"options,omitempty"`
}
Column represents a table column definition
func (*Column) CarriesCharset ¶ added in v0.17.0
CarriesCharset reports whether the column's type stores text, and therefore has a charset and collation that participate in comparisons. Numeric, date, binary, JSON and spatial types are excluded: they carry at most a synthetic "binary" charset that is identical for any two columns of the same type.
func (*Column) EffectiveCharsetCollation ¶ added in v0.17.0
func (c *Column) EffectiveCharsetCollation(table *CreateTable) (cs, collation string)
EffectiveCharsetCollation returns the charset and collation the column actually compares under, given the table that owns it. It resolves the column's own clauses against the table defaults exactly as MySQL does (see resolvedCharsetCollation), and then fills in the charset's *default* collation when no COLLATE was written anywhere. That last step matters because SHOW CREATE TABLE omits COLLATE whenever it is the charset default, so on MySQL 8.0 a table spelled `DEFAULT CHARSET=utf8mb4` really means utf8mb4_0900_ai_ci and must compare unequal to one that spells `COLLATE=utf8mb4_general_ci`. This is decidable without a server: a charset used without a collation takes that charset's default collation — collation_server does not enter into it.
Either return value is "" when the statement does not determine it: a table with no DEFAULT CHARSET at all (only reachable from hand-written DDL, since SHOW CREATE TABLE always emits one) inherits the schema/server default, and a charset this parser does not know has no default collation to look up. Callers must treat "" as "unknown" rather than as a value that can differ.
Names are returned in MySQL 8.0's spelling: the legacy utf8/utf8_* forms are folded onto utf8mb3/utf8mb3_*, so the two spellings of the same charset compare equal.
The diff does not use this: it deliberately treats an unwritten collation as a match (see charsetCollationEqual) so it never emits a MODIFY it cannot prove converged. A linter has the opposite bias — it reports a difference it can prove, and stays silent otherwise.
type Constraint ¶
type Constraint struct {
Raw *ast.Constraint `json:"-"`
Name string `json:"name"`
Type string `json:"type"` // CHECK, FOREIGN KEY, etc.
Columns []string `json:"columns,omitempty"`
Expression *string `json:"expression,omitempty"`
References *ForeignKeyReference `json:"references,omitempty"`
Definition *string `json:"definition,omitempty"` // Generated definition string for compatibility
NotEnforced bool `json:"not_enforced,omitempty"` // CHECK constraints only: true when NOT ENFORCED
Options map[string]any `json:"options,omitempty"`
}
Constraint represents a table constraint
func (Constraint) GetName ¶
func (c Constraint) GetName() string
type Constraints ¶
type Constraints []Constraint
func (Constraints) ByName ¶
func (constraints Constraints) ByName(name string) *Constraint
func (Constraints) HasForeignKeys ¶
func (constraints Constraints) HasForeignKeys() bool
type CreateTable ¶
type CreateTable struct {
Raw *ast.CreateTableStmt `json:"-"`
TableName string `json:"table_name"`
Temporary bool `json:"temporary"`
IfNotExists bool `json:"if_not_exists"`
Columns Columns `json:"columns"`
Indexes Indexes `json:"indexes"`
Constraints Constraints `json:"constraints"`
TableOptions *TableOptions `json:"table_options,omitempty"`
Partition *PartitionOptions `json:"partition,omitempty"`
}
CreateTable represents a parsed CREATE TABLE statement with structured data
func ParseCreateTable ¶
func ParseCreateTable(sql string) (*CreateTable, error)
ParseCreateTable parses a CREATE TABLE statement and returns an analyzer This function is particularly designed to be used with the output of SHOW CREATE TABLE, which we consider to be the "canonical" form of a CREATE TABLE statement.
Because there's so much variation in the ways a human might write a CREATE TABLE statement, from index names being auto-generated to column attributes being turned into table options, you should consider use of this function on non-canonical CREATE statements to be experimental at best.
Note also that this parser does not attempt to validate the SQL beyond what the underlying parser does. For example, it will not check that a PRIMARY KEY column is NOT NULL, or that column names are unique, or that indexed columns exist.
func (*CreateTable) Diff ¶ added in v0.11.0
func (ct *CreateTable) Diff(target *CreateTable, opts *DiffOptions) ([]*AbstractStatement, error)
Diff compares this CreateTable (source) with another CreateTable (target) and returns ALTER TABLE statements needed to transform source into target. Most changes produce a single statement, but some (e.g. changing partition type) require multiple sequential statements. Returns nil if the tables are identical. If opts is nil, NewDiffOptions() defaults are used.
func (*CreateTable) GetColumns ¶
func (ct *CreateTable) GetColumns() Columns
func (*CreateTable) GetConstraints ¶
func (ct *CreateTable) GetConstraints() Constraints
func (*CreateTable) GetCreateTable ¶
func (ct *CreateTable) GetCreateTable() *CreateTable
func (*CreateTable) GetIndexes ¶
func (ct *CreateTable) GetIndexes() Indexes
func (*CreateTable) GetPartition ¶
func (ct *CreateTable) GetPartition() *PartitionOptions
func (*CreateTable) GetTableName ¶
func (ct *CreateTable) GetTableName() string
func (*CreateTable) GetTableOptions ¶
func (ct *CreateTable) GetTableOptions() map[string]any
func (*CreateTable) ToTableInfo ¶ added in v0.17.0
func (ct *CreateTable) ToTableInfo(schemaName string) (*table.TableInfo, error)
ToTableInfo builds a connection-less table.TableInfo from the parsed CREATE TABLE, carrying the column types and primary key columns that Spirit's checks read from table metadata. schemaName names the schema the table lives in; it is only used for error messages and by checks that query MySQL, which cannot run against the returned TableInfo anyway (see table.NewTableInfoFromMeta).
This lets a caller holding a table's DDL — typically its SHOW CREATE TABLE — supply check.Resources.Table without opening a connection.
func (*CreateTable) ToTableSchema ¶ added in v0.11.3
func (ct *CreateTable) ToTableSchema() (table.TableSchema, error)
ToTableSchema converts a parsed CreateTable back to a table.TableSchema by restoring the AST to SQL. This is useful when callers have already parsed schemas (e.g. for linting) but need to pass them to DeclarativeToImperative.
type DiffOptions ¶ added in v0.11.0
type DiffOptions struct {
// IgnoreAutoIncrement skips diffing the AUTO_INCREMENT table option
// (the table-level next-value counter, e.g. `AUTO_INCREMENT=100`).
// Default: true (via NewDiffOptions).
IgnoreAutoIncrement bool
// IgnoreColumnAutoIncrement skips diffing the column-level AUTO_INCREMENT
// attribute (whether a column carries the AUTO_INCREMENT flag). This is
// distinct from IgnoreAutoIncrement, which only covers the table-option
// counter. Default: false (via NewDiffOptions) — for general schema diffing
// a column gaining or losing AUTO_INCREMENT is a real change. It is enabled
// by consumers like the move-tables target-state check, where an unsharded
// source legitimately differs from a sharded target that drops
// AUTO_INCREMENT in favor of a Vitess sequence: the difference does not
// affect copy correctness and must not block the move.
IgnoreColumnAutoIncrement bool
// IgnoreNotNullRelaxation lets the schema being validated be STRICTER than
// its reference on nullability, and only stricter: a validated column
// declared NOT NULL where the reference permits NULL is accepted, while one
// that permits NULL where the reference is NOT NULL remains a real
// difference. The option therefore can never quietly accept a schema that
// lost a NOT NULL the reference had.
//
// Default: false (via NewDiffOptions) — for general schema diffing a column
// gaining or losing NOT NULL is a real change.
//
// It is enabled by the move-tables target checks (see
// move/check.TargetSchemaDiff), where the reference is the move's SOURCE and
// the validated schema is its physical TARGET. What that permits is a target
// column declared NOT NULL where the source still permits NULL — an
// unsharded source moving into a sharded target whose shard key must be
// NOT NULL, because a Vitess primary vindex cannot map NULL to a keyspace
// id.
//
// In terms of Diff's own arguments the reference is the parameter and the
// validated schema is the receiver, because DiffCreateTables diffs
// got->want. Stating the direction that way inverts it, which is why the
// wording above and TestDiff_IgnoreNotNullRelaxation both name the two
// schemas by role instead.
//
// That is safe for a move because nullability is metadata, not row bytes:
// the copy and the checksum compare values, and every column's NULL-ness is
// compared explicitly (see ColumnMapping.ChecksumExprs, which emits an
// ISNULL() digit per column). A tightened column whose source data holds no
// NULLs is therefore identical on both sides, and this option hides nothing
// about the rows themselves. One that does hold a NULL fails the move
// instead of being accepted, and fails before the checksum ever runs — see
// move/check.TargetSchemaDiff for where and why.
IgnoreNotNullRelaxation bool
// IgnoreEngine skips diffing the ENGINE table option.
// Default: true (via NewDiffOptions).
IgnoreEngine bool
// IgnoreCharsetCollation skips diffing CHARSET and COLLATION table options.
// Default: false (via NewDiffOptions).
IgnoreCharsetCollation bool
// IgnorePartitioning skips diffing partition options entirely.
// Default: false (via NewDiffOptions).
IgnorePartitioning bool
// IgnoreRowFormat skips diffing the ROW_FORMAT table option.
// Default: true (via NewDiffOptions).
// ROW_FORMAT=DYNAMIC is the InnoDB default in MySQL 8.0+, so differences
// between an unspecified ROW_FORMAT and an explicit DYNAMIC are cosmetic.
IgnoreRowFormat bool
}
DiffOptions controls the behavior of the Diff operation.
func NewDiffOptions ¶ added in v0.11.0
func NewDiffOptions() *DiffOptions
NewDiffOptions returns DiffOptions with sensible defaults. By default, AUTO_INCREMENT, ENGINE, and ROW_FORMAT differences are ignored.
type ForeignKeyReference ¶
type ForeignKeyReference struct {
Table string `json:"table"`
Columns []string `json:"columns"`
OnDelete *string `json:"on_delete,omitempty"`
OnUpdate *string `json:"on_update,omitempty"`
}
ForeignKeyReference represents a foreign key reference
type HasName ¶
type HasName interface {
GetName() string
}
HasName is a type constraint for types that have a Name field
type Index ¶
type Index struct {
Raw *ast.Constraint `json:"-"`
Name string `json:"name"`
Type string `json:"type"` // PRIMARY, UNIQUE, INDEX, FULLTEXT, SPATIAL
Columns []string `json:"columns"` // Deprecated: use ColumnList for full details
ColumnList []IndexColumn `json:"column_list,omitempty"` // Full column specifications including prefix/expression
Invisible *bool `json:"invisible,omitempty"`
Using *string `json:"using,omitempty"` // BTREE, HASH, RTREE
Comment *string `json:"comment,omitempty"`
KeyBlockSize *uint64 `json:"key_block_size,omitempty"`
ParserName *string `json:"parser_name,omitempty"`
Options map[string]string `json:"options,omitempty"`
// InlineDerived marks a UNIQUE index that indexNormalizer synthesized
// from an inline column-level UNIQUE (`c INT UNIQUE`). Its name is only a
// guess at the server-assigned one (the column name, suffixed on collision),
// so diffIndexes pairs it with an equivalent live unique index by column set
// even when the names differ, rather than emitting a spurious DROP+ADD.
// Not serialized: it is a diff-time hint, not part of the logical schema.
InlineDerived bool `json:"-"`
}
Index represents an index definition
type IndexColumn ¶ added in v0.11.0
type IndexColumn struct {
Name string `json:"name,omitempty"` // Column name (empty for expression indexes)
Expression *string `json:"expression,omitempty"` // Expression for functional indexes
Length *int `json:"length,omitempty"` // Prefix length for string columns
Desc bool `json:"desc,omitempty"` // Descending key part (MySQL 8.0+), e.g. KEY (a DESC)
}
IndexColumn represents a column or expression in an index
type Normalizer ¶ added in v0.16.0
type Normalizer interface {
// Name identifies the rule, for registry determinism and debugging.
Name() string
// Normalize returns ct rewritten to MySQL's canonical form for this rule.
Normalize(ct *CreateTable) *CreateTable
}
Normalizer applies a single MySQL canonicalization to a parsed CreateTable. A rule takes a CreateTable and returns the normalized CreateTable — it is free to mutate and return the same instance, or to return a new one. It is deliberately a standalone type rather than a method on CreateTable so rules live in their own files and compose as a pipeline.
type Options ¶ added in v0.12.0
type Options struct {
// AllowMixedStatementTypes permits multi-statement input containing different
// DDL types (e.g., CREATE TABLE + ALTER TABLE). By default, multi-statement
// input must be all ALTER TABLE statements (required for atomic schema changes).
// Enable this when using New() to split/parse schema files that may contain
// a mix of DDL statement types.
AllowMixedStatementTypes bool
}
Options configures the behavior of statement parsing.
type PartitionDefinition ¶
type PartitionDefinition struct {
Name string `json:"name"`
Values *PartitionValues `json:"values,omitempty"` // VALUES LESS THAN or VALUES IN
Comment *string `json:"comment,omitempty"`
Engine *string `json:"engine,omitempty"`
Options map[string]any `json:"options,omitempty"`
SubPartitions []SubPartitionDefinition `json:"subpartitions,omitempty"`
}
PartitionDefinition represents a single partition definition
type PartitionOptions ¶
type PartitionOptions struct {
Type string `json:"type"` // RANGE, LIST, HASH, KEY
Expression *string `json:"expression,omitempty"` // For HASH and RANGE
Columns []string `json:"columns,omitempty"` // For KEY, RANGE COLUMNS, LIST COLUMNS
Linear bool `json:"linear,omitempty"` // For LINEAR HASH/KEY
Partitions uint64 `json:"partitions,omitempty"` // Number of partitions
Definitions []PartitionDefinition `json:"definitions,omitempty"` // Individual partition definitions
SubPartition *SubPartitionOptions `json:"subpartition,omitempty"` // Subpartitioning options
}
PartitionOptions represents table partitioning configuration
type PartitionValues ¶
type PartitionValues struct {
Type string `json:"type"` // "LESS_THAN", "IN", "MAXVALUE"
Values []any `json:"values"` // The actual values
}
PartitionValues represents the VALUES clause in partition definitions
type StatementType ¶ added in v0.11.1
type StatementType int
StatementType represents the type of a SQL statement.
const ( StatementUnknown StatementType = iota StatementAlterTable // ALTER TABLE ... StatementCreateTable // CREATE TABLE ... StatementDropTable // DROP TABLE ... StatementRenameTable // RENAME TABLE ... StatementTruncateTable // TRUNCATE TABLE ... StatementCreateIndex // CREATE INDEX ... StatementDropIndex // DROP INDEX ... StatementCreateView // CREATE VIEW ... StatementInsert // INSERT ... StatementUpdate // UPDATE ... StatementDelete // DELETE ... )
func (StatementType) IsDDL ¶ added in v0.11.1
func (t StatementType) IsDDL() bool
IsDDL returns true if this is a DDL statement type.
func (StatementType) IsDML ¶ added in v0.11.1
func (t StatementType) IsDML() bool
IsDML returns true if this is a DML statement type.
func (StatementType) String ¶ added in v0.11.1
func (t StatementType) String() string
String returns the human-readable name for a StatementType.
type SubPartitionDefinition ¶
type SubPartitionDefinition struct {
Name string `json:"name"`
Comment *string `json:"comment,omitempty"`
Engine *string `json:"engine,omitempty"`
Options map[string]any `json:"options,omitempty"`
}
SubPartitionDefinition represents a single subpartition definition
type SubPartitionOptions ¶
type SubPartitionOptions struct {
Type string `json:"type"` // HASH, KEY
Expression *string `json:"expression,omitempty"` // For HASH
Columns []string `json:"columns,omitempty"` // For KEY
Linear bool `json:"linear,omitempty"` // For LINEAR HASH/KEY
Count uint64 `json:"count,omitempty"` // Number of subpartitions
}
SubPartitionOptions represents subpartitioning configuration
type TableOptions ¶
type TableOptions struct {
Engine *string `json:"engine,omitempty"`
Charset *string `json:"charset,omitempty"`
Collation *string `json:"collation,omitempty"`
Comment *string `json:"comment,omitempty"`
AutoIncrement *uint64 `json:"auto_increment,omitempty"`
RowFormat *string `json:"row_format,omitempty"`
}
TableOptions represents table-level options
Source Files
¶
- accessors.go
- charset.go
- classify.go
- create_table.go
- declarative.go
- diff.go
- equality.go
- format.go
- normalize.go
- normalize_binary_attribute.go
- normalize_charsetless_types.go
- normalize_column_checks.go
- normalize_expression_parens.go
- normalize_function_aliases.go
- normalize_index_names.go
- normalize_integer_display_width.go
- normalize_partition_comment.go
- normalize_primary_key.go
- normalize_vector_dimension.go
- parse_helpers.go
- schema_compare.go
- secondary_indexes.go
- statement.go
- table_info.go
- table_options.go
- utils.go