2.2.3 执行Prepared Query
前面提到,预处理查询(Prepared Query)是sqlite执行所有sql命令的方式,包括以下三个过程:
(1)Preparation
分析器(parser),分词器(tokenizer)和代码生成器(code generator)把sql Statement编译成VDBE字节码,编译器会创建一个statement句柄(sqlite3_stmt),它包括字节码以及其它执行命令和遍历结果集的所有资源。
相应的C API为sqlite3_prepare_v2(),位于prepare.c文件中,如下:
int sqlite3_prepare_v2(
sqlite3 *db,/* Database handle. */
const char *zsql,/* UTF-8 encoded sql statement. */
int nBytes,/* Length of zsql in bytes. */
sqlite3_stmt **ppStmt,/* OUT: A pointer to the prepared statement */
const char **pzTail /* OUT: End of parsed string */
){
int rc;
rc = sqlite3LockAndPrepare(db,zsql,nBytes,1,0,ppStmt,pzTail);
assert( rc==sqlITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */
return rc;
}
(2) Execution
VDBE执行字节码,执行过程是一个步进(stepwise)的过程,每一步(step)由sqlite3_step()启动,并由VDBE执行一段字节码。在遍历结果集的过程中,它返回sqlITE_ROW,当到达结果末尾时,返回sqlITE_DONE。
相应的C API为sqlite3_step(),位于Vdbeapi.c文件中,如下:
int sqlite3_step(sqlite3_stmt @H_404_52@*pStmt){
int rc @H_404_52@= sqlITE_OK; /* Result from sqlite3Step() */
int rc2 @H_404_52@= sqlITE_OK; /* Result from sqlite3Reprepare() */
Vdbe @H_404_52@*v @H_404_52@= (Vdbe@H_404_52@*)pStmt; /* the prepared statement */
int cnt @H_404_52@= 0; /* Counter to prevent infinite loop of reprepares */
sqlite3 @H_404_52@*db; /* The database connection */
if( vdbeSafetyNotNull(v) ){
return sqlITE_MISUSE_BKPT;
}
db @H_404_52@= v@H_404_52@->db;
sqlite3_mutex_enter(db@H_404_52@->mutex);
v@H_404_52@->doingRerun @H_404_52@= 0;
while( (rc @H_404_52@= sqlite3Step(v))@H_404_52@==sqlITE_SCHEMA
@H_404_52@&& cnt@H_404_52@++ @H_404_52@< sqlITE_MAX_SCHEMA_RETRY ){
int savedPc @H_404_52@= v@H_404_52@->pc;
rc2 @H_404_52@= rc @H_404_52@= sqlite3Reprepare(v);
if( rc@H_404_52@!=sqlITE_OK) break;
sqlite3_reset(pStmt);
if( savedPc@H_404_52@>=0 ) v@H_404_52@->doingRerun @H_404_52@= 1;
assert( v@H_404_52@->expired@H_404_52@==0 );
}
if( rc2@H_404_52@!=sqlITE_OK ){
const char @H_404_52@*zErr @H_404_52@= (const char @H_404_52@*)sqlite3_value_text(db@H_404_52@->pErr);
sqlite3DbFree(db,v@H_404_52@->zErrMsg);
if( @H_404_52@!db@H_404_52@->mallocFailed ){
v@H_404_52@->zErrMsg @H_404_52@= sqlite3DbStrDup(db,zErr);
v@H_404_52@->rc @H_404_52@= rc2;
} else {
v@H_404_52@->zErrMsg @H_404_52@= 0;
v@H_404_52@->rc @H_404_52@= rc @H_404_52@= sqlITE_NOMEM;
}
}
rc @H_404_52@= sqlite3ApiExit(db,rc);
sqlite3_mutex_leave(db@H_404_52@->mutex);
return rc;
}
(3)Finalization
VDBE关闭statement,释放资源。
相应的C API为sqlite3_finalize(),位于Vdbeapi.c文件中,如下:
int sqlite3_finalize(sqlite3_stmt *pStmt){
int rc;
if( pStmt==0 ){
rc = sqlITE_OK;
}else{
Vdbe *v = (Vdbe*)pStmt;
sqlite3 *db = v->db;
if( vdbeSafety(v) ) return sqlITE_MISUSE_BKPT;
sqlite3_mutex_enter(db->mutex);
checkProfileCallback(db,v);
rc = sqlite3VdbeFinalize(v);
rc = sqlite3ApiExit(db,rc);
sqlite3LeaveMutexAndCloseZombie(db);
}
return rc;
}
这三步-preparation,execution,finalization-分别代表不同的statement句柄状态- prepared,active,or finalized。图2.3显示了这些步骤和状态。
下边我们可以用一段伪代码展示一下执行过程,代码如下:
# 1. Open the database,create a connection object (db) db = open('foods.db') # 2.A. Prepare a statement stmt = db.prepare('select * from episodes') # 2.B. Execute. Call step() is until cursor reaches end of result set. while stmt.step() == sqlITE_ROW print stmt.column('name') end # 2.C. Finalize. Release read lock. stmt.finalize() # 3. Insert a record stmt = db.prepare('INSERT INTO foods VALUES (…)') stmt.step() stmt.finalize() # 4. Close database connection. db.close()
图2.3 语句执行过程 2.2.4 执行Wrapped Query 前边已经提到过,wrapped query只是对prepared query的三个过程封装而已。Wrapped query包括二个函数,sqlite3_exec()以及sqlite3_get_table()。这两个函数都可用于查询,不过sqlite3_exec()主要用于不返回数据的查询,而sqlite3_get_table()则相反。其中sqlite3_exec()位于Legacy.c,而sqlite3_get_table()位于table.c。