SQLite源代码分析----------分词器①

2021SC@SDUSC

Tokenizer功能介绍

       当执行一个包含SQL语句的字符串时,接口程序要把这个字符串传递给Tokenizer。Tokenizer的任务是把原有字符串分成一个个标示符,并把这些标示符传递给剖析器。
       当向SQLite提交SQL程序时,第一步是将源文本拆分为“tokens”。一个“token”可能是:

1.像“SELECT”或“UPDATE”这样的语言关键字。
2.表、列或变量的标识符。
3.像“,”或“==”或“;”这样的标点符号。
4.文字值:数值或字符串常量。
5.空白或评论。

空格和注释标记会被丢弃。所有其他令牌都被输入到LALR(1)解析器分析输入程序的结构,并生成一个抽象语法树(AST)输入程序。

代码分析

       在fts3_Tokenizer.c文件中定义了下面的方法用于查找源文本中的“token”:

/* Find the start of the next token. */
  int sqlite3Fts3IsIdChar(char c){
    
    
  static const char isFtsIdChar[] = {
    
    
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x */
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 1x */
      0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 2x */
      1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,  /* 3x */
      0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /* 4x */
      1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,  /* 5x */
      0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /* 6x */
      1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,  /* 7x */
  };
  return (c&0x80 || isFtsIdChar[(int)(c)]);
}

const char *sqlite3Fts3NextToken(const char *zStr, int *pn){
    
    
  const char *z1;
  const char *z2 = 0;

  /* Find the start of the next token. */
  z1 = zStr;
  while( z2==0 ){
    
    
    char c = *z1;
    switch( c ){
    
    
      case '\0': return 0;        /* No more tokens here */
      case '\'':
      case '"':
      case '`': {
    
    
        z2 = z1;
        while( *++z2 && (*z2!=c || *++z2==c) );
        break;
      }
      case '[':
        z2 = &z1[1];
        while( *z2 && z2[0]!=']' ) z2++;
        if( *z2 ) z2++;
        break;

      default:
        if( sqlite3Fts3IsIdChar(*z1) ){
    
    
          z2 = &z1[1];
          while( sqlite3Fts3IsIdChar(*z2) ) z2++;
        }else{
    
    
          z1++;
        }
    }
  }

  *pn = (int)(z2-z1);
  return z1;
}

       从上面的代码中可以看出,所有被Tokenizer找出的“token”都被sqlite3Fts3IsIdChar(char c)方法储存起来,最后该表会被用于全文索引的创建;在其他组成文件中可以通过以下方法调用fts3_Tokenizer()函数:

SELECT fts3_tokenizer(<tokenizer-name>);
SELECT fts3_tokenizer(<tokenizer-name>, <sqlite3_tokenizer_module ptr>);

其中:

       “tokenizer-name”是使用sqlite3_bind_text()绑定到的字符串的参数;“sqlite3_tokenizer_module ptr”是使用 sqlite3_bind_blob()绑定到的参数;BLOB的值是指向sqlite3_tokenizer_module结构的指针。如果存在第二个参数,它将注册为标记器“tokenizer-name”,并返回它的副本。如果只传递一个参数,则返回一个指向当前注册为“tokenizer-name”的标记器实现的指针,并编码为一个blob。或者,如果不存在这样的标记器,则会引发一个SQL异常(错误)。

自定义分词器

SQLite在fts3_tokenizer.h中提供了各种接口供用户自定义分词器:

#ifndef _FTS3_TOKENIZER_H_
#define _FTS3_TOKENIZER_H_
#include "sqlite3.h"
typedef struct sqlite3_tokenizer_module sqlite3_tokenizer_module;
typedef struct sqlite3_tokenizer sqlite3_tokenizer;
typedef struct sqlite3_tokenizer_cursor sqlite3_tokenizer_cursor;

struct sqlite3_tokenizer_module {
    
    
  int iVersion;
  
  int (*xCreate)(
    int argc,                           /* Size of argv array */
    const char *const*argv,             /* Tokenizer argument strings */
    sqlite3_tokenizer **ppTokenizer     /* OUT: Created tokenizer */
  );


  int (*xDestroy)(sqlite3_tokenizer *pTokenizer);

  int (*xOpen)(
    sqlite3_tokenizer *pTokenizer,       /* Tokenizer object */
    const char *pInput, int nBytes,      /* Input buffer */
    sqlite3_tokenizer_cursor **ppCursor  /* OUT: Created tokenizer cursor */
  );


  int (*xClose)(sqlite3_tokenizer_cursor *pCursor);


  int (*xNext)(
    sqlite3_tokenizer_cursor *pCursor,   /* Tokenizer cursor */
    const char **ppToken, int *pnBytes,  /* OUT: Normalized text for token */
    int *piStartOffset,  /* OUT: Byte offset of token in input buffer */
    int *piEndOffset,    /* OUT: Byte offset of end of token in input buffer */
    int *piPosition      /* OUT: Number of tokens returned before this one */
  );


  int (*xLanguageid)(sqlite3_tokenizer_cursor *pCsr, int iLangid);
};

struct sqlite3_tokenizer {
    
    
  const sqlite3_tokenizer_module *pModule;  /* The module for this tokenizer */
  /* Tokenizer implementations will typically add additional fields */
};

struct sqlite3_tokenizer_cursor {
    
    
  sqlite3_tokenizer *pTokenizer;       /* Tokenizer for this cursor. */
  /* Tokenizer implementations will typically add additional fields */
};

int fts3_global_term_cnt(int iTerm, int iCol);
int fts3_term_cnt(int iTerm, int iCol);


#endif /* _FTS3_TOKENIZER_H_ */

Guess you like

Origin blog.csdn.net/wy_csdn_sdu/article/details/120687071