sqlite3源码解析之sql解析(二)

sqlite3ParserInit函数

主要目的就是初始化一个解析器

SQLITE_PRIVATEvoid sqlite3ParserInit(void *yypParser){

  yyParser *pParser = (yyParser*)yypParser;//解析器对象

#ifdef YYTRACKMAXSTACKDEPTH

  pParser->yyhwm = 0;

#endif

#ifYYSTACKDEPTH<=0

  pParser->yytos = NULL;

  pParser->yystack = NULL;

  pParser->yystksz = 0;

  if( yyGrowStack(pParser) ){

    pParser->yystack = &pParser->yystk0;

    pParser->yystksz = 1;

  }

#endif

#ifndefYYNOERRORRECOVERY

  pParser->yyerrcnt = -1;

#endif

  pParser->yytos = pParser->yystack;

  pParser->yystack[0].stateno = 0;

  pParser->yystack[0].major = 0;

#ifYYSTACKDEPTH>0

  pParser->yystackEnd = &pParser->yystack[YYSTACKDEPTH-1];

#endif

}


sqlite3GetToken函数

 这个函数说起来有点复杂,我尽量说清楚。

我先分步解析,再总体说明。

我用select id,name from stu;这个sql语句来解析Token的解析过程。

1:aiClass[*z]数组确定case,

 例如第一个词select ,通过s的ASCII码115 ,找到aiClass[115]这个数,

找到的这个数为1

 

 

通过这个1我们找到了一个case

这里面CC_KYWD==1。

在这个case里面要做这么几件事情:

    1:通过一个for循环确定i的大小及select的长度。这里为6。

它是如何确定i的大小呢?

 答案是:z[ i]数组放的是select这个词,然后依次遍历这个词只要满足条件就使i++,这样就可以确定i的大小。

 

2:执行这两个东西

keywordCode函数是一个查找关键字的函数。

 

i = ((charMap(z[0])*4) ^ (charMap(z[n-1])*3) ^ n) % 127;

确定了i的值,charMap(z[0])z[0]代表select中的s,z[n-1]代表select中的t。

charMap()这个宏就是找到相应字符的小写ASCII码。

下面就是字符间的转换。

 

最后一步就是确定*pType的值

 

现在,我总体说一下这个函数

 

 在sqlite3GetToken()函数中,实现了aiClass [c]上的switch()使用查找表,而直接在上的switch()使用二进制搜索。查找表要快得多。

观察 下面的查找表,上面定义的宏与下面的表是相互对应的。

 

#defineCC_X          0    /* The letter 'x', or start of BLOB literal (字母“x”或BLOB文字的开始)*/

#defineCC_KYWD       1    /* Alphabetics or '_'.  Usable in a keyword(字母或'_'。可用于关键字) */

#defineCC_ID         2    /* unicode characters usable in IDs(可用于ID的unicode字符) */

#defineCC_DIGIT      3    /* Digits(数字) */

#defineCC_DOLLAR     4    /* '$' */

#defineCC_VARALPHA   5    /* '@', '#', ':'.  Alphabetic SQL variables */

#defineCC_VARNUM     6    /* '?'.  SQL variables */

#defineCC_SPACE      7    /* Space characters */

#defineCC_QUOTE      8    /* '"', '\'', or '`'.  String literals, quoted ids */

#defineCC_QUOTE2     9    /* '['.   [...] style quoted ids */

#defineCC_PIPE      10    /* '|'.   Bitwise OR or concatenate */

#defineCC_MINUS     11    /* '-'.  Minus or SQL-style comment */

#defineCC_LT        12    /* '<'.  Part of < or <= or <> */

#defineCC_GT        13    /* '>'.  Part of > or >= */

#defineCC_EQ        14    /* '='.  Part of = or == */

#defineCC_BANG      15    /* '!'.  Part of != */

#defineCC_SLASH     16    /* '/'.  / or c-style comment */

#defineCC_LP        17    /* '(' */

#defineCC_RP        18    /* ')' */

#defineCC_SEMI      19    /* ';' */

#defineCC_PLUS      20    /* '+' */

#defineCC_STAR      21    /* '*' */

#defineCC_PERCENT   22    /* '%' */

#defineCC_COMMA     23    /* ',' */

#defineCC_AND       24    /* '&' */

#defineCC_TILDA     25    /* '~' */

#defineCC_DOT       26    /* '.' */

#defineCC_ILLEGAL   27    /* Illegal character */

 

