SQLite4
Check-in [3b2515079a]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:File Format Change Modify the key encoding so that final BLOBs are entered byte-for-byte with no terminator.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 3b2515079a119e6bc201db2621eac38b422d5e8a
User & Date: drh 2013-02-25 16:36:40
Context
2013-02-25
17:18
Various fixes for test cases. check-in: 6b27bf4069 user: dan tags: trunk
16:36
File Format Change Modify the key encoding so that final BLOBs are entered byte-for-byte with no terminator. check-in: 3b2515079a user: drh tags: trunk
2013-02-24
00:43
Enhancements to the sqlite4_mm implementation. Fix the amalgamation generator so that it works after the addition of sqlite4_mm. check-in: 4424d6f7b3 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/delete.c.

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
...
205
206
207
208
209
210
211
212

213
214
215
216
217
218
219
...
261
262
263
264
265
266
267
268

269
270
271
272
273
274
275
  }
  sqlite4SelectDestInit(&dest, SRT_EphemTab, iCur);
  sqlite4Select(pParse, pDup, &dest);
  sqlite4SelectDelete(db, pDup);
}
#endif /* !defined(SQLITE4_OMIT_VIEW) && !defined(SQLITE4_OMIT_TRIGGER) */

#if defined(SQLITE4_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE4_OMIT_SUBQUERY)

/*
** Generate an expression tree to implement the WHERE, ORDER BY,
** and LIMIT/OFFSET portion of DELETE and UPDATE statements.
**
**     DELETE FROM table_wxyz WHERE a<5 ORDER BY a LIMIT 1;
**                            \__________________________/
**                               pLimitWhere (pInClause)
*/
Expr *sqlite4LimitWhere(
  Parse *pParse,               /* The parser context */
  SrcList *pSrc,               /* the FROM clause -- which tables to scan */
  Expr *pWhere,                /* The WHERE clause.  May be null */
  ExprList *pOrderBy,          /* The ORDER BY clause.  May be null */
  Expr *pLimit,                /* The LIMIT clause.  May be null */
  Expr *pOffset,               /* The OFFSET clause.  May be null */
  char *zStmtType              /* Either DELETE or UPDATE.  For error messages. */
){
  Expr *pWhereRowid = NULL;    /* WHERE rowid .. */
  Expr *pInClause = NULL;      /* WHERE rowid IN ( select ) */
  Expr *pSelectRowid = NULL;   /* SELECT rowid ... */
  ExprList *pEList = NULL;     /* Expression list contaning only pSelectRowid */
  SrcList *pSelectSrc = NULL;  /* SELECT rowid FROM x ... (dup of pSrc) */
  Select *pSelect = NULL;      /* Complete SELECT tree */

  /* Check that there isn't an ORDER BY without a LIMIT clause.
  */
  if( pOrderBy && (pLimit == 0) ) {
    sqlite4ErrorMsg(pParse, "ORDER BY without LIMIT on %s", zStmtType);
    goto limit_where_cleanup_2;
  }
................................................................................
limit_where_cleanup_2:
  sqlite4ExprDelete(pParse->db, pWhere);
  sqlite4ExprListDelete(pParse->db, pOrderBy);
  sqlite4ExprDelete(pParse->db, pLimit);
  sqlite4ExprDelete(pParse->db, pOffset);
  return 0;
}
#endif /* defined(SQLITE4_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE4_OMIT_SUBQUERY) */


/*
** Generate code for a DELETE FROM statement.
**
**     DELETE FROM table_wxyz WHERE a<5 AND b NOT NULL;
**                 \________/       \________________/
**                  pTabList              pWhere
................................................................................
  ** delete.  */
  if( sqlite4IsReadOnly(pParse, pTab, pTrigger!=0) ) goto delete_from_cleanup;
  assert( !IsView(pTab) || pTrigger );
  assert( !IsView(pTab) || pTab->pIndex==0 );

  /* Invoke the authorization callback */
  rcauth = sqlite4AuthCheck(pParse, SQLITE4_DELETE, pTab->zName, 0, zDb);
  assert( rcauth==SQLITE4_OK || rcauth==SQLITE4_DENY || rcauth==SQLITE4_IGNORE );

  if( rcauth==SQLITE4_DENY ){
    goto delete_from_cleanup;
  }

  /* Assign a cursor number to the table or view this statement is 
  ** deleting from. If pTab is actually a view, this will be used as the
  ** ephemeral table cursor. 







|
>









|
|
|
|
|
|
|

|
|
|
|
|
|







 







|
>







 







|
>







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
152
...
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
...
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
  }
  sqlite4SelectDestInit(&dest, SRT_EphemTab, iCur);
  sqlite4Select(pParse, pDup, &dest);
  sqlite4SelectDelete(db, pDup);
}
#endif /* !defined(SQLITE4_OMIT_VIEW) && !defined(SQLITE4_OMIT_TRIGGER) */

