Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Enhance the RowDecoder object so that it persists on a VdbeCursor and can be reused for multiple OP_Column operations. This opens the possibility of adding caching of header information and/or values in a later check-in. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
6ed358511ba7b0ac8ca73e04a2b40ab8 |
User & Date: | drh 2013-07-25 00:55:46.620 |
Context
2013-07-25
| ||
01:12 | Fix the RowDecoder caching logic by adding new cache clears to opcodes that move the cursor. check-in: d5abe1bca0 user: drh tags: trunk | |
00:55 | Enhance the RowDecoder object so that it persists on a VdbeCursor and can be reused for multiple OP_Column operations. This opens the possibility of adding caching of header information and/or values in a later check-in. check-in: 6ed358511b user: drh tags: trunk | |
2013-07-24
| ||
21:38 | Move all VdbeCursor methods into the vdbecursor.c source file. check-in: 5d08b14478 user: drh tags: trunk | |
Changes
Changes to src/fts5.c.
︙ | ︙ | |||
2826 2827 2828 2829 2830 2831 2832 | if( rc==SQLITE4_OK ){ rc = sqlite4KVCursorSeek(pCsr->pCsr, aKey, nKey, 0); if( rc==SQLITE4_NOTFOUND ){ rc = SQLITE4_CORRUPT_BKPT; } } | < < < < | | | | 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 | if( rc==SQLITE4_OK ){ rc = sqlite4KVCursorSeek(pCsr->pCsr, aKey, nKey, 0); if( rc==SQLITE4_NOTFOUND ){ rc = SQLITE4_CORRUPT_BKPT; } } if( rc==SQLITE4_OK ){ int i; RowDecoder *pCodec; /* The decoder object */ rc = sqlite4VdbeDecoderCreate(db,0, pCsr->pCsr, pInfo->nCol, &pCodec); for(i=0; rc==SQLITE4_OK && i<pInfo->nCol; i++){ rc = sqlite4VdbeDecoderGetColumn(pCodec, i, 0, &pCsr->aMem[i]); } sqlite4VdbeDecoderDestroy(pCodec); } if( rc==SQLITE4_OK ) pCsr->bMemValid = 1; } } if( rc==SQLITE4_OK ){ |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | if( p->apCsr[iCur] ){ sqlite4VdbeFreeCursor(p->apCsr[iCur]); p->apCsr[iCur] = 0; } if( SQLITE4_OK==sqlite4VdbeMemGrow(pMem, nByte, 0) ){ p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->z; memset(pCx, 0, sizeof(VdbeCursor)); pCx->iDb = iDb; pCx->nField = nField; sqlite4_buffer_init(&pCx->sSeekKey, p->db->pEnv->pMM); } return pCx; } /* ** Try to convert a value into a numeric representation if we can | > > | 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 | if( p->apCsr[iCur] ){ sqlite4VdbeFreeCursor(p->apCsr[iCur]); p->apCsr[iCur] = 0; } if( SQLITE4_OK==sqlite4VdbeMemGrow(pMem, nByte, 0) ){ p->apCsr[iCur] = pCx = (VdbeCursor*)pMem->z; memset(pCx, 0, sizeof(VdbeCursor)); pCx->db = p->db; pCx->iDb = iDb; pCx->nField = nField; pCx->rowChnged = 1; sqlite4_buffer_init(&pCx->sSeekKey, p->db->pEnv->pMM); } return pCx; } /* ** Try to convert a value into a numeric representation if we can |
︙ | ︙ | |||
2094 2095 2096 2097 2098 2099 2100 | ** ** If the OPFLAG_CLEARCACHE bit is set on P5 and P1 is a pseudo-table cursor, ** then the cache of the cursor is reset prior to extracting the column. ** The first OP_Column against a pseudo-table after the value of the content ** register has changed should have this bit set. */ case OP_Column: { | < < > < < < < < < < | < < < < < < < < < < < < < < < < | | > > | < | | | < < < | 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 | ** ** If the OPFLAG_CLEARCACHE bit is set on P5 and P1 is a pseudo-table cursor, ** then the cache of the cursor is reset prior to extracting the column. ** The first OP_Column against a pseudo-table after the value of the content ** register has changed should have this bit set. */ case OP_Column: { int p1; /* Index of VdbeCursor to decode */ int mxField; /* Maximum column number */ VdbeCursor *pC; /* The VDBE cursor */ Mem *pDest; /* Where to write the results */ Mem *pDefault; /* Default value from P4 */ p1 = pOp->p1; assert( p1<p->nCursor ); assert( pOp->p3>0 && pOp->p3<=p->nMem ); pDest = &aMem[pOp->p3]; memAboutToChange(p, pDest); pC = p->apCsr[p1]; assert( pC!=0 ); #ifndef SQLITE4_OMIT_VIRTUALTABLE assert( pC->pVtabCursor==0 ); #endif if( pC->pDecoder==0 ){ mxField = pC->nField; if( pC->pKeyInfo && pC->pKeyInfo->nData ) mxField = pC->pKeyInfo->nData; rc = sqlite4VdbeDecoderCreate(db, pC, 0, mxField, &pC->pDecoder); pC->rowChnged = 1; } if( rc==SQLITE4_OK ){ pDefault = (pOp->p4type==P4_MEM) ? pOp->p4.pMem : 0; rc = sqlite4VdbeDecoderGetColumn(pC->pDecoder, pOp->p2, pDefault, pDest); }else{ sqlite4VdbeMemSetNull(pDest); } UPDATE_MAX_BLOBSIZE(pDest); REGISTER_TRACE(pOp->p3, pDest); break; } /* Opcode: Affinity P1 P2 * P4 * ** ** Apply affinities to a range of P2 registers starting with P1. ** |
︙ | ︙ | |||
2853 2854 2855 2856 2857 2858 2859 | case OP_OpenPseudo: { VdbeCursor *pCx; assert( pOp->p1>=0 ); pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, 0); if( pCx==0 ) goto no_mem; pCx->nullRow = 1; | | | 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 | case OP_OpenPseudo: { VdbeCursor *pCx; assert( pOp->p1>=0 ); pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, 0); if( pCx==0 ) goto no_mem; pCx->nullRow = 1; pCx->pPseudoTab = aMem + pOp->p2; break; } /* Opcode: Close P1 * * * * ** ** Close a cursor previously opened as P1. If P1 is not ** currently open, this instruction is a no-op. |
︙ | ︙ | |||
2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 | ); nVarint = sqlite4VarintLen(pPk->iRoot); rc = sqlite4_buffer_resize(&pPk->sSeekKey, nVarint + nKey - nShort); if( rc!=SQLITE4_OK ) break; putVarint32((u8 *)(pPk->sSeekKey.p), pPk->iRoot); memcpy(((u8*)pPk->sSeekKey.p) + nVarint, &aKey[nShort], nKey-nShort); assert( pPk->sSeekKey.n>0 ); } break; } /* Opcode: SeekGe P1 P2 P3 P4 * ** ** P1 identifies an open database cursor. The cursor is repositioned so ** that it points to the smallest entry in its index that is greater than ** or equal to the key formed by the array of P4 registers starting at ** register P3. ** ** If there are no records greater than or equal to the key and P2 is ** not zero, then jump to P2. ** ** See also: Found, NotFound, Distinct, SeekLt, SeekGt, SeekLe */ /* Opcode: SeekGt P1 P2 P3 P4 * ** | > | | | | < | | | | | | < | | | | | | < | | > | | 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 | ); nVarint = sqlite4VarintLen(pPk->iRoot); rc = sqlite4_buffer_resize(&pPk->sSeekKey, nVarint + nKey - nShort); if( rc!=SQLITE4_OK ) break; putVarint32((u8 *)(pPk->sSeekKey.p), pPk->iRoot); memcpy(((u8*)pPk->sSeekKey.p) + nVarint, &aKey[nShort], nKey-nShort); assert( pPk->sSeekKey.n>0 ); pPk->rowChnged = 1; } break; } /* Opcode: SeekGe P1 P2 P3 P4 * ** ** P1 identifies an open database cursor. The cursor is repositioned so ** that it points to the smallest entry in its index that is greater than ** or equal to the key formed by the array of P4 registers starting at ** register P3. ** ** If there are no records greater than or equal to the key and P2 is ** not zero, then jump to P2. ** ** See also: Found, NotFound, Distinct, SeekLt, SeekGt, SeekLe */ /* Opcode: SeekGt P1 P2 P3 P4 * ** ** P1 identifies an open database cursor. The cursor is repositioned so ** that it points to the smallest entry in its index that is greater than ** the key formed by the array of P4 registers starting at ** register P3. ** ** If there are no records greater than the key and P2 is ** not zero, then jump to P2. ** ** See also: Found, NotFound, Distinct, SeekLt, SeekGe, SeekLe */ /* Opcode: SeekLt P1 P2 P3 P4 * ** ** P1 identifies an open database cursor. The cursor is repositioned so ** that it points to the largest entry in its index that is less than ** the key formed by the array of P4 registers starting at ** register P3. ** ** If there are no records less than the key and P2 is ** not zero, then jump to P2. ** ** See also: Found, NotFound, Distinct, SeekGt, SeekGe, SeekLe */ /* Opcode: SeekLe P1 P2 P3 P4 * ** ** P1 identifies an open database cursor. The cursor is repositioned so ** that it points to the largest entry in its index that is less than or ** equal to the key formed by the array of P4 registers starting at ** register P3. ** ** If there are no records less than or equal to the key and P2 is ** not zero, then jump to P2. ** ** See also: Found, NotFound, Distinct, SeekGt, SeekGe, SeekLt */ case OP_SeekLt: /* jump, in3 */ case OP_SeekLe: /* jump, in3 */ case OP_SeekGe: /* jump, in3 */ case OP_SeekGt: { /* jump, in3 */ int op; /* Copy of pOp->opcode (the op-code) */ VdbeCursor *pC; /* Cursor P1 */ int nField; /* Number of values to encode into key */ KVByteArray *aProbe; /* Buffer containing encoded key */ KVSize nProbe; /* Size of aProbe[] in bytes */ int dir; /* KV search dir (+ve or -ve) */ const KVByteArray *aKey; /* Pointer to final cursor key */ KVSize nKey; /* Size of aKey[] in bytes */ pC = p->apCsr[pOp->p1]; pC->nullRow = 0; pC->sSeekKey.n = 0; pC->rowChnged = 1; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); assert( pOp->p2!=0 ); assert( pC!=0 ); assert( pC->pPseudoTab==0 ); assert( OP_SeekLe == OP_SeekLt+1 ); assert( OP_SeekGe == OP_SeekLt+2 ); assert( OP_SeekGt == OP_SeekLt+3 ); /* Encode a database key consisting of the contents of the P4 registers ** starting at register P3. Have the vdbecodec module allocate an extra ** free byte at the end of the database key (see below). */ |
︙ | ︙ | |||
3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 | #endif alreadyExists = 0; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); assert( pOp->p4type==P4_INT32 ); pC = p->apCsr[pOp->p1]; pC->sSeekKey.n = 0; assert( pC!=0 ); pIn3 = &aMem[pOp->p3]; assert( pC->pKVCur!=0 ); if( pOp->p4.i>0 ){ rc = sqlite4VdbeEncodeKey( db, pIn3, pOp->p4.i, pOp->p4.i + (pOp->p5 & OPFLAG_PARTIALKEY), pC->iRoot, pC->pKeyInfo, &pProbe, &nProbe, 0 | > | 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 | #endif alreadyExists = 0; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); assert( pOp->p4type==P4_INT32 ); pC = p->apCsr[pOp->p1]; pC->sSeekKey.n = 0; pC->rowChnged = 1; assert( pC!=0 ); pIn3 = &aMem[pOp->p3]; assert( pC->pKVCur!=0 ); if( pOp->p4.i>0 ){ rc = sqlite4VdbeEncodeKey( db, pIn3, pOp->p4.i, pOp->p4.i + (pOp->p5 & OPFLAG_PARTIALKEY), pC->iRoot, pC->pKeyInfo, &pProbe, &nProbe, 0 |
︙ | ︙ | |||
3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 | */ case OP_Delete: { VdbeCursor *pC; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->sSeekKey.n==0 ); rc = sqlite4KVCursorDelete(pC->pKVCur); if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++; break; } /* Opcode: ResetCount * * * * * ** | > | 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 | */ case OP_Delete: { VdbeCursor *pC; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->sSeekKey.n==0 ); pC->rowChnged = 1; rc = sqlite4KVCursorDelete(pC->pKVCur); if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++; break; } /* Opcode: ResetCount * * * * * ** |
︙ | ︙ | |||
3590 3591 3592 3593 3594 3595 3596 | /* Note that RowKey and RowData are really exactly the same instruction */ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; rc = sqlite4VdbeCursorMoveto(pC); if( rc!=SQLITE4_OK ) break; assert( pC->nullRow==0 ); | | | 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 | /* Note that RowKey and RowData are really exactly the same instruction */ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; rc = sqlite4VdbeCursorMoveto(pC); if( rc!=SQLITE4_OK ) break; assert( pC->nullRow==0 ); assert( pC->pPseudoTab==0 ); assert( pC->pKVCur!=0 ); pCrsr = pC->pKVCur; if( pOp->opcode==OP_RowKey ){ rc = sqlite4KVCursorKey(pCrsr, &pData, &nData); if( pOp->p5 ){ nData = sqlite4VdbeShortKey(pData, nData, 1, 0); |
︙ | ︙ | |||
3646 3647 3648 3649 3650 3651 3652 | pKey = &aMem[pOp->p2]; aIncr = &aMem[pOp->p3]; nTotal = pOp->p4.i; pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->nullRow==0 ); | | | 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 | pKey = &aMem[pOp->p2]; aIncr = &aMem[pOp->p3]; nTotal = pOp->p4.i; pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( pC->nullRow==0 ); assert( pC->pPseudoTab==0 ); assert( pC->pKVCur!=0 ); assert( pOp->p4type==P4_INT32 ); rc = sqlite4KVCursorKey(pC->pKVCur, &pNew, &nNew); if( rc==SQLITE4_OK ){ assert( pKey->flags & (MEM_Blob|MEM_Null) ); if( pKey->flags & MEM_Blob ){ |
︙ | ︙ | |||
3704 3705 3706 3707 3708 3709 3710 | int n; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; rc = sqlite4VdbeCursorMoveto(pC); if( rc!=SQLITE4_OK ) break; assert( pC->sSeekKey.n==0 ); | | | 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 | int n; assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; rc = sqlite4VdbeCursorMoveto(pC); if( rc!=SQLITE4_OK ) break; assert( pC->sSeekKey.n==0 ); assert( pC->pPseudoTab==0 ); if( pC->nullRow ){ pOut->flags = MEM_Null; break; #ifndef SQLITE4_OMIT_VIRTUALTABLE }else if( pC->pVtabCursor ){ pVtab = pC->pVtabCursor->pVtab; pModule = pVtab->pModule; |
︙ | ︙ |
Changes to src/vdbeInt.h.
︙ | ︙ | |||
46 47 48 49 50 51 52 53 54 55 56 57 | ** entries or retrieve the key or data from the entry that the cursor ** is currently pointing to. ** ** Every cursor that the virtual machine has open is represented by an ** instance of the following structure. */ struct VdbeCursor { KVCursor *pKVCur; /* The cursor structure of the storage engine */ KVStore *pTmpKV; /* Separate file holding a temporary table */ KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */ int iDb; /* Index of cursor database in db->aDb[] (or -1) */ int iRoot; /* Root page of the table */ | > < > > > | 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | ** entries or retrieve the key or data from the entry that the cursor ** is currently pointing to. ** ** Every cursor that the virtual machine has open is represented by an ** instance of the following structure. */ struct VdbeCursor { sqlite4 *db; /* The connection that owns this cursor */ KVCursor *pKVCur; /* The cursor structure of the storage engine */ KVStore *pTmpKV; /* Separate file holding a temporary table */ KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */ int iDb; /* Index of cursor database in db->aDb[] (or -1) */ int iRoot; /* Root page of the table */ int nField; /* Number of fields in the header */ Bool nullRow; /* True if pointing to a row with no data */ Bool rowChnged; /* True if row has changed out from under pDecoder */ i64 seqCount; /* Sequence counter */ Mem *pPseudoTab; /* Register holding pseudotable content */ VdbeSorter *pSorter; /* Sorter object for OP_SorterOpen cursors */ Fts5Cursor *pFts; /* Fts5 cursor object (or NULL) */ RowDecoder *pDecoder; /* Decoder for row content */ sqlite4_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */ const sqlite4_module *pModule; /* Module for cursor pVtabCursor */ sqlite4_buffer sSeekKey; /* Key for deferred seek */ }; /* Methods for the VdbeCursor object */ void sqlite4VdbeFreeCursor(VdbeCursor*); |
︙ | ︙ | |||
350 351 352 353 354 355 356 | */ void sqliteVdbePopStack(Vdbe*,int); #if defined(SQLITE4_DEBUG) || defined(VDBE_PROFILE) void sqlite4VdbePrintOp(FILE*, int, Op*); #endif void sqlite4VdbeDeleteAuxData(VdbeFunc*, int); | | | | | | | 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 | */ void sqliteVdbePopStack(Vdbe*,int); #if defined(SQLITE4_DEBUG) || defined(VDBE_PROFILE) void sqlite4VdbePrintOp(FILE*, int, Op*); #endif void sqlite4VdbeDeleteAuxData(VdbeFunc*, int); int sqlite4VdbeDecoderCreate( sqlite4 *db, /* The database connection */ VdbeCursor *pCur, /* Cursor associated with this decoder */ KVCursor *pKVCur, /* Alternative cursor if pCur is NULL */ int mxCol, /* Maximum number of columns in aIn[] */ RowDecoder **ppOut /* The newly generated decoder object */ ); int sqlite4VdbeDecoderDestroy(RowDecoder *pDecoder); int sqlite4VdbeDecoderGetColumn( RowDecoder *pDecoder, /* The decoder for the whole string */ int iVal, /* Index of the value to decode. First is 0 */ Mem *pDefault, /* The default value. Often NULL */ Mem *pOut /* Write the result here */ ); int sqlite4VdbeEncodeData( sqlite4 *db, /* The database connection */ |
︙ | ︙ |
Changes to src/vdbecodec.c.
︙ | ︙ | |||
26 27 28 29 30 31 32 | ** ** When the VDBE needs to extract multiple columns from the same row, it will ** try to reuse a single decoder object. The decoder, therefore, should attempt ** to cache any intermediate results that might be useful on later invocations. */ struct RowDecoder { sqlite4 *db; /* The database connection */ | > > | > | > | | | | | > > | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | ** ** When the VDBE needs to extract multiple columns from the same row, it will ** try to reuse a single decoder object. The decoder, therefore, should attempt ** to cache any intermediate results that might be useful on later invocations. */ struct RowDecoder { sqlite4 *db; /* The database connection */ VdbeCursor *pCur; /* The cursor for being decoded */ KVCursor *pKVCur; /* Alternative KVCursor if pCur is NULL */ const KVByteArray *a; /* Content to be decoded */ const KVByteArray *aKey; /* Key content */ KVSize n; /* Bytes of content in a[] */ KVSize nKey; /* Bytes of key content */ int mxCol; /* Maximum number of columns */ }; /* ** Create an object that can be used to decode fields of the data encoding. ** ** The aIn[] value must remain stable for the life of the decoder. */ int sqlite4VdbeDecoderCreate( sqlite4 *db, /* The database connection */ VdbeCursor *pCur, /* The cursor associated with this decoder */ KVCursor *pKVCur, /* Alternative KVCursor */ int mxCol, /* Maximum number of columns to ever decode */ RowDecoder **ppOut /* Return the answer here */ ){ RowDecoder *p; assert( pCur==0 || pKVCur==0 ); assert( pCur!=0 || pKVCur!=0 ); p = sqlite4DbMallocZero(db, sizeof(*p)); *ppOut = p; if( p==0 ) return SQLITE4_NOMEM; p->db = db; p->pCur = pCur; p->pKVCur = pKVCur; p->mxCol = mxCol; return SQLITE4_OK; } /* ** Destroy a decoder object previously created ** using sqlite4VdbeCreateDecoder(). */ int sqlite4VdbeDecoderDestroy(RowDecoder *p){ if( p ){ sqlite4DbFree(p->db, p); } return SQLITE4_OK; } /* ** Make sure the p->a and p->n fields are valid and current. */ static int decoderFetchData(RowDecoder *p){ VdbeCursor *pCur = p->pCur; int rc; if( pCur==0 ){ rc = sqlite4KVCursorData(p->pKVCur, 0, -1, &p->a, &p->n); return rc; } if( 1 /*pCur->rowChnged*/ ){ /* FIXME: Row cache not always cleared */ p->a = 0; p->aKey = 0; pCur->rowChnged = pCur->pPseudoTab!=0; } if( p->a ) return SQLITE4_OK; rc = sqlite4VdbeCursorMoveto(pCur); if( rc ) return rc; if( pCur->nullRow ){ p->a = 0; p->n = 0; return SQLITE4_OK; } if( pCur->pKVCur ){ rc = sqlite4KVCursorData(pCur->pKVCur, 0, -1, &p->a, &p->n); }else{ Mem *pReg = pCur->pPseudoTab; assert( pReg!=0 ); p->a = (const KVByteArray*)pReg->z; p->n = pReg->n; rc = SQLITE4_OK; } return rc; } /* ** Decode a single value from a data string. Store that value in pOut. ** ** If the value is a FROM-KEY reference (header codes 22 and 23) then the ** pOut->flags field is set to MEM_FromKey and pOut->iOfst is the offset into ** the key of the start of the actual value. The pOut->type field is set to ** SQLITE_FLOAT if a numeric value extracted from the key should be interpreted ** as a floating point even if it has no fractional part. */ int sqlite4VdbeDecoderGetColumn( RowDecoder *p, /* The decoder for the whole string */ int iVal, /* Index of the value to decode. First is 0 */ Mem *pDefault, /* The default value. Often NULL */ Mem *pOut /* Write the result here */ ){ u32 size; /* Size of a field */ sqlite4_uint64 ofst; /* Offset to the payload */ sqlite4_uint64 type; /* Datatype */ sqlite4_uint64 subtype; /* Subtype for a typed blob */ int cclass; /* class of content */ int n; /* Offset into the header */ int i; /* Loop counter */ int sz; /* Size of a varint */ int endHdr; /* First byte past header */ int rc; /* Return code */ sqlite4VdbeMemSetNull(pOut); assert( iVal<=p->mxCol ); rc = decoderFetchData(p); if( rc ) return rc; if( p->a==0 ) return SQLITE4_OK; n = sqlite4GetVarint64(p->a, p->n, &ofst); if( n==0 ) return SQLITE4_CORRUPT; ofst += n; endHdr = ofst; if( endHdr>p->n ) return SQLITE4_CORRUPT; for(i=0; i<=iVal && n<endHdr; i++){ sz = sqlite4GetVarint64(p->a+n, p->n-n, &type); |
︙ | ︙ |
Changes to src/vdbecursor.c.
︙ | ︙ | |||
48 49 50 51 52 53 54 55 56 57 58 59 60 61 | rc = SQLITE4_CORRUPT_BKPT; }else if( rc==SQLITE4_INEXACT ){ rc = sqlite4KVCursorKey(pCur, &aKey, &nKey); if( rc==SQLITE4_OK && (nKey<nProbe || memcmp(aKey, aProbe, nProbe)!=0) ){ rc = SQLITE4_NOTFOUND; } } return rc; } /* ** Move a VDBE cursor to the next element in its table. ** Return SQLITE4_NOTFOUND if the seek falls of the end of the table. | > | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | rc = SQLITE4_CORRUPT_BKPT; }else if( rc==SQLITE4_INEXACT ){ rc = sqlite4KVCursorKey(pCur, &aKey, &nKey); if( rc==SQLITE4_OK && (nKey<nProbe || memcmp(aKey, aProbe, nProbe)!=0) ){ rc = SQLITE4_NOTFOUND; } } pC->rowChnged = 1; return rc; } /* ** Move a VDBE cursor to the next element in its table. ** Return SQLITE4_NOTFOUND if the seek falls of the end of the table. |
︙ | ︙ | |||
72 73 74 75 76 77 78 79 80 81 82 83 84 85 | rc = sqlite4KVCursorKey(pCur, &aKey, &nKey); if( rc==SQLITE4_OK ){ iTabno = 0; sqlite4GetVarint64(aKey, nKey, &iTabno); if( iTabno!=pC->iRoot ) rc = SQLITE4_NOTFOUND; } } return rc; } /* ** Move a VDBE cursor to the previous element in its table. ** Return SQLITE4_NOTFOUND if the seek falls of the end of the table. */ | > | 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | rc = sqlite4KVCursorKey(pCur, &aKey, &nKey); if( rc==SQLITE4_OK ){ iTabno = 0; sqlite4GetVarint64(aKey, nKey, &iTabno); if( iTabno!=pC->iRoot ) rc = SQLITE4_NOTFOUND; } } pC->rowChnged = 1; return rc; } /* ** Move a VDBE cursor to the previous element in its table. ** Return SQLITE4_NOTFOUND if the seek falls of the end of the table. */ |
︙ | ︙ | |||
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | rc = sqlite4KVCursorKey(pCur, &aKey, &nKey); if( rc==SQLITE4_OK ){ iTabno = 0; sqlite4GetVarint64(aKey, nKey, &iTabno); if( iTabno!=pC->iRoot ) rc = SQLITE4_NOTFOUND; } } return rc; } /* ** Close a VDBE cursor and release all the resources that cursor ** happens to hold. */ void sqlite4VdbeFreeCursor(VdbeCursor *pCx){ if( pCx==0 ){ return; } sqlite4Fts5Close(pCx->pFts); if( pCx->pKVCur ){ sqlite4KVCursorClose(pCx->pKVCur); } if( pCx->pTmpKV ){ sqlite4KVStoreClose(pCx->pTmpKV); } sqlite4_buffer_clear(&pCx->sSeekKey); #ifndef SQLITE4_OMIT_VIRTUALTABLE if( pCx->pVtabCursor ){ sqlite4_vtab_cursor *pVtabCursor = pCx->pVtabCursor; const sqlite4_module *pModule = pCx->pModule; p->inVtabMethod = 1; | > > > > > | 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | rc = sqlite4KVCursorKey(pCur, &aKey, &nKey); if( rc==SQLITE4_OK ){ iTabno = 0; sqlite4GetVarint64(aKey, nKey, &iTabno); if( iTabno!=pC->iRoot ) rc = SQLITE4_NOTFOUND; } } pC->rowChnged = 1; return rc; } /* ** Close a VDBE cursor and release all the resources that cursor ** happens to hold. */ void sqlite4VdbeFreeCursor(VdbeCursor *pCx){ if( pCx==0 ){ return; } sqlite4Fts5Close(pCx->pFts); if( pCx->pKVCur ){ sqlite4KVCursorClose(pCx->pKVCur); } if( pCx->pTmpKV ){ sqlite4KVStoreClose(pCx->pTmpKV); } if( pCx->pDecoder ){ sqlite4VdbeDecoderDestroy(pCx->pDecoder); pCx->pDecoder = 0; } sqlite4_buffer_clear(&pCx->sSeekKey); #ifndef SQLITE4_OMIT_VIRTUALTABLE if( pCx->pVtabCursor ){ sqlite4_vtab_cursor *pVtabCursor = pCx->pVtabCursor; const sqlite4_module *pModule = pCx->pModule; p->inVtabMethod = 1; |
︙ | ︙ | |||
145 146 147 148 149 150 151 152 153 154 | assert( pPk->pKeyInfo->nPK==0 ); rc = sqlite4KVCursorSeek(pPk->pKVCur, pPk->sSeekKey.p, pPk->sSeekKey.n, 0); if( rc==SQLITE4_NOTFOUND ){ rc = SQLITE4_CORRUPT_BKPT; } pPk->nullRow = 0; pPk->sSeekKey.n = 0; } return rc; } | > | 152 153 154 155 156 157 158 159 160 161 162 | assert( pPk->pKeyInfo->nPK==0 ); rc = sqlite4KVCursorSeek(pPk->pKVCur, pPk->sSeekKey.p, pPk->sSeekKey.n, 0); if( rc==SQLITE4_NOTFOUND ){ rc = SQLITE4_CORRUPT_BKPT; } pPk->nullRow = 0; pPk->sSeekKey.n = 0; pPk->rowChnged = 1; } return rc; } |