SQLIte DROP table ROLL back - android

In Android SQLite I had one table MyTable. By mistake I dropped it after upgrade the DB.
How can I ROLL BACK that dropped table if it's possible.
Any good answer will be accepted.
Thanks.

Dropping tables is not a recoverable action, unless performed as part of a transaction that is rolled back (which appears to be not the scenario for your particular case).
From the SQLite documentation:
The DROP TABLE statement removes a table added with the CREATE TABLE statement. The name specified is the table name.
The dropped table is completely removed from the database schema and the disk file. The table can not be recovered. All indices and triggers associated with the table are also deleted.
That's not quite the complete picture, as the behaviour under rolled-back transaction can be seen with (tested on https://sqliteonline.com/):
drop table if exists paxtable;
create table paxtable (paxcolumn integer);
insert into paxtable values (42);
begin transaction;
drop table paxtable;
rollback;
select paxcolumn from paxtable;
That shows that the table still exists after the rollback. If you commit rather than roll back (or if you remove the transactional control altogether), the table has died, expired, gone to meet its maker, shuffled off this mortal coil, <insert your favourite metaphor here>.
So, since you didn't do it as part of a rolled-back transaction (as evidenced by the fact the table has actually gone), you'll need to re-create it from scratch (or from backups if possible).

CLARIFICATION:
Although you can commit or rollback DML statements like "insert" or "delete" (provided you do it within a transaction), in general you cannot rollback a DDL statement like "alter table" or "drop table".
This is true for most databases under most circumstances: Oracle, MSSQL, mySQL, etc.
There is an exception for sqlite: if you drop table in a transaction, then a rollback will restore that table.
Otherwise (per the sqlite manual):
http://sqlite.org/lang_droptable.html
The DROP TABLE statement removes a table added with the CREATE TABLE
statement. The name specified is the table name. The dropped table is
completely removed from the database schema and the disk file. The
table can not be recovered. All indices and triggers associated with
the table are also deleted.
PS:
This link discusses "DDL", "DML" and related acronyms, if you're interested:
http://www.orafaq.com/faq/what_are_the_difference_between_ddl_dml_and_dcl_commands

I think there's two different interpretations of this question and I want to make sure both get answered and demonstrated conclusively since this is still the top search result for sqlite drop table rollback (and the links to the SQLite documentation seems misleading as well).
To the first question, you can rollback a drop table DDL action that occurs within a transaction scope, i.e.,
// with connection created
var transaction = connection.BeginTransaction();
try {
// create a table
// drop a different table
transaction.Commit(); // go ahead and commit if everything is successfully
}
catch
{
transaction.Rollback(); // rollback in case of error
}
And to confirm this is the same behavior in a language-agnostic fashion, here's the same behavior using the SQ Lite command-line shell:
sqlite3 demo
// outside transaction scope
create table tbl1( col varchar(10));
// list the current tables
.tables
// start a transaction that wraps both your DDL commands
begin transaction;
enter code here
create table tbl2 (col varchar(10));
drop table tbl1;
rollback;
.tables
The expectation is that the final list tables command, should still return tbl1 since both the create table and drop table commands were both rolled back. Another way to say this is that SQLite is not bound by the same DML/DDL distinction for what operations can be rolled back that are present in Oracle.
For the second interpretation of the question, i.e., can I recover a table dropped outside of a transaction scope (which would also entail the "Oh S#%T" experience you may have had as a developer as well as disaster recovery), the references to the SQ Lite documentation are appropriate:
The dropped table is completely removed from the database schema and the disk file. The table can not be recovered. All indices and triggers associated with the table are also deleted.

Related

How do SQLite transactions on Android work?

My understanding of SQLite transactions on Android is based largely on this article. In its gist it suggests that
if you do not wrap calls to SQLite in an explicit transaction it will
create an implicit transaction for you. A consequence of these
implicit transactions is a loss of speed
.
That observation is correct - I started using transactions to fix just that issue:speed. In my own Android app I use a number of rather complex SQLite tables to store JSON data which I manipulate via the SQLite JSON1 extension - I use SQLCipher which has JSON1 built in.
At any given time I have to manipulate - insert, update or delete - rows in several tables. Given the complexity of the JSON I do this with the help of temporary tables I create for each table manipulation. The start of the manipulation begins with SQL along the lines of
DROP TABLE IF EXISTS h1;
CREATE TEMP TABLE h1(v1 TEXT,v2 TEXT,v3 TEXT,v4 TEXT,v5 TEXT);
Some tables require just one table - which I usually call h1 - others need two in which case I call them h1 and h2.
The entire sequence of operations in any single set of manipulations takes the form
begin transaction
manipulate Table 1 which
which creates its own temp tables, h1[h2],
then extracts relevant existing JSON from Table 1 into the temps
manipulates h1[h2]
performs inserts, updates, deletes in Table 1
on to the next table, Table 2 where the same sequence is repeated
continue with a variable list of such tables - never more than 5
end transaction
My questions
does this sound like an efficient way to do things or would it be better to wrap each individual table operation in its own transaction?
it is not clear to me what happens to my DROP TABLE/CREATE TEMP TABLE calls. If I end up with h1[h2] temp tables that are pre-populated with data from manipulating Table(n - 1) when working with Table(n) then the updates on Table(n) will go totally wrong. I am assuming that the DROP TABLE bit I have is taking care of this issue. Am I right in assuming this?
I have to admit to not being an expert with SQL, even less so with SQLite and quite a newbie when it comes to using transactions. The SQLite JSON extension is very powerful but introduces a whole new level of complexity when manipulating data.
The main reason to use transactions is to reduce the overheads of writing to the disk.
So if you don't wrap multiple changes (inserts, deletes and updates) in a transaction then each will result in the database being written to disk and the overheads involved.
If you wrap them in a transaction and the in-memory version will be written only when the transaction is completed (note that if using the SQLiteDatabase beginTransaction/endTransaction methods, that you should, as part of ending the transaction use the setTransactionSuccessful method and then use the endTransaction method).
That is, the SQLiteDatabase method are is different to doing this via pure SQL when you'd begin the transaction and then end/commit it/them (i.e. the SQLiteDatabase methods would otherwise automatically rollback the transactions).
Saying that the statement :-
if you do not wrap calls to SQLite in an explicit transaction it will
create an implicit transaction for you. A consequence of these
implicit transactions is a loss of speed
basically reiterates :-
Any command that changes the database (basically, any SQL command
other than SELECT) will automatically start a transaction if one is
not already in effect. Automatically started transactions are
committed when the last query finishes.
SQL As Understood By SQLite - BEGIN TRANSACTION i.e. it's not Android specific.
does this sound like an efficient way to do things or would it be
better to wrap each individual table operation in its own transaction?
Doing all the operations in a single transaction will be more efficient as there is just the single write to disk operation.
it is not clear to me what happens to my DROP TABLE/CREATE TEMP TABLE
calls. If I end up with h1[h2] temp tables that are pre-populated with
data from manipulating Table(n - 1) when working with Table(n) then
the updates on Table(n) will go totally wrong. I am assuming that the
DROP TABLE bit I have is taking care of this issue. Am I right in
assuming this?
Dropping the tables will ensure data integrity (i.e. you should, by the sound of it, do this), you could also use :-
CREATE TEMP TABLE IF NOT EXISTS h1(v1 TEXT,v2 TEXT,v3 TEXT,v4 TEXT,v5 TEXT);
DELETE FROM h1;

SQLiteLog Accessing the log or piping it out [Android]

Is there a way to access the SQLiteLog or at least pipe out errors to do with SQLite?
I would like to automatically send any errors, like the below, so I can optimise the database by adding in indexes, or making other changes as need be.
E/SQLiteLog: (284) automatic index on messages(chat_id)
It could well be that I'd only want to catch code 284, rather than getting everything. Is there a way of doing this when building the app, as would be useful to pass to crashlytics to help with development going forward
A potential alternative, would be to run the queries preceded with EXPLAIN QUERY PLAN, and to then check for AUTOMATIC COVERING INDEX in the results.
e.g.
DROP TABLE IF EXISTS table1;
DROP TABLE IF EXISTS table2;
CREATE TABLE IF NOT EXISTS table1 (column1 TEXT, column2 TEXT);
CREATE TABLE IF NOT EXISTS table2 (column3, column4);
EXPLAIN QUERY PLAN
SELECT * FROM table1, table2 WHERE column1=column3;
Results in :-
As you can see this is based upon a predication of the number of rows rather than the actual number of rows, so works if there is no data (as above), which could well be beneficial, from a development perspective, as opposed to trying to trap on a as happens basis.

Delete all record from the data base

I am working on a project on android where thousands of tables exist.Unfortunately I do not have fresh data base so what can I do to delete all record from all tables. i am using sqlite database .If it is possible please tell me.
If you want to remove the entire rows/data from table, then it's better to drop the table and recreate it. This is the usual convention and for this reason SqLiteOpenHelper has onCreate() and onUpgrade() method which creates table or upgrades it, when table is dropped, or database version is changed
For deleting/dropping table, the code fragment is
db.execSQL("DROP TABLE IF EXISTS " + YOUR_TABLE);
Check the first answer for reference What happens if an android app, which creates database, is then uninstalled?

drop or delete a sqlite - table as fast as possible on Android device

I have a table with 1400 rows. Every row has a blob field which holds data between 10kb and 500kb. I need to delete that table. It takes me 3.5 minutes to delete the table and 3 minutes to drop the table. Thats too long for the users.
How can I remove that table as fast as possible ? ( No rollback needed or any security, just remove it. )
I already tried the following.
1. Set pagesize :
sqlitedatabase.setPageSize(8000);
sqlitedatabase.execSQL("DROP TABLE IF EXISTS " + sTableName);
2. deactivate journallog which did not work.
sqlitedatabase.rawQuery("PRAGMA journal_mode=OFF",null);
sqlitedatabase.execSQL("DROP TABLE IF EXISTS " + sTableName);
this doesn't work for me. journal log, which I guess takes a lot of time, is still be written on to the disk.
From the SQLite manual (with emphasis added):
SQLite is slower than the other databases when it comes to dropping tables. This probably is because when SQLite drops a table, it has to go through and erase the records in the database file that deal with that table. MySQL and PostgreSQL, on the other hand, use separate files to represent each table so they can drop a table simply by deleting a file, which is much faster.
You do have the option of creating and storing multiple database files, which you can then manage from a single connection with ATTACH and DETACH queries.
Here's an example I just ran in SQLite3's command-line client:
sqlite> ATTACH 'example.sqlite' AS example;
sqlite> CREATE TABLE example.ex ( a INTEGER );
sqlite> INSERT INTO example.ex VALUES (1),(2),(3);
sqlite> SELECT * FROM example.ex;
1
2
3
sqlite> DETACH example;
sqlite>
Since the ex table is in its own file, example.sqlite, I can simply detach that DB from the connection and delete the entire file, which will be much faster.
Bear in mind that the number of DBs you can attach is fairly low (with default compile options: 7). I've also read that foreign keys aren't supported in this scenario, though that info might be out of date.
I got a solution for me, which speeds up the deletion 6 times.
with
connection_read.enableWriteAheadLogging();
I drop my table in 30 Seconds. Without it it takes the mentoined 3 minutes.
enableWriteAheadLogging is an alternative journal log which is way faster.
Why not just put the drop table code in a separate thread? The user shouldn't have to wait for the app to drop a table.

How should I remove linked rows in SQLite with Android?

I have a very simple link table set up, I need to delete rows from all 3 tables
Table 1 - Assignment {assignment_id}
LinkTable - AssignmentTasks {assignment_id, task_id}
Table 2 - Tasks {task_id}
I can delete from Assignment and AssignmentTasks easily as I have the Id but I don't have the list of Tasks related to this assignment.
I've built a cursor which returns all the task_ids related to an assignment, but I can't remove them whilst the records in the link table refer to them. (I don't think I can as the foreign key constraint should stop me deleting rows referenced elsewhere)
Do I need to store a list of task_ids, delete the assignment_tasks records, delete the assignment record then iterate through the stored list of task_ids and delete each task ? or is there a better way of doing this ?
Or you can turn foreign key constraint checking off temporarily:
pragma foreign_keys = off;
But that shouldn't be necessary.
The other issue here is that this is currently written as a many-to-many relationship. This would imply that multiple assignments could refer to a one task. It probably wouldn't be OK to delete the task just because one of the assignments referencing it was deleted. Instead, you would need to check that the task is no longer referenced before deleting it.
Alternatively, if you really meant for each task to belong to only one assignment, you could set your schema up like this:
CREATE TABLE Assignment (assignment_id int PRIMARY KEY);
CREATE TABLE Task (
task_id int PRIMARY KEY,
assignment_id int FOREIGN KEY REFERENCES Assignment ON DELETE CASCADE
);
The ON DELETE CASCADE bit causes the Task entry to be deleted in the event that the assignment it refers to is deleted. This only works if foreign key constraints are enabled, of course. If the assignment is being deleted by a trigger or due to some other cascade, you may need to enable recursive triggers as well with pragma recursive_triggers = on.
Another possibility (if you want to retain the original schema) is to make the foreign key references in the AssignmentTask table do the cascading delete. That way those rows are deleted automatically as you delete the Tasks. Then you can delete the Assignment once all of those are taken care of.
Why not query the task_id based upon the assignment_id that you intent to delete.
You can leave the deletion of the related data to the database but that depends if you have defined cascade action onDelete when you created the relationships.
If you intend to use cascade onDelete as far as I know you need to enable that on sqlite. See this post for how to. Foreign key constraints in Android using SQLite? on Delete cascade
You can use a raw query. e.g.
delete from tasks where task_id in (select task_id from assignments where assignment_id=your_assignment_id_here)
I would also suggest using transaction for this for two reason a) so you can rollback in case the either of your queries fail. b) sqlite in general works better with transactions speedwise if you have multiple queries. So place all of your delete queires for a given action in a transaction.
Link below is for rawQuery:
http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#rawQuery(java.lang.String, java.lang.String[])

Categories

Resources