#if defined(SQLITE4_ENABLE_UPDATE_DELETE_LIMIT) \
 && !defined(SQLITE4_OMIT_SUBQUERY)
/*
** Generate an expression tree to implement the WHERE, ORDER BY,
** and LIMIT/OFFSET portion of DELETE and UPDATE statements.
**
**     DELETE FROM table_wxyz WHERE a<5 ORDER BY a LIMIT 1;
**                            \__________________________/
**                               pLimitWhere (pInClause)
*/
Expr *sqlite4LimitWhere(
  Parse *pParse,            /* The parser context */
  SrcList *pSrc,            /* the FROM clause -- which tables to scan */
  Expr *pWhere,             /* The WHERE clause.  May be null */
  ExprList *pOrderBy,       /* The ORDER BY clause.  May be null */
  Expr *pLimit,             /* The LIMIT clause.  May be null */
  Expr *pOffset,            /* The OFFSET clause.  May be null */
  char *zStmtType           /* Either DELETE or UPDATE. For error messages. */
){
  Expr *pWhereRowid = NULL; /* WHERE rowid .. */
  Expr *pInClause = NULL;   /* WHERE rowid IN ( select ) */
  Expr *pSelectRowid = NULL;/* SELECT rowid ... */
  ExprList *pEList = NULL;  /* Expression list contaning only pSelectRowid */
  SrcList *pSelectSrc = NULL;/* SELECT rowid FROM x ... (dup of pSrc) */
  Select *pSelect = NULL;   /* Complete SELECT tree */

  /* Check that there isn't an ORDER BY without a LIMIT clause.
  */
  if( pOrderBy && (pLimit == 0) ) {
    sqlite4ErrorMsg(pParse, "ORDER BY without LIMIT on %s", zStmtType);
    goto limit_where_cleanup_2;
  }
................................................................................
limit_where_cleanup_2:
  sqlite4ExprDelete(pParse->db, pWhere);
  sqlite4ExprListDelete(pParse->db, pOrderBy);
  sqlite4ExprDelete(pParse->db, pLimit);
  sqlite4ExprDelete(pParse->db, pOffset);
  return 0;
}
#endif /* defined(SQLITE4_ENABLE_UPDATE_DELETE_LIMIT) */
       /* && !defined(SQLITE4_OMIT_SUBQUERY) */

/*
** Generate code for a DELETE FROM statement.
**
**     DELETE FROM table_wxyz WHERE a<5 AND b NOT NULL;
**                 \________/       \________________/
**                  pTabList              pWhere
................................................................................
  ** delete.  */
  if( sqlite4IsReadOnly(pParse, pTab, pTrigger!=0) ) goto delete_from_cleanup;
  assert( !IsView(pTab) || pTrigger );
  assert( !IsView(pTab) || pTab->pIndex==0 );

  /* Invoke the authorization callback */
  rcauth = sqlite4AuthCheck(pParse, SQLITE4_DELETE, pTab->zName, 0, zDb);
  assert( rcauth==SQLITE4_OK || rcauth==SQLITE4_DENY
         || rcauth==SQLITE4_IGNORE );
  if( rcauth==SQLITE4_DENY ){
    goto delete_from_cleanup;
  }

  /* Assign a cursor number to the table or view this statement is 
  ** deleting from. If pTab is actually a view, this will be used as the
  ** ephemeral table cursor. 

Changes to src/sqliteInt.h.

2246
2247
2248
2249
2250
2251
2252

2253
2254
2255
2256
2257
2258
2259
  Parse *pParse;              /* The Parse structure */
};

