[sqlite] Handling the whole select query from an index

2015-09-20 Thread Simon Slavin

On 20 Sep 2015, at 11:18pm, James K. Lowden  wrote:

> Rob Willett  wrote:
> 
>> Thanks. We?ve got 100 requests a second which may be enough. We?ll
>> keep looking though for any time.
> 
> I suppose you know that 100/sec is about 0.1% of what the machine is
> capable of.

SQLite is really a trivial part of this.  Doing things in the obvious way OP is 
triggering SQLite commands from a web-based interface, with a new process 
created for each command.  Then the new process needs a SQLite database 
connection and only then can you get down to issuing a SQLite command.

OP could redesign his app to call a persistent SQLite server which runs 
constantly in the background, holding a connection to the SQLite database open. 
 Requires more memory and more programming but it should speed up things quite 
a bit.

Simon.


[sqlite] disable update's & delete's via triggers?

2015-09-20 Thread Simon Slavin

On 20 Sep 2015, at 11:13pm, James Hartley  wrote:

> As I look at the flowchart for triggers at the following:
> 
> https://www.sqlite.org/lang_createtrigger.html
> 
> It appears that the body of a trigger must specify some kind of statement.
> 
> I ask because I am wanting to log all activity on another table.  I can
> successfully do this with triggers.  What I am curious to do is disable
> UPDATE's & DELETE's on the log tables themselves.

You can create TRIGGERs which operate BEFORE, AFTER or INSTEAD OF.  So perhaps 
just create an INSTEAD OF trigger which does nothing.  Perhaps a SELECT command 
or a DELETE command with a WHERE clause which is never satisfied (e.g. rowid < 
0).

Then your next concern is over how to zero-out the log if you really needed to 
do that.

Simon.


[sqlite] disable update's & delete's via triggers?

2015-09-20 Thread Igor Tandetnik
On 9/20/2015 6:13 PM, James Hartley wrote:
> I ask because I am wanting to log all activity on another table.  I can
> successfully do this with triggers.  What I am curious to do is disable
> UPDATE's & DELETE's on the log tables themselves.

Something along these lines, perhaps:

create trigger no_delete before delete on log_table
begin
   select raise(IGNORE);
end;

-- 
Igor Tandetnik



[sqlite] disable update's & delete's via triggers?

2015-09-20 Thread James Hartley
I appreciate the discussion thus far.

I tried the following syntax:

CREATE TRIGGER update_history_table_trigger INSTEAD OF UPDATE ON
history_table
BEGIN
UPDATE history_table SET new_value = 1 WHERE 0 = 1;
END ;

CREATE TRIGGER delete_history_table_trigger INSTEAD OF DELETE ON
history_table
BEGIN
DELETE FROM history_tble WHERE 0 = 1;
END ;

...received the following error:  "cannot create INSTEAD OF trigger on
table: history_table"

Googling revealed the following link from 2012:

http://stackoverflow.com/questions/9487381/why-sqlite-error-cannot-create-instead-of-trigger-on-table

...which states that INSTEAD OF triggers are to be used with views, not
tables.  Is this still true?  I'm using SQlite 3.8.9.

Thanks, again.

On Sun, Sep 20, 2015 at 6:34 PM, Simon Slavin  wrote:

>
> On 21 Sep 2015, at 12:21am, James Hartley  wrote:
>
> > I am assuming that dropping the trigger
> > will re-enable any action which had been disabled by creating the
> trigger.
> >
> > Is this incorrect?
>
> Nope.  That's one way to do it.  Another is to set "PRAGMA
> recursive_triggers = OFF" then have a TRIGGER make changes to the table.
>
> Simon.
> ___
> sqlite-users mailing list
> sqlite-users at mailinglists.sqlite.org
> http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
>


[sqlite] How to know when a sqlite3_stmt has been recompiled ?

2015-09-20 Thread Nicolas Jäger
hi,


Scott Robison wrote:

> 
> 3. Some time passes and some external process may alter the schema.
> 

