Skip to content

table.upsert/upsert_all fails to write row when not_null is absent and the schema definition includes not_null #610

Open
@alexwlchan

Description

@alexwlchan

I found a bug where calls to upsert() and upsert_all() don't write rows if:

  1. There's a not_null kwarg on the table definition, and
  2. You don't pass not_null in the upsert() call

This doesn't affect insert() or insert_all().

Repro example

from sqlite_utils import Database

db = Database(":memory:")

db["birds"].create(
    {"id": int, "name": str},
    pk="id",
    not_null={"name"},
)

db["birds"].insert({"id": 1, "name": "flamingo"})
print("insert:               ", len(list(db["birds"].rows)))

db["birds"].insert({"id": 2, "name": "goldfinch"}, not_null={"name"})
print("insert, not_null:     ", len(list(db["birds"].rows)))

db["birds"].upsert({"id": 3, "name": "loon"}, pk="id")
print("upsert:               ", len(list(db["birds"].rows)))

db["birds"].upsert({"id": 4, "name": "stork"}, pk="id", not_null={"name"})
print("upsert, not_null:     ", len(list(db["birds"].rows)))

db["birds"].insert_all([{"id": 5, "name": "magpie"}])
print("insert_all:           ", len(list(db["birds"].rows)))

db["birds"].insert_all([{"id": 6, "name": "gull"}], not_null={"name"})
print("insert_all, not_null: ", len(list(db["birds"].rows)))

db["birds"].upsert_all([{"id": 7, "name": "dodo"}], pk="id")
print("upsert_all:           ", len(list(db["birds"].rows)))

db["birds"].upsert_all([{"id": 8, "name": "crow"}], pk="id", not_null={"name"})
print("upsert_all, not_null: ", len(list(db["birds"].rows)))

Here's the output (with my comments on the right)

sqlite-utils, version 3.36
insert:                1
insert, not_null:      2
upsert:                2    <-- no write
upsert, not_null:      3
insert_all:            4
insert_all, not_null:  5
upsert_all:            5    <-- no write
upsert_all, not_null:  6

So calling upsert() and upsert_all() without passing not_null isn't actually inserting a record.

This problem goes away if:

  • I add the not_null argument to the upsert() calls, or
  • Remove the not_null from the table definition

Version info

  • Python: 3.12.0
  • sqlite-utils: 3.36
  • sqlite: 3.39.5 2022-10-14

Related issues

It seems very likely that this is related to #538, which was also about upsert() and the not_null flag.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions