Okay, I have givven up implementing direct VDBE access in a loadable extension. 
Last thing I tried was to link the extension against all needed objects. Read:

> cd sqlite/src
> for f in *.c; do gcc -c "$f"; done
> cd ../..
> gcc -shared sqlite/src/*.o ext.o -o ext.so

...or something like that. But then I could not get SQLite's malloc subsystem 
running from within the extension - segfaulted.

Instead of digging even deeper into SQLite, I added some lines of code to 
insert.c and parse.y - diff is attached (yes, public domain).

I have added "INSERT INTO INDEX [db.]index VALUES(...)" to be able to insert 
into a table's index directly, without having redundant data in table and index.

However, my code does no checking for correct values or unique constraints. it 
just inserts what you throw at it :)

Accessing the data only works if the query uses the index, for example:

> CREATE TABLE t (a INTEGER, b TEXT);
> CREATE UNIQUE INDEX i ON t (a, b);
> 
> INSERT INTO t VALUES (1, "a");
> INSERT INTO INDEX i VALUES (2, "b");
> 
> SELECT * FROM t; -- access table only
>> 1|a
> SELECT * FROM t WHERE a > 0; -- access index only
>> 2|b

This saves me about 50% of disk space - 2GB vs. 4GB :)

Cheers
--- cvs-090731/sqlite/src/insert.c      2009-07-24 19:58:53.000000000 +0200
+++ cvs-090725-183100/sqlite/src/insert.c       2009-07-31 13:05:53.155154176 
+0200
@@ -1060,6 +1060,90 @@
   sqlite3DbFree(db, aRegIdx);
 }
 
+void sqlite3InsertIntoIndex(
+       Parse *pParse,        /* Parser context */
+       SrcList *pIdxName,    /* Name of index into which we are inserting */
+       ExprList *pValues    /* List of values to be inserted */
+){
+       sqlite3 *db;
+       Index *pIdx;
+       char *zIdx;
+       const char *zDb;
+       Vdbe *v;
+       int nColumn;
+       int iDb;
+       Db *pDb;
+       int i;
+       
+       assert( pIdxName->nSrc==1 );
+       
+       db = pParse->db;
+       v = sqlite3GetVdbe(pParse);
+       if( v== 0 ){
+               sqlite3ErrorMsg(pParse, "Could not init VDBE", 0);
+               goto insert_cleanup;
+       }
+       
+       zIdx = pIdxName->a[0].zName;
+       //if( NEVER(zIdx==0) ) goto insert_cleanup;
+       zDb = pIdxName->a[0].zDatabase;
+       
+       pIdx = sqlite3FindIndex(pParse->db, zIdx, zDb);
+       if( pIdx==0 ){
+               sqlite3ErrorMsg(pParse, "no such index: %S", pIdxName, 0);
+               goto insert_cleanup;
+       }
+       
+       /* insert must cover all index fields */
+       if( pIdx->nColumn!=pValues->nExpr ){
+               sqlite3ErrorMsg(pParse, "%i values for %i columns", 
pValues->nExpr, pIdx->nColumn);
+               goto insert_cleanup;
+       }
+       
+       iDb = sqlite3SchemaToIndex(db, pIdx->pSchema);
+       
+       sqlite3BeginWriteOperation(pParse, 0, iDb);
+       
+       KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
+       
+       int iMem = ++pParse->nMem;
+       pParse->nMem += pValues->nExpr + 3; // values, rowid, record, rowcount
+       
+       // open cursor 0 on index
+       sqlite3VdbeAddOp4(v, OP_OpenWrite, 0, pIdx->tnum, iDb, (char*)pKey, 
P4_KEYINFO_HANDOFF);
+       
+       // push values onto stack
+       for( i=0; i<pValues->nExpr; i++ ){
+               sqlite3ExprCode(pParse, pValues->a[i].pExpr, ++iMem);
+       }
+       
+       // pseudo row id (zero)
+       sqlite3VdbeAddOp2(v, OP_Integer, 0, ++iMem);
+       
+       // build index record
+       sqlite3VdbeAddOp3(v, OP_MakeRecord, (iMem - pValues->nExpr - 1), 
pValues->nExpr+1, ++iMem);
+       sqlite3IndexAffinityStr(v, pIdx);
+       
+       // insert
+       sqlite3VdbeAddOp2(v, OP_IdxInsert, 0, iMem);
+       
+       // close cursor 0
+       sqlite3VdbeAddOp1(v, OP_Close, 0);
+       
+       if( db->flags & SQLITE_CountRows ){
+               // set row count
+               sqlite3VdbeAddOp2(v, OP_Integer, 1, ++iMem);
+               sqlite3VdbeAddOp2(v, OP_ResultRow, iMem, 1);
+       }
+       sqlite3VdbeSetNumCols(v, 1);
+       sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows inserted", 
SQLITE_STATIC);
+       
+insert_cleanup:
+       
+       sqlite3SrcListDelete(db, pIdxName);
+       sqlite3ExprListDelete(db, pValues);
+}
+
 /*
 ** Generate code to do constraint checks prior to an INSERT or an UPDATE.
 **
--- cvs-090731/sqlite/src/parse.y       2009-07-03 17:37:28.000000000 +0200
+++ cvs-090725-183100/sqlite/src/parse.y        2009-07-29 18:39:43.757241718 
+0200
@@ -687,6 +687,9 @@
 cmd ::= insert_cmd(R) INTO fullname(X) inscollist_opt(F) DEFAULT VALUES.
             {sqlite3Insert(pParse, X, 0, 0, F, R);}
 
+cmd ::= insert_cmd INTO INDEX fullname(X) VALUES LP itemlist(Y) RP.
+            {sqlite3InsertIntoIndex(pParse, X, Y);}
+
 %type insert_cmd {int}
 insert_cmd(A) ::= INSERT orconf(R).   {A = R;}
 insert_cmd(A) ::= REPLACE.            {A = OE_Replace;}
_______________________________________________
sqlite-users mailing list
sqlite-users@sqlite.org
http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users

Reply via email to