is it really possible ? if the answer is yes (I thought when a process open a 
communication with
the DB, other processes can't alter the DB), for me that would mean that the 
design(s) of the
program(s) wich communicates with the DB is bad.

If I would like several process to communicate with a DB, I write first a 
`demon` wich receive/send
the querries one by one to the DB and send one-by-one the results to the 
processes. So with that
design I consider avoiding any overlapping.

regards,
nicolas


[sqlite] I don't understand how to use NOT EXISTS

2015-09-20 Thread Simon Slavin

On 20 Sep 2015, at 7:15pm, James K. Lowden  wrote:

> Simon Slavin  wrote:
> 
>> Constructions like this
>> 
>>> INSERT INTO _TAG_EXISTS_RESULT_ ( NAME, BOOL )
>>> SELECT 'evil little sister'
>> 
>> should be rewritten so that you are not trying to do a SELECT in the
>> middle of your INSERT.
> 
> Why in the world would you say that?  That's the SQL assignment
> function, the equivalent of 
> 
>   A = A + B

I would argue that that would be UPDATE, not INSERT.  But I see your side of 
the issue.

> Anything you'd do to rewrite it would result in something more complex,
> doubly so if it included the atomicity guarantee of the original. 

Suppose the SELECT doesn't return anything.  Do you still want to do the INSERT 
? Do you now have to look up the values to INSERT elsewhere ?  Put the commands 
in a transaction if that worries you.

You're right -- I should probably have written "I preffer" instead if making it 
an absolute statement.

Simon.


[sqlite] I don't understand how to use NOT EXISTS

2015-09-20 Thread James K. Lowden
On Sun, 20 Sep 2015 19:33:35 +0100
Simon Slavin  wrote:

> On 20 Sep 2015, at 7:15pm, James K. Lowden 
> wrote:
> 
> > Simon Slavin  wrote:
> > 
> >> Constructions like this
> >> 
> >>> INSERT INTO _TAG_EXISTS_RESULT_ ( NAME, BOOL )
> >>> SELECT 'evil little sister'
> >> 
> >> should be rewritten so that you are not trying to do a SELECT in
> >> the middle of your INSERT.
> > 
> > Why in the world would you say that?  That's the SQL assignment
> > function, the equivalent of 
> > 
> > A = A + B
> 
> I would argue that that would be UPDATE, not INSERT.  But I see your
> side of the issue.

I actually think that's the crux of the matter, Simon.  If you think
you're operating on a row, then A = A + B is UPDATE, yes.  If you think
you're operating on tables, then A = A + B is INSERT, and UPDATE
is more like 

A = (A - C) + B

where C is the set of rows being replaced by B. 

> Suppose the SELECT doesn't return anything.  Do you still want to do
> the INSERT ? 

If I said WHERE NOT EXISTS, why would I still want to "do the insert"?!
I'm with Yoda here: there is no try.  

> Do you now have to look up the values to INSERT elsewhere ?

No, I do not, not if the values I didn't insert can be specified, e.g.

insert into S 
select * from T where exists 
(select 1 from R where ... );

If the values can't be specified in like manner, that would suggest to
me a problem with the database design.  

TIMTOWTDI, for sure.  More than one way to think about it, too.  But I
see no downside to using INSERT...SELECT, except that it's startling to
someone unfamiliar with it.  

--jkl


[sqlite] disable update's & delete's via triggers?

2015-09-20 Thread James Hartley
On Sun, Sep 20, 2015 at 5:20 PM, Simon Slavin  wrote:

>
> Then your next concern is over how to zero-out the log if you really
> needed to do that.
>
> That is a valid concern, however, I am assuming that dropping the trigger
will re-enable any action which had been disabled by creating the trigger.

 Is this incorrect?


[sqlite] Handling the whole select query from an index

2015-09-20 Thread James K. Lowden
On Sat, 19 Sep 2015 14:24:24 +0100
Rob Willett  wrote:

> Thanks. We?ve got 100 requests a second which may be enough. We?ll
> keep looking though for any time.

I suppose you know that 100/sec is about 0.1% of what the machine is
capable of.  

You spoke of read-only data that changes infrequently, and you wanted
maximum speed.  I would sort them into a static C array, and use
std::lower_bound to search it.  I would expose that as a function in a
shared library, and publish updates by updating the shared library.  I
would expect at least 100,000 invocations per second, with the added
benefit that the iterator returned by lower_bound instantly answers the
question of existence for the provide string.  

Everything DHR said of advantages to using SQLite is true.  If what you
want is to minimize lookup time on static data, though, searching sorted
data will give you better locality of reference and fewer machine
instructions than any interpreted b-tree.  

HTH.  

--jkl


[sqlite] using mprint as a global variable inside a query

2015-09-20 Thread E.Pasma
Here is still a follow up of last weeks discussion "Worked in 3.8.9  
but no longer in .." which is about the following case:
a large table includes a datetime field. From the points in time one  
wants to report time intervals (from - to).
The datetime field is indexed.
The fastest solution that was proposed involves the creation of a temp  
table.

Na?vely I searched a faster solution that should just do a single scan  
of the existing index on datetime. And to report intervals this  
somehow needs to access the result of two rows at the time, say the  
current row and the previous row.
Assuming the execution plan is as expected, this can be achieved with  
a sort of global variable. That is to be set at each row and hold the  
point in time and recalled at the next row to report it as the from  
date.
An SQL function is required then to set and get the value. I had a  
look at sqlite3_mprintf and this comes close if it would write the  
string in some global variable.
Based on that I created function mprint() as limited version of  
mprintf. It accepts no format, only a value parameter. Furthermore, if  
called with no parameter at all, it returns the last printed value.

The query is now:

.load mprint
CREATE TABLE securities(calc_date);
WITH RECURSIVE c(x) AS (VALUES(1) UNION SELECT x+1 FROM c WHERE  
x<630)
INSERT INTO securities(calc_date)
   SELECT datetime(2440587.5 + ((x*123456789012345)%1670)/1000.0)  
FROM c;
CREATE INDEX securities_calcdate ON securities(calc_date);

select mprint() as calc_date0, --previous value
  mprint(calc_date) as tmw --new value
from (select mprint(''))--initial value
join securities
group by calc_date
having strftime('%w',calc_date)<>'0'
;

and the result is as expected and comes almost twice as fast.

Possibly I am a bit flattered by this result,
Is a function like this of any gene ral use?
Should I mail the extension source?

~


[sqlite] How to know when a sqlite3_stmt has been recompiled ?

2015-09-20 Thread Scott Robison
On Sun, Sep 20, 2015 at 5:53 PM, Nicolas J?ger 
wrote:

> hi,
>
>
> Scott Robison wrote:
>
> >
> > 3. Some time passes and some external process may alter the schema.
> >
>
> is it really possible ? if the answer is yes (I thought when a process
> open a communication with
> the DB, other processes can't alter the DB), for me that would mean that
> the design(s) of the
> program(s) wich communicates with the DB is bad.
>
> If I would like several process to communicate with a DB, I write first a
> `demon` wich receive/send
> the querries one by one to the DB and send one-by-one the results to the
> processes. So with that
> design I consider avoiding any overlapping.
>

It is possible and is by design. Whether or not you have to worry about
this is a different story: if you don't have any processes changing the
schema, it is unlikely the schema will change under you.

The reason the sqlite3_prepare_v2 interfaces were created was because of
the need to recompile queries if the schema changed. The older interfaces
returned an error when the schema changed, and the v2 interfaces automated
the process. The only time this should be possible is after a prepared
statement has been stepped until done, then restarted. There is a window of
opportunity where another process can execute other queries, including
schema changing queries.


>
> regards,
> nicolas
> ___
> sqlite-users mailing list
> sqlite-users at mailinglists.sqlite.org
> http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
>



-- 
Scott Robison


[sqlite] How to know when a sqlite3_stmt has been recompiled ?

2015-09-20 Thread Scott Robison
On Sun, Sep 20, 2015 at 5:47 PM, Simon Slavin  wrote:

>
> On 21 Sep 2015, at 12:32am, Scott Robison  wrote:
>
> > 4. Step through the prepared statement from #1 again after doing any
> > necessary reset. No finalize / re-prepare step.
>
> I believe that if you have done the first _step() then the SELECT will not
> notice any schema change until you have received SQLITE_DONE or done
> _reset() or _finalize().  In other words, you don't have to worry about the
> issue.  It might be interesting to check this with and without WAL
> journalling.
>
> I agree that if you do a _reset() then you might have to worry about
> columns being changed.  I believe that _reset() releases locks, just like
> the other two things I mentioned above.
>

Right, and that seems to be the crux of the OP question. Can he tell when a
statement has been recompiled due to a schema change, because it might
invalidate information he has cached locally in process.

This may be a case of premature optimization, worrying about how much time
a language boundary transition might take. Or perhaps the OP has found a
use case where regular but not frequent schema changes might be called for.

-- 
Scott Robison


[sqlite] disable update's & delete's via triggers?

2015-09-20 Thread Keith Medcalf

Not really.  Normal increment of the rowid increments by 1:

sqlite> create table x(x);
sqlite> insert into x (rowid, x) values (-100, 1);
sqlite> insert into x values (2);
sqlite> insert into x values (3);
sqlite> insert into x values (4);
sqlite> select rowid, x from x;
-100|1
-99|2
-98|3
-97|4

AUTOINCREMENT will make the value "greater than the largest value that has ever 
been in the table" and will indeed make sure that autoincremented rowid's are 
greater than 0, however, it does not prevent a rowid with a value less than 0.

sqlite> create table y(rowid integer primary key autoincrement, x);
sqlite> insert into y (rowid, x) values (-100, 1);
sqlite> insert into y (x) values (2);
sqlite> insert into y (x) values (3);
sqlite> insert into y (x) values (4);
sqlite> delete from y where x=4;
sqlite> insert into y (x) values (5);
sqlite> select * from y;
-100|1
1|2
2|3
4|5
sqlite>


> On 20 Sep 2015, at 11:59pm, Keith Medcalf  wrote:
> 
> > The RowID is an integer.  It is perfectly possible to have RowID's with
> a value less than 0.
> >
> > sqlite> create table x(x);
> > sqlite> insert into x (rowid, x) values (-1, -1);
> > sqlite> select rowid, x from x;
> > -1|-1
> 
> Yep.  But it's unlikely in a world where you allow it to be set by
> autoincrement.
> 
> Simon.
> ___
> sqlite-users mailing list
> sqlite-users at mailinglists.sqlite.org
> http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users





[sqlite] How to know when a sqlite3_stmt has been recompiled ?

2015-09-20 Thread Scott Robison
On Sun, Sep 20, 2015 at 8:11 AM, Simon Slavin  wrote:

>
> On 20 Sep 2015, at 2:55pm, gwenn  wrote:
>
> > But if a column is added to one table in your database, your statement
> > is successfully/transparently recompiled (when calling sqlite3_step)
> > and the column count may be changed.
>
> Let's assume that you have not used any PRAGMAs to defeat the concurrency
> and locking operations of SQLite, to share the cache, or anything else
> which is obviously unsafe in a multi-access scenario.  If this is so then
> you do not have to worry about this problem.
>
> Depending on your settings one of two things will happen.
>
> A) Use of ALTER TABLE ... ADD COLUMN requires locking the database.  This
> will not be permitted because the database will already be locked, from the
> first execution of sqlite3_step() until sqlite3_step() returns SQLITE_DONE
> or an error message.
>
> B) The connection executing sqlite3_step() reads from the database.  The
> connection executing ALTER TABLE ... ADD COLUMN creates a modification of
> the database which the first connection can't see.  It won't be able to see
> that change until it has released its lock on the database.
>
> Which of these happens depends at least on the journal mode of the
> database, and perhaps on other things I can't think of right now.  But it
> will always be one or the other.
>

