Repository navigation
Description
What happened?
When a SQL Server table has no primary key and its entity doesn't configure source.key-fields, DAB uses the key that FillSchema infers. That key is made of the columns SQL Server reports as key columns (CommandBehavior.KeyInfo). For a table without a primary key, SQL Server reports the columns of a unique index, even when that index is disabled.
A disabled index doesn't enforce uniqueness, so DAB can treat columns that hold duplicate values as the primary key. Requests by key then read or change the wrong number of rows.
Steps to reproduce
CREATE TABLE dbo.Product (code int NOT NULL, name nvarchar(50) NOT NULL); -- no primary key
CREATE UNIQUE INDEX ux_code ON dbo.Product(code);
ALTER INDEX ux_code ON dbo.Product DISABLE;
INSERT dbo.Product VALUES (1, N'Widget'), (1, N'Gadget'), (2, N'Gizmo');dab init --database-type mssql --connection-string "<connection string>" --host-mode development
dab add Product --source dbo.Product --source.type table --permissions "anonymous:*"
dab startDAB starts and logs Primary key column name: code. Then:
| Request | Result |
|---|---|
GET /api/Product/code/1 |
200 with only Widget; Gadget isn't returned. |
PATCH /api/Product/code/1 with {"name":"Patched"} |
201 Created: DAB inserts a third row with code = 1 instead of updating. The upsert updates only when exactly one row matches (IF @ROWS_TO_UPDATE = 1). |
DELETE /api/Product/code/1 |
204, and all three rows with code = 1 are deleted. |
Expected behavior
DAB shouldn't infer a key from an index that doesn't enforce uniqueness. If a table has no primary key and no enabled unique index, startup should fail with Primary key not configured on the given database object, so source.key-fields is required. That's what already happens for a table without any key.
Notes
-
Checked on SQL Server 2025 (LocalDB), using tables with no primary key and one unique index each:
Unique index Reported as key ( IsKey)FillSchemaprimary keyRegular codecodeHypothetical none none Filtered none none Disabled codecode -
This isn't new: every table goes through
FillSchema. It came up while reviewing Skip unsupported column data types during schema discovery #3802, whose fallback for tablesFillSchemacan't read infers keys the same way. -
A check at startup can't catch an index that is disabled after DAB starts, so a warning or documentation may be part of the fix.
-
Workaround: rebuild the index (
ALTER INDEX ux_code ON dbo.Product REBUILD), add a primary key, or configuresource.key-fieldswith columns that are unique.
Version
Reproduced on a local 2.1.0 build. The table above doesn't reach #3802's changes, so this is main's behavior.
What database are you using?
Azure SQL / SQL Server
Activity