diff --git a/manifest b/manifest index 4daf105d88..6576ccf22b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\srecent\sbranch-3.54\sfixes\sinto\strunk. -D 2026-10-12T12:51:45.528 +C Speed\sup\ssubstr()\sstart\sscanning\sfor\sASCII\stext\n\nSkip\sbounded\sgroups\sof\seight\snonzero\sASCII\sbytes\swhile\sadvancing\sthe\sstart\sposition.\sKeep\sthe\sexisting\sscalar\shandling\sfor\sNUL,\snon-ASCII\sbytes,\sand\sshort\stails.\n +D 2026-10-12T22:38:23.189 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -757,7 +757,7 @@ F src/delete.c 59eeca3fb88c29329afc41bb803ee568b120d9dd7470b5f38ab55cc38390b451 F src/expr.c 874e2907699dd181a7baee4941c1f2ee7b86ca5f2c0cf6163e6d89146f47cb38 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 26788ae6c785d70f9829c4176e9764447014fc73e6ba31e9f1881720a64ae7f1 -F src/func.c 54d96eeafcb6ec4cff92028ea0f7bb09e27b375b248d969aeb80a61e560ef302 +F src/func.c 9372b65d0e5e6fc9fff7c4fc20558c5e68babcc7f54f033bba67da39f47acc37 F src/global.c 7eea537ac0c113ac55cb2dd4d8fc2a6a91ae478be34231b4efaffc46817fee85 F src/hash.c 03c8c0f4be9e8bcb6de65aa26d34a61d48a9430747084a69f9469fbb00ea52ca F src/hash.h 46b92795a95bfefb210f52f0c316e9d7cdbcdd7e7fcfb0d8be796d3a5767cddf @@ -2284,8 +2284,11 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P 85adb10e22ac33500f974d756bcf1fac46b7d98868cb4e00e59f30c075001b5b af570c8fc22dc682ab71d8e97c20268971fb33032530d3fa9908e1995bed529e -R 99ee32c98dc326807c59b15ba4b8a633 -U drh -Z 909700f48f5b4fd3ed90f4021834fc08 +P a9d8cddccc77bf6c09531e1051eba36f1bd2e95c4e62921c07c4772f12f351ca +R a449b0d474f3b3bfc313835c8a117209 +T *branch * opt-substr-ascii8 +T *sym-opt-substr-ascii8 * +T -sym-trunk * +U jeffchen +Z 773054ce143461c3d197b92e5707954c # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.tags b/manifest.tags index bec971799f..d619e6f079 100644 --- a/manifest.tags +++ b/manifest.tags @@ -1,2 +1,2 @@ -branch trunk -tag trunk +branch opt-substr-ascii8 +tag opt-substr-ascii8 diff --git a/manifest.uuid b/manifest.uuid index d009b6dcc0..584463e1f6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a9d8cddccc77bf6c09531e1051eba36f1bd2e95c4e62921c07c4772f12f351ca +5749b0489c50a9ea3ee576cb565810cb2f6d766635c6f1dd38cdc65a76a6d237 diff --git a/src/func.c b/src/func.c index 33b25f4d85..9b48dd42ee 100644 --- a/src/func.c +++ b/src/func.c @@ -333,6 +333,14 @@ static void printfFunc( } } +/* Return true if any of the eight bytes in word is NUL or non-ASCII. */ +static SQLITE_INLINE int containsNulOrNonAscii(u64 word){ + const u64 byteOnes = UINT64_C(0x0101010101010101); + const u64 byteHighBits = UINT64_C(0x8080808080808080); + /* NUL causes a borrow into a high bit; non-ASCII already has one set. */ + return ((word | (word - byteOnes)) & byteHighBits)!=0; +} + /* ** Implementation of the substr() function. ** @@ -416,6 +424,20 @@ static void substrFunc( } assert( p1>=0 && p2>=0 ); if( p0type!=SQLITE_BLOB ){ + if( p1>=8 ){ + /* Skip 8 characters at a time while all 8 bytes are in 0x01..0x7f */ + const unsigned char *zEnd = z + sqlite3_value_bytes(argv[0]); + while( p1>=8 && zEnd-z>=8 ){ + u64 word; + memcpy(&word, z, sizeof(word)); + /* Handle NUL and UTF-8 with the scalar loop below. */ + if( containsNulOrNonAscii(word) ){ + break; + } + z += 8; + p1 -= 8; + } + } for( ; p1>0; p1--){ /* vvvvvv---- See tag-20260418-01 */ if( (u8)(z[0]-1)<(0x80-1) ){