/*
** Bitfield flags for P5 value in OP_Insert and OP_Delete
*/
#define OPFLAG_NCHANGE       0x01    /* Set to update db->nChange */

#define OPFLAG_ISUPDATE      0x04    /* This OP_Insert is an sql UPDATE */
#define OPFLAG_APPEND        0x08    /* This is likely to be an append */
#define OPFLAG_SEQCOUNT      0x10    /* Append sequence number to key */
#define OPFLAG_CLEARCACHE    0x20    /* Clear pseudo-table cache in OP_Column */
#define OPFLAG_APPENDBIAS    0x40    /* Bias inserts for appending */

/*







>







2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
  Parse *pParse;              /* The Parse structure */
};

/*
** Bitfield flags for P5 value in OP_Insert and OP_Delete
*/
#define OPFLAG_NCHANGE       0x01    /* Set to update db->nChange */
#define OPFLAG_PARTIALKEY    0x02    /* Not all values given to OP_MakeIdxKey */
#define OPFLAG_ISUPDATE      0x04    /* This OP_Insert is an sql UPDATE */
#define OPFLAG_APPEND        0x08    /* This is likely to be an append */
#define OPFLAG_SEQCOUNT      0x10    /* Append sequence number to key */
#define OPFLAG_CLEARCACHE    0x20    /* Clear pseudo-table cache in OP_Column */
#define OPFLAG_APPENDBIAS    0x40    /* Bias inserts for appending */