If I am understanding correctly, what the OP wants to know is:

1. Prepare a statement such as "select * from some_table".

2. Step through it, caching column count information after the first step.

3. Some time passes and some external process may alter the schema.

4. Step through the prepared statement from #1 again after doing any
necessary reset. No finalize / re-prepare step.

4a. The column count from the first run of the query was cached back during
step 2. Can it be determined if the schema changed without making an
"expensive" call to get the column count again? Obviously sqlite is able to
detect that the schema changed and only re-prepare the query if necessary.
Is that functionality available to ordinary applications?

I suspect that the answer is either "no" it is not directly available, or
it will involve calling an equally expensive API function to detect the
schema signature value. Either way, something will have to be called in the
sqlite3 api and that will be potentially expensive if it involves a
boundary transition in JNI or go or whatever examples were cited previously.

-- 
Scott Robison


[sqlite] disable update's & delete's via triggers?

2015-09-20 Thread Scott Robison
On Sun, Sep 20, 2015 at 5:18 PM, Simon Slavin  wrote:

>
> On 20 Sep 2015, at 11:59pm, Keith Medcalf  wrote:
>
> > The RowID is an integer.  It is perfectly possible to have RowID's with
> a value less than 0.
> >
> > sqlite> create table x(x);
> > sqlite> insert into x (rowid, x) values (-1, -1);
> > sqlite> select rowid, x from x;
> > -1|-1
>
> Yep.  But it's unlikely in a world where you allow it to be set by
> autoincrement.
>

