Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Memory handling fixes and optimizations in the VDBE. Ticket #862. (CVS 1909) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
5f8d246852c7cefd5941b8c7bb22177d |
User & Date: | drh 2004-08-28 18:17:48.000 |
Context
2004-08-28
| ||
18:21 | Add prototype in sqlite3.h for the sqlite3_libversion() function. (CVS 1910) (check-in: d50c47b499 user: drh tags: trunk) | |
18:17 | Memory handling fixes and optimizations in the VDBE. Ticket #862. (CVS 1909) (check-in: 5f8d246852 user: drh tags: trunk) | |
16:19 | Add the sqlite3_libversion() API (ticket #834). Fix the build scripts to correctly build the shared libraries with version 8.4 of Tcl. (CVS 1908) (check-in: 6db26a19ea user: drh tags: trunk) | |
Changes
Changes to src/vdbe.c.
︙ | ︙ | |||
39 40 41 42 43 44 45 | ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** | | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** ** $Id: vdbe.c,v 1.410 2004/08/28 18:17:48 drh Exp $ */ #include "sqliteInt.h" #include "os.h" #include <ctype.h> #include "vdbeInt.h" /* |
︙ | ︙ | |||
788 789 790 791 792 793 794 | ** sqlite3_bind() API. */ case OP_Variable: { int j = pOp->p1 - 1; assert( j>=0 && j<p->nVar ); pTos++; | | < < < < < | 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 | ** sqlite3_bind() API. */ case OP_Variable: { int j = pOp->p1 - 1; assert( j>=0 && j<p->nVar ); pTos++; sqlite3VdbeMemShallowCopy(pTos, &p->aVar[j], MEM_Static); break; } /* Opcode: Pop P1 * * ** ** P1 elements are popped off of the top of stack and discarded. */ |
︙ | ︙ | |||
827 828 829 830 831 832 833 | ** ** Also see the Pull instruction. */ case OP_Dup: { Mem *pFrom = &pTos[-pOp->p1]; assert( pFrom<=pTos && pFrom>=p->aStack ); pTos++; | | < < | | < < < < < < < < < < < < | 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 | ** ** Also see the Pull instruction. */ case OP_Dup: { Mem *pFrom = &pTos[-pOp->p1]; assert( pFrom<=pTos && pFrom>=p->aStack ); pTos++; sqlite3VdbeMemShallowCopy(pTos, pFrom, MEM_Ephem); if( pOp->p2 ){ Deephemeralize(pTos); } break; } /* Opcode: Pull P1 * * ** ** The P1-th element is removed from its current location on |
︙ | ︙ | |||
894 895 896 897 898 899 900 | ** stack (P1==0 is the top of the stack) with the value ** of the top of the stack. Then pop the top of the stack. */ case OP_Push: { Mem *pTo = &pTos[-pOp->p1]; assert( pTo>=p->aStack ); | < | < < < < < | 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 | ** stack (P1==0 is the top of the stack) with the value ** of the top of the stack. Then pop the top of the stack. */ case OP_Push: { Mem *pTo = &pTos[-pOp->p1]; assert( pTo>=p->aStack ); sqlite3VdbeMemMove(pTo, pTos); pTos--; break; } /* Opcode: Callback P1 * * ** ** Pop P1 values off the stack and form them into an array. Then |
︙ | ︙ | |||
1236 1237 1238 1239 1240 1241 1242 | if( ctx.pVdbeFunc ){ sqlite3VdbeDeleteAuxData(ctx.pVdbeFunc, pOp->p2); pOp->p3 = (char *)ctx.pVdbeFunc; pOp->p3type = P3_VDBEFUNC; } /* Copy the result of the function to the top of the stack */ | < | | | | | 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 | if( ctx.pVdbeFunc ){ sqlite3VdbeDeleteAuxData(ctx.pVdbeFunc, pOp->p2); pOp->p3 = (char *)ctx.pVdbeFunc; pOp->p3type = P3_VDBEFUNC; } /* Copy the result of the function to the top of the stack */ sqlite3VdbeChangeEncoding(&ctx.s, db->enc); pTos++; pTos->flags = 0; sqlite3VdbeMemMove(pTos, &ctx.s); /* If the function returned an error, throw an exception */ if( ctx.isError ){ if( !(pTos->flags&MEM_Str) ){ sqlite3SetString(&p->zErrMsg, "user function error", (char*)0); }else{ sqlite3SetString(&p->zErrMsg, sqlite3_value_text(pTos), (char*)0); sqlite3VdbeChangeEncoding(pTos, db->enc); |
︙ | ︙ | |||
1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 | int i; /* Loop counter */ char *zData; /* Part of the record being decoded */ Mem sMem; /* For storing the record being decoded */ sMem.flags = 0; assert( p1<p->nCursor ); pTos++; /* This block sets the variable payloadSize to be the total number of ** bytes in the record. ** ** zRec is set to be the complete text of the record if it is available. ** The complete record text is always available for pseudo-tables and ** when we are decoded a record from the stack. If the record is stored | > | 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 | int i; /* Loop counter */ char *zData; /* Part of the record being decoded */ Mem sMem; /* For storing the record being decoded */ sMem.flags = 0; assert( p1<p->nCursor ); pTos++; pTos->flags = MEM_Null; /* This block sets the variable payloadSize to be the total number of ** bytes in the record. ** ** zRec is set to be the complete text of the record if it is available. ** The complete record text is always available for pseudo-tables and ** when we are decoded a record from the stack. If the record is stored |
︙ | ︙ | |||
1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 | pC->aOffset = aOffset; pC->cacheValid = 1; } } /* Get the column information. */ if( zRec ){ zData = &zRec[aOffset[p2]]; }else{ len = sqlite3VdbeSerialTypeLen(aType[p2]); sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, pC->keyAsData, &sMem); zData = sMem.z; } sqlite3VdbeSerialGet(zData, aType[p2], pTos); | > > > < < < | > > > | > > > > > > > > | > > > | 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 | pC->aOffset = aOffset; pC->cacheValid = 1; } } /* Get the column information. */ if( rc!=SQLITE_OK ){ goto abort_due_to_error; } if( zRec ){ zData = &zRec[aOffset[p2]]; }else{ len = sqlite3VdbeSerialTypeLen(aType[p2]); sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, pC->keyAsData, &sMem); zData = sMem.z; } sqlite3VdbeSerialGet(zData, aType[p2], pTos); pTos->enc = db->enc; /* If we dynamically allocated space to hold the data (in the ** sqlite3VdbeMemFromBtree() call above) then transfer control of that ** dynamically allocated space over to the pTos structure rather. ** This prevents a memory copy. */ if( (sMem.flags & MEM_Dyn)!=0 ){ assert( pTos->flags & MEM_Ephem ); assert( pTos->flags & (MEM_Str|MEM_Blob) ); assert( pTos->z==sMem.z ); assert( sMem.flags & MEM_Term ); pTos->flags &= ~MEM_Ephem; pTos->flags |= MEM_Dyn|MEM_Term; } /* pTos->z might be pointing to sMem.zShort[]. Fix that so that we ** can abandon sMem */ rc = sqlite3VdbeMemMakeWriteable(pTos); /* Release the aType[] memory if we are not dealing with cursor */ if( !pC ){ sqliteFree(aType); } break; } |
︙ | ︙ | |||
3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 | Cursor *pC; assert( i>=0 && i<p->nCursor ); assert( p->apCsr[i]!=0 ); assert( p->apCsr[i]->keyAsData ); assert( !p->apCsr[i]->pseudoTable ); pTos++; if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ i64 amt; char *z; sqlite3VdbeCursorMoveto(pC); assert( pC->intKey==0 ); sqlite3BtreeKeySize(pCrsr, &amt); | > | 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 | Cursor *pC; assert( i>=0 && i<p->nCursor ); assert( p->apCsr[i]!=0 ); assert( p->apCsr[i]->keyAsData ); assert( !p->apCsr[i]->pseudoTable ); pTos++; pTos->flags = MEM_Null; if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ i64 amt; char *z; sqlite3VdbeCursorMoveto(pC); assert( pC->intKey==0 ); sqlite3BtreeKeySize(pCrsr, &amt); |
︙ | ︙ | |||
3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 | int i = pOp->p1; BtCursor *pCrsr; Cursor *pC; assert( i>=0 && i<p->nCursor ); assert( p->apCsr[i]!=0 ); pTos++; if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ i64 rowid; assert( pC->deferredMoveto==0 ); assert( pC->intKey==0 ); if( pC->nullRow ){ pTos->flags = MEM_Null; }else{ rc = sqlite3VdbeIdxRowid(pCrsr, &rowid); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } pTos->flags = MEM_Int; pTos->i = rowid; } | > < < | 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 | int i = pOp->p1; BtCursor *pCrsr; Cursor *pC; assert( i>=0 && i<p->nCursor ); assert( p->apCsr[i]!=0 ); pTos++; pTos->flags = MEM_Null; if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ i64 rowid; assert( pC->deferredMoveto==0 ); assert( pC->intKey==0 ); if( pC->nullRow ){ pTos->flags = MEM_Null; }else{ rc = sqlite3VdbeIdxRowid(pCrsr, &rowid); if( rc!=SQLITE_OK ){ goto abort_due_to_error; } pTos->flags = MEM_Int; pTos->i = rowid; } } break; } /* Opcode: IdxGT P1 P2 * ** ** The top of the stack is an index entry that omits the ROWID. Compare |
︙ | ︙ | |||
4015 4016 4017 4018 4019 4020 4021 | pSorter->pNext = p->pSort; p->pSort = pSorter; assert( pTos->flags & MEM_Dyn ); pSorter->nKey = pTos->n; pSorter->zKey = pTos->z; pSorter->data.flags = MEM_Null; rc = sqlite3VdbeMemMove(&pSorter->data, pNos); | < < | 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 | pSorter->pNext = p->pSort; p->pSort = pSorter; assert( pTos->flags & MEM_Dyn ); pSorter->nKey = pTos->n; pSorter->zKey = pTos->z; pSorter->data.flags = MEM_Null; rc = sqlite3VdbeMemMove(&pSorter->data, pNos); pTos -= 2; break; } /* Opcode: Sort * * P3 ** ** Sort all elements on the sorter. The algorithm is a |
︙ | ︙ | |||
4076 4077 4078 4079 4080 4081 4082 | Sorter *pSorter = p->pSort; CHECK_FOR_INTERRUPT; if( pSorter!=0 ){ p->pSort = pSorter->pNext; pTos++; pTos->flags = MEM_Null; rc = sqlite3VdbeMemMove(pTos, &pSorter->data); | < | 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 | Sorter *pSorter = p->pSort; CHECK_FOR_INTERRUPT; if( pSorter!=0 ){ p->pSort = pSorter->pNext; pTos++; pTos->flags = MEM_Null; rc = sqlite3VdbeMemMove(pTos, &pSorter->data); sqliteFree(pSorter->zKey); sqliteFree(pSorter); }else{ pc = pOp->p2 - 1; } break; } |
︙ | ︙ | |||
4105 4106 4107 4108 4109 4110 4111 | ** for all memory locations between 0 and P1 inclusive. ** ** After the data is stored in the memory location, the ** stack is popped once if P2 is 1. If P2 is zero, then ** the original data remains on the stack. */ case OP_MemStore: { | < < | < | < < < < < < | 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 | ** for all memory locations between 0 and P1 inclusive. ** ** After the data is stored in the memory location, the ** stack is popped once if P2 is 1. If P2 is zero, then ** the original data remains on the stack. */ case OP_MemStore: { assert( pTos>=p->aStack ); assert( pOp->p1>=0 && pOp->p1<p->nMem ); rc = sqlite3VdbeMemMove(&p->aMem[pOp->p1], pTos); pTos--; /* If P2 is 0 then fall thru to the next opcode, OP_MemLoad, that will ** restore the top of the stack to its original value. */ if( pOp->p2 ){ break; |
︙ | ︙ | |||
4139 4140 4141 4142 4143 4144 4145 | ** location is subsequently changed (using OP_MemStore) then the ** value pushed onto the stack will change too. */ case OP_MemLoad: { int i = pOp->p1; assert( i>=0 && i<p->nMem ); pTos++; | | < < < < < | 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 | ** location is subsequently changed (using OP_MemStore) then the ** value pushed onto the stack will change too. */ case OP_MemLoad: { int i = pOp->p1; assert( i>=0 && i<p->nMem ); pTos++; sqlite3VdbeMemShallowCopy(pTos, &p->aMem[i], MEM_Ephem); break; } /* Opcode: MemIncr P1 P2 * ** ** Increment the integer valued memory cell P1 by 1. If P2 is not zero ** and the result after the increment is greater than zero, then jump |
︙ | ︙ | |||
4318 4319 4320 4321 4322 4323 4324 | ** ** Move the top of the stack into the P2-th field of the current ** aggregate. String values are duplicated into new memory. */ case OP_AggSet: { AggElem *pFocus; int i = pOp->p2; | < < | < < < < < < < | < < | < < < > > | 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 | ** ** Move the top of the stack into the P2-th field of the current ** aggregate. String values are duplicated into new memory. */ case OP_AggSet: { AggElem *pFocus; int i = pOp->p2; rc = AggInFocus(&p->agg, &pFocus); if( rc!=SQLITE_OK ) goto abort_due_to_error; assert( pTos>=p->aStack ); if( pFocus==0 ) goto no_mem; assert( i>=0 && i<p->agg.nMem ); rc = sqlite3VdbeMemMove(&pFocus->aMem[i], pTos); pTos--; break; } /* Opcode: AggGet * P2 * ** ** Push a new entry onto the stack which is a copy of the P2-th field ** of the current aggregate. Strings are not duplicated so ** string values will be ephemeral. */ case OP_AggGet: { AggElem *pFocus; int i = pOp->p2; rc = AggInFocus(&p->agg, &pFocus); if( rc!=SQLITE_OK ) goto abort_due_to_error; if( pFocus==0 ) goto no_mem; assert( i>=0 && i<p->agg.nMem ); pTos++; sqlite3VdbeMemShallowCopy(pTos, &pFocus->aMem[i], MEM_Ephem); assert( (pTos->flags & MEM_Str)==0 || pTos->enc==db->enc ); #if 0 if( pTos->flags&MEM_Str ){ sqlite3VdbeChangeEncoding(pTos, db->enc); } #endif break; } /* Opcode: AggNext * P2 * ** ** Make the next aggregate value the current aggregate. The prior ** aggregate is deleted. If all aggregate values have been consumed, |
︙ | ︙ |
Changes to src/vdbeInt.h.
︙ | ︙ | |||
377 378 379 380 381 382 383 384 385 386 387 388 389 390 | int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*); int sqlite3VdbeRecordCompare(void*,int,const void*,int, const void*); int sqlite3VdbeIdxRowidLen(int,const u8*); int sqlite3VdbeExec(Vdbe*); int sqlite3VdbeList(Vdbe*); int sqlite3VdbeChangeEncoding(Mem *, int); int sqlite3VdbeMemCopy(Mem*, const Mem*); int sqlite3VdbeMemMove(Mem*, Mem*); int sqlite3VdbeMemNulTerminate(Mem*); int sqlite3VdbeMemSetStr(Mem*, const char*, int, u8, void(*)(void*)); void sqlite3VdbeMemSetInt64(Mem*, i64); void sqlite3VdbeMemSetDouble(Mem*, double); void sqlite3VdbeMemSetNull(Mem*); int sqlite3VdbeMemMakeWriteable(Mem*); | > | 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 | int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*); int sqlite3VdbeRecordCompare(void*,int,const void*,int, const void*); int sqlite3VdbeIdxRowidLen(int,const u8*); int sqlite3VdbeExec(Vdbe*); int sqlite3VdbeList(Vdbe*); int sqlite3VdbeChangeEncoding(Mem *, int); int sqlite3VdbeMemCopy(Mem*, const Mem*); void sqlite3VdbeMemShallowCopy(Mem*, const Mem*, int); int sqlite3VdbeMemMove(Mem*, Mem*); int sqlite3VdbeMemNulTerminate(Mem*); int sqlite3VdbeMemSetStr(Mem*, const char*, int, u8, void(*)(void*)); void sqlite3VdbeMemSetInt64(Mem*, i64); void sqlite3VdbeMemSetDouble(Mem*, double); void sqlite3VdbeMemSetNull(Mem*); int sqlite3VdbeMemMakeWriteable(Mem*); |
︙ | ︙ |
Changes to src/vdbemem.c.
︙ | ︙ | |||
295 296 297 298 299 300 301 | sqlite3VdbeMemRelease(pMem); pMem->r = val; pMem->flags = MEM_Real; pMem->type = SQLITE_FLOAT; } /* | | > > > | < < | > | > > > > > > > > > > > > > > > > | > > > > > > > > > > > | | 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 | sqlite3VdbeMemRelease(pMem); pMem->r = val; pMem->flags = MEM_Real; pMem->type = SQLITE_FLOAT; } /* ** Make an shallow copy of pFrom into pTo. Prior contents of ** pTo are overwritten. The pFrom->z field is not duplicated. If ** pFrom->z is used, then pTo->z points to the same thing as pFrom->z ** and flags gets srcType (either MEM_Ephem or MEM_Static). */ void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){ memcpy(pTo, pFrom, sizeof(*pFrom)-sizeof(pFrom->zShort)); pTo->xDel = 0; if( pTo->flags & (MEM_Str|MEM_Blob) ){ pTo->flags &= ~(MEM_Dyn|MEM_Static|MEM_Short|MEM_Ephem); assert( srcType==MEM_Ephem || srcType==MEM_Static ); pTo->flags |= srcType; } } /* ** Make a full copy of pFrom into pTo. Prior contents of pTo are ** freed before the copy is made. */ int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){ int rc; if( pTo->flags & MEM_Dyn ){ sqlite3VdbeMemRelease(pTo); } sqlite3VdbeMemShallowCopy(pTo, pFrom, MEM_Ephem); if( pTo->flags & MEM_Ephem ){ rc = sqlite3VdbeMemMakeWriteable(pTo); }else{ rc = SQLITE_OK; } return rc; } /* ** Transfer the contents of pFrom to pTo. Any existing value in pTo is ** freed. If pFrom contains ephemeral data, a copy is made. ** ** pFrom contains an SQL NULL when this routine returns. SQLITE_NOMEM ** might be returned if pFrom held ephemeral data and we were unable ** to allocate enough space to make a copy. */ int sqlite3VdbeMemMove(Mem *pTo, Mem *pFrom){ int rc; if( pTo->flags & MEM_Dyn ){ sqlite3VdbeMemRelease(pTo); } memcpy(pTo, pFrom, sizeof(Mem)); if( pFrom->flags & MEM_Short ){ pTo->z = pTo->zShort; } pFrom->flags = MEM_Null; pFrom->xDel = 0; if( pTo->flags & MEM_Ephem ){ rc = sqlite3VdbeMemMakeWriteable(pTo); }else{ rc = SQLITE_OK; } return rc; } /* ** Change the value of a Mem to be a string or a BLOB. */ int sqlite3VdbeMemSetStr( Mem *pMem, /* Memory cell to set to string value */ |
︙ | ︙ |