diff --git a/ext/lsm1/lsm_vtab.c b/ext/lsm1/lsm_vtab.c index e4d89e46f7..46d83d591c 100644 --- a/ext/lsm1/lsm_vtab.c +++ b/ext/lsm1/lsm_vtab.c @@ -83,12 +83,21 @@ static int lsm1Connect( } /* Column numbers */ -#define LSM1_COLUMN_KEY 0 -#define LSM1_COLUMN_VALUE 1 -#define LSM1_COLUMN_COMMAND 2 +#define LSM1_COLUMN_KEY 0 +#define LSM1_COLUMN_BLOBKEY 1 +#define LSM1_COLUMN_VALUE 2 +#define LSM1_COLUMN_BLOBVALUE 3 +#define LSM1_COLUMN_COMMAND 4 rc = sqlite3_declare_vtab(db, - "CREATE TABLE x(key,value,command hidden)"); + "CREATE TABLE x(" + " key," /* The primary key. Any non-NULL */ + " blobkey," /* Pure BLOB primary key */ + " value," /* The value associated with key. Any non-NULL */ + " blobvalue," /* Pure BLOB value */ + " command hidden" /* Insert here for control operations */ + ");" + ); connect_failed: if( rc!=SQLITE_OK ){ if( pNew ){ @@ -173,6 +182,72 @@ static int lsm1Eof(sqlite3_vtab_cursor *cur){ return pCur->atEof; } +/* +** Rowids are not supported by the underlying virtual table. So always +** return 0 for the rowid. +*/ +static int lsm1Rowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ + *pRowid = 0; + return SQLITE_OK; +} + +/* +** Type prefixes on LSM keys +*/ +#define LSM1_TYPE_NEGATIVE 0 +#define LSM1_TYPE_POSITIVE 1 +#define LSM1_TYPE_TEXT 2 +#define LSM1_TYPE_BLOB 3 + +/* +** Generate a key encoding for pValue such that all keys compare in +** lexicographical order. Return an SQLite error code or SQLITE_OK. +** +** The key encoding is *pnKey bytes in length written into *ppKey. +** Space to hold the key is taken from pSpace if sufficient, or else +** from sqlite3_malloc(). The caller is responsible for freeing malloced +** space. +*/ +static int lsm1EncodeKey( + sqlite3_value *pValue, /* Value to be encoded */ + unsigned char **ppKey, /* Write the encoding here */ + int *pnKey, /* Write the size of the encoding here */ + unsigned char *pSpace, /* Use this space if it is large enough */ + int nSpace /* Size of pSpace[] */ +){ + int eType = sqlite3_value_type(pValue); + *ppKey = 0; + *pnKey = 0; + switch( eType ){ + default: { + return SQLITE_ERROR; /* We cannot handle NULL keys */ + } + case SQLITE_BLOB: + case SQLITE_TEXT: { + int nVal = sqlite3_value_bytes(pValue); + const void *pVal; + if( eType==SQLITE_BLOB ){ + eType = LSM1_TYPE_BLOB; + pVal = sqlite3_value_blob(pValue); + }else{ + eType = LSM1_TYPE_TEXT; + pVal = (const void*)sqlite3_value_text(pValue); + if( pVal==0 ) return SQLITE_NOMEM; + } + if( nVal+1>nSpace ){ + pSpace = sqlite3_malloc( nVal+1 ); + if( pSpace==0 ) return SQLITE_NOMEM; + } + pSpace[0] = eType; + memcpy(&pSpace[1], pVal, nVal); + *ppKey = pSpace; + *pnKey = nVal+1; + break; + } + } + return SQLITE_OK; +} + /* ** Return values of columns for the row at which the lsm1_cursor ** is currently pointing. @@ -184,10 +259,34 @@ static int lsm1Column( ){ lsm1_cursor *pCur = (lsm1_cursor*)cur; switch( i ){ - case LSM1_COLUMN_KEY: { + case LSM1_COLUMN_BLOBKEY: { const void *pVal; int nVal; - if( lsm_csr_key(pCur->pLsmCur, (const void**)&pVal, &nVal)==LSM_OK ){ + if( lsm_csr_key(pCur->pLsmCur, &pVal, &nVal)==LSM_OK ){ + sqlite3_result_blob(ctx, pVal, nVal, SQLITE_TRANSIENT); + } + break; + } + case LSM1_COLUMN_KEY: { + const unsigned char *pVal; + int nVal; + if( lsm_csr_key(pCur->pLsmCur, (const void**)&pVal, &nVal)==LSM_OK + && nVal>=1 + ){ + if( pVal[0]==LSM1_TYPE_BLOB ){ + sqlite3_result_blob(ctx, (const void*)&pVal[1],nVal-1, + SQLITE_TRANSIENT); + }else if( pVal[0]==LSM1_TYPE_TEXT ){ + sqlite3_result_text(ctx, (const char*)&pVal[1],nVal-1, + SQLITE_TRANSIENT); + } + } + break; + } + case LSM1_COLUMN_BLOBVALUE: { + const void *pVal; + int nVal; + if( lsm_csr_value(pCur->pLsmCur, (const void**)&pVal, &nVal)==LSM_OK ){ sqlite3_result_blob(ctx, pVal, nVal, SQLITE_TRANSIENT); } break; @@ -203,7 +302,7 @@ static int lsm1Column( case SQLITE_INTEGER: { sqlite3_uint64 x = 0; int j; - for(j=1; j<=8; j++){ + for(j=1; j?1 +** bit 3 key>=?1 +** bit 4 key?1 +** 4 key>=?1 +** 8 key?1 AND key=?1 AND key?1 AND key<=?2 +** 20 key>=?1 AND key<=?2 +** 33..52 Use blobkey in place of key... */ static int lsm1BestIndex( sqlite3_vtab *tab, @@ -337,6 +445,11 @@ int lsm1Update( int eType; int rc; sqlite3_value *pValue; + const unsigned char *pVal; + unsigned char *pData; + int nVal; + unsigned char pSpace[100]; + if( argc==1 ){ pVTab->zErrMsg = sqlite3_mprintf("cannot DELETE"); return SQLITE_ERROR; @@ -352,60 +465,69 @@ int lsm1Update( if( sqlite3_value_type(argv[2+LSM1_COLUMN_COMMAND])!=SQLITE_NULL ){ return SQLITE_OK; } - if( sqlite3_value_type(argv[2+LSM1_COLUMN_KEY])!=SQLITE_BLOB ){ - pVTab->zErrMsg = sqlite3_mprintf("BLOB keys only"); - return SQLITE_ERROR; + if( sqlite3_value_type(argv[2+LSM1_COLUMN_BLOBKEY])==SQLITE_BLOB ){ + /* Use the blob key exactly as supplied */ + pKey = sqlite3_value_blob(argv[2+LSM1_COLUMN_BLOBKEY]); + nKey = sqlite3_value_bytes(argv[2+LSM1_COLUMN_BLOBKEY]); + }else{ + /* Use a key encoding that sorts in lexicographical order */ + rc = lsm1EncodeKey(argv[2+LSM1_COLUMN_KEY], + (unsigned char**)&pKey,&nKey, + pSpace,sizeof(pSpace)); + if( rc ) return rc; } - pKey = sqlite3_value_blob(argv[2+LSM1_COLUMN_KEY]); - nKey = sqlite3_value_bytes(argv[2+LSM1_COLUMN_KEY]); - pValue = argv[2+LSM1_COLUMN_VALUE]; - eType = sqlite3_value_type(pValue); - switch( eType ){ - case SQLITE_NULL: { - rc = lsm_delete(p->pDb, pKey, nKey); - break; - } - case SQLITE_BLOB: - case SQLITE_TEXT: { - const unsigned char *pVal; - unsigned char *pData; - int nVal; - if( eType==SQLITE_TEXT ){ - pVal = sqlite3_value_text(pValue); - }else{ - pVal = (unsigned char*)sqlite3_value_blob(pValue); + if( sqlite3_value_type(argv[2+LSM1_COLUMN_BLOBVALUE])==SQLITE_BLOB ){ + pVal = sqlite3_value_blob(argv[2+LSM1_COLUMN_BLOBVALUE]); + nVal = sqlite3_value_bytes(argv[2+LSM1_COLUMN_BLOBVALUE]); + rc = lsm_insert(p->pDb, pKey, nKey, pVal, nVal); + }else{ + pValue = argv[2+LSM1_COLUMN_VALUE]; + eType = sqlite3_value_type(pValue); + switch( eType ){ + case SQLITE_NULL: { + rc = lsm_delete(p->pDb, pKey, nKey); + break; } - nVal = sqlite3_value_bytes(pValue); - pData = sqlite3_malloc( nVal+1 ); - if( pData==0 ){ - rc = SQLITE_NOMEM; - }else{ - pData[0] = eType; - memcpy(&pData[1], pVal, nVal); - rc = lsm_insert(p->pDb, pKey, nKey, pData, nVal+1); - sqlite3_free(pData); + case SQLITE_BLOB: + case SQLITE_TEXT: { + if( eType==SQLITE_TEXT ){ + pVal = sqlite3_value_text(pValue); + }else{ + pVal = (unsigned char*)sqlite3_value_blob(pValue); + } + nVal = sqlite3_value_bytes(pValue); + pData = sqlite3_malloc( nVal+1 ); + if( pData==0 ){ + rc = SQLITE_NOMEM; + }else{ + pData[0] = eType; + memcpy(&pData[1], pVal, nVal); + rc = lsm_insert(p->pDb, pKey, nKey, pData, nVal+1); + sqlite3_free(pData); + } + break; } - break; - } - case SQLITE_INTEGER: - case SQLITE_FLOAT: { - sqlite3_uint64 x; - unsigned char aVal[9]; - int i; - if( eType==SQLITE_INTEGER ){ - *(sqlite3_int64*)&x = sqlite3_value_int64(pValue); - }else{ - *(double*)&x = sqlite3_value_double(pValue); + case SQLITE_INTEGER: + case SQLITE_FLOAT: { + sqlite3_uint64 x; + unsigned char aVal[9]; + int i; + if( eType==SQLITE_INTEGER ){ + *(sqlite3_int64*)&x = sqlite3_value_int64(pValue); + }else{ + *(double*)&x = sqlite3_value_double(pValue); + } + for(i=8; x>0 && i>=1; i--){ + aVal[i] = x & 0xff; + x >>= 8; + } + aVal[i] = eType; + rc = lsm_insert(p->pDb, pKey, nKey, &aVal[i], 9-i); + break; } - for(i=8; i>=1; i--){ - aVal[i] = x & 0xff; - x >>= 8; - } - aVal[0] = eType; - rc = lsm_insert(p->pDb, pKey, nKey, aVal, 9); - break; } } + if( pKey!=(const void*)pSpace ) sqlite3_free((void*)pKey); return rc==LSM_OK ? SQLITE_OK : SQLITE_ERROR; } diff --git a/manifest b/manifest index 1e5e787b25..7f7120c7c5 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Basic\sfunctionality\sis\snow\sworking. -D 2015-11-17T02:23:09.421 +C Work\stoward\smore\sflexible\styping\sfor\skeys\sand\svalues. +D 2015-11-19T19:27:07.806 F Makefile.in d828db6afa6c1fa060d01e33e4674408df1942a1 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.msc e928e68168df69b353300ac87c10105206653a03 @@ -205,7 +205,7 @@ F ext/lsm1/lsm_str.c 77ebdd5040ddf267a6f724d4c83132d2dce8a226 F ext/lsm1/lsm_tree.c 5d9fb2bc58a1a70c75126bd8d7198f7b627e165b F ext/lsm1/lsm_unix.c fcaf5b6738713f1229dc0e1a90393ecf24f787f2 F ext/lsm1/lsm_varint.c b19ae9bd26b5a1e8402fb8a564b25d9542338a41 -F ext/lsm1/lsm_vtab.c 1ffcc9bfbf4fc46ba8c6b3734309781a35c7d1e9 +F ext/lsm1/lsm_vtab.c 37be4d5928de455f752fdd8108ea1e6cd06ce6e0 F ext/misc/amatch.c a1a8f66c29d40bd71b075546ddeddb477b17a2bb F ext/misc/closure.c 0d2a038df8fbae7f19de42e7c7d71f2e4dc88704 F ext/misc/compress.c 122faa92d25033d6c3f07c39231de074ab3d2e83 @@ -1419,7 +1419,7 @@ F tool/vdbe_profile.tcl 246d0da094856d72d2c12efec03250d71639d19f F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P a32849d6bf66462d1f511714a00f24519d7b7079 -R cc1cce61ea394db14460eb0001eb1ea8 +P aa129c51ecf5c917cfac30be330886f8a10f49e1 +R 0be85f8175b37708c20cac5856fe94dc U drh -Z 05fa355531114cffc58ad422946d5107 +Z 35d0ab7ac6da941b099070286c057861 diff --git a/manifest.uuid b/manifest.uuid index df03eaf0e6..61047cebc0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -aa129c51ecf5c917cfac30be330886f8a10f49e1 \ No newline at end of file +5c79f53131a7ab3c83f49e35a5021a6cdb2518fc \ No newline at end of file