/* * SQLite manages explicit transactions by setting a flag when a BEGIN; is * issued, then starting an actual transaction in the btree layer when the * first operation happens (a read txn if it's a read op, a write txn if write) * Then each statement will be contained in a sub-transaction. Since sequences * are implemented using a custom function, we need to emulate that * functionality. So there are three cases here: * - Not in an explicit transaction - start a statement, since we might do * write operations, and thus we need a valid statement_txn. * - In an explicit transaction, and the first statement. Start a txn and a statement txn. * - In an explicit transaction and not the first statemetn. Start a statement * transaction. * * The SQLite vdbe will take care of closing the statement transaction for us, * so we don't need to worry about that. * * Caching sequences can't be transactionally protected, so it's a no-op in * that case (and this function should not be called). * * It's safe to call this method multiple times since both * sqlite3BtreeBeginTrans and sqlite3BtreeBeginStmt are no-ops on subsequent * calls. */ static int btreeSeqStartTransaction( sqlite3_context *context, Btree *p, int is_write) { sqlite3 *db; Vdbe *vdbe; int rc; db = sqlite3_context_db_handle(context); /* * TODO: This is actually a linked list of VDBEs, not necessarily * the vdbe we want. I can't see a way to get the correct * vdbe handle. * It's possible that there is only one VDBE handle in DB, since * we use a shared cache. */ vdbe = db->pVdbe; if (!sqlite3BtreeIsInTrans(p) && (rc = btreeBeginTransInternal(p, 1)) != SQLITE_OK) { btreeSeqError(context, SQLITE_ERROR, "Could not begin transaction."); return (rc); } /* * TODO: Do we need logic bumping the VDBE statement count here? * vdbe.c:OP_Transaction does, but adding it here causes an * assert failure. It should be OK, because this code is only * really relevant in the case where there is a single statement. */ rc = sqlite3BtreeBeginStmt(p, vdbe->iStatement); return (rc); }
/* ** Usage: btree_begin_statement ID ** ** Start a new statement transaction */ static int btree_begin_statement( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ Btree *pBt; int rc; if( argc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID\"", 0); return TCL_ERROR; } pBt = sqlite3TestTextToPtr(argv[1]); sqlite3BtreeEnter(pBt); rc = sqlite3BtreeBeginStmt(pBt); sqlite3BtreeLeave(pBt); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; } return TCL_OK; }