staticconstunsignedchar aiClass[] = {

#ifdefSQLITE_ASCII

/*         x0  x1  x2  x3  x4  x5  x6  x7  x8  x9  xa  xb  xc  xd  xe  xf */

/* 0x */   27, 27, 27, 27, 27, 27, 27, 27, 27,  7,  7, 27,  7,  7, 27, 27,

/* 1x */   27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,

/* 2x */    7, 15,  8,  5,  4, 22, 24,  8, 17, 18, 21, 20, 23, 11, 26, 16,

/* 3x */    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  5, 19, 12, 14, 13,  6,

/* 4x */    5,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,

/* 5x */    1,  1,  1,  1,  1,  1,  1,  1,  0,  1,  1,  9, 27, 27, 27,  1,

/* 6x */    8,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,

/* 7x */    1,  1,  1,  1,  1,  1,  1,  1,  0,  1,  1, 27, 10, 27, 25, 27,

/* 8x */    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,

/* 9x */    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,

/* Ax */    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,

/* Bx */    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,

/* Cx */    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,

/* Dx */    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,

/* Ex */    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,

/* Fx */    2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2

 

 

 

关键字查询的函数实现(keywordCode函数)

(检查看z[0..n-1]是否是关键字,如果是的话就将该关键字的解析器符号代码写入*pType)。

   返回token的长度

   */

staticint keywordCode(constchar *z, intn, int *pType){

  int i, j;

  constchar *zKW;

  if( n>=2 ){

    i = ((charMap(z[0])*4) ^ (charMap(z[n-1])*3) ^ n) % 127;//确定i的值 i值得确定是通过sql语句的第一个词的首尾字符确定的(比如select 是由s ,t确定)

    for(i=((int)aKWHash[i])-1; i>=0; i=((int)aKWNext[i])-1){//aKWHash[]数组中对应的是第i个keyword的哈希值(比如18对应的是116 t的ASCII码)

      if( aKWLen[i]!=n ) continue;

      j = 0;

      zKW = &zKWText[aKWOffset[i]];//S

#ifdefSQLITE_ASCII

      while( j<n && (z[j]&~0x20)==zKW[j] ){ j++; }//小写转换为大写

#endif

#ifdef SQLITE_EBCDIC

      while( j<n && toupper(z[j])==zKW[j] ){ j++; }

#endif

      if( j<n ) continue;

        。。。。。。

      *pType = aKWCode[i];

      break;

    }

  }

  returnn;

}

  

          *pType = aKWCode[i]对应的表,*pType就是传给sqlite3Parser函数的第二个参数

 

   在测试时select对应的i==18, 找到aKWCode[18]中的 TK_SELECT,

 

staticconstunsignedchar aKWCode[124] = {

  TK_REINDEX,    TK_INDEXED,    TK_INDEX,      TK_DESC,       TK_ESCAPE,    

  TK_EACH,       TK_CHECK,      TK_KEY,        TK_BEFORE,     TK_FOREIGN,   

  TK_FOR,        TK_IGNORE,     TK_LIKE_KW,    TK_EXPLAIN,    TK_INSTEAD,   

  TK_ADD,        TK_DATABASE,   TK_AS,         TK_SELECT,     TK_TABLE,     

  TK_JOIN_KW,    TK_THEN,       TK_END,        TK_DEFERRABLE, TK_ELSE,      

  TK_EXCEPT,     TK_TRANSACTION,TK_ACTION,     TK_ON,         TK_JOIN_KW,   

  TK_ALTER,      TK_RAISE,      TK_EXCLUSIVETK_EXISTS,     TK_SAVEPOINT

  TK_INTERSECTTK_TRIGGER,    TK_REFERENCES, TK_CONSTRAINT, TK_INTO,      

  TK_OFFSET,     TK_OF,         TK_SET,        TK_TEMP,       TK_TEMP,      

  TK_OR,         TK_UNIQUE,     TK_QUERY,      TK_WITHOUT,    TK_WITH,      

  TK_JOIN_KW,    TK_RELEASE,    TK_ATTACH,     TK_HAVING,     TK_GROUP,     

  TK_UPDATE,     TK_BEGIN,      TK_JOIN_KW,    TK_RECURSIVETK_BETWEEN,   

  TK_NOTNULL,    TK_NOT,        TK_NO,         TK_NULL,       TK_LIKE_KW,   

  TK_CASCADE,    TK_ASC,        TK_DELETE,     TK_CASE,       TK_COLLATE,   

  TK_CREATE,     TK_CTIME_KW,   TK_DETACH,     TK_IMMEDIATETK_JOIN,      

  TK_INSERT,     TK_MATCH,      TK_PLAN,       TK_ANALYZE,    TK_PRAGMA,    

  TK_ABORT,      TK_VALUES,     TK_VIRTUAL,    TK_LIMIT,      TK_WHEN,      

  TK_WHERE,      TK_RENAME,     TK_AFTER,      TK_REPLACE,    TK_AND,       

  TK_DEFAULT,    TK_AUTOINCR,   TK_TO,         TK_IN,         TK_CAST,      

  TK_COLUMNKW,   TK_COMMIT,     TK_CONFLICT,   TK_JOIN_KW,    TK_CTIME_KW,  

  TK_CTIME_KW,   TK_PRIMARY,    TK_DEFERRED,   TK_DISTINCT,   TK_IS,        

  TK_DROP,       TK_FAIL,       TK_FROM,       TK_JOIN_KW,    TK_LIKE_KW,   

  TK_BY,         TK_IF,         TK_ISNULL,     TK_ORDER,      TK_RESTRICT,  

  TK_JOIN_KW,    TK_ROLLBACK,   TK_ROW,        TK_UNION,      TK_USING,     

  TK_VACUUM,     TK_VIEW,       TK_INITIALLYTK_ALL,       

};




  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值