Competitor watch: the CREATE script that lies
I checked 12 open DDL-script bugs from DBeaver, DataGrip, HeidiSQL and DbGate against SQLly. Seven were ours; all are fixed, plus one new feature.
Every SQL client offers to show you the script that would build an object: "Show SQL", "Create code", "Script as CREATE". You trust it, copy it, run it somewhere else, and find out later what it left behind. So I read twelve open issues from four other SQL clients where that script lied a little, and checked every one against SQLly.
SQLly had seven of them, and all seven are fixed today and ship in the next release (changelog). One feature request talked me into building it: PostgreSQL privileges, revoked defaults included, in Script as CREATE and dumps. The other four I checked, and SQLly doesn't have them.
This is the daily competitor watch. I take a batch of open issues from other SQL clients' public trackers, check whether SQLly has the same problem, and fix it if it does. The people who reported these did the hard part, so every one of them is named and linked below. Today's batch is about generated DDL: INCLUDE columns at the front of an index, a lost FOLLOWS, the comment block on top of a view, a missing semicolon, a lost md5(...), and a sequence default that turned into AUTO_INCREMENT. I ran the same objects through SQLly against real SQL Server, PostgreSQL, MySQL, MariaDB, Oracle and SQLite databases, and restored SQLly's own scripts to see whether they ran. They didn't all run. Ages are as of October 21, 2026. "Vendor" means someone the tracker marks as a member, collaborator or staff.
The twelve issues
SQL Server: INCLUDE columns are displayed before key columns because their ordinal position is 0 DBeaver #42377
Age: opened 9 days ago (October 12, 2026). No vendor reply yet. Labelled external.
Reactions / comments: 0 / 1.
The vibe: a tidy diagnosis. SQL Server gives INCLUDE columns a key ordinal of 0, DBeaver sorts by it, and the leaf-level passengers end up at the front of the index. Anyone reading it to work out which seeks the index supports gets exactly the wrong answer.
Credit: @iunoictsolutions reported it with the before-and-after tables. @davestokes said thanks.
SQLly: checked, not a problem we have. SQLly lists key columns first, in key order, and then the INCLUDE columns, both in the index's properties and in its generated CREATE INDEX … INCLUDE (…). We created the reporter's exact index on SQL Server 2025 to make sure. (changelog)
Extra space added between CREATE and PROCEDURE on every save DBeaver #42350
Age: opened 12 days ago (October 9, 2026). No vendor reply yet.
Reactions / comments: 0 / 1.
The vibe: every save adds one more space after CREATE. Save ten times and your procedure header has a little indented gap, and every git diff has a whitespace change. The reporter says it's been going on "for a long time". DBeaver couldn't reproduce it, so for now it's a ghost that only haunts one SQL Server.
Credit: @dre40 reported it. @davestokes tried and couldn't reproduce it.
SQLly: we expected to be innocent and weren't. SQL Server stores a CREATE OR ALTER VIEW as CREATE VIEW, with the OR ALTER replaced by spaces, and SQLly's Script as ALTER kept that gap, so every round trip on SQL Server 2025 added two more spaces. Schema Compare's redeploys did the same. Both now collapse the gap to a single space, and a live test deploys twice to make sure it stays put. (changelog)
PostgreSQL: revoked privileges from public not reflected in DDL DBeaver #42343
Age: opened 13 days ago (October 8, 2026). Last vendor reply 13 days ago (a thank-you).
Reactions / comments: 0 / 2.
The vibe: a carefully argued request. PostgreSQL gives public EXECUTE on every new function, so a DDL script that leaves out the REVOKE builds a different function from the one you copied. The reporter brought a working query and pointed at pg_dump as the model. Twelve days later someone else turned up with the root cause and offered to fix it.
Credit: @michal-bartak reported it with the catalog query. @Rishavbhattarai traced the cause and offered a patch. @SolovevAnton thanked them.
SQLly: a fair request, and one we couldn't brag about: SQLly's PostgreSQL CREATE scripts carried no privileges at all, neither GRANTs nor REVOKEs. So we built it today, the way the reporter asked, pg_dump style. SQLly compares each object's privileges with PostgreSQL's defaults for its type and owner: defaults you took away become REVOKEs, extra access becomes GRANTs (with WITH GRANT OPTION where it applies), and an object nobody has touched gets nothing. It's on by default for definitions and Script as CREATE, and an "Include privileges" checkbox adds it to database dumps. We revoked EXECUTE from public on a function, granted it to a role, dropped the function, ran our script, and got the identical ACL back. (changelog)
[postgresql] The public pseudorole handled wrong way (and more) DBeaver #42303
Age: opened 16 days ago (October 5, 2026). No vendor reply yet. Labelled wait for response.
Reactions / comments: 0 / 1.
The vibe: PostgreSQL lets you create a real role called "PUBLIC", which is different from the built-in public everyone belongs to. information_schema writes both in capitals, so a tool that trusts it mixes them up and grants or revokes the wrong thing. The reporter even left the warning for the next implementer: use aclexplode(). The issue is labelled "wait for response", though it isn't clear whose.
Credit: @michal-bartak reported it (their second in this batch). @davestokes said thanks.
SQLly: we had it too. We created a role named "PUBLIC" on PostgreSQL 18, and SQLly's Security dialog listed 192 table grants for it, every one of which actually belonged to the built-in public. Unticking one would have revoked nothing. Fixed: SQLly now reads grants straight from each table's access list and matches roles by identity, not spelling, so the impostor sees only its own grants. We took the reporter's advice and used aclexplode(). (changelog)
Missing 'follows otherTrigger' in generated DDL for triggers DataGrip DBE-20597
Age: opened 2 years, 5 months ago (April 24, 2024). Confirmed by JetBrains 2 days later. Last vendor reply 2 days ago.
Reactions / comments: 1 vote / 5.
The vibe: the trigger runs after another one, the generated source says nothing about it, and only "Request and copy original DDL" tells the truth. The reporter called it "highly misleading". It sat confirmed for two and a half years until a nudge last week drew an honest reply: "Yes, we missed this issue, sorry." We'll give them points for the apology.
Credit: Thomas Jenny reported it with a full Oracle script. Marco Wienkoop nudged it last week. Leonid Bushuev replied for JetBrains.
SQLly: fine on Oracle, guilty on MySQL and MariaDB. On Oracle, SQLly asks the database for the trigger's DDL and follows trg_upd_status_date comes back intact; we checked on Oracle 23ai Free. MySQL and MariaDB don't keep the FOLLOWS clause, only a firing order, and SQLly ignored it. We scripted two triggers where a_two follows z_one, and SQLly wrote them out alphabetically with no FOLLOWS. Run that, and they fire the other way round. Fixed: the trigger definition now says FOLLOWS, and a dump writes triggers in firing order, so a restore on MySQL 8.4 or MariaDB 11.8 fires them the way the original did. (changelog)
Comments lost when saving View in MS SQL Server DataGrip DBE-6546
Age: opened 8 years, 4 months ago (June 1, 2018). Last vendor reply 1 year, 9 months ago.
Reactions / comments: 8 votes / 7.
The vibe: this one is old enough to be in third grade. Write a view with the usual SSMS-style header block (Author, Create date, Description), run it, and the header is gone from the stored view. The official workaround is a setting plus selecting the whole script before running it. Some people say it works for them and some say it doesn't. Teams that share code with SSMS users keep turning up to say "still happening", the most recent one last week.
Credit: David Faivre reported it. Vasilii Chernov posted the workaround. Matthew Macdonald said "2024 and it's STILL occurring". ProKlutch hit it on stored procedures. Seth Reeise asked for eyes on it. Piotr Namysł has it too. Goran Genter lost a commented-out WHERE line.
SQLly: mostly innocent, partly guilty. Running a view or procedure from a SQLly query tab keeps the header: we ran the reporter's example on SQL Server 2025 and OBJECT_DEFINITION came back with every comment line. But Run SQL File stripped comment lines from the top of each batch, so the same script run from a file stored the view bare. And Schema Compare's deploy script cut off everything above CREATE (and, it turns out, the word VIEW with it). Both fixed: Run SQL File now sends the comments above each statement, and Schema Compare keeps the header and the object keyword. A live test checks that OBJECT_DEFINITION still has the header afterwards. (changelog)
PostgreSQL SQL export: missing semicolon after CREATE TABLE and empty table name in CREATE INDEX statement HeidiSQL #2591
Age: opened 1 month, 2 weeks ago (September 5, 2026). Last vendor reply 41 days ago.
Reactions / comments: 0 / 1.
The vibe: four separate problems with one Django-shaped table: no semicolon, ON "", no schema, no operator class. The maintainer's honest answer was that the SQL export is "quite MySQL/MariaDB only". It's a fair answer, and not much consolation if you're on PostgreSQL.
Credit: @bernd670 reported it with expected output and the Django background. @ansgarbecker explained the export's scope.
SQLly: three out of four we were fine on. SQLly writes the index exactly as PostgreSQL stores it, with table, schema, USING btree and varchar_pattern_ops. But the missing semicolon? We had that one, just not where HeidiSQL does. A SQLite table with an index came out as CREATE TABLE …) with no semicolon, so restoring it failed. Two PostgreSQL functions in a row ran into each other. MySQL and MariaDB triggers and routines had no terminator and no DELIMITER. Fixed: every generated statement now ends properly, and MySQL/MariaDB routines and triggers come wrapped in DELIMITER $$. A SQLite dump now restores cleanly with the sqlite3 shell, and that's in the test suite. (changelog)
The generated "Create Code" for a table in a sqlite database is invalid HeidiSQL #2589
Age: opened 1 month, 2 weeks ago (September 1, 2026). No vendor reply, ever.
Reactions / comments: 0 / 0.
The vibe: HeidiSQL made the table itself, then described it with AUTO_INCREMENT, which is MySQL and not SQLite. The reporter wrote out the correct SQLite version and asked politely. Seven weeks of quiet so far.
Credit: @Virock reported it with the corrected SQL.
SQLly: checked, the AUTO_INCREMENT mix-up isn't one we have. On SQLite, SQLly shows the CREATE text SQLite itself stored, so INTEGER PRIMARY KEY AUTOINCREMENT comes back exactly as written. Honesty clause: for this very table, with its index, our script did have the missing-semicolon bug from #2591 above, and it's fixed along with that one. (changelog)
MariaDB - using sequence in DEFAULT column value HeidiSQL #2586
Age: opened 1 month, 3 weeks ago (August 27, 2026). No vendor reply, ever.
Reactions / comments: 0 / 0.
The vibe: DEFAULT nextval(test.users.row_change_sequence) goes in, and HeidiSQL's preview says AUTO_INCREMENT. These aren't the same thing. A sequence can be shared by several tables, and AUTO_INCREMENT can't. A short, precise report, and no reply yet.
Credit: @IHaveIssuesWithYourThing reported it. (Best GitHub handle in today's batch.)
SQLly: guilty, in two accents. On MariaDB, SQLly's CREATE script dropped the DEFAULT nextval(...) entirely, along with the other defaults, UNSIGNED and the primary key, and left the sequence out of the dump. On PostgreSQL it made HeidiSQL's exact mistake: a column defaulting to a shared sequence came out as GENERATED BY DEFAULT AS IDENTITY. Fixed: MySQL and MariaDB tables now script from the server's own definition, nextval included, and on PostgreSQL only a sequence the column owns counts as an identity. We dropped and recreated each table from its script on PostgreSQL, MySQL and MariaDB and compared the catalogs. (changelog)
empty body for triggers HeidiSQL #2577
Age: opened 2 months, 2 weeks ago (August 8, 2026). No vendor reply, ever.
Reactions / comments: 0 / 1.
The vibe: the reporter tracked it down to a regular expression whose . doesn't cross line breaks, so a trigger written over several lines shows up empty. A second user found worse: an empty body, the wrong table, and UPDATE turned into INSERT. In other words, the editor reset to a blank new trigger. Ten weeks, no reply.
Credit: @dsan0815 reported it and diagnosed the regex. @IHaveIssuesWithYourThing added the wrong-table detail.
SQLly: checked, not a problem we have. SQLly doesn't parse the trigger text with a pattern. It reads the timing, event, table and body as separate catalog fields. We created the reporter's multi-line trigger on MariaDB 11, and SQLly showed the full BEGIN … END body on the right table. (changelog)
Change View definition of PostgreSQL error HeidiSQL #2291
Age: opened 11 months ago (November 3, 2025). Last vendor reply 11 months ago. Labelled bug.
Reactions / comments: 0 / 2.
The vibe: HeidiSQL saves a changed PostgreSQL view with ALTER VIEW … AS SELECT, which PostgreSQL has never accepted. The maintainer found the right statement the next day (CREATE OR REPLACE VIEW) and linked the docs. The issue is still open eleven months later.
Credit: @FlashIvano reported it. @ansgarbecker found the fix in the PostgreSQL docs.
SQLly: checked, not a problem we have. Script as ALTER on a PostgreSQL view gives you CREATE OR REPLACE VIEW, and we ran it, Chinese column alias and all, on PostgreSQL 18 without complaint. (changelog)
BUG: "show sql" and "view structure" does not show a table's layout correctly when using a functional index DbGate #1494
Age: opened 3 months, 4 weeks ago (June 24, 2026). No vendor reply, ever.
Reactions / comments: 0 / 0.
The vibe: a unique index on two columns plus md5(feed_xml::text) is shown as a unique index on just the two columns, which is a much stricter promise. The reporter included psql's \d output to show what it should look like. Four months, no reply.
Credit: @KanchiMoe reported it with a full reproduction.
SQLly: half guilty. The CREATE script was right: SQLly writes the index as PostgreSQL stores it, md5((feed_xml)::text) included. But the index's Columns page in SQLly dropped the expression, just like DbGate's structure view, and on the same page an INCLUDE column was shown as a third key column. Fixed: the Columns page lists expression keys, marks INCLUDE and descending columns for what they are, and the CREATE script replays functional indexes exactly as PostgreSQL defines them. (changelog)
That's the batch: seven bugs SQLly had, seven fixed; four it didn't; one idea built. Thanks to everyone who took the time to write these up. A good bug report helps every SQL client, including the ones it wasn't written for.
What changed in SQLly today
- Generated scripts end every statement, and MySQL/MariaDB routines and triggers are wrapped in
DELIMITER, so dumps restore cleanly. - Run SQL File keeps the comments above each statement, so a SQL Server view keeps its header.
- Schema Compare deploys changed views and routines correctly, keeping comments and the object keyword, with no growing gap after
CREATE. - PostgreSQL functional indexes show their expressions and replay exactly in Script as CREATE.
- Table DDL keeps defaults, keys and sequence defaults on PostgreSQL, MySQL and MariaDB.
- MySQL and MariaDB triggers keep their firing order in definitions and dumps.
- A PostgreSQL role named "PUBLIC" is no longer confused with PUBLIC.
- PostgreSQL scripts carry privileges, including revoked defaults, with an Include privileges option for dumps. See DDL source.