/ Check-in [75a8ed7a]
Login

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

Overview
Comment:If a write statement fails with OE_Abort, but there is no statement journal, roll the entire transaction back instead.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | rollback-abort
Files: files | file ages | folders
SHA3-256: 75a8ed7a4227493c0d992ceeef6d631ef9c3643fef380fc2c467916d8761551f
User & Date: dan 2019-01-26 18:10:05
Context
2019-01-26
19:09
Fix a broken assert() in fts3. check-in: b8dd2d67 user: dan tags: rollback-abort
18:10
If a write statement fails with OE_Abort, but there is no statement journal, roll the entire transaction back instead. check-in: 75a8ed7a user: dan tags: rollback-abort
17:47
Fix "PRAGMA journal_mode" so that if it fails because there is a transaction open, it does not roll that transaction back. check-in: 9f39cb5b user: dan tags: rollback-abort
15:40
Add the ".eqp trace" command to the CLI when using SQLITE_DEBUG, as a convenient shorthand for "PRAGMA vdbe_debug=ON" but with automatic indentation feature for program listings provided by the CLI. check-in: 626502fa user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/vdbe.c.

984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
*/
case OP_Halt: {
  VdbeFrame *pFrame;
  int pcx;

  pcx = (int)(pOp - aOp);
#ifdef SQLITE_DEBUG
  if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); }
