diff --git a/sqlite_utils/db.py b/sqlite_utils/db.py index 2005210..38e95c7 100644 --- a/sqlite_utils/db.py +++ b/sqlite_utils/db.py @@ -3179,6 +3179,20 @@ class Table(Queryable): return a list of ``(sql, parameters)`` 2-tuples which, when executed in order, perform the desired INSERT / UPSERT / REPLACE operation. """ + # Dict-mode insert({}) has no explicit columns; SQLite spells that as + # DEFAULT VALUES. List mode with no columns is a different input shape. + if not list_mode and not all_columns: + or_clause = "" + if replace: + or_clause = " OR REPLACE" + elif ignore: + or_clause = " OR IGNORE" + sql = ( + f"INSERT{or_clause} INTO {quote_identifier(self.name)} " + "DEFAULT VALUES" + ) + return [(sql, []) for _ in chunk] + if hash_id_columns and hash_id is None: hash_id = "id" @@ -3603,7 +3617,11 @@ class Table(Queryable): assert ( num_columns <= SQLITE_MAX_VARS ), "Rows can have a maximum of {} columns".format(SQLITE_MAX_VARS) - batch_size = max(1, min(batch_size, SQLITE_MAX_VARS // num_columns)) + batch_size = ( + 1 + if num_columns == 0 + else max(1, min(batch_size, SQLITE_MAX_VARS // num_columns)) + ) self.last_rowid = None self.last_pk = None if truncate and self.exists(): diff --git a/tests/test_default_value.py b/tests/test_default_value.py index c594c9f..c5e4b17 100644 --- a/tests/test_default_value.py +++ b/tests/test_default_value.py @@ -31,3 +31,24 @@ def test_quote_default_value(fresh_db, column_def, initial_value, expected_value assert expected_value == fresh_db.quote_default_value( fresh_db["foo"].columns[0].default_value ) + + +def test_insert_empty_record_uses_default_values(fresh_db): + fresh_db.execute(""" + CREATE TABLE has_defaults ( + id INTEGER PRIMARY KEY, + name TEXT, + timestamp TEXT DEFAULT CURRENT_TIMESTAMP, + is_active INTEGER NOT NULL DEFAULT 1 + ) + """) + + table = fresh_db["has_defaults"] + table.insert({}) + + rows = list(table.rows) + assert len(rows) == 1 + assert rows[0]["id"] == 1 + assert rows[0]["name"] is None + assert rows[0]["timestamp"] is not None + assert rows[0]["is_active"] == 1