From 2bf2f8cbeea0fcfaab461f035d7f01cad4f1029e Mon Sep 17 00:00:00 2001 From: drh <> Date: Wed, 29 Mar 2023 00:05:54 +0000 Subject: [PATCH] Modify the OP_IsType opcode so that it does not need to distinguish between NaN and other floating point values. FossilOrigin-Name: 242cb36c3bd0192208d948214b510348f561e0fe56f1c77b4a5e4fd84bd42cca --- manifest | 17 ++++---- manifest.uuid | 2 +- src/pragma.c | 47 ++++++++++++++++------ src/vdbe.c | 105 ++++++++++++++++---------------------------------- 4 files changed, 80 insertions(+), 91 deletions(-) diff --git a/manifest b/manifest index d5fb3e57d7..e9c48c0633 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sweird\scorner\scase\sin\saggregate\sfunction\sprocessing\sthat\sresults\sfrom\sthe\nrecent\saddition\sof\ssupport\sfor\sindex\sexpressions\son\saggregate\squeries.\n[forum:/forumpost/bad532820c|Forum\spost\sbad532820c]. -D 2023-03-28T16:02:28.157 +C Modify\sthe\sOP_IsType\sopcode\sso\sthat\sit\sdoes\snot\sneed\sto\sdistinguish\sbetween\nNaN\sand\sother\sfloating\spoint\svalues. +D 2023-03-29T00:05:54.101 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -618,7 +618,7 @@ F src/parse.y 424e49ed8fc6c907920db9be5a13a75ed43811e1ea8dd21b0fa9ef97f083dc6b F src/pcache.c 842410539b544e12d5fccfcf29890782f46a58f227a77bc0bd76243799662c0c F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5 F src/pcache1.c dee95e3cd2b61e6512dc814c5ab76d5eb36f0bfc9441dbb4260fccc0d12bbddc -F src/pragma.c 367652f5374b2f17761c96b262d9534d89bf089572a1ebba70d426a138c6802a +F src/pragma.c 2e3413d4509bbae184c0489ef5855267e7a0c1f2c7bc1986b44daf550614adc8 F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7 F src/prepare.c ce87a08cfddd45a147150db34190b1986f2d4a0e0828858cb6bd908c78fb02e3 F src/printf.c 7eac1a9896a80697e03e08963e210830532ae2ff610e16c193e95af007ca5623 @@ -695,7 +695,7 @@ F src/upsert.c 5303dc6c518fa7d4b280ec65170f465c7a70b7ac2b22491598f6d0b4875b3145 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 F src/util.c 3ff7bc2b48dd425b1448304bb86273b05da1621f136d51dbb9789f8803559a1f F src/vacuum.c 84ce7f01f8a7a08748e107a441db83bcec13970190ddcb0c9ff522adbc1c23fd -F src/vdbe.c 2bb4694bff3c1c4f52fd47e66be30278b5251d62d23b768af7c3b3a0dd7ba901 +F src/vdbe.c 2fb5cace3431d56e866ae5abbbba2700a18e15b57abc0f38f9d6e59fb2107d4f F src/vdbe.h 73b904a6b3bb27f308c6cc287a5751ebc7f1f89456be0ed068a12b92844c6e8c F src/vdbeInt.h a4147a4ddf613cb1bcb555ace9e9e74a9c099d65facd88155f191b1fb4d74cfb F src/vdbeapi.c 40c47b1528d308a322203de21d2e0d711753257ed9771771b6129214b1d65932 @@ -2051,8 +2051,11 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P c8bedef0d61731c29ae34de1594222d15b578f9e2cddbbd5b74fb3059644fe0f -R 68fb0cae877919b0f69109342d216ada +P c34fd9fe1b76e0a5943f014f46141cbe55d41bb1e6980adf9bcb6785a03e7883 +R d40ca8a393cdc77a3a8c6e0ac8d14846 +T *branch * istype-opcode-refactor +T *sym-istype-opcode-refactor * +T -sym-trunk * U drh -Z f12fcdd961dcea42a705ad864ed7007e +Z c3941d4e38d885dcc893fe5f74a5950c # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index a6c7d49117..bf3b0c5c96 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c34fd9fe1b76e0a5943f014f46141cbe55d41bb1e6980adf9bcb6785a03e7883 \ No newline at end of file +242cb36c3bd0192208d948214b510348f561e0fe56f1c77b4a5e4fd84bd42cca \ No newline at end of file diff --git a/src/pragma.c b/src/pragma.c index 4138752455..74fbce77e6 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -346,6 +346,36 @@ static void pragmaFunclistLine( } } +/* +** Generate a sequence of opcodes to test the type of a value. +** +** The byte code sequence might be either OP_Column, OP_IsType +** or it might be just OP_IsType. In either case, the address +** returned is the opcode of the OP_IsType. +** +** This subroutine assumes that register 3 is available as a +** temporary register. Hence, this subroutine can really only +** be used by PRAGMA integrity_check. +*/ +static int generateIsTypeOpcode( + Vdbe *v, /* VDBE under construction */ + int p1, /* Cursor holding the value to check. -1 means none */ + int p2, /* Jump here if P1.P3 is correct */ + int p3, /* Column to examine */ + int p4, /* Default type of P1.P3 if does not exist */ + int p5 /* Bitmask of allowed types */ +){ + int addr; + if( p1<0 ){ + addr = sqlite3VdbeAddOp4Int(v, OP_IsType, p5, p2, p3, p4); + }else{ + sqlite3VdbeAddOp4Int(v, OP_Column, p1, p3, 3, p4); + sqlite3VdbeChangeP5(v, OPFLAG_TYPEOFARG); + addr = sqlite3VdbeAddOp3(v, OP_IsType, p5, p2, 3); + } + return addr; +} + /* ** Helper subroutine for PRAGMA integrity_check: @@ -1880,8 +1910,7 @@ void sqlite3Pragma( labelOk = sqlite3VdbeMakeLabel(pParse); if( pCol->notNull ){ /* (1) NOT NULL columns may not contain a NULL */ - int jmp2 = sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4); - sqlite3VdbeChangeP5(v, 0x0f); + int jmp2 = generateIsTypeOpcode(v, p1, labelOk, p3, p4, 0x0f); VdbeCoverage(v); zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName, pCol->zCnName); @@ -1903,9 +1932,8 @@ void sqlite3Pragma( 0x13, /* REAL */ 0x14 /* TEXT */ }; - sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4); - assert( pCol->eCType>=1 && pCol->eCType<=sizeof(aStdTypeMask) ); - sqlite3VdbeChangeP5(v, aStdTypeMask[pCol->eCType-1]); + generateIsTypeOpcode(v, p1, labelOk, p3, p4, + aStdTypeMask[pCol->eCType-1]); VdbeCoverage(v); zErr = sqlite3MPrintf(db, "non-%s value in %s.%s", sqlite3StdType[pCol->eCType-1], @@ -1914,8 +1942,7 @@ void sqlite3Pragma( }else if( !bStrict && pCol->affinity==SQLITE_AFF_TEXT ){ /* (3) Datatype for TEXT columns in non-STRICT tables must be ** NULL, TEXT, or BLOB. */ - sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4); - sqlite3VdbeChangeP5(v, 0x1c); /* NULL, TEXT, or BLOB */ + generateIsTypeOpcode(v, p1, labelOk, p3, p4, 0x1c); VdbeCoverage(v); zErr = sqlite3MPrintf(db, "NUMERIC value in %s.%s", pTab->zName, pTab->aCol[j].zCnName); @@ -1923,15 +1950,13 @@ void sqlite3Pragma( }else if( !bStrict && pCol->affinity>=SQLITE_AFF_NUMERIC ){ /* (4) Datatype for numeric columns in non-STRICT tables must not ** be a TEXT value that can be converted to numeric. */ - sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4); - sqlite3VdbeChangeP5(v, 0x1b); /* NULL, INT, FLOAT, or BLOB */ + generateIsTypeOpcode(v, p1, labelOk, p3, p4, 0x1b); VdbeCoverage(v); if( p1>=0 ){ sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, j, 3); } sqlite3VdbeAddOp4(v, OP_Affinity, 3, 1, 0, "C", P4_STATIC); - sqlite3VdbeAddOp4Int(v, OP_IsType, -1, labelOk, 3, p4); - sqlite3VdbeChangeP5(v, 0x1c); /* NULL, TEXT, or BLOB */ + generateIsTypeOpcode(v, -1, labelOk, 3, p4, 0x1c); VdbeCoverage(v); zErr = sqlite3MPrintf(db, "TEXT value in %s.%s", pTab->zName, pTab->aCol[j].zCnName); diff --git a/src/vdbe.c b/src/vdbe.c index 4c66d555f3..e8f198ce51 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -2606,88 +2606,34 @@ case OP_IsNull: { /* same as TK_ISNULL, jump, in1 */ break; } -/* Opcode: IsType P1 P2 P3 P4 P5 -** Synopsis: if typeof(P1.P3) in P5 goto P2 +/* Opcode: IsType P1 P2 P3 * * +** Synopsis: if typeof(P3) in P1 goto P2 ** -** Jump to P2 if the type of a column in a btree is one of the types specified -** by the P5 bitmask. +** Jump to P2 if register P3 has one of the datatypes specified +** by the P1 bitmask. ** -** P1 is normally a cursor on a btree for which the row decode cache is -** valid through at least column P3. In other words, there should have been -** a prior OP_Column for column P3 or greater. If the cursor is not valid, -** then this opcode might give spurious results. -** The the btree row has fewer than P3 columns, then use P4 as the -** datatype. -** -** If P1 is -1, then P3 is a register number and the datatype is taken -** from the value in that register. -** -** P5 is a bitmask of data types. SQLITE_INTEGER is the least significant +** P1 is a bitmask of data types. SQLITE_INTEGER is the least significant ** (0x01) bit. SQLITE_FLOAT is the 0x02 bit. SQLITE_TEXT is 0x04. ** SQLITE_BLOB is 0x08. SQLITE_NULL is 0x10. ** ** Take the jump to address P2 if and only if the datatype of the -** value determined by P1 and P3 corresponds to one of the bits in the -** P5 bitmask. +** value determined by P1 and P3 corresponds to one of the bits in P1. ** */ case OP_IsType: { /* jump */ - VdbeCursor *pC; u16 typeMask; - u32 serialType; - assert( pOp->p1>=(-1) && pOp->p1nCursor ); - assert( pOp->p1>=0 || (pOp->p3>=0 && pOp->p3<=(p->nMem+1 - p->nCursor)) ); - if( pOp->p1>=0 ){ - pC = p->apCsr[pOp->p1]; - assert( pC!=0 ); - assert( pOp->p3>=0 ); - if( pOp->p3nHdrParsed ){ - serialType = pC->aType[pOp->p3]; - if( serialType>=12 ){ - if( serialType&1 ){ - typeMask = 0x04; /* SQLITE_TEXT */ - }else{ - typeMask = 0x08; /* SQLITE_BLOB */ - } - }else{ - static const unsigned char aMask[] = { - 0x10, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x2, - 0x01, 0x01, 0x10, 0x10 - }; - testcase( serialType==0 ); - testcase( serialType==1 ); - testcase( serialType==2 ); - testcase( serialType==3 ); - testcase( serialType==4 ); - testcase( serialType==5 ); - testcase( serialType==6 ); - testcase( serialType==7 ); - testcase( serialType==8 ); - testcase( serialType==9 ); - testcase( serialType==10 ); - testcase( serialType==11 ); - typeMask = aMask[serialType]; - } - }else{ - typeMask = 1 << (pOp->p4.i - 1); - testcase( typeMask==0x01 ); - testcase( typeMask==0x02 ); - testcase( typeMask==0x04 ); - testcase( typeMask==0x08 ); - testcase( typeMask==0x10 ); - } - }else{ - assert( memIsValid(&aMem[pOp->p3]) ); - typeMask = 1 << (sqlite3_value_type((sqlite3_value*)&aMem[pOp->p3])-1); - testcase( typeMask==0x01 ); - testcase( typeMask==0x02 ); - testcase( typeMask==0x04 ); - testcase( typeMask==0x08 ); - testcase( typeMask==0x10 ); - } - VdbeBranchTaken( (typeMask & pOp->p5)!=0, 2); - if( typeMask & pOp->p5 ){ + assert( (pOp->p1 & 0x1f)==pOp->p1 ); + assert( pOp->p3>=0 && pOp->p3<(p->nMem+1 - p->nCursor) ); + assert( memIsValid(&aMem[pOp->p3]) ); + typeMask = 1 << (sqlite3_value_type((sqlite3_value*)&aMem[pOp->p3])-1); + testcase( typeMask==0x01 ); + testcase( typeMask==0x02 ); + testcase( typeMask==0x04 ); + testcase( typeMask==0x08 ); + testcase( typeMask==0x10 ); + VdbeBranchTaken( (typeMask & pOp->p1)!=0, 2); + if( typeMask & pOp->p1 ){ goto jump_to_p2; } break; @@ -2797,7 +2743,8 @@ case OP_Offset: { /* out3 */ ** ** If the record contains fewer than P2 fields, then extract a NULL. Or, ** if the P4 argument is a P4_MEM use the value of the P4 argument as -** the result. +** the result. If the P4 argument is P4_INT32 than P4 determines the +** datatype of a constructed element that becomes the result. ** ** If the OPFLAG_LENGTHARG bit is set in P5 then the result is guaranteed ** to only be used by the length() function or the equivalent. The content @@ -3003,6 +2950,20 @@ op_column_restart: sqlite3VdbeMemShallowCopy(pDest, pOp->p4.pMem, MEM_Static); }else{ sqlite3VdbeMemSetNull(pDest); + if( pOp->p4type==P4_INT32 ){ + static unsigned char aType[] = { + 0, + MEM_Int, + MEM_Real, + MEM_Str, + MEM_Blob, + MEM_Null + }; + assert( pOp->p4.i>=SQLITE_INTEGER ); + assert( pOp->p4.i<=SQLITE_NULL ); + sqlite3VdbeMemSetZeroBlob(pDest, 0); + pDest->flags = aType[pOp->p4.i]; + } } goto op_column_out; }