Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Take care to track ephemeral strings in the VDBE and make copies of ephemeral strings that need to be preserved. Ticket #177. (CVS 769) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
562da534bbb605a8ce15824135b012ef |
User & Date: | drh 2002-10-22 15:04:34.000 |
Context
2002-10-22
| ||
23:38 | Correctly handle column names and string constants in parentheses. Fix for ticket #179. (CVS 770) (check-in: 3b68aa25c4 user: drh tags: trunk) | |
15:04 | Take care to track ephemeral strings in the VDBE and make copies of ephemeral strings that need to be preserved. Ticket #177. (CVS 769) (check-in: 562da534bb user: drh tags: trunk) | |
2002-10-20
| ||
18:19 | Rework the changes for ticket #176 (check-ins (760) and (761)) to be more consistent with the rest of the source code. (CVS 768) (check-in: f50a177b42 user: drh tags: trunk) | |
Changes
Changes to src/vdbe.c.
︙ | ︙ | |||
32 33 34 35 36 37 38 | ** ** 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. ** | | | 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | ** ** 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.181 2002/10/22 15:04:34 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> /* ** The makefile scans this source file and creates the following ** array of string constants which are the names of all VDBE opcodes. |
︙ | ︙ | |||
148 149 150 151 152 153 154 | /* ** Allowed values for Stack.flags */ #define STK_Null 0x0001 /* Value is NULL */ #define STK_Str 0x0002 /* Value is a string */ #define STK_Int 0x0004 /* Value is an integer */ #define STK_Real 0x0008 /* Value is a real number */ | | > | 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | /* ** Allowed values for Stack.flags */ #define STK_Null 0x0001 /* Value is NULL */ #define STK_Str 0x0002 /* Value is a string */ #define STK_Int 0x0004 /* Value is an integer */ #define STK_Real 0x0008 /* Value is a real number */ #define STK_Dyn 0x0010 /* Need to call sqliteFree() on zStack[] */ #define STK_Static 0x0020 /* zStack[] points to a static string */ #define STK_Ephem 0x0040 /* zStack[] points to an ephemeral string */ /* The following STK_ value appears only in AggElem.aMem.s.flag fields. ** It indicates that the corresponding AggElem.aMem.z points to a ** aggregate function context that needs to be finalized. */ #define STK_AggCtx 0x0040 /* zStack[] points to an agg function context */ |
︙ | ︙ | |||
793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 | pStack->z[0] = 0; } *pzStack = pStack->z; pStack->n = strlen(*pzStack)+1; pStack->flags = STK_Str; return 0; } /* ** Release the memory associated with the given stack level */ #define Release(P,I) if((P)->aStack[I].flags&STK_Dyn){ hardRelease(P,I); } static void hardRelease(Vdbe *p, int i){ sqliteFree(p->zStack[i]); p->zStack[i] = 0; | > > > > > > > > > > > > > > > > > > > > > > > > > | | 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 | pStack->z[0] = 0; } *pzStack = pStack->z; pStack->n = strlen(*pzStack)+1; pStack->flags = STK_Str; return 0; } /* ** An ephemeral string value (signified by the STK_Ephem flag) contains ** a pointer to a dynamically allocated string where some other entity ** is responsible for deallocating that string. Because the stack entry ** does not control the string, it might be deleted without the stack ** entry knowing it. ** ** This routine converts an ephemeral string into a dynamically allocated ** string that the stack entry itself controls. In other words, it ** converts an STK_Ephem string into an STK_Dyn string. */ #define Deephemeralize(P,I) \ if( ((P)->aStack[I].flags&STK_Ephem)!=0 && hardDeephem(P,I) ){ goto no_mem;} static int hardDeephem(Vdbe *p, int i){ Stack *pStack = &p->aStack[i]; char **pzStack = &p->zStack[i]; char *z; assert( (pStack->flags & STK_Ephem)!=0 ); z = sqliteMalloc( pStack->n ); if( z==0 ) return 1; memcpy(z, *pzStack, pStack->n); *pzStack = z; return 0; } /* ** Release the memory associated with the given stack level */ #define Release(P,I) if((P)->aStack[I].flags&STK_Dyn){ hardRelease(P,I); } static void hardRelease(Vdbe *p, int i){ sqliteFree(p->zStack[i]); p->zStack[i] = 0; p->aStack[i].flags &= ~(STK_Str|STK_Dyn|STK_Static|STK_Ephem); } /* ** Convert the given stack entity into a integer if it isn't one ** already. ** ** Any prior string or real representation is invalidated. |
︙ | ︙ | |||
1573 1574 1575 1576 1577 1578 1579 | case OP_Dup: { int i = p->tos - pOp->p1; int j = ++p->tos; VERIFY( if( i<0 ) goto not_enough_stack; ) VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; ) memcpy(&aStack[j], &aStack[i], sizeof(aStack[i])-NBFS); if( aStack[j].flags & STK_Str ){ | | > > | > | | 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 | case OP_Dup: { int i = p->tos - pOp->p1; int j = ++p->tos; VERIFY( if( i<0 ) goto not_enough_stack; ) VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; ) memcpy(&aStack[j], &aStack[i], sizeof(aStack[i])-NBFS); if( aStack[j].flags & STK_Str ){ int isStatic = (aStack[j].flags & STK_Static)!=0; if( pOp->p2 || isStatic ){ zStack[j] = zStack[i]; aStack[j].flags &= ~STK_Dyn; if( !isStatic ) aStack[j].flags |= STK_Ephem; }else if( aStack[i].n<=NBFS ){ memcpy(aStack[j].z, zStack[i], aStack[j].n); zStack[j] = aStack[j].z; aStack[j].flags &= ~(STK_Static|STK_Dyn|STK_Ephem); }else{ zStack[j] = sqliteMalloc( aStack[j].n ); if( zStack[j]==0 ) goto no_mem; memcpy(zStack[j], zStack[i], aStack[j].n); aStack[j].flags &= ~(STK_Static|STK_Ephem); aStack[j].flags |= STK_Dyn; } } break; } /* Opcode: Pull P1 * * ** |
︙ | ︙ | |||
1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 | int to = p->tos; int i; Stack ts; char *tz; VERIFY( if( from<0 ) goto not_enough_stack; ) ts = aStack[from]; tz = zStack[from]; for(i=from; i<to; i++){ aStack[i] = aStack[i+1]; if( aStack[i].flags & (STK_Dyn|STK_Static) ){ zStack[i] = zStack[i+1]; }else{ zStack[i] = aStack[i].z; } } aStack[to] = ts; if( aStack[to].flags & (STK_Dyn|STK_Static) ){ zStack[to] = tz; }else{ zStack[to] = aStack[to].z; } break; } | > > > > | 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 | int to = p->tos; int i; Stack ts; char *tz; VERIFY( if( from<0 ) goto not_enough_stack; ) ts = aStack[from]; tz = zStack[from]; Deephemeralize(p, to); for(i=from; i<to; i++){ Deephemeralize(p, i); aStack[i] = aStack[i+1]; assert( (aStack[i].flags & STK_Ephem)==0 ); if( aStack[i].flags & (STK_Dyn|STK_Static) ){ zStack[i] = zStack[i+1]; }else{ zStack[i] = aStack[i].z; } } aStack[to] = ts; assert( (aStack[to].flags & STK_Ephem)==0 ); if( aStack[to].flags & (STK_Dyn|STK_Static) ){ zStack[to] = tz; }else{ zStack[to] = aStack[to].z; } break; } |
︙ | ︙ | |||
1640 1641 1642 1643 1644 1645 1646 1647 | int from = p->tos; int to = p->tos - pOp->p1; VERIFY( if( to<0 ) goto not_enough_stack; ) if( aStack[to].flags & STK_Dyn ){ sqliteFree(zStack[to]); } aStack[to] = aStack[from]; | > | | | 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 | int from = p->tos; int to = p->tos - pOp->p1; VERIFY( if( to<0 ) goto not_enough_stack; ) if( aStack[to].flags & STK_Dyn ){ sqliteFree(zStack[to]); } Deephemeralize(p, from); aStack[to] = aStack[from]; if( aStack[to].flags & (STK_Dyn|STK_Static|STK_Ephem) ){ zStack[to] = zStack[from]; }else{ zStack[to] = aStack[to].z; } aStack[from].flags = 0; p->tos--; break; } /* Opcode: ColumnCount P1 * * ** ** Specify the number of column values that will appear in the |
︙ | ︙ | |||
2892 2893 2894 2895 2896 2897 2898 | ** the key itself. */ case OP_IncrKey: { int tos = p->tos; VERIFY( if( tos<0 ) goto bad_instruction ); if( Stringify(p, tos) ) goto no_mem; | | | 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 | ** the key itself. */ case OP_IncrKey: { int tos = p->tos; VERIFY( if( tos<0 ) goto bad_instruction ); if( Stringify(p, tos) ) goto no_mem; if( aStack[tos].flags & (STK_Static|STK_Ephem) ){ /* CANT HAPPEN. The IncrKey opcode is only applied to keys ** generated by MakeKey or MakeIdxKey and the results of those ** operands are always dynamic strings. */ goto abort_due_to_error; } zStack[tos][aStack[tos].n-1]++; |
︙ | ︙ | |||
3802 3803 3804 3805 3806 3807 3808 | /* amt and offset now hold the offset to the start of data and the ** amount of data. Go get the data and put it on the stack. */ if( amt==0 ){ aStack[tos].flags = STK_Null; }else if( zRec ){ | | | 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 | /* amt and offset now hold the offset to the start of data and the ** amount of data. Go get the data and put it on the stack. */ if( amt==0 ){ aStack[tos].flags = STK_Null; }else if( zRec ){ aStack[tos].flags = STK_Str | STK_Ephem; aStack[tos].n = amt; zStack[tos] = &zRec[offset]; }else{ if( amt<=NBFS ){ aStack[tos].flags = STK_Str; zStack[tos] = aStack[tos].z; aStack[tos].n = amt; |
︙ | ︙ | |||
4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 | ** the original data remains on the stack. */ case OP_MemStore: { int i = pOp->p1; int tos = p->tos; char *zOld; Mem *pMem; VERIFY( if( tos<0 ) goto not_enough_stack; ) if( i>=p->nMem ){ int nOld = p->nMem; Mem *aMem; p->nMem = i + 5; aMem = sqliteRealloc(p->aMem, p->nMem*sizeof(p->aMem[0])); if( aMem==0 ) goto no_mem; | > | 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 | ** the original data remains on the stack. */ case OP_MemStore: { int i = pOp->p1; int tos = p->tos; char *zOld; Mem *pMem; int flags; VERIFY( if( tos<0 ) goto not_enough_stack; ) if( i>=p->nMem ){ int nOld = p->nMem; Mem *aMem; p->nMem = i + 5; aMem = sqliteRealloc(p->aMem, p->nMem*sizeof(p->aMem[0])); if( aMem==0 ) goto no_mem; |
︙ | ︙ | |||
4787 4788 4789 4790 4791 4792 4793 | } p->aMem = aMem; if( nOld<p->nMem ){ memset(&p->aMem[nOld], 0, sizeof(p->aMem[0])*(p->nMem-nOld)); } } pMem = &p->aMem[i]; | > | > | | > > | | | 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 | } p->aMem = aMem; if( nOld<p->nMem ){ memset(&p->aMem[nOld], 0, sizeof(p->aMem[0])*(p->nMem-nOld)); } } pMem = &p->aMem[i]; flags = pMem->s.flags; if( flags & STK_Dyn ){ zOld = pMem->z; }else{ zOld = 0; } pMem->s = aStack[tos]; flags = pMem->s.flags; if( flags & (STK_Static|STK_Dyn|STK_Ephem) ){ if( (flags & STK_Static)!=0 || (pOp->p2 && (flags & STK_Dyn)!=0) ){ pMem->z = zStack[tos]; }else if( flags & STK_Str ){ pMem->z = sqliteMalloc( pMem->s.n ); if( pMem->z==0 ) goto no_mem; memcpy(pMem->z, zStack[tos], pMem->s.n); pMem->s.flags |= STK_Dyn; pMem->s.flags &= ~(STK_Static|STK_Ephem); } }else{ pMem->z = pMem->s.z; } if( zOld ) sqliteFree(zOld); if( pOp->p2 ){ zStack[tos] = 0; |
︙ | ︙ | |||
4830 4831 4832 4833 4834 4835 4836 | int tos = ++p->tos; int i = pOp->p1; VERIFY( if( NeedStack(p, tos) ) goto no_mem; ) VERIFY( if( i<0 || i>=p->nMem ) goto bad_instruction; ) memcpy(&aStack[tos], &p->aMem[i].s, sizeof(aStack[tos])-NBFS);; if( aStack[tos].flags & STK_Str ){ zStack[tos] = p->aMem[i].z; | | | 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 | int tos = ++p->tos; int i = pOp->p1; VERIFY( if( NeedStack(p, tos) ) goto no_mem; ) VERIFY( if( i<0 || i>=p->nMem ) goto bad_instruction; ) memcpy(&aStack[tos], &p->aMem[i].s, sizeof(aStack[tos])-NBFS);; if( aStack[tos].flags & STK_Str ){ zStack[tos] = p->aMem[i].z; aStack[tos].flags |= STK_Ephem; aStack[tos].flags &= ~STK_Dyn; } break; } /* Opcode: MemIncr P1 P2 * ** |
︙ | ︙ | |||
4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 | Mem *pMem = &pFocus->aMem[i]; char *zOld; if( pMem->s.flags & STK_Dyn ){ zOld = pMem->z; }else{ zOld = 0; } pMem->s = aStack[tos]; if( pMem->s.flags & STK_Dyn ){ pMem->z = zStack[tos]; zStack[tos] = 0; aStack[tos].flags = 0; }else if( pMem->s.flags & (STK_Static|STK_AggCtx) ){ pMem->z = zStack[tos]; | > | 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 | Mem *pMem = &pFocus->aMem[i]; char *zOld; if( pMem->s.flags & STK_Dyn ){ zOld = pMem->z; }else{ zOld = 0; } Deephemeralize(p, tos); pMem->s = aStack[tos]; if( pMem->s.flags & STK_Dyn ){ pMem->z = zStack[tos]; zStack[tos] = 0; aStack[tos].flags = 0; }else if( pMem->s.flags & (STK_Static|STK_AggCtx) ){ pMem->z = zStack[tos]; |
︙ | ︙ | |||
5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 | VERIFY( if( NeedStack(p, tos) ) goto no_mem; ) if( pFocus==0 ) goto no_mem; if( VERIFY( i>=0 && ) i<p->agg.nMem ){ Mem *pMem = &pFocus->aMem[i]; aStack[tos] = pMem->s; zStack[tos] = pMem->z; aStack[tos].flags &= ~STK_Dyn; } break; } /* Opcode: AggNext * P2 * ** ** Make the next aggregate value the current aggregate. The prior | > | 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 | VERIFY( if( NeedStack(p, tos) ) goto no_mem; ) if( pFocus==0 ) goto no_mem; if( VERIFY( i>=0 && ) i<p->agg.nMem ){ Mem *pMem = &pFocus->aMem[i]; aStack[tos] = pMem->s; zStack[tos] = pMem->z; aStack[tos].flags &= ~STK_Dyn; aStack[tos].flags |= STK_Ephem; } break; } /* Opcode: AggNext * P2 * ** ** Make the next aggregate value the current aggregate. The prior |
︙ | ︙ | |||
5066 5067 5068 5069 5070 5071 5072 | (*p->agg.apFunc[i]->xFinalize)(&ctx); if( freeCtx ){ sqliteFree( aMem[i].z ); } aMem[i].s = ctx.s; aMem[i].z = ctx.z; if( (aMem[i].s.flags & STK_Str) && | | | 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 | (*p->agg.apFunc[i]->xFinalize)(&ctx); if( freeCtx ){ sqliteFree( aMem[i].z ); } aMem[i].s = ctx.s; aMem[i].z = ctx.z; if( (aMem[i].s.flags & STK_Str) && (aMem[i].s.flags & (STK_Dyn|STK_Static|STK_Ephem))==0 ){ aMem[i].z = aMem[i].s.z; } nErr += ctx.isError; } } break; } |
︙ | ︙ | |||
5181 5182 5183 5184 5185 5186 5187 | pc = pOp->p2 - 1; } } tos = ++p->tos; VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; ) zStack[tos] = sqliteHashKey(pSet->prev); aStack[tos].n = sqliteHashKeysize(pSet->prev); | | | 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 | pc = pOp->p2 - 1; } } tos = ++p->tos; VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; ) zStack[tos] = sqliteHashKey(pSet->prev); aStack[tos].n = sqliteHashKeysize(pSet->prev); aStack[tos].flags = STK_Str | STK_Ephem; break; } /* An other opcode is illegal... */ default: { sprintf(zBuf,"%d",pOp->opcode); |
︙ | ︙ | |||
5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 | fprintf(p->trace, " r:%g", aStack[i].r); }else if( aStack[i].flags & STK_Str ){ int j, k; char zBuf[100]; zBuf[0] = ' '; if( aStack[i].flags & STK_Dyn ){ zBuf[1] = 'z'; }else if( aStack[i].flags & STK_Static ){ zBuf[1] = 't'; }else{ zBuf[1] = 's'; } zBuf[2] = '['; k = 3; for(j=0; j<20 && j<aStack[i].n; j++){ int c = zStack[i][j]; | > > > > > | 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 | fprintf(p->trace, " r:%g", aStack[i].r); }else if( aStack[i].flags & STK_Str ){ int j, k; char zBuf[100]; zBuf[0] = ' '; if( aStack[i].flags & STK_Dyn ){ zBuf[1] = 'z'; assert( (aStack[i].flags & (STK_Static|STK_Ephem))==0 ); }else if( aStack[i].flags & STK_Static ){ zBuf[1] = 't'; assert( (aStack[i].flags & (STK_Dyn|STK_Ephem))==0 ); }else if( aStack[i].flags & STK_Ephem ){ zBuf[1] = 'e'; assert( (aStack[i].flags & (STK_Static|STK_Dyn))==0 ); }else{ zBuf[1] = 's'; } zBuf[2] = '['; k = 3; for(j=0; j<20 && j<aStack[i].n; j++){ int c = zStack[i][j]; |
︙ | ︙ |