⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fts3_expr.c

📁 sqlite最新源码
💻 C
📖 第 1 页 / 共 2 页
字号:
** Note that when using the old query syntax, the OR operator has a higher** precedence than the AND operator.*/static int opPrecedence(Fts3Expr *p){  assert( p->eType!=FTSQUERY_PHRASE );  if( sqlite3_fts3_enable_parentheses ){    return p->eType;  }else if( p->eType==FTSQUERY_NEAR ){    return 1;  }else if( p->eType==FTSQUERY_OR ){    return 2;  }  assert( p->eType==FTSQUERY_AND );  return 3;}/*** Argument ppHead contains a pointer to the current head of a query ** expression tree being parsed. pPrev is the expression node most recently** inserted into the tree. This function adds pNew, which is always a binary** operator node, into the expression tree based on the relative precedence** of pNew and the existing nodes of the tree. This may result in the head** of the tree changing, in which case *ppHead is set to the new root node.*/static void insertBinaryOperator(  Fts3Expr **ppHead,       /* Pointer to the root node of a tree */  Fts3Expr *pPrev,         /* Node most recently inserted into the tree */  Fts3Expr *pNew           /* New binary node to insert into expression tree */){  Fts3Expr *pSplit = pPrev;  while( pSplit->pParent && opPrecedence(pSplit->pParent)<=opPrecedence(pNew) ){    pSplit = pSplit->pParent;  }  if( pSplit->pParent ){    assert( pSplit->pParent->pRight==pSplit );    pSplit->pParent->pRight = pNew;    pNew->pParent = pSplit->pParent;  }else{    *ppHead = pNew;  }  pNew->pLeft = pSplit;  pSplit->pParent = pNew;}/*** Parse the fts3 query expression found in buffer z, length n. This function** returns either when the end of the buffer is reached or an unmatched ** closing bracket - ')' - is encountered.**** If successful, SQLITE_OK is returned, *ppExpr is set to point to the** parsed form of the expression and *pnConsumed is set to the number of** bytes read from buffer z. Otherwise, *ppExpr is set to 0 and SQLITE_NOMEM** (out of memory error) or SQLITE_ERROR (parse error) is returned.*/static int fts3ExprParse(  ParseContext *pParse,                   /* fts3 query parse context */  const char *z, int n,                   /* Text of MATCH query */  Fts3Expr **ppExpr,                      /* OUT: Parsed query structure */  int *pnConsumed                         /* OUT: Number of bytes consumed */){  Fts3Expr *pRet = 0;  Fts3Expr *pPrev = 0;  Fts3Expr *pNotBranch = 0;               /* Only used in legacy parse mode */  int nIn = n;  const char *zIn = z;  int rc = SQLITE_OK;  int isRequirePhrase = 1;  while( rc==SQLITE_OK ){    Fts3Expr *p = 0;    int nByte = 0;    rc = getNextNode(pParse, zIn, nIn, &p, &nByte);    if( rc==SQLITE_OK ){      int isPhrase;      if( !sqlite3_fts3_enable_parentheses        && p->eType==FTSQUERY_PHRASE && p->pPhrase->isNot       ){        /* Create an implicit NOT operator. */        Fts3Expr *pNot = sqlite3_malloc(sizeof(Fts3Expr));        if( !pNot ){          sqlite3Fts3ExprFree(p);          rc = SQLITE_NOMEM;          goto exprparse_out;        }        memset(pNot, 0, sizeof(Fts3Expr));        pNot->eType = FTSQUERY_NOT;        pNot->pRight = p;        if( pNotBranch ){          pNotBranch->pLeft = p;          pNot->pRight = pNotBranch;        }        pNotBranch = pNot;      }else{        int eType = p->eType;        assert( eType!=FTSQUERY_PHRASE || !p->pPhrase->isNot );        isPhrase = (eType==FTSQUERY_PHRASE || p->pLeft);        /* The isRequirePhrase variable is set to true if a phrase or        ** an expression contained in parenthesis is required. If a        ** binary operator (AND, OR, NOT or NEAR) is encounted when        ** isRequirePhrase is set, this is a syntax error.        */        if( !isPhrase && isRequirePhrase ){          sqlite3Fts3ExprFree(p);          rc = SQLITE_ERROR;          goto exprparse_out;        }          if( isPhrase && !isRequirePhrase ){          /* Insert an implicit AND operator. */          Fts3Expr *pAnd;          assert( pRet && pPrev );          pAnd = sqlite3_malloc(sizeof(Fts3Expr));          if( !pAnd ){            sqlite3Fts3ExprFree(p);            rc = SQLITE_NOMEM;            goto exprparse_out;          }          memset(pAnd, 0, sizeof(Fts3Expr));          pAnd->eType = FTSQUERY_AND;          insertBinaryOperator(&pRet, pPrev, pAnd);          pPrev = pAnd;        }        /* This test catches attempts to make either operand of a NEAR        ** operator something other than a phrase. For example, either of        ** the following:        **        **    (bracketed expression) NEAR phrase        **    phrase NEAR (bracketed expression)        **        ** Return an error in either case.        */        if( pPrev && (            (eType==FTSQUERY_NEAR && !isPhrase && pPrev->eType!=FTSQUERY_PHRASE)         || (eType!=FTSQUERY_PHRASE && isPhrase && pPrev->eType==FTSQUERY_NEAR)        )){          sqlite3Fts3ExprFree(p);          rc = SQLITE_ERROR;          goto exprparse_out;        }          if( isPhrase ){          if( pRet ){            assert( pPrev && pPrev->pLeft && pPrev->pRight==0 );            pPrev->pRight = p;            p->pParent = pPrev;          }else{            pRet = p;          }        }else{          insertBinaryOperator(&pRet, pPrev, p);        }        isRequirePhrase = !isPhrase;      }      assert( nByte>0 );    }    assert( rc!=SQLITE_OK || (nByte>0 && nByte<=nIn) );    nIn -= nByte;    zIn += nByte;    pPrev = p;  }  if( rc==SQLITE_DONE && pRet && isRequirePhrase ){    rc = SQLITE_ERROR;  }  if( rc==SQLITE_DONE ){    rc = SQLITE_OK;    if( !sqlite3_fts3_enable_parentheses && pNotBranch ){      if( !pRet ){        rc = SQLITE_ERROR;      }else{        pNotBranch->pLeft = pRet;        pRet = pNotBranch;      }    }  }  *pnConsumed = n - nIn;exprparse_out:  if( rc!=SQLITE_OK ){    sqlite3Fts3ExprFree(pRet);    sqlite3Fts3ExprFree(pNotBranch);    pRet = 0;  }  *ppExpr = pRet;  return rc;}/*** Parameters z and n contain a pointer to and length of a buffer containing** an fts3 query expression, respectively. This function attempts to parse the** query expression and create a tree of Fts3Expr structures representing the** parsed expression. If successful, *ppExpr is set to point to the head** of the parsed expression tree and SQLITE_OK is returned. If an error** occurs, either SQLITE_NOMEM (out-of-memory error) or SQLITE_ERROR (parse** error) is returned and *ppExpr is set to 0.**** If parameter n is a negative number, then z is assumed to point to a** nul-terminated string and the length is determined using strlen().**** The first parameter, pTokenizer, is passed the fts3 tokenizer module to** use to normalize query tokens while parsing the expression. The azCol[]** array, which is assumed to contain nCol entries, should contain the names** of each column in the target fts3 table, in order from left to right. ** Column names must be nul-terminated strings.**** The iDefaultCol parameter should be passed the index of the table column** that appears on the left-hand-side of the MATCH operator (the default** column to match against for tokens for which a column name is not explicitly** specified as part of the query string), or -1 if tokens may by default** match any table column.*/int sqlite3Fts3ExprParse(  sqlite3_tokenizer *pTokenizer,      /* Tokenizer module */  char **azCol,                       /* Array of column names for fts3 table */  int nCol,                           /* Number of entries in azCol[] */  int iDefaultCol,                    /* Default column to query */  const char *z, int n,               /* Text of MATCH query */  Fts3Expr **ppExpr                   /* OUT: Parsed query structure */){  int nParsed;  int rc;  ParseContext sParse;  sParse.pTokenizer = pTokenizer;  sParse.azCol = (const char **)azCol;  sParse.nCol = nCol;  sParse.iDefaultCol = iDefaultCol;  sParse.nNest = 0;  if( z==0 ){    *ppExpr = 0;    return SQLITE_OK;  }  if( n<0 ){    n = strlen(z);  }  rc = fts3ExprParse(&sParse, z, n, ppExpr, &nParsed);  /* Check for mismatched parenthesis */  if( rc==SQLITE_OK && sParse.nNest ){    rc = SQLITE_ERROR;    sqlite3Fts3ExprFree(*ppExpr);    *ppExpr = 0;  }  return rc;}/*** Free a parsed fts3 query expression allocated by sqlite3Fts3ExprParse().*/void sqlite3Fts3ExprFree(Fts3Expr *p){  if( p ){    sqlite3Fts3ExprFree(p->pLeft);    sqlite3Fts3ExprFree(p->pRight);    sqlite3_free(p);  }}/*********************************************************************************************************************************************************** Everything after this point is just test code.*/#ifdef SQLITE_TEST#include <stdio.h>/*** Function to query the hash-table of tokenizers (see README.tokenizers).*/static int queryTestTokenizer(  sqlite3 *db,   const char *zName,    const sqlite3_tokenizer_module **pp){  int rc;  sqlite3_stmt *pStmt;  const char zSql[] = "SELECT fts3_tokenizer(?)";  *pp = 0;  rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);  if( rc!=SQLITE_OK ){    return rc;  }  sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC);  if( SQLITE_ROW==sqlite3_step(pStmt) ){    if( sqlite3_column_type(pStmt, 0)==SQLITE_BLOB ){      memcpy(pp, sqlite3_column_blob(pStmt, 0), sizeof(*pp));    }  }  return sqlite3_finalize(pStmt);}/*** This function is part of the test interface for the query parser. It** writes a text representation of the query expression pExpr into the** buffer pointed to by argument zBuf. It is assumed that zBuf is large ** enough to store the required text representation.*/static void exprToString(Fts3Expr *pExpr, char *zBuf){  switch( pExpr->eType ){    case FTSQUERY_PHRASE: {      Fts3Phrase *pPhrase = pExpr->pPhrase;      int i;      zBuf += sprintf(zBuf, "PHRASE %d %d", pPhrase->iColumn, pPhrase->isNot);      for(i=0; i<pPhrase->nToken; i++){        zBuf += sprintf(zBuf," %.*s",pPhrase->aToken[i].n,pPhrase->aToken[i].z);        zBuf += sprintf(zBuf,"%s", (pPhrase->aToken[i].isPrefix?"+":""));      }      return;    }    case FTSQUERY_NEAR:      zBuf += sprintf(zBuf, "NEAR/%d ", pExpr->nNear);      break;    case FTSQUERY_NOT:      zBuf += sprintf(zBuf, "NOT ");      break;    case FTSQUERY_AND:      zBuf += sprintf(zBuf, "AND ");      break;    case FTSQUERY_OR:      zBuf += sprintf(zBuf, "OR ");      break;  }  zBuf += sprintf(zBuf, "{");  exprToString(pExpr->pLeft, zBuf);  zBuf += strlen(zBuf);  zBuf += sprintf(zBuf, "} ");  zBuf += sprintf(zBuf, "{");  exprToString(pExpr->pRight, zBuf);  zBuf += strlen(zBuf);  zBuf += sprintf(zBuf, "}");}/*** This is the implementation of a scalar SQL function used to test the ** expression parser. It should be called as follows:****   fts3_exprtest(<tokenizer>, <expr>, <column 1>, ...);**** The first argument, <tokenizer>, is the name of the fts3 tokenizer used** to parse the query expression (see README.tokenizers). The second argument** is the query expression to parse. Each subsequent argument is the name** of a column of the fts3 table that the query expression may refer to.** For example:****   SELECT fts3_exprtest('simple', 'Bill col2:Bloggs', 'col1', 'col2');*/static void fts3ExprTest(  sqlite3_context *context,  int argc,  sqlite3_value **argv){  sqlite3_tokenizer_module const *pModule = 0;  sqlite3_tokenizer *pTokenizer = 0;  int rc;  char **azCol = 0;  const char *zExpr;  int nExpr;  int nCol;  int ii;  Fts3Expr *pExpr;  sqlite3 *db = sqlite3_context_db_handle(context);  if( argc<3 ){    sqlite3_result_error(context,         "Usage: fts3_exprtest(tokenizer, expr, col1, ...", -1    );    return;  }  rc = queryTestTokenizer(db,                          (const char *)sqlite3_value_text(argv[0]), &pModule);  if( rc==SQLITE_NOMEM ){    sqlite3_result_error_nomem(context);    goto exprtest_out;  }else if( !pModule ){    sqlite3_result_error(context, "No such tokenizer module", -1);    goto exprtest_out;  }  rc = pModule->xCreate(0, 0, &pTokenizer);  assert( rc==SQLITE_NOMEM || rc==SQLITE_OK );  if( rc==SQLITE_NOMEM ){    sqlite3_result_error_nomem(context);    goto exprtest_out;  }  pTokenizer->pModule = pModule;  zExpr = (const char *)sqlite3_value_text(argv[1]);  nExpr = sqlite3_value_bytes(argv[1]);  nCol = argc-2;  azCol = (char **)sqlite3_malloc(nCol*sizeof(char *));  if( !azCol ){    sqlite3_result_error_nomem(context);    goto exprtest_out;  }  for(ii=0; ii<nCol; ii++){    azCol[ii] = (char *)sqlite3_value_text(argv[ii+2]);  }  rc = sqlite3Fts3ExprParse(      pTokenizer, azCol, nCol, nCol, zExpr, nExpr, &pExpr  );  if( rc==SQLITE_NOMEM ){    sqlite3_result_error_nomem(context);    goto exprtest_out;  }else if( rc==SQLITE_OK ){    char zBuf[4096];    exprToString(pExpr, zBuf);    sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);    sqlite3Fts3ExprFree(pExpr);  }else{    sqlite3_result_error(context, "Error parsing expression", -1);  }exprtest_out:  if( pModule && pTokenizer ){    rc = pModule->xDestroy(pTokenizer);  }  sqlite3_free(azCol);}/*** Register the query expression parser test function fts3_exprtest() ** with database connection db. */void sqlite3Fts3ExprInitTestInterface(sqlite3* db){  sqlite3_create_function(      db, "fts3_exprtest", -1, SQLITE_UTF8, 0, fts3ExprTest, 0, 0  );}#endif#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -