Skip to content

Conversation

@myndzi
Copy link
Collaborator

@myndzi myndzi commented Nov 15, 2025

Fixes #4070, #6074

Clauses such as "HAVING" and "WHERE" have no effect on "DELETE" or "TRUNCATE" statements. Due to the architecture of knex, dialects override various base methods for building specific statements. The methods implementing these statements don't explicitly check for the presence of clauses that a user might expect to have an effect, but there isn't a good place to ensure that such queries fail systematically.

This commit introduces a "_preValidate" method on the root QueryCompiler class and a set of disallowed verb/clause combinations that will throw an error before doing any SQL-building work. This should make it consistent to prevent anything like knex.having(...).del() from unintentionally deleting all rows.

The current configuration disallows "HAVING" from "DELETE" statements, and both "WHERE" and "HAVING" from "TRUNCATE" statements.

Update:
Now also rejects "LIMIT" from "DELETE" and "TRUNCATE"

DRI:@myndzi

@myndzi
Copy link
Collaborator Author

myndzi commented Nov 15, 2025

r? @mercmobily

@coveralls
Copy link

coveralls commented Nov 15, 2025

Coverage Status

coverage: 93.095% (+0.02%) from 93.076%
when pulling 1f51849 on myndzi:myndzi/issue-4070/fail-delete-having
into c92bbb3 on knex:master.

@myndzi myndzi force-pushed the myndzi/issue-4070/fail-delete-having branch from b8b071a to 802b2b6 Compare November 18, 2025 15:30
@myndzi
Copy link
Collaborator Author

myndzi commented Nov 19, 2025

(This needs a re-run of the one CI task - it failed on a network error updating coveralls)

// here is intentionally not complete; it's just checking the things that allow users
// to make dangerous errors.
const invalid = invalidClauses[verb];
for (let i = 0; i < invalid.length; i++) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not use for of?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Combination of:

  • presuming it's a hot path, so avoiding extra garbage and/or cpu overhead generated by the iterator protocol
  • this loop pattern is generally so recognizable that I don't expect it to be a legibility disadvantage

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me know if you'd prefer I changed this

Copy link
Collaborator

@kibertoad kibertoad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this behaviour needs to be documented

… executing

Fixes knex#4070

Clauses such as "HAVING" and "WHERE" have no effect on "DELETE" or "TRUNCATE"
statements. Due to the architecture of knex, dialects override various
base methods for building specific statements. The methods implementing
these statements don't explicitly check for the presence of clauses that
a user might expect to have an effect, but there isn't a good place to ensure
that such queries fail systematically.

This commit introduces a "_preValidate" method on the root QueryCompiler class
and a set of disallowed verb/clause combinations that will throw an error before
doing any SQL-building work. This should make it consistent to prevent anything
like `knex.having(...).del()` from unintentionally deleting all rows.

The current configuration disallows "HAVING" from "DELETE" statements, and
both "WHERE" and "HAVING" from "TRUNCATE" statements.
sqlite and mssql technically support these, but support is not
implemented in knex yet
- Move delete + limit test to unit test
- Consolidate "invalid combination" tests
- Also exercise "implied" where/having
@myndzi myndzi force-pushed the myndzi/issue-4070/fail-delete-having branch from e7f575f to 1f51849 Compare December 12, 2025 19:18
@myndzi
Copy link
Collaborator Author

myndzi commented Dec 12, 2025

(rebased onto master)

@kibertoad kibertoad merged commit 2c230b5 into knex:master Dec 23, 2025
44 checks passed
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.

knex('table').having({ field: 'value' }).del() silently deletes ALL rows!

4 participants