Index: ext/lsm1/lsm_vtab.c ================================================================== --- ext/lsm1/lsm_vtab.c +++ ext/lsm1/lsm_vtab.c @@ -241,17 +241,20 @@ 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; inVal++; } lsm1VblobAppendText(&sql, - ", lsm1_command HIDDEN, lsm1_key HIDDEN, lsm1_value HIDDEN)"); + ", lsm1_command HIDDEN" + ", lsm1_key HIDDEN" + ", lsm1_value HIDDEN) WITHOUT ROWID"); lsm1VblobAppend(&sql, (u8*)"", 1); if( sql.errNoMem ){ rc = SQLITE_NOMEM; goto connect_failed; } @@ -666,10 +669,35 @@ } } } 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, @@ -678,31 +706,20 @@ ){ 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; + 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 ){ - 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; - } + lsm1KeyFromValue(keyType, argv[0], aKey1, &pVal, &nVal); } switch( idxNum ){ case 0: { /* key==argv[0] */ assert( argc==1 ); seekType = LSM_SEEK_EQ; @@ -868,49 +885,43 @@ int argc, sqlite3_value **argv, sqlite_int64 *pRowid ){ lsm1_vtab *p = (lsm1_vtab*)pVTab; - int nKey; + int nKey, nKey2; int i; int rc = LSM_OK; - unsigned char *pKey; + const u8 *pKey, *pKey2; unsigned char aKey[16]; unsigned char pSpace[16]; lsm1_vblob val; if( argc==1 ){ - pVTab->zErrMsg = sqlite3_mprintf("cannot DELETE"); - return SQLITE_ERROR; + /* 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 ){ - pVTab->zErrMsg = sqlite3_mprintf("cannot UPDATE"); - return SQLITE_ERROR; + /* 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; } - 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; - } - } + lsm1KeyFromValue(p->keyType, argv[2], aKey, &pKey, &nKey); memset(&val, 0, sizeof(val)); for(i=0; inVal; i++){ sqlite3_value *pArg = argv[3+i]; u8 eType = sqlite3_value_type(pArg); switch( eType ){ Index: ext/lsm1/test/lsm1_simple.test ================================================================== --- ext/lsm1/test/lsm1_simple.test +++ ext/lsm1/test/lsm1_simple.test @@ -21,11 +21,11 @@ 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 + 0 a UINT 1 {} 1 1 b {} 0 {} 0 2 c {} 0 {} 0 3 d {} 0 {} 0 } @@ -33,17 +33,19 @@ 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 { +do_execsql_test 1.2 { UPDATE x1 SET d = d+1.0 WHERE a=15; -} {1 {cannot UPDATE}} + 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_catchsql_test 1.3 { +do_execsql_test 1.3 { DELETE FROM x1 WHERE a=15; -} {1 {cannot DELETE}} + 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}