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: 6ed358511ba7b0ac8ca73e04a2b40ab8d8ea30eb
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
Unified Diff Ignore Whitespace Patch
Changes to src/fts5.c.
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
        if( rc==SQLITE4_OK ){
          rc = sqlite4KVCursorSeek(pCsr->pCsr, aKey, nKey, 0);
          if( rc==SQLITE4_NOTFOUND ){
            rc = SQLITE4_CORRUPT_BKPT;
          }
        }

        if( rc==SQLITE4_OK ){
          rc = sqlite4KVCursorData(pCsr->pCsr, 0, -1, &aData, &nData);
        }

        if( rc==SQLITE4_OK ){
          int i;
          RowDecoder *pCodec;   /* The decoder object */

          rc = sqlite4VdbeCreateDecoder(db, aData, nData, pInfo->nCol, &pCodec);
          for(i=0; rc==SQLITE4_OK && i<pInfo->nCol; i++){
            rc = sqlite4VdbeExtractColumn(pCodec, i, 0, &pCsr->aMem[i]);
          }
          sqlite4VdbeDestroyDecoder(pCodec);
        }

        if( rc==SQLITE4_OK ) pCsr->bMemValid = 1;
      }
    }

    if( rc==SQLITE4_OK ){







<
<
<
<




|

|

|







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
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
2140
2141
2142
2143


2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
**
** 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: {
  KVCursor *pKVCur;         /* Cursor for current entry in the KV storage */
  RowDecoder *pCodec;       /* The decoder object */
  int p1;                   /* Index of VdbeCursor to decode */

  VdbeCursor *pC;           /* The VDBE cursor */
  Mem *pDest;               /* Where to write the results */
  const KVByteArray *aData; /* The content to be decoded */
  KVSize nData;             /* Size of aData[] in bytes */
  Mem *pDefault;            /* Default value from P4 */
  Mem *pReg;                /* */

  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
  pKVCur = pC->pKVCur;
  if( pKVCur!=0 ){
    rc = sqlite4VdbeCursorMoveto(pC);
    if( rc!=SQLITE4_OK ) break;
    if( pC->nullRow ){
      aData = 0;
    }else{
      rc = sqlite4KVCursorData(pKVCur, 0, -1, &aData, &nData);
    }
  }else if( ALWAYS(pC->pseudoTableReg>0) ){
    pReg = &aMem[pC->pseudoTableReg];
    assert( pReg->flags & MEM_Blob );
    assert( memIsValid(pReg) );
    aData = (const KVByteArray*)pReg->z;
    nData = pReg->n;
  }else{
    aData = 0;
    MemSetTypeFlag(pDest, MEM_Null);
  }
  if( rc==SQLITE4_OK && aData ){
    /* TODO: Fix this somehow... */
    int nField = pC->nField;
    if( pC->pKeyInfo && pC->pKeyInfo->nData ) nField = pC->pKeyInfo->nData;



    rc = sqlite4VdbeCreateDecoder(db, aData, nData, nField, &pCodec);
    if( rc==0 ){
      pDefault = (pOp->p4type==P4_MEM) ? pOp->p4.pMem : 0;
      rc = sqlite4VdbeExtractColumn(pCodec, pOp->p2, pDefault, pDest);
      sqlite4VdbeDestroyDecoder(pCodec);
    }
  }else{
    sqlite4VdbeMemSetNull(pDest);
  }
  UPDATE_MAX_BLOBSIZE(pDest);
  REGISTER_TRACE(pOp->p3, pDest);
  assert( rc<100 );
  break;
}

/* Opcode: Affinity P1 P2 * P4 *
**
** Apply affinities to a range of P2 registers starting with P1.
**







<
<

>


<
<

<











<
<
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
|
>
>
|
<
|
|
|
<
<





<







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
2860
2861
2862
2863
2864
2865
2866
2867
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->pseudoTableReg = 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.







|







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
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
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993

2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
    );
    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 *
**
** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), 
** use the value in register P3 as a key. If cursor P1 refers 
** to an SQL index, then P3 is the first in an array of P4 registers 
** that are used as an unpacked index key. 
**
** Reposition cursor P1 so that  it points to the smallest entry that 
** is greater than the key value. 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 * 
**
** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), 
** use the value in register P3 as a key. If cursor P1 refers 
** to an SQL index, then P3 is the first in an array of P4 registers 
** that are used as an unpacked index key. 
**
** Reposition cursor P1 so that  it points to the largest entry that 
** is less than the key value. 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 *
**
** If cursor P1 refers to an SQL table (B-Tree that uses integer keys), 
** use the value in register P3 as a key. If cursor P1 refers 
** to an SQL index, then P3 is the first in an array of P4 registers 
** that are used as an unpacked index key. 
**
** Reposition cursor P1 so that it points to the largest entry that 
** is less than or equal to the key value. 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;


  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  assert( pOp->p2!=0 );
  assert( pC!=0 );
  assert( pC->pseudoTableReg==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).  */







>



















|
|
|
|

<
|
|





|
|
|
|

<
|
|





|
|
|
|

<
|
|



















>




|







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
3597
3598
3599
3600
3601
3602
3603
3604

  /* 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->pseudoTableReg==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);







|







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
3653
3654
3655
3656
3657
3658
3659
3660

  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->pseudoTableReg==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 ){







|







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
3711
3712
3713
3714
3715
3716
3717
3718
  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->pseudoTableReg==0 );
  if( pC->nullRow ){
    pOut->flags = MEM_Null;
    break;
#ifndef SQLITE4_OMIT_VIRTUALTABLE
  }else if( pC->pVtabCursor ){
    pVtab = pC->pVtabCursor->pVtab;
    pModule = pVtab->pModule;







|







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
58
59
60

61

62
63

64
65
66
67
68
69
70
** 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 */
  int pseudoTableReg;   /* Register holding pseudotable content. */
  int nField;           /* Number of fields in the header */
  Bool nullRow;         /* True if pointing to a row with no data */

  i64 seqCount;         /* Sequence counter */

  VdbeSorter *pSorter;  /* Sorter object for OP_SorterOpen cursors */
  Fts5Cursor *pFts;     /* Fts5 cursor object (or NULL) */

  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*);







