Skip to content

.limit() silently dropped on delete requests. #798

Description

@torinmr

Describe the issue

Fluent allows .limit() on delete operations and silently drops them from the Postgres query

Vapor version

4.12.0

Operating system and version

macOS 26.4.1

Swift version

Swift Package Manager - Swift 6.3.1

Steps to reproduce

Here is code from our application which triggered this issue:

let query = DomainResultModel.query(on: db)
    .filter(\.$runTime < date)
    .limit(1000)

let numToDelete = try await query.count()
span.attributes["numDeleted"] = numToDelete
try await query.delete()

Outcome

Reading the code, it looks like it should issue a delete of up to 1000 items.
Or, given that Postgres doesn't support limited deletes, I would expect the delete query to fail with a syntax error.
In reality, it issued an unlimited delete statement: DELETE FROM domain_results WHERE date < $1

Additional notes

Postgres does not support LIMIT on DELETE statements, so DELETE FROM mytable WHERE date < $1 LIMIT 100 is invalid syntax.

However, Fluent is happy to let you write: MyModel.query().filter(\.date < date).limit(100).delete()

Which will actually issue the query `DELETE FROM mytable WHERE date < $1 ', which can take an arbitrary amount of time and use arbitrary Postgres resources.

I had code in my app that did a periodic cleanup of stale data, with a limit to avoid doing large deletes in one go and bogging down the application. However, unbeknownst to me it was actually doing an unlimited DELETE statement. When I reduced the retention period on my data, this caused it to try to delete millions of rows at once, freezing my app and bogging down Postgres.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions