回顾《Sqlite3 源码---Parser(1)》,lemon的语法文件:(1)自顶向下定义规则;(2)自底向上进行归约;(3)归约时,会生成对应数据类型和执行对应的动作。
本文给出sqlite3源码中lemon的输入文件parse.y对sql语法的定义。
SQL
// Input is a single SQL commandinput ::= cmdlist.cmdlist ::= cmdlist ecmd.cmdlist ::= ecmd.ecmd ::= SEMI.ecmd ::= cmdx SEMI.%ifndef SQLITE_OMIT_EXPLAINecmd ::= explain cmdx SEMI. {NEVER-REDUCE}explain ::= EXPLAIN. { pParse->explain = 1; }explain ::= EXPLAIN QUERY PLAN. { pParse->explain = 2; }%endif SQLITE_OMIT_EXPLAINcmdx ::= cmd. { sqlite3FinishCoding(pParse); }
这部分,指定了一条sql语句的格式为:[EXPLAIN] [QUERY PLAN] cmd;
sql语句必须以分号结束,cmd符号指代的是具体的sql语句。
下面针对以下6类sql分别罗列其语法:
begin/end transaction
create/drop table
create/drop view
delete
update
insert
cmd ::= BEGIN transtype(Y) trans_opt. {sqlite3BeginTransaction(pParse, Y);}
trans_opt ::= .
trans_opt ::= TRANSACTION.
trans_opt ::= TRANSACTION nm.
%type transtype {int}
transtype(A) ::= . {A = TK_DEFERRED;}
transtype(A) ::= DEFERRED(X). {A = @X; /*A-overwrites-X*/}
transtype(A) ::= IMMEDIATE(X). {A = @X; /*A-overwrites-X*/}
transtype(A) ::= EXCLUSIVE(X). {A = @X; /*A-overwrites-X*/}
cmd ::= COMMIT|END(X) trans_opt. {sqlite3EndTransaction(pParse,@X);}
cmd ::= ROLLBACK(X) trans_opt. {(pParse,@X);}
savepoint_opt ::= SAVEPOINT.
savepoint_opt ::= .
cmd ::= SAVEPOINT nm(X). {
sqlite3Savepoint(pParse, SAVEPOINT_BEGIN, &X);
}
cmd ::= RELEASE savepoint_opt nm(X). {
sqlite3Savepoint(pParse, SAVEPOINT_RELEASE, &X);
}
cmd ::= ROLLBACK trans_opt TO savepoint_opt nm(X). {
sqlite3Savepoint(pParse, SAVEPOINT_ROLLBACK, &X);
}
CREATE TABLE
cmd ::= create_table create_table_args.
create_table ::= createkw temp(T) TABLE ifnotexists(E) nm(Y) dbnm(Z). {
sqlite3StartTable(pParse,&Y,&Z,T,0,0,E);
}
createkw(A) ::= CREATE(A). {disableLookaside(pParse);}
%type ifnotexists {int}
ifnotexists(A) ::= . {A = 0;}
ifnotexists(A) ::= IF NOT EXISTS. {A = 1;}
%type temp {int}
%ifndef SQLITE_OMIT_TEMPDB
temp(A) ::= TEMP. {A = 1;}
%endif SQLITE_OMIT_TEMPDB
temp(A) ::= . {A = 0;}
create_table_args ::= LP columnlist conslist_opt(X) RP(E) table_options(F). {
sqlite3EndTable(pParse,&X,&E,F,0);
}
create_table_args ::= AS select(S). {
sqlite3EndTable(pParse,0,0,0,S);
sqlite3SelectDelete(pParse->db, S);
}
%type table_options {int}
table_options(A) ::= . {A = 0;}
table_options(A) ::= WITHOUT nm(X). {
if( X.n==5 && sqlite3_strnicmp(X.z,"rowid",5)==0 ){
A = TF_WithoutRowid | TF_NoVisibleRowid;
}else{
A = 0;
sqlite3ErrorMsg(pParse, "unknown table option: %.*s", X.n, X.z);
}
}
columnlist ::= columnlist COMMA columnname carglist.
columnlist ::= columnname carglist.
columnname(A) ::= nm(A) typetoken(Y). {sqlite3AddColumn(pParse,&A,&Y);}
create table时,会执行下面三个函数:
sqlite3StartTable(pParse,&Y,&Z,T,0,0,E);sqlite3AddColumn(pParse,&A,&Y);sqlite3EndTable(pParse,&X,&E,F,0);
给程序打断点,发现执行create table语句,调用函数顺序和上面一致。并且在这些函数内部会调用sqlite3VdbeAddOp系列函数生成虚拟机的字节码。
下图是,在shell里运行create table语句时的函数调用堆栈:
sqlite3_prepare_v2会调用编译器的入口函数sqlite3RunParser,然后根据传入的sql语句,执行不同的函数,这里我们断点执行sqlite3StartTable
DROP TABLE
cmd ::= DROP TABLE ifexists(E) fullname(X). { sqlite3DropTable(pParse, X, 0, E);}%type ifexists {int}ifexists(A) ::= IF EXISTS. {A = 1;}ifexists(A) ::= . {A = 0;}
CREATE VIEW
%ifndef SQLITE_OMIT_VIEWcmd ::= createkw(X) temp(T) VIEW ifnotexists(E) nm(Y) dbnm(Z) eidlist_opt(C) AS select(S). { sqlite3CreateView(pParse, &X, &Y, &Z, C, S, T, E);}cmd ::= DROP VIEW ifexists(E) fullname(X). { sqlite3DropTable(pParse, X, 1, E);}%endif SQLITE_OMIT_VIEW
%ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
cmd ::= with DELETE FROM xfullname(X) indexed_opt(I) where_opt(W)
orderby_opt(O) limit_opt(L). {
sqlite3SrcListIndexedBy(pParse, X, &I);
#ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
sqlite3ExprListDelete(pParse->db, O); O = 0;
sqlite3ExprDelete(pParse->db, L); L = 0;
#endif
sqlite3DeleteFrom(pParse,X,W,O,L);
}
%endif
%ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
cmd ::= with DELETE FROM xfullname(X) indexed_opt(I) where_opt(W). {
sqlite3SrcListIndexedBy(pParse, X, &I);
sqlite3DeleteFrom(pParse,X,W,0,0);
}
%endif
%type where_opt {Expr*}
%destructor where_opt {sqlite3ExprDelete(pParse->db, $$);}
where_opt(A) ::= . {A = 0;}
where_opt(A) ::= WHERE expr(X). {A = X;}
%ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
cmd ::= with UPDATE orconf(R) xfullname(X) indexed_opt(I) SET setlist(Y)
where_opt(W) orderby_opt(O) limit_opt(L). {
sqlite3SrcListIndexedBy(pParse, X, &I);
sqlite3ExprListCheckLength(pParse,Y,"set list");
sqlite3Update(pParse,X,Y,W,R,O,L,0);
}
%endif
%ifndef SQLITE_ENABLE_UPDATE_DELETE_LIMIT
cmd ::= with UPDATE orconf(R) xfullname(X) indexed_opt(I) SET setlist(Y)
where_opt(W). {
sqlite3SrcListIndexedBy(pParse, X, &I);
sqlite3ExprListCheckLength(pParse,Y,"set list");
sqlite3Update(pParse,X,Y,W,R,0,0,0);
}
%endif
%type setlist {ExprList*}
%destructor setlist {sqlite3ExprListDelete(pParse->db, $$);}
setlist(A) ::= setlist(A) COMMA nm(X) EQ expr(Y). {
A = sqlite3ExprListAppend(pParse, A, Y);
sqlite3ExprListSetName(pParse, A, &X, 1);
}
setlist(A) ::= setlist(A) COMMA LP idlist(X) RP EQ expr(Y). {
A = sqlite3ExprListAppendVector(pParse, A, X, Y);
}
setlist(A) ::= nm(X) EQ expr(Y). {
A = sqlite3ExprListAppend(pParse, 0, Y);
sqlite3ExprListSetName(pParse, A, &X, 1);
}
setlist(A) ::= LP idlist(X) RP EQ expr(Y). {
A = sqlite3ExprListAppendVector(pParse, 0, X, Y);
}
cmd ::= with insert_cmd(R) INTO xfullname(X) idlist_opt(F) select(S)
upsert(U). {
sqlite3Insert(pParse, X, S, F, R, U);
}
cmd ::= with insert_cmd(R) INTO xfullname(X) idlist_opt(F) DEFAULT VALUES.
{
sqlite3Insert(pParse, X, 0, F, R, 0);
}
%type upsert {Upsert*}
// Because upsert only occurs at the tip end of the INSERT rule for cmd,
// there is never a case where the value of the upsert pointer will not
// be destroyed by the cmd action. So comment-out the destructor to
// avoid unreachable code.
//%destructor upsert {sqlite3UpsertDelete(pParse->db,$$);}
upsert(A) ::= . { A = 0; }
upsert(A) ::= ON CONFLICT LP sortlist(T) RP where_opt(TW)
DO UPDATE SET setlist(Z) where_opt(W).
{ A = sqlite3UpsertNew(pParse->db,T,TW,Z,W);}
upsert(A) ::= ON CONFLICT LP sortlist(T) RP where_opt(TW) DO NOTHING.
{ A = sqlite3UpsertNew(pParse->db,T,TW,0,0); }
upsert(A) ::= ON CONFLICT DO NOTHING.
{ A = sqlite3UpsertNew(pParse->db,0,0,0,0); }
%type insert_cmd {int}
insert_cmd(A) ::= INSERT orconf(R). {A = R;}
insert_cmd(A) ::= REPLACE. {A = OE_Replace;}
%type idlist_opt {IdList*}
%destructor idlist_opt {sqlite3IdListDelete(pParse->db, $$);}
%type idlist {IdList*}
%destructor idlist {sqlite3IdListDelete(pParse->db, $$);}
idlist_opt(A) ::= . {A = 0;}
idlist_opt(A) ::= LP idlist(X) RP. {A = X;}
idlist(A) ::= idlist(A) COMMA nm(Y).
{A = sqlite3IdListAppend(pParse,A,&Y);}
idlist(A) ::= nm(Y).
{A = sqlite3IdListAppend(pParse,0,&Y); /*A-overwrites-Y*/}
以上分别展示了6类sql语句的文法,当按产生式进行归约时,触发的动作action里涉及到的函数主要有以下这些:
sqlite3BeginTransaction
sqlite3EndTransaction
sqlite3Savepoint
sqlite3StartTable
sqlite3EndTable
sqlite3SelectDelete
sqlite3AddColumn
sqlite3DropTable
sqlite3CreateView
sqlite3DropTable
sqlite3SrcListIndexedBy
sqlite3ExprListDelete
sqlite3DeleteFrom
sqlite3ExprDelete
sqlite3ExprListCheckLength
sqlite3Update
sqlite3ExprListAppend
sqlite3ExprListSetName
sqlite3ExprListAppendVector
sqlite3Insert
sqlite3UpsertNew
sqlite3IdListDelete
sqlite3IdListAppend
这些函数大部分实现都位于build.c中。但调试时,使用sqlite3.c中的代码设置断点。