SQLite

Check-in [003e1c8c27]
Login

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

Overview
Comment:Allow arbitrary expressions as the second argument to RAISE().
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | enhanced-raise
Files: files | file ages | folders
SHA3-256: 003e1c8c27824cb917b3869bdf9000f32ff0b6887a2aff8516712cfe865cf34d
User & Date: drh 2024-05-08 17:42:13.761
Context
2024-05-17
14:26
Merge branches "fix-onerow-opt", "faster-openread", "fts5-delay-tokenizer" and "enhanced-raise", each containing minor enhancements prepared for 3.46, into this branch. (Closed-Leaf check-in: 6dc6472175 user: dan tags: pending-3.46)
2024-05-08
17:42
Allow arbitrary expressions as the second argument to RAISE(). (Closed-Leaf check-in: 003e1c8c27 user: drh tags: enhanced-raise)
11:51
Fix a hyperlink typo in session documentation. (check-in: 42d67c6fed user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/expr.c.
5302
5303
5304
5305
5306
5307
5308
5309
5310
5311
5312

5313
5314
5315
5316
5317
5318
5319
5320
5321
5322
5323
5324
        return 0;
      }
      if( pExpr->affExpr==OE_Abort ){
        sqlite3MayAbort(pParse);
      }
      assert( !ExprHasProperty(pExpr, EP_IntValue) );
      if( pExpr->affExpr==OE_Ignore ){
        sqlite3VdbeAddOp4(
            v, OP_Halt, SQLITE_OK, OE_Ignore, 0, pExpr->u.zToken,0);
        VdbeCoverage(v);
      }else{

        sqlite3HaltConstraint(pParse,
             pParse->pTriggerTab ? SQLITE_CONSTRAINT_TRIGGER : SQLITE_ERROR,
             pExpr->affExpr, pExpr->u.zToken, 0, 0);
      }

      break;
    }
#endif
  }
  sqlite3ReleaseTempReg(pParse, regFree1);
  sqlite3ReleaseTempReg(pParse, regFree2);
  return inReg;







|
<


>
|

|

<







5302
5303
5304
5305
5306
5307
5308
5309

5310
5311
5312
5313
5314
5315
5316

5317
5318
5319
5320
5321
5322
5323
        return 0;
      }
      if( pExpr->affExpr==OE_Abort ){
        sqlite3MayAbort(pParse);
      }
      assert( !ExprHasProperty(pExpr, EP_IntValue) );
      if( pExpr->affExpr==OE_Ignore ){
        sqlite3VdbeAddOp2(v, OP_Halt, SQLITE_OK, OE_Ignore);

        VdbeCoverage(v);
      }else{
        r1 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree1);
        sqlite3VdbeAddOp3(v, OP_Halt, 
             pParse->pTriggerTab ? SQLITE_CONSTRAINT_TRIGGER : SQLITE_ERROR,
             pExpr->affExpr, r1);
      }

      break;
    }
#endif
  }
  sqlite3ReleaseTempReg(pParse, regFree1);
  sqlite3ReleaseTempReg(pParse, regFree2);
  return inReg;
Changes to src/fkey.c.
1324
1325
1326
1327
1328
1329
1330
1331

