"Ulrich Telle" <[EMAIL PROTECTED]> wrote:
> 
> Sure, it would be nice if SQLITE_SCHEMA errors could be handled internally
> by SQLite, but I think it's a non-trivial task to handle this kind of error.
> 
> When I created my SQLite C++ wrapper wxSQLite3 I thought about handling
> SCHEMA errors, but decided against it due to the complexities involved. 

Isn't that really the whole point of a wrapper - to deal with complexities
so that the user doesn't have to.  If you are passing all of the 
complexities up to the user, why use you wrapper at all?  Just call
SQLite directly.

> 
> For INSERT, UPDATE or DELETE a simple retry might be a good choice. But how
> often should the retry take place? The SQLite FAQ code example contains an
> endless loop! 

Not.  OK, I guess in theory, if another process were updating the
schema at just the right rate so that the schema was different every
times you retried, you could get an infinite loop.  But in practice,
the loop never runs more than twice - 3 times in the extreme.

> Additionally the number of columns in a table used in these statements might
> have changed, that is the statement would probably fail again.

If the number of columns changes, you will get a syntax error, not
a schema error.  At that point you exit the loop.

> 
> In case of a SELECT statement the situation is still more complex. The
> SCHEMA error could happen after reading several result rows.

No.  SCHEMA errors happen prior to reading any data.

> 
> When retrying a query another problem arises if the SQL statement contains
> bind variables. You would have to rebind the variables. To handle this
> automatically would induce a lot of extra house keeping, wouldn't it?

See the sqlite3_transfer_bindings() API.

------------------------ A Digression --------------------------

To all writers of wrappers, my I please call your attention to
the TCL wrapper for SQLite.  In that wrapper I have attempted
to hide as many details of the interface as possible from the user and
to make everything automatic.  This allows the user to focus on their
application and not worry so much about the details of the interface
to the database.  I and everybody else I have talked to find this to
be a very refreshing approach.

In the TCL wrapper, you run SQL statements using this template:

     DBOBJECT eval SQL-STATEMENT CODE-TO-HANDLE-EACH-RESULT-ROW

The DBOBJECT is the object that is created when you open the database.
On this object you call the "eval" method with two arguments, the
text of the SQL you want to process and a lambda procedure that runs
once for each row of output.  (The lambda is optional and is usually
omitted for non-query statements.)  The bindings automatically process
named parameters within the SQL statement by binding them with the
value of TCL variables of the same name.  So for example, if you
say:

    db eval {UPDATE table1 SET x=$var1 WHERE y=$rownum}

The $var1 and $rownum named parameters are bound to the values of
the var1 and rownum variables in TCL.  This is all automatic.

Within the lambda procedure that runs once for each row of the result,
local variables are created to contain the value of each column - 
the names of the local variables are chosen to match the column names.
That way the user does not have to remember any method calls or
other such complication to get at the results.

Note the complete absence of prepared statements.  Prepared statements
are handled automatically by the wrapper.  The wrapper keep a cache
of recently used SQL statements and reuses them if the reappear.
Statements are cleared from the cache using the LRU algorithm.  There
are methods on the database object to changes the size of the prepared
cache or flush the cache.  But those methods never get used in practice
because the cache just seems to work without any problems.

Note also that the user never needs to worry about how to bind
values.  Bindings all happens automatically and transparently.

SQLITE_SCHEMA errors are also handled automatically.

The end results it that the user of the TCL binds does not need to
remember much about how the wrapper work.  If they can just remember
how to create a database object (hint: use the sqlite3 constructor)
and how to run the eval method, then they have access to the full
power of the SQLite interface without having to know or remember 
ny of the details.

There is an important principle at work here:  keep it simple.
An interface with less complication, with fewer choices and options,
with less to remember and think about, is a better interface.  I
want to encourage all authors of wrappers and bindings for SQLite
and for other libraries to keep this principle in mind.

--
D. Richard Hipp <[EMAIL PROTECTED]>

Reply via email to