NAME
DBIO::MySQL::Diff::Table - Diff operations for MySQL/MariaDB tables
VERSION
version 0.900004
DESCRIPTION
Represents a table-level diff operation in MySQL/MariaDB: CREATE TABLE, DROP TABLE or, for a table whose collation changes, ALTER TABLE ... CONVERT TO (see "The collation of an existing table"). create ops carry the target columns and FKs so as_sql can render the full inline definition (parallel to DBIO::SQLite::Diff::Table).
The foreign keys a create op carries are the ones its CREATE TABLE is to have, and DBIO::MySQL::Diff chooses them: a foreign key that needs an index the same diff creates (a unique key of a table it creates, say) is left out and added after the index, where the server would refuse it here; and so is one whose columns an index the diff creates on the table covers, where the server would make a second index over them. The CREATE TABLE carries no index but the primary key, and a DROP TABLE comes after the DROP FOREIGN KEY of every constraint that references the table.
The one exception to the primary key being the only key of a CREATE TABLE: an AUTO_INCREMENT column that is not in the primary key has to be a key at the moment the table is created (the server refuses it otherwise, "there can be only one auto column and it must be defined as a key"). DBIO::MySQL::Diff hands such a table the index the target has over the column (indexes, hashrefs { index_name, index_info }), and it stands in the CREATE TABLE as UNIQUE KEY or KEY, not as a CREATE INDEX after it, so the table that an upgrade creates is the table install_ddl creates.
The collation of an existing table
The character set and collation of a table are part of the target model (mysql_charset and mysql_collate of the result class, table_collation of DBIO::MySQL::Introspect::Tables); the CREATE TABLE of a new table writes them. A table that exists with another collation is changed with
ALTER TABLE `t` CONVERT TO CHARACTER SET x COLLATE y;
-- but only where the data provably survives. The statement
rewrites every text column of the table, and what it does to the data was
measured on MySQL 8.0.30 and MariaDB 11.8.9 (both behave alike unless said):
Same character set, other collation (
utf8mb4_unicode_citoutf8mb4_binand back): the bytes stay, nothing is re-encoded. Umlauts, CJK and 4-byte characters were identical afterwards;FULLTEXTindexes kept matching;BLOB,VARBINARYandBINARYcolumns are not touched; a column with a collation of its own gets the table's (the model has no per-column collation);TINYTEXT/TEXTkeep their type. A unique key whose values collide under the new collation (abc,ABCfrom_binto_ci) is refused by the server (1062, "Duplicate entry"), atomically -- the table was unchanged afterwards; that error is the server's, a diff cannot know it in advance.Another character set, target
utf8mb4: widening, the characters are kept (latin1with umlauts andutf8mb3with Japanese text were identical afterwards). Two things are not safe and are refused instead:TINYTEXT,TEXTandMEDIUMTEXTcolumns are silently promoted toTEXT,MEDIUMTEXTandLONGTEXT(the type changes, so a later diff would turn it back and cut), andENUM/SETcolumns oflatin1lose their non-ASCII members (MySQL 8.0.30 left the definitionenum('','b')and emptied the data without an error; MariaDB refused with "Data truncated"). An index over a longVARCHARcan exceed the key length; MySQL refuses (1071, atomically), MariaDB keeps the statement and shortens the key to a prefix.Any other target character set (
latin1,utf8mb3, ...) for a column that has another one: narrowing. Characters outside the target are lost (with strict mode the server refuses, "Incorrect string value", and the table stays; a session without it wrote?for each of them and the data differed afterwards). Refused.A foreign key that has a text column of the table on either side: the server refuses the conversion of either table of the pair on its own (MySQL: "Referencing column ... and referenced column ... are incompatible", MariaDB: "Cannot change column ... used in a foreign key constraint"), and one statement cannot convert both. Refused.
A refusal is a DBIO::Exception that names the table, both collations and the column or constraint, thrown while the diff is built, before any statement ran. The columns of a converted table are not compared for character set and collation: the conversion gives them the collation of the target.
METHODS
diff
my @ops = DBIO::MySQL::Diff::Table->diff(
$source_tables, $target_tables,
$target_columns, $target_fks,
$target_indexes, $source_columns, $source_fks,
);
The last two are the columns and foreign keys of the source, by table; they are what the refusals of a collation change look at.
refuse_unprovable_conversion
DBIO::MySQL::Diff::Table::refuse_unprovable_conversion(
$table, $old_collation, $new_collation, $source_columns, $source_fks);
Throws a DBIO::Exception when CONVERT TO would not keep the data of the table, see "The collation of an existing table". Returns nothing otherwise.
as_sql
The CREATE TABLE, DROP TABLE or ALTER TABLE ... CONVERT TO statement. Every name in it is quoted with "quote_ident" in DBIO::MySQL::Identifier. A foreign key with a SET DEFAULT action throws ("refuse_set_default" in DBIO::MySQL::Diff::ForeignKey).
summary
AUTHOR
DBIO & DBIx::Class Authors
COPYRIGHT AND LICENSE
Copyright (C) 2026 DBIO Authors Portions Copyright (C) 2005-2025 DBIx::Class Authors Based on DBIx::Class, heavily modified.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.