/ Check-in [69f51f83]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Consolidate two branches of code in the "PRAGMA foreign_key_check" implementation.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 69f51f838abcf57b35e41f7a10fbb45f56536f93825aac865debc3c8315930be
User & Date: dan 2017-04-17 18:42:33
Context
2017-04-17
20:50
Do not allow a Mem object to be both NULL and some other type at the same time. check-in: e698db19 user: drh tags: trunk
18:42
Consolidate two branches of code in the "PRAGMA foreign_key_check" implementation. check-in: 69f51f83 user: dan tags: trunk
18:02
Fix a problem in "PRAGMA foreign_key_check" in handling a WITHOUT ROWID child table with an INTEGER PRIMARY KEY parent key. Also, if an FK violation is detected in a WITHOUT ROWID child table, do not try to read and return the rowid. The second column returned by "PRAGMA foreign_key_check" in this case (WITHOUT ROWID child table) is now always set to NULL. check-in: 690870bd user: dan tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/pragma.c.

1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345




1346

1347
1348
1349
1350



1351
1352
1353
1354
1355





1356
1357

1358
1359
1360
1361
1362
1363
1364
        pIdx = 0;
        aiCols = 0;
        if( pParent ){
          x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, &aiCols);
          assert( x==0 );
        }
        addrOk = sqlite3VdbeMakeLabel(v);
        if( pParent && pIdx==0 ){
          int iKey = pFK->aCol[0].iFrom;
          assert( iKey>=0 && iKey<pTab->nCol );
          if( iKey!=pTab->iPKey ){
            sqlite3ExprCodeGetColumnOfTable(
                v, pTab, 0, pFK->aCol[0].iFrom, regRow);
            sqlite3VdbeAddOp2(v, OP_IsNull, regRow, addrOk); VdbeCoverage(v);
          }else{
            sqlite3VdbeAddOp2(v, OP_Rowid, 0, regRow);
          }
          sqlite3VdbeAddOp3(v, OP_SeekRowid, i, 0, regRow); VdbeCoverage(v);
          sqlite3VdbeGoto(v, addrOk);
          sqlite3VdbeJumpHere(v, sqlite3VdbeCurrentAddr(v)-2);
        }else{




          for(j=0; j<pFK->nCol; j++){

            sqlite3ExprCodeGetColumnOfTable(v, pTab, 0,
                            aiCols ? aiCols[j] : pFK->aCol[j].iFrom, regRow+j);
            sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk); VdbeCoverage(v);
          }



          if( pParent ){
            sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, pFK->nCol, regKey,
                              sqlite3IndexAffinityStr(db,pIdx), pFK->nCol);
            sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0);
            VdbeCoverage(v);





          }
        }

        if( HasRowid(pTab) ){
          sqlite3VdbeAddOp2(v, OP_Rowid, 0, regResult+1);
        }else{
          sqlite3VdbeAddOp2(v, OP_Null, 0, regResult+1);
        }
        sqlite3VdbeMultiLoad(v, regResult+2, "si", pFK->zTo, i-1);
        sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, 4);







<
<
<
<
<
<
<
<
<
|
<
<
<
<
>
>
>
>
|
>
|
<
|
|
>
>
>
|
|
|
|
|
>
>
>
>
>
|
|
>







1325
1326
1327
1328
1329
1330
1331









1332




1333
1334
1335
1336
1337
1338
1339

1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
        pIdx = 0;
        aiCols = 0;
        if( pParent ){
          x = sqlite3FkLocateIndex(pParse, pParent, pFK, &pIdx, &aiCols);
          assert( x==0 );
        }
        addrOk = sqlite3VdbeMakeLabel(v);














        /* Generate code to read the child key values into registers
        ** regRow..regRow+n. If any of the child key values are NULL, this 
        ** row cannot cause an FK violation. Jump directly to addrOk in 
        ** this case. */
        for(j=0; j<pFK->nCol; j++){
          int iCol = aiCols ? aiCols[j] : pFK->aCol[j].iFrom;
          sqlite3ExprCodeGetColumnOfTable(v, pTab, 0, iCol, regRow+j);

          sqlite3VdbeAddOp2(v, OP_IsNull, regRow+j, addrOk); VdbeCoverage(v);
        }

        /* Generate code to query the parent index for a matching parent
        ** key. If a match is found, jump to addrOk. */
        if( pIdx ){
          sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, pFK->nCol, regKey,
              sqlite3IndexAffinityStr(db,pIdx), pFK->nCol);
          sqlite3VdbeAddOp4Int(v, OP_Found, i, addrOk, regKey, 0);
          VdbeCoverage(v);
        }else if( pParent ){
          int jmp = sqlite3VdbeCurrentAddr(v)+2;
          sqlite3VdbeAddOp3(v, OP_SeekRowid, i, jmp, regRow); VdbeCoverage(v);
          sqlite3VdbeGoto(v, addrOk);
          assert( pFK->nCol==1 );
        }

        /* Generate code to report an FK violation to the caller. */
        if( HasRowid(pTab) ){
          sqlite3VdbeAddOp2(v, OP_Rowid, 0, regResult+1);
        }else{
          sqlite3VdbeAddOp2(v, OP_Null, 0, regResult+1);
        }
        sqlite3VdbeMultiLoad(v, regResult+2, "si", pFK->zTo, i-1);
        sqlite3VdbeAddOp2(v, OP_ResultRow, regResult, 4);

Changes to test/fkey5.test.

407
408
409
410
411
412
413
414












415
do_execsql_test 10.2 {
  PRAGMA foreign_key_check;
}
do_execsql_test 10.3 {
  INSERT INTO c30 VALUES(45, 45);
  PRAGMA foreign_key_check;
} {c30 {} p30 0}













finish_test








>
>
>
>
>
>
>
>
>
>
>
>

407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
do_execsql_test 10.2 {
  PRAGMA foreign_key_check;
}
do_execsql_test 10.3 {
  INSERT INTO c30 VALUES(45, 45);
  PRAGMA foreign_key_check;
} {c30 {} p30 0}

#-------------------------------------------------------------------------
# Test "foreign key mismatch" errors.
#
reset_db
do_execsql_test 11.0 {
  CREATE TABLE tt(y);
  CREATE TABLE c11(x REFERENCES tt(y));
}
do_catchsql_test 11.1 {
  PRAGMA foreign_key_check;
} {1 {foreign key mismatch - "c11" referencing "tt"}}

finish_test