Build plugin tables through createTableSql(), so optional columns get defaults - #23
Merged
Merged
Conversation
… defaults GH-1245. A column declared NOT NULL with no DEFAULT is only mandatory if something enforces it, and for nine years nothing did: PDODB cleared sql_mode on every connection, so the server downgraded the error to a warning and substituted an implicit zero. Removing the clear turned every one of those declarations into a real constraint, and an INSERT that omits one now fails with error 1364. FOG's schema step 348 repairs the tables an install already has. It cannot repair ours: createSql() runs as step 0 of each plugin's own schema(), so a plugin installed AFTER the migration gets a table built the old way -- every optional column mandatory again. FOGManagerController::createTableSql() (fogproject #1275) takes the identical arguments and fills a default into every NOT NULL column that has none, leaving bare only the primary key and auto-increment column, anything the model declares required, and anything whose name ends in ID. A default a manager passes explicitly always wins, so nothing stated here changes. Measured against the live 1.6 install, across all 23 tables the probe can build: 60 columns now carry a default where 29 did, and the 52 left bare are each bare for one of those three stated reasons. Every CREATE TABLE is still accepted by the server. The test stub gains a pass-through createTableSql(). It deliberately does not reimplement the rule: the real one only ADDS defaults, so a pass-through cannot mask an assertion about a default a manager sets deliberately -- which is what oidc-provider-safety checks -- and a copy of the rule would only give it somewhere to drift from. Requires fogproject FOG_PLUGINS_VERSION to be bumped to the release carrying this, and that release requires #1275. Co-Authored-By: Claude <noreply@anthropic.com>
This was referenced Aug 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Companion to fogproject #1275 (merged), which added the seam. GH-1245.
The problem
A column declared
NOT NULLwith noDEFAULTis only mandatory if something enforces it. For nine years nothing did —PDODBclearedsql_modeon every connection, so the server downgraded the error to a warning and substituted an implicit zero. Removing the clear turned every one of those declarations into a real constraint, and an INSERT that omits one now fails witherror 1364.FOG's schema step 348 repairs the tables an install already has. It cannot repair ours:
createSql()runs as step 0 of each plugin's ownschema(), so a plugin installed after the migration gets a table built the old way — every optional column mandatory again.The change
FOGManagerController::createTableSql()takes the identical arguments and fills a default into everyNOT NULLcolumn that has none, leaving bare only:ID— an INSERT that forgets the row it hangs off should fail, not make a silent orphan.A default a manager passes explicitly always wins, so nothing already stated here changes. 25 call sites, one token each.
Verification
Against the live 1.6 install (
prove_plugin_table_defaults_16.phpin the fogproject scripts calls every manager'screateSql(), creates the table under a scratch name, and reads the result back out ofinformation_schema):Each of the 52 is bare for one of the three stated reasons. Negative control — the wrapper filling nothing — puts 31 columns back to optional-and-still-mandatory.
WolbroadcastManagerbuilds its table insideinstall()rather thancreateSql(), so the probe can't call it; its call site is switched the same way and is covered by the new test.Tests
New
tests/tables-carry-column-defaults.test.php— asserts no manager callsSchema::createTable()directly and every table-builder goes through the wrapper. It strips comments first, because two managers mentionSchema::createTable()in prose explaining how it names its indexes. 49 checks; two mutations, two caught (a reverted manager, and a scan that reaches nothing).The stub gains a pass-through
createTableSql(). It deliberately does not reimplement the rule: the real one only adds defaults, so a pass-through cannot mask an assertion about a default a manager sets deliberately — which is exactly whatoidc-provider-safetychecks (opEnabled,opJITProvision,opAllowAPImust ship off) — and a copy of the rule would only give it somewhere to drift from.Suite: 8/8.
Shipping
Needs a release, and then
FOG_PLUGINS_VERSIONbumped in fogproject to match. fogproject #1275 is already merged, so the seam is present onworking-1.6.🤖 Generated with Claude Code