>





<


>

>


>







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
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
*/
void sqliteVdbePopStack(Vdbe*,int);
#if defined(SQLITE4_DEBUG) || defined(VDBE_PROFILE)
void sqlite4VdbePrintOp(FILE*, int, Op*);
#endif
void sqlite4VdbeDeleteAuxData(VdbeFunc*, int);

int sqlite4VdbeCreateDecoder(
  sqlite4 *db,                /* The database connection */
  const unsigned char *aIn,   /* The input data blob */
  int nIn,                    /* Number of bytes in aIn[] */
  int mxCol,                  /* Maximum number of columns in aIn[] */
  RowDecoder **ppOut          /* The newly generated decoder object */
);
int sqlite4VdbeDestroyDecoder(RowDecoder *pDecoder);
int sqlite4VdbeExtractColumn(
  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 */







|

|
|



|
|







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


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
**
** 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 */


  const u8 *a;                /* Content to be decoded */

  int n;                      /* Bytes of content in a[] */

  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 sqlite4VdbeCreateDecoder(
  sqlite4 *db,                /* The database connection */
  const unsigned char *aIn,   /* The input data blob */
  int nIn,                    /* Number of bytes in aIn[] */
  int mxCol,                  /* Maximum number of columns in aIn[] */
  RowDecoder **ppOut          /* The newly generated decoder object */
){
  RowDecoder *p;



  p = sqlite4DbMallocZero(db, sizeof(*p));
  *ppOut = p;
  if( p==0 ) return SQLITE4_NOMEM;
  p->db = db;
  p->a = aIn;
  p->n = nIn;
  p->mxCol = mxCol;
  return SQLITE4_OK;
}

/*
** Destroy a decoder object previously created
** using sqlite4VdbeCreateDecoder().
*/
int sqlite4VdbeDestroyDecoder(RowDecoder *p){
  if( p ){
    sqlite4DbFree(p->db, p);
  }
  return SQLITE4_OK;
}




































/*
** 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 sqlite4VdbeExtractColumn(
  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 */


  sqlite4VdbeMemSetNull(pOut);
  assert( iVal<=p->mxCol );



  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);







>
>
|
>
|
>








|

|
|
|
|



>
>




|
|








|





>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>










|














>



>
>
>







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;
}