aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <>2023-07-21 18:09:07 +0000
committerdrh <>2023-07-21 18:09:07 +0000
commit569700a72e58a1cf9efc7fb743768a64cfd77d3c (patch)
treea364da6db67db8dc3bd718a99e8d9c1f313593f0 /src
parenteee8687a9ff50465a720298bd8d50cbd85bb0fe7 (diff)
downloadsqlite-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.c4
-rw-r--r--src/vdbeInt.h1
-rw-r--r--src/vdbeapi.c10
-rw-r--r--src/vdbemem.c31
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;