insert: don't crash on header-only CSV with --detect-types

When the input has a header but no data rows, the insert path never
creates the table - the row loop has nothing to feed into the first
insert. The post-insert tracker.transform call then asserts the table
exists and blows up:

    AssertionError: Cannot transform a table that doesn't exist yet

Reported in #702 with the exact fix in the body. Guard the transform
on db[table].exists() so an empty CSV is just a no-op, matching what
--detect-types already does for a zero-byte CSV (no header either).

Closes #702.

Signed-off-by: Charlie Tonneslan <cst0520@gmail.com>
This commit is contained in:
Charlie Tonneslan 2026-05-17 19:54:45 -04:00
commit 33cab5e4ff
2 changed files with 21 additions and 1 deletions

View file

@ -1175,7 +1175,10 @@ def insert_upsert_implementation(
) )
else: else:
raise raise
if tracker is not None: # An empty CSV (header row but no data rows) never creates the table,
# so there's nothing to transform. Without this guard, --detect-types
# crashes on header-only input (see #702).
if tracker is not None and db[table].exists():
db.table(table).transform(types=tracker.types) db.table(table).transform(types=tracker.types)
# Clean up open file-like objects # Clean up open file-like objects

View file

@ -2318,6 +2318,23 @@ def test_upsert_detect_types(tmpdir, option):
] ]
@pytest.mark.parametrize("option", ("-d", "--detect-types"))
def test_insert_csv_header_only_with_detect_types(tmpdir, option):
"""Header-only CSVs (no data rows) used to crash --detect-types because
the transform step ran against a table that was never created. Now we
skip transform when there's nothing to transform. (#702)"""
db_path = str(tmpdir / "test.db")
result = CliRunner().invoke(
cli.cli,
["insert", db_path, "empty", "-", "--csv", option],
catch_exceptions=False,
input="name,age,weight\n",
)
assert result.exit_code == 0
db = Database(db_path)
assert "empty" not in db.table_names()
def test_csv_detect_types_creates_real_columns(tmpdir): def test_csv_detect_types_creates_real_columns(tmpdir):
"""Test that CSV import creates REAL columns for floats (default behavior)""" """Test that CSV import creates REAL columns for floats (default behavior)"""
db_path = str(tmpdir / "test.db") db_path = str(tmpdir / "test.db")