From: drh Date: Fri, 12 Jan 2018 21:00:14 +0000 (+0000) Subject: Add the experimental sqlite3_value_nochange() interface usable by xUpdate X-Git-Tag: version-3.22.0~41^2~1 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ce2fbd1b029477fd8745ca6381cd0b264fd901c5;p=thirdparty%2Fsqlite.git Add the experimental sqlite3_value_nochange() interface usable by xUpdate methods of virtual tables to see if a column has actually changed values. FossilOrigin-Name: 8b7be15ece9e2e83959bb0e21e240106fe1077431242c3cc6b81f1baa2382f40 --- diff --git a/manifest b/manifest index d9b6cfb745..c96606d8a9 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Simplification\sto\sthe\simplementation\sof\sOP_Insert. -D 2018-01-12T19:33:18.062 +C Add\sthe\sexperimental\ssqlite3_value_nochange()\sinterface\susable\sby\sxUpdate\nmethods\sof\svirtual\stables\sto\ssee\sif\sa\scolumn\shas\sactually\schanged\svalues. +D 2018-01-12T21:00:14.387 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 38f84f301cbef443b2d269f67a74b8cc536469831f70df7c3e912acc04932cc2 @@ -487,7 +487,7 @@ F src/resolve.c bbee7e31d369a18a2f4836644769882e9c5d40ef4a3af911db06410b65cb3730 F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac F src/select.c 8b22abe193e4d8243befa2038e4ae2405802fed1c446e5e502d11f652e09ba74 F src/shell.c.in b87abffd0db09203ad8a133d56fe8f154ace5ec0a14197a153fb7d80b1438c01 -F src/sqlite.h.in f83e63a48fb31fefc69c83bbe8700b4b44acdd64e440219087b0f14e35eeb8d4 +F src/sqlite.h.in 8c9b7bf8f635c13371d8060061e83d19623c77e7e4430dff7713e47761d1b972 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h c02d628cca67f3889c689d82d25c3eb45e2c155db08e4c6089b5840d64687d34 F src/sqliteInt.h fd8702c65994d7de3e2d8f7d85d958731da1ed29476571fdfa2290fd8ec0bf80 @@ -550,17 +550,17 @@ F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c 5b0c661a85f783d35b9883830736eeb63be4aefc4f6b7d9cd081d48782c041e2 F src/treeview.c eae35972ff44f67064de2eaf35f04afe94e7aea3271a8b3bcebb3f954880fec3 F src/trigger.c a34539c69433276d37b0da9a89c117726ff2d292c0902895af1f393a983cd3a1 -F src/update.c 8bd52c38d6d426925be4488ee106db26d9ee344406315671ed246ddace8d6091 +F src/update.c 7736ffc60d9fdfaae4e294d76158c0a9f752b369ae2b22ef9fc800d08e0bf31e F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5 F src/util.c 7315e97a8dc2c8e19ca64196c652cf0a65d13fd0a211b2cec082062372dc6261 F src/vacuum.c 90839322fd5f00df9617eb21b68beda9b6e2a2937576b0d65985e4aeb1c53739 -F src/vdbe.c e660530c799acf41616200373cdaec7af3fce5a25de40d900e8319d50971df73 +F src/vdbe.c 07dd1909ceac146717cc248838ffe2f85165e50e468e6a0c378d840c1caf6e98 F src/vdbe.h 134beb7a12a6213c00eba58febaede33447cc4441bc568a0d9c144b33fc3720a -F src/vdbeInt.h a0969c14950bcc61b2dfa19c6f62b42c5012013fcda342ca927a192ed37e6592 -F src/vdbeapi.c f519346f6db99a1eb3f85ca3ae8aede9ff9c4d90fec809dae7cb946786b2e270 -F src/vdbeaux.c 7d635c30e55196ee8e0af605aceab0c3036ed6d6ed55dd6639c4b2a2a4593b4f +F src/vdbeInt.h 5442fc816b6cf19c8801724199fd6b77a02eb31a7a174021713f8c59b30e51fa +F src/vdbeapi.c 02f773681d06e46454b0606339068d4d4490873dc4a7334bc0c6030552bb2c8c +F src/vdbeaux.c fc124962c9900b19d201e57084a4302d07136a77f51fdbdfabd625a3ca3b6dc1 F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191 -F src/vdbemem.c 8478f7fb1948bf8fdeec7c2cb59ea58155c31258b9cd43c56d485e03ed40bd07 +F src/vdbemem.c 7548dd5af03d24d534a5dbc41e3bbdf1fab83e9c8856a8d2549ed2ccf33d0e80 F src/vdbesort.c 731a09e5cb9e96b70c394c1b7cf3860fbe84acca7682e178615eb941a3a0ef2f F src/vdbetrace.c 48e11ebe040c6b41d146abed2602e3d00d621d7ebe4eb29b0a0f1617fd3c2f6c F src/vtab.c 0e4885495172e1bdf54b12cce23b395ac74ef5729031f15e1bc1e3e6b360ed1a @@ -1699,7 +1699,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 874285e477dd9bd164e25ddb08b6b80daaa8cfd111b4180ecce59b1ce26f77a5 -R 0ce0db05c5816c8a3f6d5399a0318468 +P 6acbdba59e9df4313a6232d925a70390acdc43dfa380b4fba7bb8bd442d6e728 +R 6f0b4cb15335f84e55c45be4e670230a +T *branch * sqlite3_value_nochange +T *sym-sqlite3_value_nochange * +T -sym-trunk * U drh -Z 101b1825b326975007694adf2a0d837c +Z 9655b705be92f16dc668ac363b3cc0e3 diff --git a/manifest.uuid b/manifest.uuid index cf6d922bb8..7fcc0b51be 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6acbdba59e9df4313a6232d925a70390acdc43dfa380b4fba7bb8bd442d6e728 \ No newline at end of file +8b7be15ece9e2e83959bb0e21e240106fe1077431242c3cc6b81f1baa2382f40 \ No newline at end of file diff --git a/src/sqlite.h.in b/src/sqlite.h.in index ba673748ed..7579b9926d 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -4847,6 +4847,12 @@ SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int), ** then the conversion is performed. Otherwise no conversion occurs. ** The [SQLITE_INTEGER | datatype] after conversion is returned.)^ ** +** ^Within the [xUpdate] method of a [virtual table], the +** sqlite3_value_nochange(X) interface returns true if and only if +** the column corresponding to X is unchanged by the UPDATE operation +** and the [xColumn] method had previously queried [sqlite3_vtab_nochange()] +** for that column and returned a NULL as a result. +** ** Please pay particular attention to the fact that the pointer returned ** from [sqlite3_value_blob()], [sqlite3_value_text()], or ** [sqlite3_value_text16()] can be invalidated by a subsequent call to @@ -4869,6 +4875,7 @@ int sqlite3_value_bytes(sqlite3_value*); int sqlite3_value_bytes16(sqlite3_value*); int sqlite3_value_type(sqlite3_value*); int sqlite3_value_numeric_type(sqlite3_value*); +int sqlite3_value_nochange(sqlite3_value*); /* ** CAPI3REF: Finding The Subtype Of SQL Values diff --git a/src/update.c b/src/update.c index 3de36fe211..ee920d2a5d 100644 --- a/src/update.c +++ b/src/update.c @@ -827,7 +827,8 @@ static void updateVirtualTable( if( aXRef[i]>=0 ){ sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i); }else{ - sqlite3VdbeAddOp4Int(v, OP_VColumn, iCsr, i, regArg+2+i, 1); + sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, i, regArg+2+i); + sqlite3VdbeChangeP5(v, 1); } } if( HasRowid(pTab) ){ @@ -862,6 +863,7 @@ static void updateVirtualTable( /* Create a record from the argument register contents and insert it into ** the ephemeral table. */ sqlite3VdbeAddOp3(v, OP_MakeRecord, regArg, nArg, regRec); + sqlite3VdbeChangeP5(v, 2); sqlite3VdbeAddOp2(v, OP_NewRowid, ephemTab, regRowid); sqlite3VdbeAddOp3(v, OP_Insert, ephemTab, regRec, regRowid); } diff --git a/src/vdbe.c b/src/vdbe.c index d66387d239..dc058b65ff 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -464,7 +464,7 @@ static void memTracePrint(Mem *p){ if( p->flags & MEM_Undefined ){ printf(" undefined"); }else if( p->flags & MEM_Null ){ - printf(" NULL"); + printf(p->flags & MEM_Zero ? " NULL-nochng" : " NULL"); }else if( (p->flags & (MEM_Int|MEM_Str))==(MEM_Int|MEM_Str) ){ printf(" si:%lld", p->u.i); }else if( p->flags & MEM_Int ){ @@ -2794,7 +2794,11 @@ case OP_MakeRecord: { assert( memIsValid(pRec) ); pRec->uTemp = serial_type = sqlite3VdbeSerialType(pRec, file_format, &len); if( pRec->flags & MEM_Zero ){ - if( nData ){ + if( serial_type==0 ){ + assert( pOp->p5==2 || CORRUPT_DB ); + /* serial_type 10 used internally only */ + pRec->uTemp = 10; + }else if( nData ){ if( sqlite3VdbeMemExpandBlob(pRec) ) goto no_mem; }else{ nZero += pRec->u.nZero; @@ -6697,15 +6701,15 @@ case OP_VFilter: { /* jump */ #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifndef SQLITE_OMIT_VIRTUALTABLE -/* Opcode: VColumn P1 P2 P3 P4 * +/* Opcode: VColumn P1 P2 P3 * P5 ** Synopsis: r[P3]=vcolumn(P2) ** ** Store in register P3 the value of the P2-th column of ** the current row of the virtual-table of cursor P1. ** ** If the VColumn opcode is being used to fetch the value of -** an unchanging column during an UPDATE operation, then the P4 -** value is 1. Otherwise, P4 is 0. The P4 value is returned +** an unchanging column during an UPDATE operation, then the P5 +** value is 1. Otherwise, P5 is 0. The P5 value is returned ** by sqlite3_vtab_nochange() routine can can be used ** by virtual table implementations to return special "no-change" ** marks which can be more efficient, depending on the virtual table. @@ -6730,8 +6734,13 @@ case OP_VColumn: { assert( pModule->xColumn ); memset(&sContext, 0, sizeof(sContext)); sContext.pOut = pDest; - sContext.bVtabNoChng = pOp->p4.i!=0; - MemSetTypeFlag(pDest, MEM_Null); + if( pOp->p5 ){ + sqlite3VdbeMemSetNull(pDest); + pDest->flags = MEM_Null|MEM_Zero; + pDest->u.nZero = 0; + }else{ + MemSetTypeFlag(pDest, MEM_Null); + } rc = pModule->xColumn(pCur->uc.pVCur, &sContext, pOp->p2); sqlite3VtabImportErrmsg(p, pVtab); if( sContext.isError ){ diff --git a/src/vdbeInt.h b/src/vdbeInt.h index f646a4036a..b7e324c94b 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -224,6 +224,8 @@ struct sqlite3_value { ** If the MEM_Null flag is set, then the value is an SQL NULL value. ** For a pointer type created using sqlite3_bind_pointer() or ** sqlite3_result_pointer() the MEM_Term and MEM_Subtype flags are also set. +** If both MEM_Null and MEM_Zero are set, that means that the value is +** an unchanging column value from VColumn. ** ** If the MEM_Str flag is set then Mem.z points at a string representation. ** Usually this is encoded in the same unicode encoding as the main diff --git a/src/vdbeapi.c b/src/vdbeapi.c index 19aa783bb6..bdd6d1cd07 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -268,6 +268,11 @@ int sqlite3_value_type(sqlite3_value* pVal){ return aType[pVal->flags&MEM_AffMask]; } +/* Return true if a parameter to xUpdate represents an unchanged column */ +int sqlite3_value_nochange(sqlite3_value *pVal){ + return (pVal->flags&(MEM_Null|MEM_Zero))==(MEM_Null|MEM_Zero); +} + /* Make a copy of an sqlite3_value object */ sqlite3_value *sqlite3_value_dup(const sqlite3_value *pOrig){ @@ -761,7 +766,7 @@ sqlite3 *sqlite3_context_db_handle(sqlite3_context *p){ */ int sqlite3_vtab_nochange(sqlite3_context *p){ assert( p ); - return p->bVtabNoChng; + return sqlite3_value_nochange(p->pOut); } /* diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 1780d37b8c..72a5b96bba 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -3454,7 +3454,11 @@ u32 sqlite3VdbeSerialGet( Mem *pMem /* Memory cell to write value into */ ){ switch( serial_type ){ - case 10: /* Reserved for future use */ + case 10: { /* Internal use only: NULL with virtual table + ** UPDATE no-change flag set */ + pMem->flags = MEM_Null|MEM_Zero; + break; + } case 11: /* Reserved for future use */ case 0: { /* Null */ /* EVIDENCE-OF: R-24078-09375 Value is a NULL. */ diff --git a/src/vdbemem.c b/src/vdbemem.c index 107d831f4c..d8f1e64328 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -43,7 +43,7 @@ int sqlite3VdbeCheckMemInvariants(Mem *p){ if( p->flags & MEM_Null ){ /* Cannot be both MEM_Null and some other type */ assert( (p->flags & (MEM_Int|MEM_Real|MEM_Str|MEM_Blob - |MEM_RowSet|MEM_Frame|MEM_Agg|MEM_Zero))==0 ); + |MEM_RowSet|MEM_Frame|MEM_Agg))==0 ); /* If MEM_Null is set, then either the value is a pure NULL (the usual ** case) or it is a pointer set using sqlite3_bind_pointer() or