1332
1333
1334
1335
1336
1337
1338
    nFrom = sqlite3Strlen30(zFrom);

    if( action==OE_Restrict ){
      int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
      SrcList *pSrc;
      Expr *pRaise; 

      pRaise = sqlite3Expr(db, TK_RAISE, "FOREIGN KEY constraint failed");

      if( pRaise ){
        pRaise->affExpr = OE_Abort;
      }
      pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
      if( pSrc ){
        assert( pSrc->nSrc==1 );
        pSrc->a[0].zName = sqlite3DbStrDup(db, zFrom);







|
>







1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
    nFrom = sqlite3Strlen30(zFrom);

    if( action==OE_Restrict ){
      int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
      SrcList *pSrc;
      Expr *pRaise; 

      pRaise = sqlite3Expr(db, TK_STRING, "FOREIGN KEY constraint failed"),
      pRaise = sqlite3PExpr(pParse, TK_RAISE, pRaise, 0);
      if( pRaise ){
        pRaise->affExpr = OE_Abort;
      }
      pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
      if( pSrc ){
        assert( pSrc->nSrc==1 );
        pSrc->a[0].zName = sqlite3DbStrDup(db, zFrom);
Changes to src/parse.y.
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
// The special RAISE expression that may occur in trigger programs
expr(A) ::= RAISE LP IGNORE RP.  {
  A = sqlite3PExpr(pParse, TK_RAISE, 0, 0); 
  if( A ){
    A->affExpr = OE_Ignore;
  }
}
expr(A) ::= RAISE LP raisetype(T) COMMA nm(Z) RP.  {
  A = sqlite3ExprAlloc(pParse->db, TK_RAISE, &Z, 1);
  if( A ) {
    A->affExpr = (char)T;
  }
}
%endif  !SQLITE_OMIT_TRIGGER

%type raisetype {int}







|
|







1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
// The special RAISE expression that may occur in trigger programs
expr(A) ::= RAISE LP IGNORE RP.  {
  A = sqlite3PExpr(pParse, TK_RAISE, 0, 0); 
  if( A ){
    A->affExpr = OE_Ignore;
  }
}
expr(A) ::= RAISE LP raisetype(T) COMMA expr(Z) RP.  {
  A = sqlite3PExpr(pParse, TK_RAISE, Z, 0);
  if( A ) {
    A->affExpr = (char)T;
  }
}
%endif  !SQLITE_OMIT_TRIGGER

%type raisetype {int}
Changes to src/treeview.c.
814
815
816
817
818
819
820
821

822
823
824
825
826
827
828
      switch( pExpr->affExpr ){
        case OE_Rollback:   zType = "rollback";  break;
        case OE_Abort:      zType = "abort";     break;
        case OE_Fail:       zType = "fail";      break;
        case OE_Ignore:     zType = "ignore";    break;
      }
      assert( !ExprHasProperty(pExpr, EP_IntValue) );
      sqlite3TreeViewLine(pView, "RAISE %s(%Q)", zType, pExpr->u.zToken);

      break;
    }
#endif
    case TK_MATCH: {
      sqlite3TreeViewLine(pView, "MATCH {%d:%d}%s",
                          pExpr->iTable, pExpr->iColumn, zFlgs);
      sqlite3TreeViewExpr(pView, pExpr->pRight, 0);







|
>







814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
      switch( pExpr->affExpr ){
        case OE_Rollback:   zType = "rollback";  break;
        case OE_Abort:      zType = "abort";     break;
        case OE_Fail:       zType = "fail";      break;
        case OE_Ignore:     zType = "ignore";    break;
      }
      assert( !ExprHasProperty(pExpr, EP_IntValue) );
      sqlite3TreeViewLine(pView, "RAISE %s", zType);
      sqlite3TreeViewExpr(pView, pExpr->pLeft, 0);
      break;
    }
#endif
    case TK_MATCH: {
      sqlite3TreeViewLine(pView, "MATCH {%d:%d}%s",
                          pExpr->iTable, pExpr->iColumn, zFlgs);
      sqlite3TreeViewExpr(pView, pExpr->pRight, 0);
Changes to src/vdbe.c.
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229

1230
1231



1232

1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253



1254
1255
1256
1257
1258
1259
1260
  if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); }
#endif
  if( (pIn3->flags & MEM_Null)==0 ) break;
  /* Fall through into OP_Halt */
  /* no break */ deliberate_fall_through
}

/* Opcode:  Halt P1 P2 * P4 P5
**
** Exit immediately.  All open cursors, etc are closed
** automatically.
**
** P1 is the result code returned by sqlite3_exec(), sqlite3_reset(),
** or sqlite3_finalize().  For a normal halt, this should be SQLITE_OK (0).
** For errors, it can be some other value.  If P1!=0 then P2 will determine
** whether or not to rollback the current transaction.  Do not rollback
** if P2==OE_Fail. Do the rollback if P2==OE_Rollback.  If P2==OE_Abort,
** then back out all changes that have occurred during this execution of the
** VDBE, but do not rollback the transaction.
**

** If P4 is not null then it is an error message string.
**



** P5 is a value between 0 and 4, inclusive, that modifies the P4 string.

**
**    0:  (no change)
**    1:  NOT NULL constraint failed: P4
**    2:  UNIQUE constraint failed: P4
**    3:  CHECK constraint failed: P4
**    4:  FOREIGN KEY constraint failed: P4
**
** If P5 is not zero and P4 is NULL, then everything after the ":" is
** omitted.
**
** There is an implied "Halt 0 0 0" instruction inserted at the very end of
** every program.  So a jump past the last instruction of the program
** is the same as executing Halt.
*/
case OP_Halt: {
  VdbeFrame *pFrame;
  int pcx;

#ifdef SQLITE_DEBUG
  if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); }
