1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-11 01:42:22 +03:00

Improvements to the way sqlite3VdbeAddOpList() works, resulting in a slightly

smaller and faster binary.

FossilOrigin-Name: 88ceb588bcdb3ca86d0c58cfdeb61b5fe070872f
This commit is contained in:
drh
2016-01-16 20:50:21 +00:00
parent 8631402e6a
commit 2ce1865dd8
6 changed files with 161 additions and 126 deletions

View File

@@ -115,38 +115,6 @@ int sqlite3_blob_open(
){
int nAttempt = 0;
int iCol; /* Index of zColumn in row-record */
/* This VDBE program seeks a btree cursor to the identified
** db/table/row entry. The reason for using a vdbe program instead
** of writing code to use the b-tree layer directly is that the
** vdbe program will take advantage of the various transaction,
** locking and error handling infrastructure built into the vdbe.
**
** After seeking the cursor, the vdbe executes an OP_ResultRow.
** Code external to the Vdbe then "borrows" the b-tree cursor and
** uses it to implement the blob_read(), blob_write() and
** blob_bytes() functions.
**
** The sqlite3_blob_close() function finalizes the vdbe program,
** which closes the b-tree cursor and (possibly) commits the
** transaction.
*/
static const int iLn = VDBE_OFFSET_LINENO(4);
static const VdbeOpList openBlob[] = {
/* {OP_Transaction, 0, 0, 0}, // 0: Inserted separately */
{OP_TableLock, 0, 0, 0}, /* 1: Acquire a read or write lock */
/* One of the following two instructions is replaced by an OP_Noop. */
{OP_OpenRead, 0, 0, 0}, /* 2: Open cursor 0 for reading */
{OP_OpenWrite, 0, 0, 0}, /* 3: Open cursor 0 for read/write */
{OP_Variable, 1, 1, 1}, /* 4: Push the rowid to the stack */
{OP_NotExists, 0, 10, 1}, /* 5: Seek the cursor */
{OP_Column, 0, 0, 1}, /* 6 */
{OP_ResultRow, 1, 0, 0}, /* 7 */
{OP_Goto, 0, 4, 0}, /* 8 */
{OP_Close, 0, 0, 0}, /* 9 */
{OP_Halt, 0, 0, 0}, /* 10 */
};
int rc = SQLITE_OK;
char *zErr = 0;
Table *pTab;
@@ -265,45 +233,80 @@ int sqlite3_blob_open(
pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(pParse);
assert( pBlob->pStmt || db->mallocFailed );
if( pBlob->pStmt ){
/* This VDBE program seeks a btree cursor to the identified
** db/table/row entry. The reason for using a vdbe program instead
** of writing code to use the b-tree layer directly is that the
** vdbe program will take advantage of the various transaction,
** locking and error handling infrastructure built into the vdbe.
**
** After seeking the cursor, the vdbe executes an OP_ResultRow.
** Code external to the Vdbe then "borrows" the b-tree cursor and
** uses it to implement the blob_read(), blob_write() and
** blob_bytes() functions.
**
** The sqlite3_blob_close() function finalizes the vdbe program,
** which closes the b-tree cursor and (possibly) commits the
** transaction.
*/
static const int iLn = VDBE_OFFSET_LINENO(3);
static const VdbeOpList openBlob[] = {
/* {OP_Transaction, 0, 0, 0}, // inserted separately */
{OP_TableLock, 0, 0, 0}, /* 0: Acquire a read or write lock */
{OP_OpenRead, 0, 0, 0}, /* 1: Open cursor 0 for reading */
{OP_OpenWrite, 0, 0, 0}, /* 2: Open cursor 0 for read/write */
{OP_Variable, 1, 1, 1}, /* 3: Push the rowid to the stack */
{OP_NotExists, 0, 10, 1}, /* 4: Seek the cursor */
{OP_Column, 0, 0, 1}, /* 5 */
{OP_ResultRow, 1, 0, 0}, /* 6 */
{OP_Goto, 0, 4, 0}, /* 7 */
{OP_Close, 0, 0, 0}, /* 8 */
{OP_Halt, 0, 0, 0}, /* 9 */
};
Vdbe *v = (Vdbe *)pBlob->pStmt;
int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
VdbeOp *aOp;
sqlite3VdbeAddOp4Int(v, OP_Transaction, iDb, flags,
pTab->pSchema->schema_cookie,
pTab->pSchema->iGeneration);
sqlite3VdbeChangeP5(v, 1);
sqlite3VdbeAddOpList(v, ArraySize(openBlob), openBlob, iLn);
aOp = sqlite3VdbeAddOpList(v, ArraySize(openBlob), openBlob, iLn);
/* Make sure a mutex is held on the table to be accessed */
sqlite3VdbeUsesBtree(v, iDb);
/* Configure the OP_TableLock instruction */
if( db->mallocFailed==0 ){
assert( aOp!=0 );
/* Configure the OP_TableLock instruction */
#ifdef SQLITE_OMIT_SHARED_CACHE
sqlite3VdbeChangeToNoop(v, 1);
aOp[0].opcode = OP_Noop;
#else
sqlite3VdbeChangeP1(v, 1, iDb);
sqlite3VdbeChangeP2(v, 1, pTab->tnum);
sqlite3VdbeChangeP3(v, 1, flags);
sqlite3VdbeChangeP4(v, 1, pTab->zName, P4_TRANSIENT);
aOp[0].p1 = iDb;
aOp[0].p2 = pTab->tnum;
aOp[0].p3 = flags;
sqlite3VdbeChangeP4(v, 1, pTab->zName, P4_TRANSIENT);
}
if( db->mallocFailed==0 ){
#endif
/* Remove either the OP_OpenWrite or OpenRead. Set the P2
** parameter of the other to pTab->tnum. */
sqlite3VdbeChangeToNoop(v, 3 - flags);
sqlite3VdbeChangeP2(v, 2 + flags, pTab->tnum);
sqlite3VdbeChangeP3(v, 2 + flags, iDb);
/* Remove either the OP_OpenWrite or OpenRead. Set the P2
** parameter of the other to pTab->tnum. */
aOp[2-flags].opcode = OP_Noop;
aOp[1+flags].p2 = pTab->tnum;
aOp[1+flags].p3 = iDb;
/* Configure the number of columns. Configure the cursor to
** think that the table has one more column than it really
** does. An OP_Column to retrieve this imaginary column will
** always return an SQL NULL. This is useful because it means
** we can invoke OP_Column to fill in the vdbe cursors type
** and offset cache without causing any IO.
*/
aOp[1+flags].p4type = P4_INT32;
aOp[1+flags].p4.i = pTab->nCol+1;
aOp[5].p2 = pTab->nCol;
/* Configure the number of columns. Configure the cursor to
** think that the table has one more column than it really
** does. An OP_Column to retrieve this imaginary column will
** always return an SQL NULL. This is useful because it means
** we can invoke OP_Column to fill in the vdbe cursors type
** and offset cache without causing any IO.
*/
sqlite3VdbeChangeP4(v, 2+flags, SQLITE_INT_TO_PTR(pTab->nCol+1),P4_INT32);
sqlite3VdbeChangeP2(v, 6, pTab->nCol);
if( !db->mallocFailed ){
pParse->nVar = 1;
pParse->nMem = 1;
pParse->nTab = 1;