Then just go with something like ((rowid - rowid) <> 0). The basic premise
still holds that it should be easy to come up with a condition that is
always false.

-- 
Scott Robison


[sqlite] disable update's & delete's via triggers?

2015-09-20 Thread James Hartley
As I look at the flowchart for triggers at the following:

https://www.sqlite.org/lang_createtrigger.html

It appears that the body of a trigger must specify some kind of statement.

I ask because I am wanting to log all activity on another table.  I can
successfully do this with triggers.  What I am curious to do is disable
UPDATE's & DELETE's on the log tables themselves.

Can anyone confirm that this is not allowed with the current triger grammar?

Thanks!


[sqlite] disable update's & delete's via triggers?

2015-09-20 Thread Keith Medcalf

> You can create TRIGGERs which operate BEFORE, AFTER or INSTEAD OF.  So
> perhaps just create an INSTEAD OF trigger which does nothing.  Perhaps a
> SELECT command or a DELETE command with a WHERE clause which is never
> satisfied (e.g. rowid < 0).

The RowID is an integer.  It is perfectly possible to have RowID's with a value 
less than 0.

sqlite> create table x(x);
sqlite> insert into x (rowid, x) values (-1, -1);
sqlite> select rowid, x from x;
-1|-1






[sqlite] How to know when a sqlite3_stmt has been recompiled ?

