Structure designer and sync
Editing structure, not rows, under the same discipline: nothing runs until you have read the SQL, and what runs, runs in one transaction.
Panes
- Columns — name, type, length, precision and scale, nullable, default, identity or auto-increment, generated expression, character set, collation, comment. Enum members are edited in their own sheet. Reordering is offered only on MySQL, which supports
AFTER; on PostgreSQL the control is absent, not disabled with a tooltip. - Indexes — name, method (btree, hash, gin, gist, brin, spgist on PostgreSQL; btree, hash, fulltext, spatial on MySQL), columns with per-column direction, unique, partial predicate, comment.
- Primary key — chosen on the Columns pane by marking columns in key order. Dropping and adding a primary key is one edit, not two.
- Foreign keys — the referenced table and each pair of columns picked from lists, ON UPDATE and ON DELETE with what each does, and a check deferred to commit on PostgreSQL and SQLite.
- Checks, Triggers, Partitions and Table (name, comment, engine and charset on MySQL, tablespace on PostgreSQL).
How a change is applied
The designer never mutates anything as you type. It holds an edited definition beside the one introspection returned. Preview diffs the two and renders the statements in execution order, syntax-highlighted; it is the only route to Execute. Everything runs in one transaction. Afterwards the table’s introspection is invalidated and the pane reloads from the server, so what you see is what the server has, never what was requested.
A change that is running can be stopped
While the review sheet executes, Cancel becomes Stop, which asks the server to end the statement — KILL QUERY on MySQL, pg_cancel_backend on PostgreSQL — rather than only closing the sheet. Meanwhile the sheet shows the elapsed time, what the server says the statement is doing (“copy to tmp table”, “Waiting for table metadata lock”), and a percentage when the server estimates one: MariaDB’s progress, MySQL’s performance_schema stages, PostgreSQL’s index builds. A stopped run is reported in the server’s own words; PostgreSQL rolls it back, and MySQL says which statements had already committed.
SQLite rebuilds a table rather than pretending to alter it
SQLite's ALTER TABLE cannot express every column change. Where it cannot, the change is applied the way SQLite's own documentation prescribes: the table is rebuilt inside one transaction, with the data copied across and the indexes, triggers and foreign keys recreated. The preview shows those statements in the order they will run, the same as anywhere else, so what you approve is what executes.
Every type the manual documents, under the manual’s name
mood enum — and then every type PostgreSQL’s manual lists, in its chapters: Numeric, Monetary, Character, Binary, Date/Time, Boolean, Geometric and on.The type pop-up carries every type the manual of each engine lists — PostgreSQL’s, MySQL’s, MariaDB’s and SQLite’s — under the manual’s own name and grouped the way the manual groups them, with the types defined on this server, such as a PostgreSQL enum, at the top. The panel under the columns says what the manual says of the selected type: its size and its range.
- A type is shown with its other names beside it —
bigint · int8,character varying · varchar— so a name known from another client finds it at once. The first name is the one the server writes back, so an untouched column never reads as changed. - The list follows the server:
vectorfrom MySQL 9.0,uuid,inet4andinet6on MariaDB, multirange types from PostgreSQL 14. MariaDB gets a list of its own, because it lacks some of MySQL’s types. - A PostgreSQL column can be an array (
integer[]), and the defaults offered are the engine’s own:gen_random_uuid(),now(),CURRENT_TIMESTAMP(6),(UUID()). - PostgreSQL’s
serialtypes are offered for a new column only, since an existing column cannot be altered to one. An integer column’s identity is None, GENERATED BY DEFAULT or GENERATED ALWAYS, with what each means said beside the choice.
Foreign keys are chosen, not typed
The Foreign Keys pane lists the table’s keys and edits the selected one beneath. The table a key points at, the local columns and the columns they point at are pop-ups filled from what the server has, with the referenced table’s key columns first. Choosing the table fills in its primary key and finds the local column named after it: customer_id for customers.id.
- Each ON DELETE and ON UPDATE action says what it does in a sentence under the choice, and only the actions the engine carries out are offered — MySQL is not offered SET DEFAULT, which InnoDB refuses. PostgreSQL and SQLite can defer the check to commit.
- What the server would refuse is said before it is asked: columns whose types differ, columns that are not unique where they are pointed at, SET NULL on a NOT NULL column. A differing type is a warning on PostgreSQL, which accepts comparable types, and an error on MySQL.
- A key with no table, or a column with nothing to point at, is incomplete, and Preview stays disabled until it is not. Everything else is advice: the server remains the judge, and its message is shown verbatim.
Create table
⌘⇧N opens the same editor with an empty definition. It emits one CREATE TABLE plus the CREATE INDEX, COMMENT ON and trigger statements the definition needs, in dependency order.
Structure sync
Between two MySQL-family servers each column keeps its character set and collation instead of quietly dropping them. The names are checked against the receiving server first, because MariaDB accepts MySQL’s utf8mb4_0900_ai_ci while MySQL refuses MariaDB’s utf8mb4_uca1400_ai_ci. Across engines a collation cannot come along at all, and that is noted once per table, naming both halves, rather than once per text column.
Structure sync compares a source table or schema against a target on any configured connection, including across engines, and produces the DDL that would make the target match. Across engines it compares the two definitions only after translating each into the target’s terms, and sets aside the facets one engine has and the other does not, so a table freshly copied across reads as identical rather than as a page of differences. It is a generator, not an applier: the result opens in a SQL editor tab. Destructive statements are listed separately in the preview and are unchecked by default. Syncing a table against itself produces no statements.