回顾《Sqlite3 源码---Parser(1)》,lemon的语法文件:(1)自顶向下定义规则;(2)自底向上进行归约;(3)归约时,会生成对应数据类型和执行对应的动作。


本文给出sqlite3源码中lemon的输入文件parse.y对sql语法的定义。


SQL

Sqlite3 源码---Parser(2)_java

Sqlite3 源码---Parser(2)_java_02

// 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分别罗列其语法:

  1. begin/end transaction

  2. create/drop table

  3. create/drop view

  4. delete

  5. update

  6. insert




Sqlite3 源码---Parser(2)_java_03

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_TEMPDBtemp(A) ::= TEMP.  {A = 1;}%endif  SQLITE_OMIT_TEMPDBtemp(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

Sqlite3 源码---Parser(2)_java_04

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

Sqlite3 源码---Parser(2)_java_05

Sqlite3 源码---Parser(2)_java_06

%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


Sqlite3 源码---Parser(2)_java_07

%ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMITcmd ::= 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_LIMITcmd ::= 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;}

Sqlite3 源码---Parser(2)_java_08


%ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMITcmd ::= 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_LIMITcmd ::= 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);}


Sqlite3 源码---Parser(2)_java_09

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中的代码设置断点。