2015-09-20 Thread gwenn
Sorry for my bad description.
Imagine that you have a cache of statements (like in tclsqlite.c)
created using sqlite3_prepare_v2.
And you want to avoid calling sqlite3_column_count/sqlite3_column_name
each time you reuse (sqlite3_step) the same statement (with Java (JNI)
or Go (cgo), a native call is not cheap).
Everything works fine if the database schema is not touched.
But if a column is added to one table in your database, your statement
is successfully/transparently recompiled (when calling sqlite3_step)
and the column count may be changed.
My problem is that I don't know that the statement has been recompiled
and that I need to invalidate/update the column count.
If there is no way to know that the statement has been recompiled, I
guess that the column count should not be cached...
But maybe there is already such feature provided by the SQLite API ?

Regards.

On Sat, Sep 19, 2015 at 10:14 PM, R.Smith  wrote:
>
>
> On 2015-09-19 06:41 PM, gwenn wrote:
>>
>> SQLITE_SCHEMA is returned only on failure.
>> But, here, there is not failure.
>>
>> Maybe I should not store the column count ?
>> Maybe I should look at schema version
>> (http://sqlite.org/pragma.html#pragma_schema_version):
>> "The schema version is used by SQLite each time a query is executed to
>> ensure that the internal cache of the schema used when compiling the
>> SQL query matches the schema of the database against which the
>> compiled query is actually executed."
>> Is there a better solution ?
>
>
> I too may be reading this thread wrong, I am not sure we're on the same
> page, but I /THINK/ maybe you are worrying about an unnecessary thing.
> The only way the column count can change for a prepared statement object, is
> if you changed it.
> If you have a prepared statement like "SELECT * FROM t..." then the
> definition might change once the SCHEMA has changed - but that will only
> have effect outside of the implicit transaction you are in, as in you will
> only notice when you reset the prepared statement - and you should always
> check column counts then.
>
> The bit I am not sure about is whether, after a schema change and reset,
> whether that select statement will give an error or simply recompile with a
> new column count - but that can be checked rather easily and then respond
> accordingly.
>
> Hope this makes some sense,
> Ryan
>
> ___
> sqlite-users mailing list
> sqlite-users at mailinglists.sqlite.org
> http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users


[sqlite] How to know when a sqlite3_stmt has been recompiled ?

2015-09-20 Thread Simon Slavin

On 20 Sep 2015, at 2:55pm, gwenn  wrote:

> But if a column is added to one table in your database, your statement
> is successfully/transparently recompiled (when calling sqlite3_step)
> and the column count may be changed.

Let's assume that you have not used any PRAGMAs to defeat the concurrency and 
locking operations of SQLite, to share the cache, or anything else which is 
obviously unsafe in a multi-access scenario.  If this is so then you do not 
have to worry about this problem.

Depending on your settings one of two things will happen.

A) Use of ALTER TABLE ... ADD COLUMN requires locking the database.  This will 
not be permitted because the database will already be locked, from the first 
execution of sqlite3_step() until sqlite3_step() returns SQLITE_DONE or an 
error message.

