I vaguely recall a while ago someone finding a small bug when "primary key 
unique" was used. Since those are redundant you should get rid of the "unique" 
in the id field creation as "primary key" takes care of that. (It "shouldn't" 
make a difference, but don't tempt fate)

Other things: run a pragma integrity_check; to look for problems. And a 
reindex; to try fixing any found index problems, as it sounds to me like an 
index got messed up somewhere along the line. If it was using the bad index for 
ordering, but displaying the id from the actual table that would explain 
showing the record out of order. And if it used that index to look for the 
record to delete then it wouldn't find 424, just whatever else was in there for 
the id. Apparently deleting something else there might have nudged it to 
correctness? I'm not sure why deleting another record would fix the index 
though, weird.

Apart from the "primary key unique" thing I don't have a clue how it would get 
into that state though, so can't help you there.


-----Original Message-----
From: sqlite-users [mailto:sqlite-users-boun...@mailinglists.sqlite.org] On 
Behalf Of Jeff B.
Sent: Monday, February 13, 2017 12:32 PM
To: sqlite-users@mailinglists.sqlite.org
Subject: [sqlite] Partially "hidden" row, very bizarre state

Hi Everyone,

Sorry for the strange subject, but the situation I'm facing is so odd 
that I wasn't even sure how to summarize it.  First, a little context:  
I'm using v1.0.104 of System.Data.SQLite.Core in my C#/.NET 4.5 
project.  I have a table that is created as follows:

                 CREATE TABLE messages_priority (
                     id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
                     type TEXT,
                     json TEXT,
                     options TEXT,
                     created TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL)

The purpose of my SQLite db is to locally queue messages until they can 
be sent to a web API, at which time they are deleted.  My single 
consumer thread basically does a "SELECT * FROM messages_priority ORDER 
BY id LIMIT 1" and then if the send to the web is successful it deletes 
that id.  This has all been working fine for months until I had one 
client hit a problem yesterday.  They kept sending the same message over 
and over to the web and would never move on to anything else.  Once I 
dug in further this is what I found:

(Note that I use a password on the database and I have not been able to 
find any db viewers for Windows which support the type of encryption 
that Windows SQLite uses, so I had to write my own simple query tool, 
the output of which is shown below)

select id,created from messages_priority order by id limit 5
id    created
424    2/12/2017 8:07:10 PM
423    2/12/2017 8:07:09 PM
425    2/12/2017 8:07:11 PM
426    2/12/2017 8:07:12 PM
427    2/12/2017 8:07:13 PM
**5 rows returned**

// So here we see the first problem.  424 is listed before 423 even 
though I'm specifying an order by id.

select id,created from messages_priority where id = 424
**No Rows**

// Now we see the next problem... even though 424 comes back in the 
first query, when I try to specify it in a WHERE clause it is not found.

select id,created from messages_priority where id = 423
id    created
423    2/12/2017 8:07:09 PM
**1 rows returned**

// 423, however, returns just fine that way...

delete from messages_priority where id = 424
**Command returned 0**

// delete doesn't throw an exception or anything, but indicates nothing 
was deleted

select id,created from messages_priority order by id limit 1
id    created
424    2/12/2017 8:07:10 PM
**1 rows returned**

// still shows up in a select with no WHERE

delete from messages_priority where id = 423
**Command returned 1**

// attempt to delete 423 is successful

select id,created from messages_priority where id = 424
id    created
424    2/12/2017 8:07:10 PM
**1 rows returned**

// now I can finally query by the id!

delete from messages_priority where id = 424
**Command returned 1**

// and delete it!

So somehow, records 423 and 424 seemed to have gotten "out of order" in 
the database, and until 423 was deleted, nothing could directly find 
424.  Because 424 could never be deleted my consumer kept getting it 
over and over and could never move on.  That makes sense at least...

But I can't imagine how I can work around this in code once the database 
has gotten into this state.  Does this seem like something that could be 
caused by improper inserts or is this possibly a bug in SQLite or the C# 
wrapper?  I don't do anything to change the defaults in terms of 
concurrency or isolation settings.  My understanding from the docs was 
that this should be thread safe without any extra locking on my end.  
Each thread that uses the db has its own connection var and re-uses that 
over and over.  The producer and consumer are separate threads but there 
is only one of each.

This is my code for inserting the rows:

             // use a transaction so we are sure to get the correct row 
id back
             using (var transaction = sqlConnection.BeginTransaction())
             {
                 try
                 {
                     var sql = String.Format("INSERT INTO 
messages_priority (type, json, options) VALUES (@p0, @p1, @p2)");
                     using (var command = new SQLiteCommand(sql, 
sqlConnection))
                     {
                         command.Parameters.Add(new 
SQLiteParameter("@p0", type));
                         command.Parameters.Add(new 
SQLiteParameter("@p1", json));
                         command.Parameters.Add(new 
SQLiteParameter("@p2", options));

                         command.ExecuteNonQuery();
                     }

                     var rowId = sqlConnection.LastInsertRowId;

                     transaction.Commit();

                     return rowId;
                 }
                 catch
                 {
                     // technically shouldn't be anything to roll back 
as we are only doing one thing and if that threw
                     // an exception then nothing happened...
                     transaction.Rollback();
                     throw;
                 }
             }

I'm pretty much stumped here, any thoughts would be greatly appreciated!

Thanks,
Jeff
_______________________________________________
sqlite-users mailing list
sqlite-users@mailinglists.sqlite.org
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
_______________________________________________
sqlite-users mailing list
sqlite-users@mailinglists.sqlite.org
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users

Reply via email to