faultsim_test_result {0 {}} {1 SQLITE_NOMEM}
}
+#-------------------------------------------------------------------------
+reset_db
+do_execsql_test 2.0 {
+ CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
+ INSERT INTO t1 VALUES(1, 'one');
+ INSERT INTO t1 VALUES(2, 'two');
+ ALTER TABLE t1 ADD COLUMN c DEFAULT 'abcdefghijklmnopqrstuvwxyz';
+}
+faultsim_save_and_close
+
+do_faultsim_test 2 -faults oom-t* -prep {
+ faultsim_restore_and_reopen
+ db eval {SELECT * FROM sqlite_schema}
+} -body {
+ sqlite3session S db main
+ S attach *
+ execsql {
+ DELETE FROM t1 WHERE a = 1;
+ }
+} -test {
+ faultsim_test_result {0 {}} {1 SQLITE_NOMEM}
+ catch { S delete }
+}
+
finish_test
int bEnable; /* True if currently recording */
int bIndirect; /* True if all changes are indirect */
int bAutoAttach; /* True to auto-attach tables */
- int bImplicitPK; /* True to handle tables with implicit PK */
- int rc; /* Non-zero if an error has occurred */
+ int bImplicitPK; /* True to handle tables with implicit PK */ int rc; /* Non-zero if an error has occurred */
void *pFilterCtx; /* First argument to pass to xTableFilter */
int (*xTableFilter)(void *pCtx, const char *zTab);
i64 nMalloc; /* Number of bytes of data allocated */
for(i=0; i<(pTab->nCol-pTab->bRowid); i++){
sqlite3_value *p = 0;
if( op!=SQLITE_INSERT ){
- TESTONLY(int trc = ) pSession->hook.xOld(pSession->hook.pCtx, i, &p);
- assert( trc==SQLITE_OK );
+ /* This may fail if the column has a non-NULL default and was added
+ ** using ALTER TABLE ADD COLUMN after this record was created. */
+ rc = pSession->hook.xOld(pSession->hook.pCtx, i, &p);
}else if( pTab->abPK[i] ){
TESTONLY(int trc = ) pSession->hook.xNew(pSession->hook.pCtx, i, &p);
assert( trc==SQLITE_OK );
}
- /* This may fail if SQLite value p contains a utf-16 string that must
- ** be converted to utf-8 and an OOM error occurs while doing so. */
- rc = sessionSerializeValue(0, p, &nByte);
+ if( rc==SQLITE_OK ){
+ /* This may fail if SQLite value p contains a utf-16 string that must
+ ** be converted to utf-8 and an OOM error occurs while doing so. */
+ rc = sessionSerializeValue(0, p, &nByte);
+ }
if( rc!=SQLITE_OK ) goto error_out;
}
if( pTab->bRowid ){
-C Fix\sharmless\sstatic\sanalyzer\swarning\sin\ssqlite3-rsync.
-D 2024-09-17T22:57:08.639
+C Fix\sthe\spreupdate\shook\sso\sthat\sit\sworks\swhen\sthe\s"old.*"\srow\shas\sa\scolumn\swith\sa\snon-NULL\sdefault\svalue\sthat\swas\sadded\sby\sALTER\sTABLE\sADD\sCOLUMN\safter\sthe\scurrent\srecord\swas\screated.
+D 2024-09-18T15:02:27.631
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F ext/session/sessiondiff.test e89f7aedcdd89e5ebac3a455224eb553a171e9586fc3e1e6a7b3388d2648ba8d
F ext/session/sessionfault.test c2b43d01213b389a3f518e90775fca2120812ba51e50444c4066962263e45c11
F ext/session/sessionfault2.test b0d6a7c1d7398a7e800d84657404909c7d385965ea8576dc79ed344c46fbf41c
-F ext/session/sessionfault3.test 7c7547202775de268f3fe6f074c4d0d165151829710b4e64f90d4a01645ba9e7
+F ext/session/sessionfault3.test ce0b5d182133935c224d72507dbf1c5be1a1febf7e85d0b0fbd6d2f724b32b96
F ext/session/sessioninvert.test 04075517a9497a80d39c495ba6b44f3982c7371129b89e2c52219819bc105a25
F ext/session/sessionmem.test f2a735db84a3e9e19f571033b725b0b2daf847f3f28b1da55a0c1a4e74f1de09
F ext/session/sessionnoact.test 506526a5fe29421ecc50d371774ef1bb04cbd9d906a8a468f0556cdbde184c22
F ext/session/sessionsize.test 8fcf4685993c3dbaa46a24183940ab9f5aa9ed0d23e5fb63bfffbdb56134b795
F ext/session/sessionstat1.test 5e718d5888c0c49bbb33a7a4f816366db85f59f6a4f97544a806421b85dc2dec
F ext/session/sessionwor.test 6fd9a2256442cebde5b2284936ae9e0d54bde692d0f5fd009ecef8511f4cf3fc
-F ext/session/sqlite3session.c c7473aafbd88f796391a8c25aa90975a8f3729ab7f4f8cf74ab9d3b014e10abe
+F ext/session/sqlite3session.c e74d3e58d4c20e72c14c23f909e1a6c7ea71ae31129fb1685babf2cab558d613
F ext/session/sqlite3session.h 683ccbf16e2c2521661fc4c1cf918ce57002039efbcabcd8097fa4bca569104b
F ext/session/test_session.c aa29abdcc9011ac02f4fa38e8ede226106eaeee7c3ea7d8b2b999a124e0c368c
F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3
F src/vacuum.c b763b6457bd058d2072ef9364832351fd8d11e8abf70cbb349657360f7d55c40
F src/vdbe.c be5f58bc29f60252e041a618eae59e8d57d460ba136c5403cf0abf955560c457
F src/vdbe.h c2549a215898a390de6669cfa32adba56f0d7e17ba5a7f7b14506d6fd5f0c36a
-F src/vdbeInt.h 949669dfd8a41550d27dcb905b494f2ccde9a2e6c1b0b04daa1227e2e74c2b2c
-F src/vdbeapi.c 7c4e2f7635ea1ab7db5e1e24b33a1c20e4a123e926456614f064b58b13b85992
-F src/vdbeaux.c 25d685cafe119ff890c94345e884ea558a6b5d823bfa52ba708eb8ff3c70aa71
+F src/vdbeInt.h af7d7e8291edd0b19f2cd698e60e4d4031078f9a2f2328ac8f0b7efb134f8a1d
+F src/vdbeapi.c 483a391801ecacfeaa1d202c1d4dc2d7e520ba67566ca540868602117d6bdec5
+F src/vdbeaux.c 676dbee99b4febdd94bc9658667a2e3bc413c4c0e356242d90f98a1155d513e5
F src/vdbeblob.c 255be187436da38b01f276c02e6a08103489bbe2a7c6c21537b7aecbe0e1f797
F src/vdbemem.c 831a244831eaa45335f9ae276b50a7a82ee10d8c46c2c72492d4eb8c98d94d89
F src/vdbesort.c d0a3c7056c081703c8b6d91ad60f17da5e062a5c64bf568ed0fa1b5f4cae311f
F test/having.test a89236dd8d55aa50c4805f82ac9daf64d477a44d712d8209c118978d0ca21ec9
F test/hexlit.test 4a6a5f46e3c65c4bf1fa06f5dd5a9507a5627751
F test/hidden.test 23c1393a79e846d68fd902d72c85d5e5dcf98711
-F test/hook.test 18cae9140fa7f9a6f346e892a3fe3e31b2ca0be1494cd01b918adb74281016a6
+F test/hook.test 3481a68009fe143e3363fca922f6fc7a1e1f3776c51e42777f1a01b26ad2a9c8
F test/hook2.test b9ff3b8c6519fb67f33192f1afe86e7782ee4ac8
F test/icu.test 8da7d52cd9722c82f33b0466ed915460cb03c23a38f18a9a2d3ff97da9a4a8c0
F test/ieee754.test b0945d12be7d255f3dfa18e2511b17ca37e0edd2b803231c52d05b86c04ab26e
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 97528788145b83a1486dbaf09326ebedbc07bd0b47a57cdff773885b0b984604
-R de863a50ae68edb342391097eaaa3380
-U drh
-Z d1cb55d24cd7d46dead0c36bd671adaa
+P a63e412b6b2939422ecfa99d91fccb7a9c61e1533bb0db20ff12f3815ef41a2c
+R 2022f5c82821db1ada9b61c2c71e65f9
+T *branch * preupdate-hook-fix
+T *sym-preupdate-hook-fix *
+T -sym-trunk *
+U dan
+Z c649b0105c7af3011732c3c809572a4f
# Remove this line to create a well-formed Fossil manifest.
-a63e412b6b2939422ecfa99d91fccb7a9c61e1533bb0db20ff12f3815ef41a2c
+00a398cf900179aa5a8aab09fe4a671d99e7a31583282848ef39390f2ef246eb
Mem *aNew; /* Array of new.* values */
Table *pTab; /* Schema object being updated */
Index *pPk; /* PK index if pTab is WITHOUT ROWID */
+ sqlite3_value **apDflt; /* Array of default values, if required */
};
/*
if( iIdx==p->pTab->iPKey ){
sqlite3VdbeMemSetInt64(pMem, p->iKey1);
}else if( iIdx>=p->pUnpacked->nField ){
- *ppValue = (sqlite3_value *)columnNullValue();
+ /* This occurs when the table has been extended using ALTER TABLE
+ ** ADD COLUMN. The value to return is the default value of the column. */
+ Column *pCol = &p->pTab->aCol[iIdx];
+ if( pCol->iDflt>0 ){
+ if( p->apDflt==0 ){
+ int nByte = sizeof(sqlite3_value*)*p->pTab->nCol;
+ p->apDflt = (sqlite3_value**)sqlite3DbMallocZero(db, nByte);
+ if( p->apDflt==0 ) goto preupdate_old_out;
+ }
+ if( p->apDflt[iIdx]==0 ){
+ Expr *pDflt = p->pTab->u.tab.pDfltList->a[pCol->iDflt-1].pExpr;
+ sqlite3_value *pVal = 0;
+ rc = sqlite3ValueFromExpr(db, pDflt, ENC(db), pCol->affinity, &pVal);
+ if( rc==SQLITE_OK && pVal==0 ){
+ rc = SQLITE_CORRUPT_BKPT;
+ }
+ p->apDflt[iIdx] = pVal;
+ }
+ *ppValue = p->apDflt[iIdx];
+ }else{
+ *ppValue = (sqlite3_value *)columnNullValue();
+ }
}else if( p->pTab->aCol[iIdx].affinity==SQLITE_AFF_REAL ){
if( pMem->flags & (MEM_Int|MEM_IntReal) ){
testcase( pMem->flags & MEM_Int );
}
sqlite3DbNNFreeNN(db, preupdate.aNew);
}
+ if( preupdate.apDflt ){
+ int i;
+ for(i=0; i<pTab->nCol; i++){
+ sqlite3ValueFree(preupdate.apDflt[i]);
+ }
+ sqlite3DbFree(db, preupdate.apDflt);
+ }
}
#endif /* SQLITE_ENABLE_PREUPDATE_HOOK */
}
}
-if 0 {
+if 1 {
# At time of writing, these two are broken. They demonstrate that the
# sqlite3_preupdate_old() method does not handle the case where ALTER TABLE
# has been used to add a column with a default value other than NULL.
#
+ # 2024-09-18: These are now fixed.
+ #
do_preupdate_test 7.5.2.1 {
DELETE FROM t8 WHERE a = 'one'
} {
INSERT INTO t4 VALUES('def', 3);
} {1 {UNIQUE constraint failed: t4.a}}
+#-------------------------------------------------------------------------
+# Test adding non-NULL default values using ALTER TABLE.
+#
+reset_db
+db preupdate hook preupdate_hook
+do_execsql_test 13.0 {
+ CREATE TABLE t1(a INTEGER PRIMARY KEY);
+ INSERT INTO t1 VALUES(100), (200), (300), (400);
+}
+
+do_execsql_test 13.1 {
+ ALTER TABLE t1 ADD COLUMN b DEFAULT 1234;
+ ALTER TABLE t1 ADD COLUMN c DEFAULT 'abcdef';
+ ALTER TABLE t1 ADD COLUMN d DEFAULT NULL;
+}
+
+do_preupdate_test 13.2 {
+ DELETE FROM t1 WHERE a=300
+} {DELETE main t1 300 300 0 300 1234 abcdef {}}
+
+do_preupdate_test 13.3 {
+ UPDATE t1 SET d='hello world' WHERE a=200
+} {
+ UPDATE main t1 200 200 0 200 1234 abcdef {}
+ 200 1234 abcdef {hello world}
+}
+
+do_preupdate_test 13.4 {
+ INSERT INTO t1 DEFAULT VALUES;
+} {
+ INSERT main t1 401 401 0 401 1234 abcdef {}
+}
+
finish_test