B) The connection executing sqlite3_step() reads from the database.  The 
connection executing ALTER TABLE ... ADD COLUMN creates a modification of the 
database which the first connection can't see.  It won't be able to see that 
change until it has released its lock on the database.

Which of these happens depends at least on the journal mode of the database, 
and perhaps on other things I can't think of right now.  But it will always be 
one or the other.

Simon.


[sqlite] I don't understand how to use NOT EXISTS

2015-09-20 Thread James K. Lowden
On Wed, 16 Sep 2015 08:23:04 +1000
Barry Smith  wrote:

> As for your original query: think about just the select clause (you
> can run it independently). This will return ('magnetohydrodynamics',
> 1) for each row in the table. 

It took me a bit to understand what you meant.  I also think there's a
better answer than resorting to LIMIT 1.  

To clarify, the OP's query is (reformatted):

> INSERT INTO TAGS ( NAME, COUNT ) 
> SELECT 'magnetohydrodynamics', 1
> FROM TAGS -- <- the error 
> WHERE NOT EXISTS (
>   SELECT * FROM TAGS 
>   WHERE NAME = 'magnetohydrodynamics' 
> );

The existence test is against the whole TAGS table.  As long as the
name 'magnetohydrodynamics' appears in the table, SELECT will return
zero rows.  But -- your point -- if the name tested does *not* appear in
the table, SELECT will return as many rows as are in the table.  

The solution is simply to say what's meant instead: 

INSERT INTO TAGS ( NAME, COUNT ) 
SELECT 'magnetohydrodynamics',1 
WHERE NOT EXISTS (
SELECT 1 FROM TAGS 
WHERE NAME = 'magnetohydrodynamics' 
);

As to the OP's question about where he went wrong, the query as
presented should not have created the results he showed.  Those results
could be explained, though, if "magnetohydrodynamics" was misspelled in
the WHERE clause.  I suspect that's what went wrong.  

--jkl


[sqlite] I don't understand how to use NOT EXISTS

2015-09-20 Thread James K. Lowden
On Wed, 16 Sep 2015 19:40:23 +0100
Simon Slavin  wrote:

> Constructions like this
> 
> > INSERT INTO _TAG_EXISTS_RESULT_ ( NAME, BOOL )
> > SELECT 'evil little sister'
> 
> should be rewritten so that you are not trying to do a SELECT in the
> middle of your INSERT.

Why in the world would you say that?  That's the SQL assignment
function, the equivalent of 

A = A + B

Anything you'd do to rewrite it would result in something more complex,
doubly so if it included the atomicity guarantee of the original.  

--jkl



[sqlite] Fwd: OT: Oracle functions for SQlite

2015-09-20 Thread John G
On 13 September 2015 at 10:06, Domingo Alvarez Duarte <
sqlite-mail at dev.dadbiz.es> wrote:

> Hello !
>
> Due the way sqlite manages it's source code (with fossil-scm) I propose to
> anyone that has any extension/custom sqlite code fork this project on
> github:
>
>
> https://github.com/mackyle/sqlite
>
> And publish it there.
>
> ___
> sqlite-users mailing list
> sqlite-users at mailinglists.sqlite.org
> http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
>

Is there an equivalent collection of Tcl - sqlite functions anywhere?
I have my own 'initcap' and 'decode' functions.

John Gillespie


[sqlite] How to know when a sqlite3_stmt has been recompiled ?

2015-09-20 Thread Igor Tandetnik
On 9/20/2015 9:55 AM, gwenn wrote:
> If there is no way to know that the statement has been recompiled, I
> guess that the column count should not be cached...

You could use sqlite3_prepare (no _v2), then you'd get an error on 
schema change. You would then re-prepare the statement and update your 
caches.
-- 
Igor Tandetnik