#endif




  /* A deliberately coded "OP_Halt SQLITE_INTERNAL * * * *" opcode indicates
  ** something is wrong with the code generator.  Raise an assertion in order
  ** to bring this to the attention of fuzzers and other testing tools. */
  assert( pOp->p1!=SQLITE_INTERNAL );

  if( p->pFrame && pOp->p1==SQLITE_OK ){







|












>
|

>
>
>
|
>

<





|
|












>
>
>







1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238

1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
  if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); }
#endif
  if( (pIn3->flags & MEM_Null)==0 ) break;
  /* Fall through into OP_Halt */
  /* no break */ deliberate_fall_through
}

/* Opcode:  Halt P1 P2 P3 P4 P5
**
** Exit immediately.  All open cursors, etc are closed
** automatically.
**
** P1 is the result code returned by sqlite3_exec(), sqlite3_reset(),
** or sqlite3_finalize().  For a normal halt, this should be SQLITE_OK (0).
** For errors, it can be some other value.  If P1!=0 then P2 will determine
** whether or not to rollback the current transaction.  Do not rollback
** if P2==OE_Fail. Do the rollback if P2==OE_Rollback.  If P2==OE_Abort,
** then back out all changes that have occurred during this execution of the
** VDBE, but do not rollback the transaction.
**
** If P3 is not zero and P4 is NULL, then P3 is a register that holds the
** text of an error message.
**
** If P3 is zero and P4 is not null then the error message string is held
** in P4.
**
** P5 is a value between 1 and 4, inclusive, then the P4 error message
** string is modified as follows:
**

**    1:  NOT NULL constraint failed: P4
**    2:  UNIQUE constraint failed: P4
**    3:  CHECK constraint failed: P4
**    4:  FOREIGN KEY constraint failed: P4
**
** If P3 is zero and P5 is not zero and P4 is NULL, then everything after
** the ":" is omitted.
**
** There is an implied "Halt 0 0 0" instruction inserted at the very end of
** every program.  So a jump past the last instruction of the program
** is the same as executing Halt.
*/
case OP_Halt: {
  VdbeFrame *pFrame;
  int pcx;

#ifdef SQLITE_DEBUG
  if( pOp->p2==OE_Abort ){ sqlite3VdbeAssertAbortable(p); }
#endif
  assert( pOp->p4type==P4_NOTUSED
       || pOp->p4type==P4_STATIC
       || pOp->p4type==P4_DYNAMIC );

  /* A deliberately coded "OP_Halt SQLITE_INTERNAL * * * *" opcode indicates
  ** something is wrong with the code generator.  Raise an assertion in order
  ** to bring this to the attention of fuzzers and other testing tools. */
  assert( pOp->p1!=SQLITE_INTERNAL );

  if( p->pFrame && pOp->p1==SQLITE_OK ){
1277
1278
1279
1280
1281
1282
1283





1284
1285
1286
1287
1288
1289
1290
1291
    pOp = &aOp[pcx];
    break;
  }
  p->rc = pOp->p1;
  p->errorAction = (u8)pOp->p2;
  assert( pOp->p5<=4 );
  if( p->rc ){





    if( pOp->p5 ){
      static const char * const azType[] = { "NOT NULL", "UNIQUE", "CHECK",
                                             "FOREIGN KEY" };
      testcase( pOp->p5==1 );
      testcase( pOp->p5==2 );
      testcase( pOp->p5==3 );
      testcase( pOp->p5==4 );
      sqlite3VdbeError(p, "%s constraint failed", azType[pOp->p5-1]);







>
>
>
>
>
|







1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
    pOp = &aOp[pcx];
    break;
  }
  p->rc = pOp->p1;
  p->errorAction = (u8)pOp->p2;
  assert( pOp->p5<=4 );
  if( p->rc ){
    if( pOp->p3>0 && pOp->p4type==P4_NOTUSED ){
      const char *zErr;
      assert( pOp->p3<=(p->nMem + 1 - p->nCursor) );
      zErr = sqlite3ValueText(&aMem[pOp->p3], SQLITE_UTF8);
      sqlite3VdbeError(p, "%s", zErr);
    }else if( pOp->p5 ){
      static const char * const azType[] = { "NOT NULL", "UNIQUE", "CHECK",
                                             "FOREIGN KEY" };
      testcase( pOp->p5==1 );
      testcase( pOp->p5==2 );
      testcase( pOp->p5==3 );
      testcase( pOp->p5==4 );
      sqlite3VdbeError(p, "%s constraint failed", azType[pOp->p5-1]);
Changes to test/colname.test.
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
# also caused by check-in https://sqlite.org/src/info/6b2ff26c25
#
# Prior to being fixed, the following CREATE TABLE caused an
# assertion fault.
#
do_catchsql_test colname-9.410 {
  CREATE TABLE t5 AS SELECT RAISE(abort,a);
} {1 {RAISE() may only be used within a trigger-program}}

# Make sure the quotation marks get removed from the column names
# when constructing a new table from an aggregate SELECT.
# Email from Juergen Palm on 2017-07-11.
#
do_execsql_test colname-10.100 {
  DROP TABLE IF EXISTS t1;







|







420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
# also caused by check-in https://sqlite.org/src/info/6b2ff26c25
#
# Prior to being fixed, the following CREATE TABLE caused an
# assertion fault.
#
do_catchsql_test colname-9.410 {
  CREATE TABLE t5 AS SELECT RAISE(abort,a);
} {1 {no such column: a}}

# Make sure the quotation marks get removed from the column names
# when constructing a new table from an aggregate SELECT.
# Email from Juergen Palm on 2017-07-11.
#
do_execsql_test colname-10.100 {
  DROP TABLE IF EXISTS t1;
Changes to test/trigger1.test.
833
834
835
836
837
838
839













840
841
reset_db
do_catchsql_test trigger1-23.1 {
  CREATE TABLE t1(a INT);
  CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN
    INSERT INTO t1 SELECT e_master LIMIT 1,#1;
  END;
} {1 {near "#1": syntax error}}














finish_test







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


833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
reset_db
do_catchsql_test trigger1-23.1 {
  CREATE TABLE t1(a INT);
  CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN
    INSERT INTO t1 SELECT e_master LIMIT 1,#1;
  END;
} {1 {near "#1": syntax error}}

# 2024-05-08 Allow arbitrary expressions as the 2nd argument to RAISE().
#
do_catchsql_test trigger1-24.1 {
  CREATE TRIGGER r1 AFTER INSERT ON t1 BEGIN
    SELECT raise(abort,format('attempt to insert %d where is not a power of 2',new.a))
     WHERE (new.a & (new.a-1))!=0;
  END;
  INSERT INTO t1 VALUES(0),(1),(2),(4),(8),(65536);
} {0 {}}
do_catchsql_test trigger1-24.2 {
  INSERT INTO t1 VALUES(9876);
} {1 {attempt to insert 9876 where is not a power of 2}}

finish_test