Manual ALTER TABLE Migration vs. Ti.Database.open Flags for Schema Upgrade
0 reputation · 01 Feb 2022, 13:11 UTC
0 reputation · 01 Feb 2022, 13:11 UTC
When upgrading a Titanium app’s SQLite database, the primary goal is to modify the schema while keeping all existing indexes and triggers intact, so that a rollback can be performed safely if needed.
Two documented methods exist: executing Ti.Database.execute('ALTER TABLE …') statements manually, and opening the database with flags such as Ti.Database.CREATE or Ti.Database.REPLACE. Manual migrations allow explicit rollback scripts, but the framework does not guarantee that indexes or triggers are recreated automatically. The CREATE flag preserves tables yet cannot change column types, while REPLACE drops the database entirely, discarding all data.
Because the behavior of ALTER TABLE with respect to indexes, triggers, and the order of multiple statements is undocumented across iOS and Android, the following questions remain unanswered:
Ti.Database.execute('ALTER TABLE …') automatically recreate all indexes and triggers on the affected table on both platforms?Ti.Database.open with Ti.Database.CREATE be used to apply a schema change without dropping indexes, or must indexes be recreated manually?33775 reputation · 01 Feb 2022, 23:36 UTC
1. Does a single Ti.Database.execute('ALTER TABLE …') automatically recreate all indexes and triggers on the affected table on both platforms?
No. A supported ALTER TABLE operation (e.g., ADD COLUMN, RENAME COLUMN) only changes the table definition. Indexes and triggers that are already attached to the table stay in place; they are not dropped or recreated automatically. However, if the migration script drops the table or recreates it, all associated indexes and triggers are lost unless they are explicitly recreated.
2. If not, what pattern should developers follow to preserve these objects during a schema upgrade?
Use a “copy‑and‑replace” migration pattern for changes that SQLite can’t express in a single ALTER statement (e.g., changing a column type). The steps are:
Ti.Database.execute('BEGIN TRANSACTION');Ti.Database.execute('CREATE TABLE new_table AS SELECT ...');Ti.Database.execute('INSERT INTO new_table SELECT ... FROM old_table');Ti.Database.execute('DROP TABLE old_table');Ti.Database.execute('ALTER TABLE new_table RENAME TO old_table');sqlite_master before dropping the table or maintain a versioned migration script that includes the DDL for each index/trigger.Ti.Database.execute('COMMIT');For simple ADD COLUMN or RENAME COLUMN operations where the table is not dropped, you can run the ALTER statements directly and then verify that sqlite_master still lists the indexes and triggers.
3. Can Ti.Database.open with Ti.Database.CREATE be used to apply a schema change without dropping indexes, or must indexes be recreated manually?
The Ti.Database.CREATE flag only ensures that the database file exists; it does not run any migration logic or modify the existing schema. If you need to change the schema, you must execute ALTER TABLE or use a migration script as described above. The flag does not preserve or recreate indexes automatically; you will still need to recreate them if the underlying table is dropped or recreated.
// Verify indexes/triggers after an ALTER
Ti.Database.execute('ALTER TABLE myTable ADD COLUMN newCol TEXT');
var rows = Ti.Database.execute(
"SELECT name, sql FROM sqlite_master WHERE type IN ('index','trigger') AND tbl_name='myTable'"
);
while (rows.isValidRow()) {
Ti.API.info('Object: ' + rows.fieldByName('name') + ' SQL: ' + rows.fieldByName('sql'));
rows.next();
}
rows.close();
Running the above after an ALTER confirms whether the indexes/triggers still exist. If you drop and recreate a table, run the same query to see that they are missing and need to be recreated.
To tailor the migration script to your exact needs, could you share the current number of indexes and triggers on the table you plan to modify? That will help us generate the exact DDL needed to recreate them after a table replacement.
Use comments to ask for clarification. Post a solution as an answer.
33,775 reputation · 02 Feb 2022, 01:09 UTC
In SQLite, ALTER TABLE … RENAME COLUMN … not only changes the column name but also automatically updates any indexes, triggers, or views that reference the old column name, so those objects remain valid after the statement. This behavior mirrors the automatic renaming of dependent objects seen with ALTER TABLE … RENAME TO …. Therefore, when a migration only needs to rename a column, you can rely on the framework to preserve indexes and triggers without extra steps, provided you do not drop and recreate the table.