Examining the VDBE code generated from some simulated operations explains how 
it works with stark clarity.

There are two constraint violation counters.  One has a "statement" scope (for 
immediate constraints), and the other a "transaction" scope (for deferred 
constraints).

Basically when the statement is executed, the appropriate violation counter is 
incremented for each violation -- even if there is a program in place that 
would "fix" the error (such as an ON ... CASCADE, etc) or even a user-defined 
trigger.  Then when the program/triggers is actually run successfully the 
appropriate violation counter is decremented.  Clearly you have to do it this 
way because this program could in turn fire a trigger (for example -- since it 
may update other tables) which itself might end up having an unresolvable 
constraint violation or otherwise fail to "resolve" the violation.

If the value of the immediate violation counter is non-zero at the end of the 
statement, then a constraint violation error is thrown.  There is no way to 
tell which of the constraints caused the error (it could be a constraint on a 
table not mentioned in the query that was updated as the result of a ON ... 
CASCADE  or a user-provided trigger or a program or trigger on any of them 
recursively).

For deferred constraints the processing is the same, just using a different 
counter that persists across statements within a transaction.  Statements which 
"clear" a pre-existing deferred constraint violation, decrement the deferred 
violation count.  At commit, a non-zero deferred violation count throws the 
constraint violation error.

Constraints such as CHECK, NOT NULL and UNIQUE cannot be "fixed" after they 
happen by a triggered update of any kind within the same statement -- nor can 
they be deferred -- and therefore they can be reported and attributed as soon 
as the violation is detected.

> -----Original Message-----
> From: sqlite-users-bounces at mailinglists.sqlite.org [mailto:sqlite-users-
> bounces at mailinglists.sqlite.org] On Behalf Of Simon Slavin
> Sent: Wednesday, 18 November, 2015 03:44
> To: SQLite mailing list
> Subject: Re: [sqlite] How hard is it to add the constraint name to the
> 'FOREIGN KEY constraint failed' message?
> 
> 
> On 18 Nov 2015, at 10:05am, Dominique Devienne <ddevienne at gmail.com>
> wrote:
> 
> > Given this pragma, then showing the FK name on immediate
> > mode is possible, no?
> 
> Unfortunately not.  [following explanation is, I suspect, simplified]
> 
> When the table schema is read from the file the table's constraints are
> 'compiled' into a set of rules.  A single rule might express the
> requirements of many different constraints.  Rules are more compact,
> faster and simpler to apply than analyzing and applying each constraint
> for each value changed.  Unfortunately because the structure of the rules
> doesn't map 1-to-1 into the constraints they came from it's not possible
> to tell, just from 'rule fails', which of the constraints that made up the
> rule was broken.
> 
> Applying the original constraints one by one would make SQLite far slower
> even for operations which did not violate any constraints, and the
> majority of users, who don't violate constraints, would get no benefit
> from it.
> 
> An earlier poster came up with a good solution: the existing 'fast check'
> is done first and then, if and only if a rule fails, a more complicated
> slower check has to be done to figure out which constraint to report as
> causing the error.  This would complicate SQLite's code, and as before
> most users wouldn't benefit from it.
> 
> As mentioned above SQLite4 is written differently and it's possible that
> reporting the violated constraint might be 'cheaper' to add to that.
> 
> Simon.
> _______________________________________________
> sqlite-users mailing list
> sqlite-users at mailinglists.sqlite.org
> http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users



Reply via email to