/ Check-in [2164031b]
Login

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

Overview
Comment:Convert the LSM1 virtual table to be WITHOUT ROWID and get UPDATE and DELETE operations working on it.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 2164031b509dc6eae367ffb9d915f3e1d33d26210506b2de8b2bfca38c53465f
User & Date: drh 2017-08-11 12:49:59
Context
2017-08-11
13:51
New test cases for LSM1. check-in: cb0c49cb user: drh tags: trunk
12:49
Convert the LSM1 virtual table to be WITHOUT ROWID and get UPDATE and DELETE operations working on it. check-in: 2164031b user: drh tags: trunk
03:47
Simplification to the like optimization logic. Remove unnecessary branches. check-in: 9466d952 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to ext/lsm1/lsm_vtab.c.

239
240
241
242
243
244
245

246
247
248
249
250
251
252


253
254
255
256
257
258
259
...
664
665
666
667
668
669
670

























671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
...
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882


883
884

885
886
887








888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
  }

  memset(&sql, 0, sizeof(sql));
  lsm1VblobAppendText(&sql, "CREATE TABLE x(");
  lsm1VblobAppendText(&sql, argv[4]);
  lsm1VblobAppendText(&sql, " ");
  lsm1VblobAppendText(&sql, argv[5]);

  for(i=6; i<argc; i++){
    lsm1VblobAppendText(&sql, ", ");
    lsm1VblobAppendText(&sql, argv[i]);
    pNew->nVal++;
  }
  lsm1VblobAppendText(&sql, 
      ", lsm1_command HIDDEN, lsm1_key HIDDEN, lsm1_value HIDDEN)");


  lsm1VblobAppend(&sql, (u8*)"", 1);
  if( sql.errNoMem ){
    rc = SQLITE_NOMEM;
    goto connect_failed;
  }
  rc = sqlite3_declare_vtab(db, (const char*)sql.a);
  sqlite3_free(sql.a);
................................................................................
      default: {
         /* A NULL.  Do nothing */
      }
    }
  }
  return SQLITE_OK;
}


























/* Move to the first row to return.
*/
static int lsm1Filter(
  sqlite3_vtab_cursor *pVtabCursor, 
  int idxNum, const char *idxStr,
  int argc, sqlite3_value **argv
){
  lsm1_cursor *pCur = (lsm1_cursor *)pVtabCursor;
  lsm1_vtab *pTab = (lsm1_vtab*)(pCur->base.pVtab);
  int rc = LSM_OK;
  int seekType = -1;
  const void *pVal = 0;
  int nVal;
  u8 keyType = pTab->keyType;
  u8 aKey1[16];

  pCur->atEof = 1;
  sqlite3_free(pCur->pKey2);
  pCur->pKey2 = 0;
  if( idxNum<99 ){
    if( keyType==SQLITE_BLOB ){
      pVal = sqlite3_value_blob(argv[0]);
      nVal = sqlite3_value_bytes(argv[0]);
    }else if( keyType==SQLITE_TEXT ){
      pVal = sqlite3_value_text(argv[0]);
      nVal = sqlite3_value_bytes(argv[0]);
    }else{
      sqlite3_int64 v = sqlite3_value_int64(argv[0]);
      if( v<0 ) v = 0;
      nVal = lsm1PutVarint64(aKey1, v);
      pVal = aKey1;
    }
  }
  switch( idxNum ){
    case 0: {   /* key==argv[0] */
      assert( argc==1 );
      seekType = LSM_SEEK_EQ;
      pCur->isDesc = 0;
      pCur->bUnique = 1;
................................................................................
int lsm1Update(
  sqlite3_vtab *pVTab,
  int argc,
  sqlite3_value **argv,
  sqlite_int64 *pRowid
){
  lsm1_vtab *p = (lsm1_vtab*)pVTab;
  int nKey;
  int i;
  int rc = LSM_OK;
  unsigned char *pKey;
  unsigned char aKey[16];
  unsigned char pSpace[16];
  lsm1_vblob val;

  if( argc==1 ){
    pVTab->zErrMsg = sqlite3_mprintf("cannot DELETE");


    return SQLITE_ERROR;
  }

  if( sqlite3_value_type(argv[0])!=SQLITE_NULL ){
    pVTab->zErrMsg = sqlite3_mprintf("cannot UPDATE");
    return SQLITE_ERROR;








  }

  /* "INSERT INTO tab(lsm1_command) VALUES('....')" is used to implement
  ** special commands.
  */
  if( sqlite3_value_type(argv[3+p->nVal])!=SQLITE_NULL ){
    return SQLITE_OK;
  }
  if( p->keyType==SQLITE_BLOB ){
    pKey = (u8*)sqlite3_value_blob(argv[2]);
    nKey = sqlite3_value_bytes(argv[2]);
  }else if( p->keyType==SQLITE_TEXT ){
    pKey = (u8*)sqlite3_value_text(argv[2]);
    nKey = sqlite3_value_bytes(argv[2]);
  }else{
    sqlite3_int64 v = sqlite3_value_int64(argv[2]);
    if( v>=0 ){
      nKey = lsm1PutVarint64(aKey, (sqlite3_uint64)v);
      pKey = aKey;
    }else{
      pVTab->zErrMsg = sqlite3_mprintf("key must be non-negative");
      return SQLITE_ERROR;
    }
  }
  memset(&val, 0, sizeof(val));
  for(i=0; i<p->nVal; i++){
    sqlite3_value *pArg = argv[3+i];
    u8 eType = sqlite3_value_type(pArg);
    switch( eType ){
      case SQLITE_NULL: {
        lsm1VblobAppendVarint(&val, SQLITE_NULL);







>






|
>
>







 







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












|








|
<
<
<
<
<
<
<
<
<
<
<







 







|


|





|
>
>
|

>

<
<
>
>
>
>
>
>
>
>








|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
...
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720











721
722
723
724
725
726
727
...
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905


906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922















923
924
925
926
927
928
929
  }

  memset(&sql, 0, sizeof(sql));
  lsm1VblobAppendText(&sql, "CREATE TABLE x(");
  lsm1VblobAppendText(&sql, argv[4]);
  lsm1VblobAppendText(&sql, " ");
  lsm1VblobAppendText(&sql, argv[5]);
  lsm1VblobAppendText(&sql, " PRIMARY KEY");
  for(i=6; i<argc; i++){
    lsm1VblobAppendText(&sql, ", ");
    lsm1VblobAppendText(&sql, argv[i]);
    pNew->nVal++;
  }
  lsm1VblobAppendText(&sql, 
      ", lsm1_command HIDDEN"
      ", lsm1_key HIDDEN"
      ", lsm1_value HIDDEN) WITHOUT ROWID");
  lsm1VblobAppend(&sql, (u8*)"", 1);
  if( sql.errNoMem ){
    rc = SQLITE_NOMEM;
    goto connect_failed;
  }
  rc = sqlite3_declare_vtab(db, (const char*)sql.a);
  sqlite3_free(sql.a);
................................................................................
      default: {
         /* A NULL.  Do nothing */
      }
    }
  }
  return SQLITE_OK;
}

/* Parameter "pValue" contains an SQL value that is to be used as
** a key in an LSM table.  The type of the key is determined by
** "keyType".  Extract the raw bytes used for the key in LSM1.
*/
static void lsm1KeyFromValue(
  int keyType,                 /* The key type */
  sqlite3_value *pValue,       /* The key value */
  u8 *pBuf,                    /* Storage space for a generated key */
  const u8 **ppKey,            /* OUT: the bytes of the key */
  int *pnKey                   /* OUT: size of the key */
){
  if( keyType==SQLITE_BLOB ){
    *ppKey = (const u8*)sqlite3_value_blob(pValue);
    *pnKey = sqlite3_value_bytes(pValue);
  }else if( keyType==SQLITE_TEXT ){
    *ppKey = (const u8*)sqlite3_value_text(pValue);
    *pnKey = sqlite3_value_bytes(pValue);
  }else{
    sqlite3_int64 v = sqlite3_value_int64(pValue);
    if( v<0 ) v = 0;
    *pnKey = lsm1PutVarint64(pBuf, v);
    *ppKey = pBuf;
  }
}

/* Move to the first row to return.
*/
static int lsm1Filter(
  sqlite3_vtab_cursor *pVtabCursor, 
  int idxNum, const char *idxStr,
  int argc, sqlite3_value **argv
){
  lsm1_cursor *pCur = (lsm1_cursor *)pVtabCursor;
  lsm1_vtab *pTab = (lsm1_vtab*)(pCur->base.pVtab);
  int rc = LSM_OK;
  int seekType = -1;
  const u8 *pVal = 0;
  int nVal;
  u8 keyType = pTab->keyType;
  u8 aKey1[16];

  pCur->atEof = 1;
  sqlite3_free(pCur->pKey2);
  pCur->pKey2 = 0;
  if( idxNum<99 ){
    lsm1KeyFromValue(keyType, argv[0], aKey1, &pVal, &nVal);











  }
  switch( idxNum ){
    case 0: {   /* key==argv[0] */
      assert( argc==1 );
      seekType = LSM_SEEK_EQ;
      pCur->isDesc = 0;
      pCur->bUnique = 1;
................................................................................
int lsm1Update(
  sqlite3_vtab *pVTab,
  int argc,
  sqlite3_value **argv,
  sqlite_int64 *pRowid
){
  lsm1_vtab *p = (lsm1_vtab*)pVTab;
  int nKey, nKey2;
  int i;
  int rc = LSM_OK;
  const u8 *pKey, *pKey2;
  unsigned char aKey[16];
  unsigned char pSpace[16];
  lsm1_vblob val;

  if( argc==1 ){
    /* DELETE the record whose key is argv[0] */
    lsm1KeyFromValue(p->keyType, argv[0], aKey, &pKey, &nKey);
    lsm_delete(p->pDb, pKey, nKey);
    return SQLITE_OK;
  }

  if( sqlite3_value_type(argv[0])!=SQLITE_NULL ){


    /* An UPDATE */
    lsm1KeyFromValue(p->keyType, argv[0], aKey, &pKey, &nKey);
    lsm1KeyFromValue(p->keyType, argv[1], pSpace, &pKey2, &nKey2);
    if( nKey!=nKey2 || memcmp(pKey, pKey2, nKey)!=0 ){
      /* The UPDATE changes the PRIMARY KEY value.  DELETE the old key */
      lsm_delete(p->pDb, pKey, nKey);
    }
    /* Fall through into the INSERT case to complete the UPDATE */
  }

  /* "INSERT INTO tab(lsm1_command) VALUES('....')" is used to implement
  ** special commands.
  */
  if( sqlite3_value_type(argv[3+p->nVal])!=SQLITE_NULL ){
    return SQLITE_OK;
  }
  lsm1KeyFromValue(p->keyType, argv[2], aKey, &pKey, &nKey);















  memset(&val, 0, sizeof(val));
  for(i=0; i<p->nVal; i++){
    sqlite3_value *pArg = argv[3+i];
    u8 eType = sqlite3_value_type(pArg);
    switch( eType ){
      case SQLITE_NULL: {
        lsm1VblobAppendVarint(&val, SQLITE_NULL);

Changes to ext/lsm1/test/lsm1_simple.test.

19
20
21
22
23
24
25
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

forcedelete testlsm.db

do_execsql_test 1.0 {
  CREATE VIRTUAL TABLE x1 USING lsm1(testlsm.db,a,UINT,b,c,d);
  PRAGMA table_info(x1);
} {
  0 a UINT 0 {} 0 
  1 b {} 0 {} 0 
  2 c {} 0 {} 0 
  3 d {} 0 {} 0
}

do_execsql_test 1.1 {
  INSERT INTO x1(a,b,c,d) VALUES(15, 11, 22, 33),(8,'banjo',x'333231',NULL),
      (12,NULL,3.25,-559281390);
  SELECT a, quote(b), quote(c), quote(d) FROM x1;
} {8 'banjo' X'333231' NULL 12 NULL 3.25 -559281390 15 11 22 33}

do_catchsql_test 1.2 {
  UPDATE x1 SET d = d+1.0 WHERE a=15;
} {1 {cannot UPDATE}}


do_catchsql_test 1.3 {
  DELETE FROM x1 WHERE a=15;
} {1 {cannot DELETE}}



do_test 1.4 {
  lsort [glob testlsm.db*]
} {testlsm.db testlsm.db-log testlsm.db-shm}

db close
do_test 1.5 {
  lsort [glob testlsm.db*]
} {testlsm.db}

finish_test







|











|

|
>

|

<
>
>











19
20
21
22
23
24
25
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

forcedelete testlsm.db

do_execsql_test 1.0 {
  CREATE VIRTUAL TABLE x1 USING lsm1(testlsm.db,a,UINT,b,c,d);
  PRAGMA table_info(x1);
} {
  0 a UINT 1 {} 1 
  1 b {} 0 {} 0 
  2 c {} 0 {} 0 
  3 d {} 0 {} 0
}

do_execsql_test 1.1 {
  INSERT INTO x1(a,b,c,d) VALUES(15, 11, 22, 33),(8,'banjo',x'333231',NULL),
      (12,NULL,3.25,-559281390);
  SELECT a, quote(b), quote(c), quote(d) FROM x1;
} {8 'banjo' X'333231' NULL 12 NULL 3.25 -559281390 15 11 22 33}

do_execsql_test 1.2 {
  UPDATE x1 SET d = d+1.0 WHERE a=15;
  SELECT a, quote(b), quote(c), quote(d) FROM x1;
} {8 'banjo' X'333231' NULL 12 NULL 3.25 -559281390 15 11 22 34.0}

do_execsql_test 1.3 {
  DELETE FROM x1 WHERE a=15;

  SELECT a, quote(b), quote(c), quote(d) FROM x1;
} {8 'banjo' X'333231' NULL 12 NULL 3.25 -559281390}

do_test 1.4 {
  lsort [glob testlsm.db*]
} {testlsm.db testlsm.db-log testlsm.db-shm}

db close
do_test 1.5 {
  lsort [glob testlsm.db*]
} {testlsm.db}

finish_test