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: |
003e1c8c27824cb917b3869bdf9000f3 |
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
Changes to src/expr.c.
︙ | ︙ | |||
5302 5303 5304 5305 5306 5307 5308 | return 0; } if( pExpr->affExpr==OE_Abort ){ sqlite3MayAbort(pParse); } assert( !ExprHasProperty(pExpr, EP_IntValue) ); if( pExpr->affExpr==OE_Ignore ){ | | < > | | < | 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, ®Free1); 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 | nFrom = sqlite3Strlen30(zFrom); if( action==OE_Restrict ){ int iDb = sqlite3SchemaToIndex(db, pTab->pSchema); SrcList *pSrc; Expr *pRaise; | | > | 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 | // 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; } } | | | | 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 | 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) ); | | > | 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 | 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 } | | > | > > > | > < | | > > > | 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 | pOp = &aOp[pcx]; break; } p->rc = pOp->p1; p->errorAction = (u8)pOp->p2; assert( pOp->p5<=4 ); if( p->rc ){ | > > > > > | | 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 | # 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); | | | 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 |