Skip to content

fix(database): flip adapter hardener S2 S6 S8 S12-S16 - #3419

Merged
bpamiri merged 6 commits into
developfrom
cursor/database-adapters-hardener-s1-s18-1a78
Aug 25, 2026
Merged

fix(database): flip adapter hardener S2 S6 S8 S12-S16#3419
bpamiri merged 6 commits into
developfrom
cursor/database-adapters-hardener-s1-s18-1a78

Conversation

@bpamiri

@bpamiri bpamiri commented Aug 25, 2026

Copy link
Copy Markdown
Collaborator

Why

Peter superseded the HOLD lock on PR #3419, then requested changes at 2c969baa: S2 no-coerce blasted validatesUniquenessOf_with_absent_scope_property (cannot cast [NULL] string to a number). Keep S2. Distinguish the literal string "null" from a missing value.

Scope

In: vendor/wheels/databaseAdapters/ plus the specs that own those adapters (vendor/wheels/tests/specs/database/). $addWhereClauseParameters marks the unquoted SQL keyword NULL as null=true with a dummy value. $queryParams binds CFML/Java null as SQL NULL. $buildWhereClausePart treats a Java-null property like absent. ForeignKeyDefinition.$appendReferentialActions shares $referentialActionSQL. addColumnOptionsSpec follows the S6/S14 contract. Migrator fixtures that passed default="" on string columns omit that argument.

Out: second PR, channel DatabaseAdapter, engineAdapters, CLI, closer keywords.

Base tip: 804573157939475fc0fafe6a9713979eab28d9c7 (develop after #3418).

Tradeoffs

S14 contract (named): Wheels.InvalidDefault. Both Abstract and PostgreSQL throw when default="" is applied to string / text / char.

S2: the quoted literal 'null' after IS / IS NOT stays a bound string. The unquoted keyword NULL (and a CFML/Java null) bind as SQL NULL so an absent uniqueness-scope integer does not send [NULL] to cfqueryparam.

S13 known values stay: none → NO ACTION, null → SET NULL, cascade / true → CASCADE. Unknown values throw Wheels.InvalidReferentialAction.

S16 identity must use the real sequence / driver-key / same-batch SCOPE_IDENTITY path or throw Wheels.IdentityNotFound.

Blast Radius

  • Bound literal "null" after IS / IS NOT stays a parameter (no string coerce)
  • Unquoted IS NULL / absent / Java null bind as SQL NULL
  • MySQL TEXT/float DEFAULT is emitted
  • Boolean yes / no are quoted
  • SQLite $supportsAdvisoryLocks is false
  • Unknown FK actions throw
  • Empty string defaults throw
  • Unmapped $getType throws Wheels.UnknownColumnType on every adapter
  • Oracle MAX(ROWID) and MSSQL @@IDENTITY last-resort are gone

PROVEN

ID Status One line
S1 PROVEN $quoteValue throws Wheels.InvalidValue for "0 OR 1=1" and "maybe"
S2 PROVEN Quoted 'null' after IS / IS NOT stays a bound string; $executeQuery does not coerce that string. Unquoted NULL / Java null bind as SQL NULL
S3 PROVEN $getColumns cache catch(any) falls through to a fresh catalog lookup
S4 PROVEN MySQL / H2 / PostgreSQL / SQLite identity unit specs
S5 PROVEN Oracle $identitySequenceName catch(any) returns ""
S6 PROVEN MySQL optionsIncludeDefault emits TEXT/float DEFAULT. Abstract stays always-true
S7 PROVEN Cockroach CrudSpec uses toBeLTE and always-run order/pagination asserts
S8 PROVEN $quoteValue quotes boolean yes / no
S9 PROVEN addColumnOptions quotes AFTER through quoteColumnName
S10 PROVEN CRDB TransactionSpec commit persists data now commits and deletes the row
S11 PROVEN TypeSpec asserts real cf_sql_* types
S12 PROVEN SQLite $supportsAdvisoryLocks is false. acquire stays a no-op and is unused
S13 PROVEN foreignKeySQL unknown onUpdate/onDelete throws Wheels.InvalidReferentialAction
S14 PROVEN Abstract and PostgreSQL throw Wheels.InvalidDefault for default="" on string-like columns
S15 PROVEN Unmapped $getType throws Wheels.UnknownColumnType on PG / SQLite / MySQL / H2 / Oracle / MSSQL
S16 PROVEN Oracle MAX(ROWID) and MSSQL @@IDENTITY last-resort dropped; miss throws Wheels.IdentityNotFound
S17 PROVEN MSSQL quoteTableName("dbo.users") is [schema].[table], no backticks
S18 PROVEN Oracle createTable uses local.col / local.fk

Verification

Commands actually run:

wheels test --core --ci --filter=database
wheels test --core --ci --filter=model

GREEN database (4ca43b796a5a6402099f60e43fcf8be271199694):

105 passed, 0 failed, 0 error, 0 skipped
bundlesDiscovered=13
totalSpecs=105
directoryRejected=false
directoryRequested=wheels.tests.specs.database
Lucee 7.0.0.395 / sqlite

GREEN model:

979 passed, 0 failed, 0 error
totalSpecs=994
directoryRequested=wheels.tests.specs.model

validatesUniquenessOf_with_absent_scope_property: Passed.

Adobe and BoxLang were not run here.

HEAD

4ca43b796a5a6402099f60e43fcf8be271199694

No closer keywords. Do not merge.

Open in Web Open in Cursor 

Quote AFTER, fix MSSQL schema.table brackets, and scope Oracle
createTable loops. HOLD pins stay unflipped.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Peter Amiri <peter@alurium.com>
cursoragent and others added 2 commits August 25, 2026 12:55
$whereClause leaves the sql structs without values. The string null
lands in $addWhereClauseParameters, which is the input $executeQuery
reads after IS / IS NOT.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Peter Amiri <peter@alurium.com>
Keep the bound string null after IS/IS NOT. Emit MySQL TEXT/float
DEFAULT. Quote boolean yes/no. SQLite advisory locks unsupported.
Unknown foreign-key actions throw. Empty string defaults throw
Wheels.InvalidDefault. Unmapped $getType throws everywhere. Drop
Oracle MAX(ROWID) and MSSQL @@IDENTITY last-resort.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Peter Amiri <peter@alurium.com>
@cursor cursor Bot changed the title test(database): pin adapter hardener S1-S18 fix(database): flip adapter hardener S2 S6 S8 S12-S16 Aug 25, 2026
cursoragent and others added 3 commits August 25, 2026 13:46
S14 throws Wheels.InvalidDefault for default="" on string columns.
Fixtures meant "no default clause"; omit the argument instead.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Peter Amiri <peter@alurium.com>
Keep the literal string "null" after IS / IS NOT as a bound parameter.
Mark the unquoted NULL keyword and CFML/Java null as SQL NULL so an
absent uniqueness-scope property does not cast [NULL] to a number.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Peter Amiri <peter@alurium.com>
Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Peter Amiri <peter@alurium.com>
@bpamiri
bpamiri marked this pull request as ready for review August 25, 2026 14:04
@bpamiri
bpamiri merged commit bb9fa68 into develop Aug 25, 2026
14 checks passed
@bpamiri
bpamiri deleted the cursor/database-adapters-hardener-s1-s18-1a78 branch August 25, 2026 14:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants