aboutsummaryrefslogtreecommitdiff
path: root/src/func.c
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2018-02-09 23:25:14 +0000
committerdrh <drh@noemail.net>2018-02-09 23:25:14 +0000
commitf313952097725eaf25f80b3431035d19bb1c5c72 (patch)
tree05cd6ce45ac920fb0310144f11d202cab3cb4288 /src/func.c
parent510fea885e5b4841a57d13c21958ce650029f408 (diff)
downloadsqlite-f313952097725eaf25f80b3431035d19bb1c5c72.tar.gz
sqlite-f313952097725eaf25f80b3431035d19bb1c5c72.zip
Improve the performance of the built-in REPLACE() function in cases where
it does many substitutions that make the string larger. OSSFuzz is reporting intermittant timeouts when running a test where it does a REPLACE() on a 930KB random blob. Perhaps this enhancement will fix that. FossilOrigin-Name: fab2c2b07b5d3cd851db3e6f5c8a44155e32b0df22905ea33412b153b825a928
Diffstat (limited to 'src/func.c')
-rw-r--r--src/func.c43
1 files changed, 26 insertions, 17 deletions
diff --git a/src/func.c b/src/func.c
index 4e80535e8..399f6dba3 100644
--- a/src/func.c
+++ b/src/func.c
@@ -1199,6 +1199,8 @@ static void replaceFunc(
i64 nOut; /* Maximum size of zOut */
int loopLimit; /* Last zStr[] that might match zPattern[] */
int i, j; /* Loop counters */
+ unsigned cntExpand; /* Number zOut expansions */
+ sqlite3 *db = sqlite3_context_db_handle(context);
assert( argc==3 );
UNUSED_PARAMETER(argc);
@@ -1230,33 +1232,40 @@ static void replaceFunc(
return;
}
loopLimit = nStr - nPattern;
+ cntExpand = 0;
for(i=j=0; i<=loopLimit; i++){
if( zStr[i]!=zPattern[0] || memcmp(&zStr[i], zPattern, nPattern) ){
zOut[j++] = zStr[i];
}else{
- u8 *zOld;
- sqlite3 *db = sqlite3_context_db_handle(context);
- nOut += nRep - nPattern;
- testcase( nOut-1==db->aLimit[SQLITE_LIMIT_LENGTH] );
- testcase( nOut-2==db->aLimit[SQLITE_LIMIT_LENGTH] );
- if( nOut-1>db->aLimit[SQLITE_LIMIT_LENGTH] ){
- sqlite3_result_error_toobig(context);
- sqlite3_free(zOut);
- return;
- }
- zOld = zOut;
- zOut = sqlite3_realloc64(zOut, (int)nOut);
- if( zOut==0 ){
- sqlite3_result_error_nomem(context);
- sqlite3_free(zOld);
- return;
+ if( nRep>nPattern ){
+ nOut += nRep - nPattern;
+ if( nOut-1>db->aLimit[SQLITE_LIMIT_LENGTH] ){
+ sqlite3_result_error_toobig(context);
+ sqlite3_free(zOut);
+ return;
+ }
+ testcase( nOut-1==db->aLimit[SQLITE_LIMIT_LENGTH] );
+ testcase( nOut-2==db->aLimit[SQLITE_LIMIT_LENGTH] );
+ cntExpand++;
+ if( (cntExpand&(cntExpand-1))==0 ){
+ /* Grow the size of the output buffer only on substitutions
+ ** whose index is a power of two: 1, 2, 4, 8, 16, 32, ... */
+ u8 *zOld;
+ zOld = zOut;
+ zOut = sqlite3_realloc64(zOut, (int)nOut + (nOut - nStr - 1));
+ if( zOut==0 ){
+ sqlite3_result_error_nomem(context);
+ sqlite3_free(zOld);
+ return;
+ }
+ }
}
memcpy(&zOut[j], zRep, nRep);
j += nRep;
i += nPattern-1;
}
}
- assert( j+nStr-i+1==nOut );
+ assert( j+nStr-i+1<=nOut );
memcpy(&zOut[j], &zStr[i], nStr-i);
j += nStr - i;
assert( j<=nOut );