1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Split the (internal) sqlite3VdbeCheckFk() routine into two variants,

sqlite3VdbeCheckFkImmediate() and sqlite3VdbeCheckFkDeferred(), which
run faster than the combined general-purpose variant.

FossilOrigin-Name: 872b1b52ed93ef85911c2ef87b15673f9e102aef564f208e0a916af62671df93
This commit is contained in:
drh
2025-07-19 18:46:03 +00:00
parent c585e03a4b
commit bcd14a0a3e
5 changed files with 37 additions and 32 deletions

View File

@@ -1726,7 +1726,7 @@ case OP_IntCopy: { /* out2 */
** RETURNING clause.
*/
case OP_FkCheck: {
if( (rc = sqlite3VdbeCheckFk(p,0))!=SQLITE_OK ){
if( (rc = sqlite3VdbeCheckFkImmediate(p))!=SQLITE_OK ){
goto abort_due_to_error;
}
break;
@@ -3910,7 +3910,7 @@ case OP_Savepoint: {
*/
int isTransaction = pSavepoint->pNext==0 && db->isTransactionSavepoint;
if( isTransaction && p1==SAVEPOINT_RELEASE ){
if( (rc = sqlite3VdbeCheckFk(p, 1))!=SQLITE_OK ){
if( (rc = sqlite3VdbeCheckFkDeferred(p))!=SQLITE_OK ){
goto vdbe_return;
}
db->autoCommit = 1;
@@ -4028,7 +4028,7 @@ case OP_AutoCommit: {
"SQL statements in progress");
rc = SQLITE_BUSY;
goto abort_due_to_error;
}else if( (rc = sqlite3VdbeCheckFk(p, 1))!=SQLITE_OK ){
}else if( (rc = sqlite3VdbeCheckFkDeferred(p))!=SQLITE_OK ){
goto vdbe_return;
}else{
db->autoCommit = (u8)desiredAutoCommit;

View File

@@ -721,9 +721,11 @@ int sqlite3VdbeCheckMemInvariants(Mem*);
#endif
#ifndef SQLITE_OMIT_FOREIGN_KEY
int sqlite3VdbeCheckFk(Vdbe *, int);
int sqlite3VdbeCheckFkImmediate(Vdbe*);
int sqlite3VdbeCheckFkDeferred(Vdbe*);
#else
# define sqlite3VdbeCheckFk(p,i) 0
# define sqlite3VdbeCheckFkImmediate(p) 0
# define sqlite3VdbeCheckFkDeferred(p) 0
#endif
#ifdef SQLITE_DEBUG

View File

@@ -3267,28 +3267,31 @@ int sqlite3VdbeCloseStatement(Vdbe *p, int eOp){
/*
** This function is called when a transaction opened by the database
** These functions are called when a transaction opened by the database
** handle associated with the VM passed as an argument is about to be
** committed. If there are outstanding deferred foreign key constraint
** violations, return SQLITE_ERROR. Otherwise, SQLITE_OK.
** committed. If there are outstanding foreign key constraint violations
** return an error code. Otherwise, SQLITE_OK.
**
** If there are outstanding FK violations and this function returns
** SQLITE_ERROR, set the result of the VM to SQLITE_CONSTRAINT_FOREIGNKEY
** and write an error message to it. Then return SQLITE_ERROR.
** non-zero, set the result of the VM to SQLITE_CONSTRAINT_FOREIGNKEY
** and write an error message to it.
*/
#ifndef SQLITE_OMIT_FOREIGN_KEY
int sqlite3VdbeCheckFk(Vdbe *p, int deferred){
static SQLITE_NOINLINE int vdbeFkError(Vdbe *p){
p->rc = SQLITE_CONSTRAINT_FOREIGNKEY;
p->errorAction = OE_Abort;
sqlite3VdbeError(p, "FOREIGN KEY constraint failed");
if( (p->prepFlags & SQLITE_PREPARE_SAVESQL)==0 ) return SQLITE_ERROR;
return SQLITE_CONSTRAINT_FOREIGNKEY;
}
int sqlite3VdbeCheckFkImmediate(Vdbe *p){
if( p->nFkConstraint==0 ) return SQLITE_OK;
return vdbeFkError(p);
}
int sqlite3VdbeCheckFkDeferred(Vdbe *p){
sqlite3 *db = p->db;
if( (deferred && (db->nDeferredCons+db->nDeferredImmCons)>0)
|| (!deferred && p->nFkConstraint>0)
){
p->rc = SQLITE_CONSTRAINT_FOREIGNKEY;
p->errorAction = OE_Abort;
sqlite3VdbeError(p, "FOREIGN KEY constraint failed");
if( (p->prepFlags & SQLITE_PREPARE_SAVESQL)==0 ) return SQLITE_ERROR;
return SQLITE_CONSTRAINT_FOREIGNKEY;
}
return SQLITE_OK;
if( (db->nDeferredCons+db->nDeferredImmCons)==0 ) return SQLITE_OK;
return vdbeFkError(p);
}
#endif
@@ -3382,7 +3385,7 @@ int sqlite3VdbeHalt(Vdbe *p){
/* Check for immediate foreign key violations. */
if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){
(void)sqlite3VdbeCheckFk(p, 0);
(void)sqlite3VdbeCheckFkImmediate(p);
}
/* If the auto-commit flag is set and this is the only active writer
@@ -3396,7 +3399,7 @@ int sqlite3VdbeHalt(Vdbe *p){
&& db->nVdbeWrite==(p->readOnly==0)
){
if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){
rc = sqlite3VdbeCheckFk(p, 1);
rc = sqlite3VdbeCheckFkDeferred(p);
if( rc!=SQLITE_OK ){
if( NEVER(p->readOnly) ){
sqlite3VdbeLeave(p);