sqlite3源码解析之sql解析(⼀)
⼀:sql准备过程
在前⾯的分析中我们知道,sqlite3_open()为我们打开了数据库并准备了所要的内存空间,锁,vfs等。
接下来就分析sql是如何被解析器⼀步⼀步解析的。
上图是准备sql语句的过程分析图。
1.1:sqlite3_prepare_v2函数:
该函数是准备的⼊⼝函数。
传⼊了5个参数:
sqlite3 *db :          sqlite3_open()返回的数据库句柄
const char *zSql:    要准备的sql语句
int nBytes :          sql语句的 长度(strlen(sql))
sqlite3_stmt **ppStmt: 准备的语句存储该结构体对象中,可以认为是预编译语句的句柄,执⾏时需要传⼊这个句柄
const char **pzTail:  指向被解析的字符串的末尾
SQLite 现在提供两个版本的编译 API 函数:遗留的和现在使⽤的。
在遗留版本中,原始 SQL ⽂本没有保存在编译后的语句(sqlite3_stmt 结构)中,因此,如
果 schema 发⽣改变,sqlite3_step()会返回 SQLITE_SCHEMA。在新版本中,编译后的语句
中保存原始 SQL ⽂本,当遇到schema 改变时⾃动重新编译。sqlite3_prepare()函数中其实只包含⼀条对 sqlite3LockAndPrepare()的调⽤语句:
SQLITE_API int sqlite3_prepare_v2(
sqlite3 *db,              /* Database handle. 成功打开的数据库句柄*/
constchar *zSql,        /* UTF-8 encoded SQL statement. UTF8编码的 SQL 语句 */
int nBytes,              /* Length of zSql in bytes. 参数 sql 的字节数, 包含 '\0'  */
sqlite3_stmt **ppStmt,    /* OUT: A pointer to the prepared statement 输出:预编译语句句柄 */
constchar **pzTail/* OUT: End of parsed string 输出:指向 sql 语句中未使⽤的部分*/
constchar **pzTail/* OUT: End of parsed string 输出:指向 sql 语句中未使⽤的部分*/
){
int rc;
rc = sqlite3LockAndPrepare(db,zSql,nBytes,SQLITE_PREPARE_SAVESQL,0,
ppStmt,pzTail);
assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 );
return rc;
}
1.2:sqlite3LockAndPrepare函数
该函数并没有做太多事情主要是多了两个参数,判断⼀下db是否合法。
调⽤sqlite3Prepare函数。
staticint sqlite3LockAndPrepare(
sqlite3 *db,              /* Database handle. */
constchar *zSql,        /* UTF-8 encoded SQL statement.(UTF-8 编码的 SQL 语句) */
int nBytes,              /* Length of zSql in bytes. (zSql 的字节数)*/
u32prepFlags,            /* Zero or more SQLITE_PREPARE_* flags(保存的sql⽂本) */
Vdbe *pOld,              /* VM being reprepared */
sqlite3_stmt **ppStmt,    /* OUT: A pointer to the prepared statement(指向已准备好的语句的指针 ) */
constchar **pzTail/* OUT: End of parsed string(未处理的 SQL 串) */
){
int rc;
#ifdef SQLITE_ENABLE_API_ARMOR
if( ppStmt==0 ) return SQLITE_MISUSE_BKPT;
#endif
*ppStmt = 0;
if( !sqlite3SafetyCheckOk(db)||zSql==0 ){//确定 db 指针的合法性
return SQLITE_MISUSE_BKPT;
}
sqlite3_mutex_enter(db->mutex);
sqlite3BtreeEnterAll(db);
rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail);//将 UTF-8 编码的 SQL 语句 zSql 编译成if( rc==SQLITE_SCHEMA ){    // 如果遇到 SCHEMA 改变,定案,再编译
sqlite3ResetOneSchema(db, -1);
sqlite3_finalize(*ppStmt);
rc = sqlite3Prepare(db, zSql, nBytes, prepFlags, pOld, ppStmt, pzTail);
}
sqlite3BtreeLeaveAll(db);
sqlite3_mutex_leave(db->mutex);
assert( rc==SQLITE_OK || *ppStmt==0 );
return rc;
}
1.3:sqlite3Prepare函数
这个函数做了以下⼏个事:
1:加⼊解析器Parse
2:所需内存的初始化以及是否禁⽤后备内存
3:判断链接的数据库是否加锁,如果加锁需要解锁
4:zSqlCopy= sqlite3DbStrNDup(db, zSql, nBytes)语句复制了zsql。
5:调⽤sqlite3RunParser(&sParse,zSql, &zErrMsg);
还有的后⾯补上
staticint sqlite3Prepare(
sqlite3 *db,              /* Database handle. */
constchar *zSql,        /* UTF-8 encoded SQL statement. */
int nBytes,              /* Length of zSql in bytes. */
u32prepFlags,            /* Zero or more SQLITE_PREPARE_* flags */
Vdbe *pReprepare,        /* VM being reprepared */
sqlite3_stmt **ppStmt,    /* OUT: A pointer to the prepared statement (输出经过处理的准备语句)*/ constchar **pzTail/* OUT: End of parsed string */
){
char *zErrMsg = 0;        /* Error message */
int rc = SQLITE_OK;      /* Result code */
int i;                    /* Loop counter */
Parse sParse;            /* Parsing context(解析语境) */
memset(&sParse, 0, PARSE_HDR_SZ);
memset(PARSE_TAIL(&sParse), 0, PARSE_TAIL_SZ);//初始化内存空间
sParse.pReprepare = pReprepare;
assert( ppStmt && *ppStmt==0 );
/* assert( !db->mallocFailed ); // not true with SQLITE_USE_ALLOCA */
assert( sqlite3_mutex_held(db->mutex) );
/* For a long-term use prepared statement avoid the use of
** lookaside memory.
(长期使⽤事先准备好的声明避免后备存储器的使⽤。)
*/
if( prepFlags & SQLITE_PREPARE_PERSISTENT ){
sParse.disableLookaside++;//禁⽤后备内存 来使需要重复使⽤的准备语句可以多次使⽤
db->lookaside.bDisable++;//同时禁⽌db中后备内存分配的参数
}
/*
**(检查以验证是否可以在所有数据库模式上获得读锁 .⽆法获得读锁,表明某些其他数据库连接持有写锁。
这反过来意味着另⼀个连接对模式做出了未提交的更改。 )
**(我们是否要继续和准备对未提交的模式更改的声明,如果这些模式更改随后回滚,并在其位置进⾏不同的更改    然后,当准备好的语句运⾏时,模式cookie将⽆法检测模式更改。灾难会随之发⽣。
*/
for(i=0; i<db->nDb; i++) {//依此遍历连接的数据库
Btree *pBt = db->aDb[i].pBt;
if( pBt ){
assert( sqlite3BtreeHoldsMutex(pBt) );
rc = sqlite3BtreeSchemaLocked(pBt);//判断这个btree是否被锁
if( rc ){ //如果是就提⽰该数据库已被加锁
constchar *zDb = db->aDb[i].zDbSName;
sqlite3ErrorWithMsg(db, rc, "database schema is locked: %s", zDb);
testcase( db->flags & SQLITE_ReadUncommit );
goto end_prepare;
}
}
}
sqlite3VtabUnlockList(db);//然后解锁
sParse.db = db;
if( nBytes>=0 && (nBytes==0 || zSql[nBytes-1]!=0) ){
char *zSqlCopy;
int mxLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH]; //准备语句最⼤长度testcase( nBytes==mxLen );
testcase( nBytes==mxLen+1 );
if( nBytes>mxLen ){//如果超过了这个长度就提⽰
sqlite3ErrorWithMsg(db, SQLITE_TOOBIG, "statement too long");
rc = sqlite3ApiExit(db, SQLITE_TOOBIG);
goto end_prepare;//结束准备阶段
}
zSqlCopy = sqlite3DbStrNDup(db, zSql, nBytes);//复制zSql字符串
if( zSqlCopy ){
sqlite3RunParser(&sParse, zSqlCopy, &zErrMsg);
sParse.zTail = &zSql[sParse.zTail-zSqlCopy];
sqlite3DbFree(db, zSqlCopy);
}else{
sParse.zTail = &zSql[nBytes];
}
}else{
sqlite3RunParser(&sParse, zSql, &zErrMsg);
}
assert( 0==sParse.nQueryLoop );
if( ==SQLITE_DONE ) = SQLITE_OK;
if( sParse.checkSchema ){
schemaIsValid(&sParse);
}
if( db->mallocFailed ){
< = SQLITE_NOMEM_BKPT;
}
if( pzTail ){
提交更改是内存条吗*pzTail = sParse.zTail;
}
rc = ;
#ifndef SQLITE_OMIT_EXPLAIN
if( rc==SQLITE_OK && sParse.pVdbe && plain ){
staticconstchar * const azColName[] = {
"addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment",
"selectid", "order", "from", "detail"
};
int iFirst, mx;
if( plain==2 ){
sqlite3VdbeSetNumCols(sParse.pVdbe, 4);
iFirst = 8;
mx = 12;
}else{
sqlite3VdbeSetNumCols(sParse.pVdbe, 8);
iFirst = 0;
mx = 8;
}
for(i=iFirst; i<mx; i++){
sqlite3VdbeSetColName(sParse.pVdbe, i-iFirst, COLNAME_NAME,
azColName[i], SQLITE_STATIC);
}
}
#endif
if( db->init.busy==0 ){
sqlite3VdbeSetSql(sParse.pVdbe, zSql, (int)(sParse.zTail-zSql), prepFlags);
}
if( sParse.pVdbe && (rc!=SQLITE_OK || db->mallocFailed) ){
sqlite3VdbeFinalize(sParse.pVdbe);
assert(!(*ppStmt));
}else{
*ppStmt = (sqlite3_stmt*)sParse.pVdbe;
}
if( zErrMsg ){
sqlite3ErrorWithMsg(db, rc, "%s", zErrMsg);
sqlite3DbFree(db, zErrMsg);
}else{
sqlite3Error(db, rc);
}
/* Delete any TriggerPrg structures allocated while parsing this statement. */ while( sParse.pTriggerPrg ){
TriggerPrg *pT = sParse.pTriggerPrg;
sParse.pTriggerPrg = pT->pNext;
sqlite3DbFree(db, pT);
}
end_prepare:
sqlite3ParserReset(&sParse);
rc = sqlite3ApiExit(db, rc);
assert( (rc&db->errMask)==rc );
return rc;
}
1.4:sqlite3RunParser函数

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。