SQLite 3.35.5 repairs the row rewrite behind DROP COLUMN
The April patch fixes DROP COLUMN defects that could corrupt a database. The implementation shows why removing a field involves both schema validation and stored-record reconstruction.
Removing a column changes more than a table declaration. SQLite has to keep each surviving field in its correct place when it reconstructs stored records. The April 19 release of SQLite 3.35.5 fixes defects in the new ALTER TABLE DROP COLUMN implementation that could corrupt the database file. That makes this maintenance release directly relevant to applications adopting the schema operation introduced in March.
The release notes do not give one universal SQL trigger for the corruption defects. They also do not say that installing the patch repairs damage left by an earlier operation. The claim is a correction to the implementation. Understanding the scope requires looking at the released code and tests without inventing a broader recovery guarantee.
I regard a database migration as an operation on stored data, even when the SQL fits on one line. SQLite's appeal as an embedded engine makes that responsibility more immediate for the application owning the file. This patch is a reason to distinguish support for the syntax from the exact engine revision carrying it out.
Schema editing and record editing are separate work
The 3.35.5 implementation of DROP COLUMN starts by locating the table and column. It rejects tables that cannot be altered through this operation. It also refuses to remove a primary-key or unique column, and prevents a table from losing its final column. Those checks happen before the code generates the stored-row rewrite.
Next, the implementation edits the table's SQL in sqlite_schema, reloads the schema, and validates it again. This sequence matters because removing a column can leave other definitions referring to a name that no longer exists. A syntactically short alteration still has consequences for the rest of the schema.
Only after those stages does the function generate instructions to edit rows on disk. For a column that is not virtual, it opens the table for writing and iterates its records. It gathers the surviving fields, makes a replacement record, and inserts that record through the appropriate table representation. The loop explicitly skips the removed column and virtual columns.
This explains why the corruption warning concerns file contents rather than only an incorrect schema string. A successful-looking declaration is insufficient evidence that every stored record has the intended fields. The implementation must preserve the association between logical columns and the values encoded in each record.
Rowid and WITHOUT ROWID use different reconstruction paths
The code branches according to whether the table has a rowid. In the rowid path, it retrieves the row identifier and later uses OP_Insert for the replacement. For a WITHOUT ROWID table, it obtains the primary-key index, copies the key fields, and ultimately uses OP_IdxInsert. Surviving values have to occupy the right record positions in both arrangements.
The WITHOUT ROWID branch maps table-column positions into index positions. It accounts for the position of the removed field while assigning registers for the remaining fields. A logical operation such as dropping the third declared column therefore depends on the physical representation of the table. Reading the declaration alone does not describe the complete rewrite.
The release-tagged regression tests include an April case with a WITHOUT ROWID table whose primary-key declaration repeats a column with a collation. The test removes another column and checks both the resulting declaration and the surviving values. That case exercises an unusual schema shape through the actual alteration operation.
Another test inserts 50,000 rows, removes the middle column, and groups the surviving data by its retained value. It expects all 50,000 rows with that value intact. The suite runs this case for both ordinary and WITHOUT ROWID tables. These are test expectations from the release source, not performance measurements or a claim about every possible database.
A concrete migration includes the values that remain
The following example uses the basic operation covered by the tests. Its purpose is to make the expected retained data explicit, without presenting it as a reproduction of every corruption defect fixed in April.
CREATE TABLE sample (
id INTEGER PRIMARY KEY,
obsolete TEXT,
retained INTEGER
);
INSERT INTO sample VALUES (1, 'remove', 456);
INSERT INTO sample VALUES (2, 'remove-too', 456);
ALTER TABLE sample DROP COLUMN obsolete;
SELECT id, retained FROM sample ORDER BY id;
The intended result retains identifiers 1 and 2, each associated with 456. Checking only that obsolete has disappeared would leave half the migration's meaning unexamined. The tagged tests follow the same principle by reading values after the alteration, including cases where the table representation differs.
Dependencies remain relevant after this fix. The suite still rejects removal of an indexed column when its index definition would refer to the missing name. It rejects a table-level check that retains a reference to the removed column as well. Correct row reconstruction does not make invalid dependent definitions acceptable.
The patch has a specific place in the March release family
The 3.35.4 notes from April 2 document a different set of corrections, including RETURNING behavior and an optimization involving EXISTS. The April 19 page carries those earlier changes forward, but labels them separately from the fixes specific to 3.35.5. A reader should not infer that every item on the cumulative page first appeared in the later patch.
The same cumulative history records an earlier DROP COLUMN correction involving quoted indexed-column names in 3.35.1. April's corruption warning is therefore a new maintenance item within a recently introduced feature, not merely another description of that earlier quoting fix. The public notes distinguish their scope even though both involve column removal.
I prefer the explicit engine revision in an upgrade explanation because it identifies the implementation of the migration. An application moving within the 3.35 family already has the SQL syntax. What it gains here is a corrected implementation of an operation that can rewrite its data file.
The April patch also fixes an obscure optimizer problem that could yield an incorrect result. Its release notes give no detailed query shape for that item, so it warrants no invented example. For column removal, the source provides more concrete evidence, separate schema validation, representation-specific reconstruction, and regression checks on surviving row values are all part of the operation corrected in this release.