/*

Changes to src/vdbe.c.

2188
2189
2190
2191
2192
2193
2194





2195
2196
2197
2198
2199
2200
2201
....
2229
2230
2231
2232
2233
2234
2235

2236
2237
2238
2239
2240
2241
2242
2243
....
2321
2322
2323
2324
2325
2326
2327

2328
2329
2330
2331
2332
2333
2334
2335
....
2980
2981
2982
2983
2984
2985
2986

2987
2988
2989
2990
2991
2992
2993
2994
....
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
....
3118
3119
3120
3121
3122
3123
3124
3125

3126

3127
3128
3129
3130
3131
3132
3133
** This instruction encodes the N values into a database key and writes
** the result to register P3. No affinity transformations are applied to 
** the input values before they are encoded. 
**
** If the OPFLAG_SEQCOUNT bit of P5 is set, then a sequence number 
** (unique within the cursor) is appended to the record. The sole purpose
** of this is to ensure that the key blob is unique within the cursors table.





*/
case OP_MakeIdxKey: {
  VdbeCursor *pC;
  KeyInfo *pKeyInfo;
  Mem *pData0;                    /* First in array of input registers */
  u8 *aRec;                       /* The constructed database key */
  int nRec;                       /* Size of aRec[] in bytes */
................................................................................

  nField = pKeyInfo->nField;
  if( pOp->p4type==P4_INT32 && pOp->p4.i ){
    nField = pOp->p4.i;
    assert( nField<=pKeyInfo->nField );
  }
  rc = sqlite4VdbeEncodeKey(

    db, pData0, nField, pC->iRoot, pKeyInfo, &aRec, &nRec, nSeq
  );

  if( rc ){
    sqlite4DbFree(db, aRec);
  }else{
    if( nSeq ){
      memcpy(&aRec[nRec], &aSeq[sizeof(aSeq)-nSeq], nSeq);
................................................................................
    }
  }

  /* Compute the key (if this is a MakeKey opcode) */
  if( pC ){
    aRec = 0;
    rc = sqlite4VdbeEncodeKey(db, 

        pData0, pC->pKeyInfo->nField, pC->iRoot, pC->pKeyInfo, &aRec, &nRec, 0
    );
    if( rc ){
      sqlite4DbFree(db, aRec);
    }else{
      rc = sqlite4VdbeMemSetStr(pKeyOut, (char *)aRec, nRec, 0,
                                SQLITE4_DYNAMIC, 0);
      REGISTER_TRACE(keyReg, pKeyOut);
................................................................................
  /* 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).  */
  op = pOp->opcode;
  nField = pOp->p4.i;
  pIn3 = &aMem[pOp->p3];
  rc = sqlite4VdbeEncodeKey(

      db, pIn3, nField, pC->iRoot, pC->pKeyInfo, &aProbe, &nProbe, 1
  );

  /*   Opcode    search-dir    increment-key
  **  --------------------------------------
  **   SeekLt    -1            no
  **   SeekLe    -1            yes
  **   SeekGe    +1            no
................................................................................
  KVSize nKey;

  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  pC = p->apCsr[pOp->p1];
  assert( pC!=0 );
  assert( pC->isTable );
  pKVCur = pC->pKVCur;
  rc = sqlite4VdbeEncodeKey(db, aMem+pOp->p2, 1, pC->iRoot, 0,
                            &aKey, &nKey, 0);
  if( rc==SQLITE4_OK ){
    rc = sqlite4KVCursorSeek(pKVCur, aKey, nKey, 0);
    if( rc==SQLITE4_NOTFOUND ) rc = SQLITE4_CORRUPT_BKPT;
  }
  sqlite4DbFree(db, aKey);
  break;
................................................................................
  assert( pOp->p4type==P4_INT32 );
  pC = p->apCsr[pOp->p1];
  assert( pC!=0 );
  pIn3 = &aMem[pOp->p3];
  assert( pC->pKVCur!=0 );
  assert( pC->isTable==0 || pOp->opcode==OP_NotExists );
  if( pOp->p4.i>0 ){
    rc = sqlite4VdbeEncodeKey(db, pIn3, pOp->p4.i, pC->iRoot,

                              pC->pKeyInfo, &pProbe, &nProbe, 0);

    pFree = pProbe;
  }else{
    pProbe = (KVByteArray*)pIn3->z;
    nProbe = pIn3->n;
    pFree = 0;
  }
  if( rc==SQLITE4_OK ){







>
>
>
>
>







 







>
|







 







>
|







 







>
|







 







|







 







|
>
|
>







2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
....
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
....
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
....
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
....
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
....
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
** This instruction encodes the N values into a database key and writes
** the result to register P3. No affinity transformations are applied to 
** the input values before they are encoded. 
**
** If the OPFLAG_SEQCOUNT bit of P5 is set, then a sequence number 
** (unique within the cursor) is appended to the record. The sole purpose
** of this is to ensure that the key blob is unique within the cursors table.
**
** If the OPFLAG_PARTIALKEY bit of P5 is set, that means the value supplied
** for N is not the true number of values in the key, only the number that
** need to be encoded for this operation.  This effects the encoding of
** final BLOBs.
*/
case OP_MakeIdxKey: {
  VdbeCursor *pC;
  KeyInfo *pKeyInfo;
  Mem *pData0;                    /* First in array of input registers */
  u8 *aRec;                       /* The constructed database key */
  int nRec;                       /* Size of aRec[] in bytes */
................................................................................

  nField = pKeyInfo->nField;
  if( pOp->p4type==P4_INT32 && pOp->p4.i ){
    nField = pOp->p4.i;
    assert( nField<=pKeyInfo->nField );
  }
  rc = sqlite4VdbeEncodeKey(
    db, pData0, nField, nField+(pOp->p5 & OPFLAG_PARTIALKEY),
    pC->iRoot, pKeyInfo, &aRec, &nRec, nSeq
  );

  if( rc ){
    sqlite4DbFree(db, aRec);
  }else{
    if( nSeq ){
      memcpy(&aRec[nRec], &aSeq[sizeof(aSeq)-nSeq], nSeq);
................................................................................
    }
  }

  /* Compute the key (if this is a MakeKey opcode) */
  if( pC ){
    aRec = 0;
    rc = sqlite4VdbeEncodeKey(db, 
        pData0, pC->pKeyInfo->nField, pC->pKeyInfo->nField,
        pC->iRoot, pC->pKeyInfo, &aRec, &nRec, 0
    );
    if( rc ){
      sqlite4DbFree(db, aRec);
    }else{
      rc = sqlite4VdbeMemSetStr(pKeyOut, (char *)aRec, nRec, 0,
                                SQLITE4_DYNAMIC, 0);
      REGISTER_TRACE(keyReg, pKeyOut);
................................................................................
  /* 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).  */
  op = pOp->opcode;
  nField = pOp->p4.i;
  pIn3 = &aMem[pOp->p3];
  rc = sqlite4VdbeEncodeKey(
      db, pIn3, nField, nField+(pOp->p5 & OPFLAG_PARTIALKEY),
      pC->iRoot, pC->pKeyInfo, &aProbe, &nProbe, 1
  );

  /*   Opcode    search-dir    increment-key
  **  --------------------------------------
  **   SeekLt    -1            no
  **   SeekLe    -1            yes
  **   SeekGe    +1            no
................................................................................
  KVSize nKey;

  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  pC = p->apCsr[pOp->p1];
  assert( pC!=0 );
  assert( pC->isTable );
  pKVCur = pC->pKVCur;
  rc = sqlite4VdbeEncodeKey(db, aMem+pOp->p2, 1, 1, pC->iRoot, 0,
                            &aKey, &nKey, 0);
  if( rc==SQLITE4_OK ){
    rc = sqlite4KVCursorSeek(pKVCur, aKey, nKey, 0);
    if( rc==SQLITE4_NOTFOUND ) rc = SQLITE4_CORRUPT_BKPT;
  }
  sqlite4DbFree(db, aKey);
  break;
................................................................................
  assert( pOp->p4type==P4_INT32 );
  pC = p->apCsr[pOp->p1];
  assert( pC!=0 );
  pIn3 = &aMem[pOp->p3];
  assert( pC->pKVCur!=0 );
  assert( pC->isTable==0 || pOp->opcode==OP_NotExists );
  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
    );
    pFree = pProbe;
  }else{
    pProbe = (KVByteArray*)pIn3->z;
    nProbe = pIn3->n;
    pFree = 0;
  }
  if( rc==SQLITE4_OK ){

Changes to src/vdbeInt.h.

372
373
374
375
376
377
378

379
380
381
382
383
384
385
386
387
388
389
390
  u8 **pzOut,                 /* The output data record */
  int *pnOut                  /* Bytes of content in pzOut */
);
int sqlite4VdbeEncodeKey(
  sqlite4 *db,                 /* The database connection */
  Mem *aIn,                    /* Values to be encoded */
  int nIn,                     /* Number of entries in aIn[] */

  int iTabno,                  /* The table this key applies to */
  KeyInfo *pKeyInfo,           /* Collating sequence information */
  u8 **pzOut,                  /* Write the resulting key here */
  int *pnOut,                  /* Number of bytes in the key */
  int bIncr                    /* Make the key "incrementable" */
);
int sqlite4VdbeEncodeIntKey(u8 *aBuf,sqlite4_int64 v);
int sqlite4VdbeDecodeIntKey(const KVByteArray*, KVSize, sqlite4_int64*);
int sqlite4VdbeShortKey(const u8 *, int, int);
int sqlite4MemCompare(const Mem*, const Mem*, const CollSeq*);
int sqlite4VdbeExec(Vdbe*);
int sqlite4VdbeList(Vdbe*);







>




|







372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
  u8 **pzOut,                 /* The output data record */
  int *pnOut                  /* Bytes of content in pzOut */
);
int sqlite4VdbeEncodeKey(
  sqlite4 *db,                 /* The database connection */
  Mem *aIn,                    /* Values to be encoded */
  int nIn,                     /* Number of entries in aIn[] */
  int nInTotal,                /* Number of values in complete key */
  int iTabno,                  /* The table this key applies to */
  KeyInfo *pKeyInfo,           /* Collating sequence information */
  u8 **pzOut,                  /* Write the resulting key here */
  int *pnOut,                  /* Number of bytes in the key */
  int nExtra                   /* Append extra bytes on end of key */
);
int sqlite4VdbeEncodeIntKey(u8 *aBuf,sqlite4_int64 v);
int sqlite4VdbeDecodeIntKey(const KVByteArray*, KVSize, sqlite4_int64*);
int sqlite4VdbeShortKey(const u8 *, int, int);
int sqlite4MemCompare(const Mem*, const Mem*, const CollSeq*);
int sqlite4VdbeExec(Vdbe*);
int sqlite4VdbeList(Vdbe*);

Changes to src/vdbecodec.c.

506
507
508
509
510
511
512
513
514
515

516
517
518
519
520
521
522
523
...
611
612
613
614
615
616
617







618
619

620
621
622
623
624
625
626
...
681
682
683
684
685
686
687




688
689
690
691
692
693
694
...
727
728
729
730
731
732
733

734
735
736
737
738
739
740
741
742
743
744
745
...
754
755
756
757
758
759
760
761

762
763
764
765
766
767
768
}


/*
** Encode a single column of the key
*/
static int encodeOneKeyValue(
  KeyEncoder *p,
  Mem *pMem,
  u8 sortOrder,

  CollSeq *pColl
){
  int flags = pMem->flags;
  int i, e;
  int n;
  int iStart = p->nOut;
  if( flags & MEM_Null ){
    if( enlargeEncoderAllocation(p, 1) ) return SQLITE4_NOMEM;
................................................................................
      p->nOut += n;
    }
    p->aOut[p->nOut++] = 0x00;

    /* Release any memory allocated to hold the translated text */
    if( pEnc==&sMem ) sqlite4VdbeMemRelease(&sMem);








  }else
  {

    const unsigned char *a;
    unsigned char s, t;
    assert( flags & MEM_Blob );
    n = pMem->n;
    a = (u8*)pMem->z;
    s = 1;
    t = 0;
................................................................................
        while( *(p++) );
        break;

      case 0xDB:                  /* Text (descending index) */
      case 0xDA:                  /* Blob (descending index) */
        while( (0xFF!=*(p++)) );
        break;





      case 0x22: case 0xDD:       /* Large positive number */
      case 0x14: case 0xEB:       /* Small negative number */
      case 0x16: case 0xE9:       /* Small positive number */
      case 0x08: case 0xF7: {     /* Large negative number */
        u8 d;                     /* Value of byte following "c" */

................................................................................
** Space to hold the key is obtained from sqlite4DbMalloc() and should
** be freed by the caller using sqlite4DbFree() to avoid a memory leak.
*/
int sqlite4VdbeEncodeKey(
  sqlite4 *db,                 /* The database connection */
  Mem *aIn,                    /* Values to be encoded */
  int nIn,                     /* Number of entries in aIn[] */

  int iTabno,                  /* The table this key applies to */
  KeyInfo *pKeyInfo,           /* Collating sequence and sort-order info */
  u8 **paOut,                  /* Write the resulting key here */
  int *pnOut,                  /* Number of bytes in the key */
  int nExtra                   /* See above */
){
  int i;
  int rc = SQLITE4_OK;
  KeyEncoder x;
  u8 *so;
  CollSeq **aColl;

................................................................................
  *pnOut = 0;

  if( enlargeEncoderAllocation(&x, (nIn+1)*10) ) return SQLITE4_NOMEM;
  x.nOut = sqlite4PutVarint64(x.aOut, iTabno);
  aColl = pKeyInfo->aColl;
  so = pKeyInfo->aSortOrder;
  for(i=0; i<nIn && rc==SQLITE4_OK; i++){
    rc = encodeOneKeyValue(&x, aIn+i, so ? so[i] : SQLITE4_SO_ASC, aColl[i]);

  }

  if( rc==SQLITE4_OK && nExtra ){ rc = enlargeEncoderAllocation(&x, nExtra); }
  if( rc ){
    sqlite4DbFree(db, x.aOut);
  }else{
    *paOut = x.aOut;







|
|
|
>
|







 







>
>
>
>
>
>
>
|
<
>







 







>
>
>
>







 







>




|







 







|
>







506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
...
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626

627
628
629
630
631
632
633
634
...
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
...
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
...
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
}


/*
** Encode a single column of the key
*/
static int encodeOneKeyValue(
  KeyEncoder *p,    /* Key encoder context */
  Mem *pMem,        /* Value to be encoded */
  u8 sortOrder,     /* Sort order for this value */
  u8 isLastValue,   /* True if this is the last value in the key */
  CollSeq *pColl    /* Collating sequence for the value */
){
  int flags = pMem->flags;
  int i, e;
  int n;
  int iStart = p->nOut;
  if( flags & MEM_Null ){
    if( enlargeEncoderAllocation(p, 1) ) return SQLITE4_NOMEM;
................................................................................
      p->nOut += n;
    }
    p->aOut[p->nOut++] = 0x00;

    /* Release any memory allocated to hold the translated text */
    if( pEnc==&sMem ) sqlite4VdbeMemRelease(&sMem);

  }else if( isLastValue ){
    /* A BLOB value that is the right-most value of a key */
    assert( flags & MEM_Blob );
    if( enlargeEncoderAllocation(p, pMem->n+1) ) return SQLITE4_NOMEM;
    p->aOut[p->nOut++] = 0x26;
    memcpy(p->aOut+p->nOut, pMem->z, pMem->n);
    p->nOut += pMem->n;
  }else{

    /* A BLOB value that is followed by other values */
    const unsigned char *a;
    unsigned char s, t;
    assert( flags & MEM_Blob );
    n = pMem->n;
    a = (u8*)pMem->z;
    s = 1;
    t = 0;
................................................................................
        while( *(p++) );
        break;

      case 0xDB:                  /* Text (descending index) */
      case 0xDA:                  /* Blob (descending index) */
        while( (0xFF!=*(p++)) );
        break;

      case 0x26:                  /* Blob-final (ascending) */
      case 0xD9:                  /* Blob-final (descending) */
        return nKey;

      case 0x22: case 0xDD:       /* Large positive number */
      case 0x14: case 0xEB:       /* Small negative number */
      case 0x16: case 0xE9:       /* Small positive number */
      case 0x08: case 0xF7: {     /* Large negative number */
        u8 d;                     /* Value of byte following "c" */

................................................................................
** Space to hold the key is obtained from sqlite4DbMalloc() and should
** be freed by the caller using sqlite4DbFree() to avoid a memory leak.
*/
int sqlite4VdbeEncodeKey(
  sqlite4 *db,                 /* The database connection */
  Mem *aIn,                    /* Values to be encoded */
  int nIn,                     /* Number of entries in aIn[] */
  int nInTotal,                /* Number of values in a complete key */
  int iTabno,                  /* The table this key applies to */
  KeyInfo *pKeyInfo,           /* Collating sequence and sort-order info */
  u8 **paOut,                  /* Write the resulting key here */
  int *pnOut,                  /* Number of bytes in the key */
  int nExtra                   /* extra bytes of space appended to the key */
){
  int i;
  int rc = SQLITE4_OK;
  KeyEncoder x;
  u8 *so;
  CollSeq **aColl;

................................................................................
  *pnOut = 0;

  if( enlargeEncoderAllocation(&x, (nIn+1)*10) ) return SQLITE4_NOMEM;
  x.nOut = sqlite4PutVarint64(x.aOut, iTabno);
  aColl = pKeyInfo->aColl;
  so = pKeyInfo->aSortOrder;
  for(i=0; i<nIn && rc==SQLITE4_OK; i++){
    rc = encodeOneKeyValue(&x, aIn+i, so ? so[i] : SQLITE4_SO_ASC,
                           i==nInTotal-1, aColl[i]);
  }

  if( rc==SQLITE4_OK && nExtra ){ rc = enlargeEncoderAllocation(&x, nExtra); }
  if( rc ){
    sqlite4DbFree(db, x.aOut);
  }else{
    *paOut = x.aOut;

Changes to src/where.c.

4161
4162
4163
4164
4165
4166
4167



4168
4169
4170
4171
4172
4173
4174
    testcase( op==OP_Rewind );
    testcase( op==OP_Last );
    testcase( op==OP_SeekGt );
    testcase( op==OP_SeekGe );
    testcase( op==OP_SeekLe );
    testcase( op==OP_SeekLt );
    sqlite4VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);




    /* Set variable op to the instruction required to determine if the
    ** cursor is passed the end of the range. If the range is unbounded,
    ** then set op to OP_Noop. Nothing to do in this case.  */
    assert( (endEq==0 || endEq==1) );
    op = aEndOp[(pRangeEnd || nEq) * (1 + (endEq+endEq) + bRev)];
    testcase( op==OP_Noop );







>
>
>







4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
    testcase( op==OP_Rewind );
    testcase( op==OP_Last );
    testcase( op==OP_SeekGt );
    testcase( op==OP_SeekGe );
    testcase( op==OP_SeekLe );
    testcase( op==OP_SeekLt );
    sqlite4VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint);
    if( pIdx->nColumn>nEq ){
      sqlite4VdbeChangeP5(v, OPFLAG_PARTIALKEY);
    }

    /* Set variable op to the instruction required to determine if the
    ** cursor is passed the end of the range. If the range is unbounded,
    ** then set op to OP_Noop. Nothing to do in this case.  */
    assert( (endEq==0 || endEq==1) );
    op = aEndOp[(pRangeEnd || nEq) * (1 + (endEq+endEq) + bRev)];
    testcase( op==OP_Noop );

Changes to www/key_encoding.wiki.

57
58
59
60
61
62
63




64
65
66
67
68
69
70






71
72
73
74
75
76
77
78
...
184
185
186
187
188
189
190

191

The text encoding ends in 0x00 in order to ensure that when there are
two strings where one is a prefix of the other that the shorter string
will sort first.

<h2>Binary Encoding</h2>





Each SQL value that is BINARY begins with a single byte of 0x25 and
ends with a single byte of 0x00.  There are zero or more intervening bytes
that encode the binary value.  None of the intervening bytes may be zero.
Each of the intervening bytes contains 7 bits of blob content with a 1 in
the high-order bit (the 0x80 bit).  The final byte before the 0x00 contains
any left-over bits of the blob content.







The initial byte of a binary value, 0x25, is larger than the initial
byte of a text value, 0x24, ensuring that every binary value will sort
after every text value.

<h2>Numeric Encoding</h2>

Numeric SQL values must be coded so as to sort in numeric order.  We assume
that numeric SQL values can be both integer and floating point values.
................................................................................
<tr><td>  zero               <td><td> 0x15
<tr><td>  positive small     <td><td> 0x16,   ~-E,    M
<tr><td>  positive medium    <td><td> 0x17+E,   M
<tr><td>  positive large     <td><td> 0x22,     E,    M
<tr><td>  positive infinity  <td><td> 0x23
<tr><td>  text               <td><td> 0x24,     T
<tr><td>  binary             <td><td> 0x25,     B

</table><blockquote>







>
>
>
>
|






>
>
>
>
>
>
|







 







>

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
...
194
195
196
197
198
199
200
201
202

The text encoding ends in 0x00 in order to ensure that when there are
two strings where one is a prefix of the other that the shorter string
will sort first.

<h2>Binary Encoding</h2>

The encoding of binaries fields is different depending on whether or not
the value to be encoded is the last value (the right-most value) in the key.

Each SQL value that is BINARY that is not the last value of the key
begins with a single byte of 0x25 and
ends with a single byte of 0x00.  There are zero or more intervening bytes
that encode the binary value.  None of the intervening bytes may be zero.
Each of the intervening bytes contains 7 bits of blob content with a 1 in
the high-order bit (the 0x80 bit).  The final byte before the 0x00 contains
any left-over bits of the blob content.

When the very last value of a key is BINARY, then it is encoded as a single
byte of 0x26 and is followed by a byte-for-byte copy of the BINARY value.
This alternative encoding is more efficient, but it only works if there are
no subsequent values in the key, since there is no termination mark on the
BLOB being encoded.

The initial byte of a binary value, 0x25 or 0x26, is larger than the initial
byte of a text value, 0x24, ensuring that every binary value will sort
after every text value.

<h2>Numeric Encoding</h2>

Numeric SQL values must be coded so as to sort in numeric order.  We assume
that numeric SQL values can be both integer and floating point values.
................................................................................
<tr><td>  zero               <td><td> 0x15
<tr><td>  positive small     <td><td> 0x16,   ~-E,    M
<tr><td>  positive medium    <td><td> 0x17+E,   M
<tr><td>  positive large     <td><td> 0x22,     E,    M
<tr><td>  positive infinity  <td><td> 0x23
<tr><td>  text               <td><td> 0x24,     T
<tr><td>  binary             <td><td> 0x25,     B
<tr><td>  final binary       <td><td> 0x26,     X
</table><blockquote>