#endif
  if( pOp->p1==SQLITE_OK && p->pFrame ){
    /* Halt the sub-program. Return control to the parent frame. */
    pFrame = p->pFrame;
    p->pFrame = pFrame->pParent;
    p->nFrame--;
    sqlite3VdbeSetChanges(db, p->nChange);







|







984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
*/
case OP_Halt: {
  VdbeFrame *pFrame;
  int pcx;

  pcx = (int)(pOp - aOp);
#ifdef SQLITE_DEBUG
  if( pOp->p2==OE_Abort && !pOp->p3 ){ sqlite3VdbeAssertAbortable(p); }
#endif
  if( pOp->p1==SQLITE_OK && p->pFrame ){
    /* Halt the sub-program. Return control to the parent frame. */
    pFrame = p->pFrame;
    p->pFrame = pFrame->pParent;
    p->nFrame--;
    sqlite3VdbeSetChanges(db, p->nChange);

Changes to src/vdbeaux.c.

632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
...
740
741
742
743
744
745
746






747
748
749
750
751
752
753
....
2199
2200
2201
2202
2203
2204
2205
2206
2207

2208
2209
2210
2211
2212
2213
2214
....
2939
2940
2941
2942
2943
2944
2945
2946


2947
2948
2949
2950
2951
2952
2953
  VdbeOpIter sIter;
  memset(&sIter, 0, sizeof(sIter));
  sIter.v = v;

  while( (pOp = opIterNext(&sIter))!=0 ){
    int opcode = pOp->opcode;
    if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename 
     || opcode==OP_VDestroy
     || ((opcode==OP_Halt || opcode==OP_HaltIfNull) 
      && ((pOp->p1&0xff)==SQLITE_CONSTRAINT && pOp->p2==OE_Abort))
    ){
      hasAbort = 1;
      break;
    }
    if( opcode==OP_CreateBtree && pOp->p3==BTREE_INTKEY ) hasCreateTable = 1;
................................................................................
          break;
        }
#ifndef SQLITE_OMIT_WAL
        case OP_Checkpoint:
#endif
        case OP_Vacuum:
        case OP_JournalMode: {






          p->readOnly = 0;
          p->bIsReader = 1;
          break;
        }
        case OP_Next:
        case OP_SorterNext: {
          pOp->p4.xAdvance = sqlite3BtreeNext;
................................................................................
  n = ROUND8(sizeof(Op)*p->nOp);              /* Bytes of opcode memory used */
  x.pSpace = &((u8*)p->aOp)[n];               /* Unused opcode memory */
  assert( EIGHT_BYTE_ALIGNMENT(x.pSpace) );
  x.nFree = ROUNDDOWN8(pParse->szOpAlloc - n);  /* Bytes of unused memory */
  assert( x.nFree>=0 );
  assert( EIGHT_BYTE_ALIGNMENT(&x.pSpace[x.nFree]) );

  resolveP2Values(p, &nArg);
  p->usesStmtJournal = (u8)(pParse->isMultiWrite && pParse->mayAbort);

  if( pParse->explain && nMem<10 ){
    nMem = 10;
  }
  p->expired = 0;

  /* Memory for registers, parameters, cursor, etc, is allocated in one or two
  ** passes.  On the first pass, we try to reuse unused memory at the 
................................................................................
        sqlite3RollbackAll(db, SQLITE_OK);
        p->nChange = 0;
      }
      db->nStatement = 0;
    }else if( eStatementOp==0 ){
      if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){
        eStatementOp = SAVEPOINT_RELEASE;
      }else if( p->errorAction==OE_Abort ){


        eStatementOp = SAVEPOINT_ROLLBACK;
      }else{
        sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK);
        sqlite3CloseSavepoints(db);
        db->autoCommit = 1;
        p->nChange = 0;
      }







|







 







>
>
>
>
>
>







 







<

>







 







|
>
>







632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
...
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
....
2205
2206
2207
2208
2209
2210
2211

2212
2213
2214
2215
2216
2217
2218
2219
2220
....
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
  VdbeOpIter sIter;
  memset(&sIter, 0, sizeof(sIter));
  sIter.v = v;

  while( (pOp = opIterNext(&sIter))!=0 ){
    int opcode = pOp->opcode;
    if( opcode==OP_Destroy || opcode==OP_VUpdate || opcode==OP_VRename 
     || opcode==OP_VDestroy || opcode==OP_Vacuum
     || ((opcode==OP_Halt || opcode==OP_HaltIfNull) 
      && ((pOp->p1&0xff)==SQLITE_CONSTRAINT && pOp->p2==OE_Abort))
    ){
      hasAbort = 1;
      break;
    }
    if( opcode==OP_CreateBtree && pOp->p3==BTREE_INTKEY ) hasCreateTable = 1;
................................................................................
          break;
        }
#ifndef SQLITE_OMIT_WAL
        case OP_Checkpoint:
#endif
        case OP_Vacuum:
        case OP_JournalMode: {
          /* Neither VACUUM or "PRAGMA journal_mode" statements generate an
          ** OP_Transaction opcode. So setting usesStmtJournal does not cause
          ** either statement to actually open a statement journal. However,
          ** it does prevent them from rolling back an entire transaction
          ** if they fail because there is already a transaction open.  */
          p->usesStmtJournal = 1;
          p->readOnly = 0;
          p->bIsReader = 1;
          break;
        }
        case OP_Next:
        case OP_SorterNext: {
          pOp->p4.xAdvance = sqlite3BtreeNext;
................................................................................
  n = ROUND8(sizeof(Op)*p->nOp);              /* Bytes of opcode memory used */
  x.pSpace = &((u8*)p->aOp)[n];               /* Unused opcode memory */
  assert( EIGHT_BYTE_ALIGNMENT(x.pSpace) );
  x.nFree = ROUNDDOWN8(pParse->szOpAlloc - n);  /* Bytes of unused memory */
  assert( x.nFree>=0 );
  assert( EIGHT_BYTE_ALIGNMENT(&x.pSpace[x.nFree]) );


  p->usesStmtJournal = (u8)(pParse->isMultiWrite && pParse->mayAbort);
  resolveP2Values(p, &nArg);
  if( pParse->explain && nMem<10 ){
    nMem = 10;
  }
  p->expired = 0;

  /* Memory for registers, parameters, cursor, etc, is allocated in one or two
  ** passes.  On the first pass, we try to reuse unused memory at the 
................................................................................
        sqlite3RollbackAll(db, SQLITE_OK);
        p->nChange = 0;
      }
      db->nStatement = 0;
    }else if( eStatementOp==0 ){
      if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){
        eStatementOp = SAVEPOINT_RELEASE;
      }else if( p->errorAction==OE_Abort 
           && (p->usesStmtJournal || p->readOnly || p->rc!=SQLITE_ERROR) 
      ){
        eStatementOp = SAVEPOINT_ROLLBACK;
      }else{
        sqlite3RollbackAll(db, SQLITE_ABORT_ROLLBACK);
        sqlite3CloseSavepoints(db);
        db->autoCommit = 1;
        p->nChange = 0;
      }

Changes to src/window.c.

1072
1073
1074
1075
1076
1077
1078



1079
1080
1081
1082
1083
1084
1085
  VdbeCoverageIf(v, eCond==1);
  VdbeCoverageIf(v, eCond==2);
  sqlite3VdbeAddOp3(v, aOp[eCond], regZero, sqlite3VdbeCurrentAddr(v)+2, reg);
  VdbeCoverageNeverNullIf(v, eCond==0);
  VdbeCoverageNeverNullIf(v, eCond==1);
  VdbeCoverageNeverNullIf(v, eCond==2);
  sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_ERROR, OE_Abort);



  sqlite3VdbeAppendP4(v, (void*)azErr[eCond], P4_STATIC);
  sqlite3ReleaseTempReg(pParse, regZero);
}

/*
** Return the number of arguments passed to the window-function associated
** with the object passed as the only argument to this function.







>
>
>







1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
  VdbeCoverageIf(v, eCond==1);
  VdbeCoverageIf(v, eCond==2);
  sqlite3VdbeAddOp3(v, aOp[eCond], regZero, sqlite3VdbeCurrentAddr(v)+2, reg);
  VdbeCoverageNeverNullIf(v, eCond==0);
  VdbeCoverageNeverNullIf(v, eCond==1);
  VdbeCoverageNeverNullIf(v, eCond==2);
  sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_ERROR, OE_Abort);
#ifdef SQLITE_DEBUG
  sqlite3VdbeChangeP3(v, -1, 1);
#endif
  sqlite3VdbeAppendP4(v, (void*)azErr[eCond], P4_STATIC);
  sqlite3ReleaseTempReg(pParse, regZero);
}

/*
** Return the number of arguments passed to the window-function associated
** with the object passed as the only argument to this function.

Changes to test/triggerG.test.

71
72
73
74
75
76
77




















78

  END;
}

do_catchsql_test 310 {
  INSERT INTO t4 VALUES(1);
} {1 {hex literal too big: 0x2147483648e0e0099}}





















finish_test








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

>
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
  END;
}

do_catchsql_test 310 {
  INSERT INTO t4 VALUES(1);
} {1 {hex literal too big: 0x2147483648e0e0099}}

#-------------------------------------------------------------------------

do_execsql_test 400 {
  CREATE TABLE x1(a, b);
  CREATE TRIGGER x1t AFTER INSERT ON x1 BEGIN
    SELECT abs(-9223372036854775808 + new.a);
  END;
  BEGIN;
}

do_catchsql_test 410 {
  INSERT INTO x1 VALUES(2, 2), (0, 0), (1, 1);
} {1 {integer overflow}}

do_execsql_test  420 {
  SELECT * FROM x1; 
} {}

do_test  430 { sqlite3_get_autocommit db } {1}

finish_test

Changes to test/window1.test.

696
697
698
699
700
701
702








703

























704
  WINDOW w1 AS (PARTITION BY b IN (SELECT rowid FROM t7));
} {
  2 10
  1 101
  3 101
}



































finish_test







>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
  WINDOW w1 AS (PARTITION BY b IN (SELECT rowid FROM t7));
} {
  2 10
  1 101
  3 101
}

#-------------------------------------------------------------------------
do_execsql_test 17.0 {
  CREATE TABLE tbl1(a,b,c,d);
  CREATE TRIGGER r1 AFTER INSERT ON tbl1 WHEN new.a NOT NULL BEGIN
    SELECT sum(d) OVER
    (PARTITION BY b ORDER BY d ROWS BETWEEN 2 PRECEDING AND -2 FOLLOWING)
    FROM tbl1;
  END;
}

do_catchsql_test 17.1.1 {
  INSERT INTO tbl1(a) VALUES(1);
} {1 {frame ending offset must be a non-negative integer}}
do_execsql_test 17.1.2 {
  SELECT count(*) FROM tbl1;
} 0

do_catchsql_test 17.2.1 {
  INSERT INTO tbl1(a) VALUES(NULL), (NULL), (1);
} {1 {frame ending offset must be a non-negative integer}}
do_execsql_test 17.2.2 {
  SELECT count(*) FROM tbl1;
} 0

do_catchsql_test 17.3.1 {
  BEGIN;
    INSERT INTO tbl1(a) VALUES(NULL);
    INSERT INTO tbl1(a) VALUES(NULL), (1);
} {1 {frame ending offset must be a non-negative integer}}
do_execsql_test 17.3.2 {
  SELECT count(*) FROM tbl1;
} 0
do_test 17.3.3 { sqlite3_get_autocommit db } 1

finish_test