diff options
author | drh <> | 2023-07-21 18:09:07 +0000 |
---|---|---|
committer | drh <> | 2023-07-21 18:09:07 +0000 |
commit | 569700a72e58a1cf9efc7fb743768a64cfd77d3c (patch) | |
tree | a364da6db67db8dc3bd718a99e8d9c1f313593f0 /src | |
parent | eee8687a9ff50465a720298bd8d50cbd85bb0fe7 (diff) | |
download | sqlite-569700a72e58a1cf9efc7fb743768a64cfd77d3c.tar.gz sqlite-569700a72e58a1cf9efc7fb743768a64cfd77d3c.zip |
Further improvements to large string handling in relation to JSON.
FossilOrigin-Name: 1e5df0aa3dae5cadbf1d07c718ae2a5212543300b68e49d35e8c96855a7f619c
Diffstat (limited to 'src')
-rw-r--r-- | src/json.c | 4 | ||||
-rw-r--r-- | src/vdbeInt.h | 1 | ||||
-rw-r--r-- | src/vdbeapi.c | 10 | ||||
-rw-r--r-- | src/vdbemem.c | 31 |
4 files changed, 34 insertions, 12 deletions
diff --git a/src/json.c b/src/json.c index a9425aecd..05046b5b5 100644 --- a/src/json.c +++ b/src/json.c @@ -501,8 +501,8 @@ static void jsonAppendValue( */ static void jsonResult(JsonString *p){ if( p->bErr==0 ){ - if( p->nAlloc>=p->nUsed+1 ) p->zBuf[p->nUsed] = 0; - sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed, + jsonAppendChar(p, 0); + sqlite3_result_text64(p->pCtx, p->zBuf, p->nUsed-1, p->bStatic ? SQLITE_TRANSIENT : sqlite3_free, SQLITE_UTF8); jsonZero(p); diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 4c3394716..3a5b961a2 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -611,6 +611,7 @@ int sqlite3VdbeMemSetZeroBlob(Mem*,int); int sqlite3VdbeMemIsRowSet(const Mem*); #endif int sqlite3VdbeMemSetRowSet(Mem*); +void sqlite3VdbeMemZeroTerminateIfAble(Mem*); int sqlite3VdbeMemMakeWriteable(Mem*); int sqlite3VdbeMemStringify(Mem*, u8, u8); int sqlite3IntFloatCompare(i64,double); diff --git a/src/vdbeapi.c b/src/vdbeapi.c index 079fb3976..92bf38160 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -514,15 +514,7 @@ void sqlite3_result_text64( (void)invokeValueDestructor(z, xDel, pCtx); }else{ setResultStrOrError(pCtx, z, (int)n, enc, xDel); - if( xDel==sqlite3_free && enc==SQLITE_UTF8 ){ - Mem *pOut = pCtx->pOut; - if( pOut->z==z - && sqlite3_msize(pOut->z) >= (sqlite3_uint64)(pOut->n+1) - && pOut->z[n]==0 - ){ - pOut->flags |= MEM_Term; - } - } + sqlite3VdbeMemZeroTerminateIfAble(pCtx->pOut); } } #ifndef SQLITE_OMIT_UTF16 diff --git a/src/vdbemem.c b/src/vdbemem.c index 1250eea77..2baa35e24 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -315,6 +315,32 @@ int sqlite3VdbeMemClearAndResize(Mem *pMem, int szNew){ } /* +** If pMem is already a string, detect if it is a zero-terminated +** string, or make it into one if possible, and mark it as such. +** +** This is an optimization. Correct operation continues even if +** this routine is a no-op. +*/ +void sqlite3VdbeMemZeroTerminateIfAble(Mem *pMem){ + if( (pMem->flags & (MEM_Str|MEM_Term))!=MEM_Str ) return; + if( pMem->enc!=SQLITE_UTF8 ) return; + if( pMem->z==0 ) return; + if( pMem->flags & MEM_Dyn ){ + if( pMem->xDel==sqlite3_free + && sqlite3_msize(pMem->z) >= pMem->n+1 + && pMem->z[pMem->n]==0 + ){ + pMem->flags |= MEM_Term; + return; + } + }else if( pMem->szMalloc>0 && pMem->szMalloc >= pMem->n+1 ){ + pMem->z[pMem->n] = 0; + pMem->flags |= MEM_Term; + return; + } +} + +/* ** It is already known that pMem contains an unterminated string. ** Add the zero terminator. ** @@ -803,6 +829,7 @@ int sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){ break; } default: { + int rc; assert( aff==SQLITE_AFF_TEXT ); assert( MEM_Str==(MEM_Blob>>3) ); pMem->flags |= (pMem->flags&MEM_Blob)>>3; @@ -810,7 +837,9 @@ int sqlite3VdbeMemCast(Mem *pMem, u8 aff, u8 encoding){ assert( pMem->flags & MEM_Str || pMem->db->mallocFailed ); pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal|MEM_Blob|MEM_Zero); if( encoding!=SQLITE_UTF8 ) pMem->n &= ~1; - return sqlite3VdbeChangeEncoding(pMem, encoding); + rc = sqlite3VdbeChangeEncoding(pMem, encoding); + if( rc ) return rc; + sqlite3VdbeMemZeroTerminateIfAble(pMem); } } return SQLITE_OK; |