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.0 +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; inExpr; 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.0 +0200
+++ cvs-090725-183100/sqlite/src/parse.y2009-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