Ensure primary keys created via the JSON API are NOT NULL

The table-create JSON API built its own CREATE TABLE without marking
primary key columns NOT NULL, so a text or composite primary key could
be created nullable. SQLite then allows rows with a NULL primary key,
which cannot be viewed, edited or deleted. Force primary key columns
NOT NULL, leaving a lone integer primary key alone since it aliases the
rowid and is never NULL.

Refs #2807

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Pranav Mishra 2026-07-07 13:46:16 -07:00
commit 3956e63650
2 changed files with 73 additions and 1 deletions

View file

@ -2296,6 +2296,63 @@ async def test_create_table_with_column_constraints(ds_write):
assert columns[4]["dflt_value"] == "'hello)'"
@pytest.mark.asyncio
async def test_create_table_primary_keys_are_not_null(ds_write):
# Primary keys created via the JSON API must be NOT NULL - see #2807
token = write_token(ds_write)
db = ds_write.get_database("data")
# Single (non-integer) primary key
response = await ds_write.client.post(
"/data/-/create",
json={
"table": "pk_single",
"columns": [
{"name": "code", "type": "text"},
{"name": "name", "type": "text"},
],
"pk": "code",
},
headers=_headers(token),
)
assert response.status_code == 201, response.text
assert "PRIMARY KEY NOT NULL" in response.json()["schema"]
columns = {
column["name"]: column
for column in (
await db.execute("select * from pragma_table_info('pk_single')")
).dicts()
}
assert columns["code"]["pk"] == 1
assert columns["code"]["notnull"] == 1
assert columns["name"]["notnull"] == 0
# Composite primary key - every key column is NOT NULL
response = await ds_write.client.post(
"/data/-/create",
json={
"table": "pk_composite",
"columns": [
{"name": "a", "type": "text"},
{"name": "b", "type": "text"},
{"name": "value", "type": "text"},
],
"pks": ["a", "b"],
},
headers=_headers(token),
)
assert response.status_code == 201, response.text
columns = {
column["name"]: column
for column in (
await db.execute("select * from pragma_table_info('pk_composite')")
).dicts()
}
assert columns["a"]["notnull"] == 1
assert columns["b"]["notnull"] == 1
assert columns["value"]["notnull"] == 0
@pytest.mark.asyncio
@pytest.mark.parametrize(
"default_expr,minimum_value,expected_schema",