Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add a test for the "colname:phrase" syntax to fts5expr1.test. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
c472cae982fc3c9289b23c5bf672df2c |
User & Date: | dan 2012-12-17 20:18:41.217 |
Context
2012-12-18
| ||
15:47 | Add support for NEAR to the fts expression parser. check-in: b1a2a17679 user: dan tags: trunk | |
2012-12-17
| ||
20:18 | Add a test for the "colname:phrase" syntax to fts5expr1.test. check-in: c472cae982 user: dan tags: trunk | |
19:36 | Add new files fts5.c and fts5func.c. check-in: bd4efbb2f7 user: dan tags: trunk | |
Changes
Changes to src/fts5.c.
︙ | ︙ | |||
685 686 687 688 689 690 691 | Fts5Tokenizer *p; for(p=db->pTokenizer; p; p=p->pNext){ if( 0==sqlite4StrICmp(zName, p->zName) ) break; } return p; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 | Fts5Tokenizer *p; for(p=db->pTokenizer; p; p=p->pNext){ if( 0==sqlite4StrICmp(zName, p->zName) ) break; } return p; } void sqlite4ShutdownFts5(sqlite4 *db){ Fts5Tokenizer *p; Fts5Tokenizer *pNext; for(p=db->pTokenizer; p; p=pNext){ pNext = p->pNext; sqlite4DbFree(db, p); } } /* ** This function is used to install custom FTS tokenizers. */ int sqlite4_create_tokenizer( sqlite4 *db, |
︙ | ︙ | |||
891 892 893 894 895 896 897 898 | } } rc = sqlite4ApiExit(db, rc); sqlite4_mutex_leave(db->mutex); return rc; } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 | } } rc = sqlite4ApiExit(db, rc); sqlite4_mutex_leave(db->mutex); return rc; } /************************************************************************** *************************************************************************** ** Below this point is test code. */ #ifdef SQLITE4_TEST static int fts5PrintExprNode(sqlite4 *, const char **, Fts5ExprNode *, char **); static int fts5PrintExprNodeParen( sqlite4 *db, const char **azCol, Fts5ExprNode *pNode, char **pzRet ){ int bParen = (pNode->eType!=TOKEN_PRIMITIVE || pNode->pPhrase->nStr>1); sqlite4_env *pEnv = sqlite4_db_env(db); char *zRet = *pzRet; if( bParen ) zRet = sqlite4_mprintf(pEnv, "%z(", zRet); fts5PrintExprNode(db, azCol, pNode, &zRet); if( bParen ) zRet = sqlite4_mprintf(pEnv, "%z)", zRet); *pzRet = zRet; return SQLITE4_OK; } static int fts5PrintExprNode( sqlite4 *db, const char **azCol, Fts5ExprNode *pNode, char **pzRet ){ sqlite4_env *pEnv = sqlite4_db_env(db); char *zRet = *pzRet; assert( pNode->eType==TOKEN_AND || pNode->eType==TOKEN_OR || pNode->eType==TOKEN_NOT || pNode->eType==TOKEN_PRIMITIVE ); assert( (pNode->eType==TOKEN_PRIMITIVE)==(pNode->pPhrase!=0) ); if( pNode->eType==TOKEN_PRIMITIVE ){ int iStr; Fts5Phrase *pPhrase = pNode->pPhrase; if( pPhrase->iCol>=0 ){ zRet = sqlite4_mprintf(pEnv, "%z\"%s\":", zRet, azCol[pPhrase->iCol]); } for(iStr=0; iStr<pPhrase->nStr; iStr++){ int iToken; Fts5Str *pStr = &pPhrase->aStr[iStr]; if( iStr>0 ){ zRet = sqlite4_mprintf( pEnv, "%z NEAR/%d ", zRet, pPhrase->aiNear[iStr-1] ); } for(iToken=0; iToken<pStr->nToken; iToken++){ int nRet = sqlite4Strlen30(zRet); const char *z = pStr->aToken[iToken].z; int n = pStr->aToken[iToken].n; int i; zRet = (char *)sqlite4_realloc(pEnv, zRet, nRet + n*2+4); if( iToken>0 ) zRet[nRet++] = '+'; zRet[nRet++] = '"'; for(i=0; i<n; i++){ if( z[i]=='"' ) zRet[nRet++] = '"'; zRet[nRet++] = z[i]; } zRet[nRet++] = '"'; zRet[nRet++] = '\0'; } } }else{ fts5PrintExprNodeParen(db, azCol, pNode->pLeft, &zRet); switch( pNode->eType ){ case TOKEN_AND: zRet = sqlite4_mprintf(pEnv, "%z AND ", zRet); break; case TOKEN_OR: zRet = sqlite4_mprintf(pEnv, "%z OR ", zRet); break; case TOKEN_NOT: zRet = sqlite4_mprintf(pEnv, "%z NOT ", zRet); break; } fts5PrintExprNodeParen(db, azCol, pNode->pRight, &zRet); } *pzRet = zRet; return SQLITE4_OK; } static int fts5PrintExpr( sqlite4 *db, const char **azCol, Fts5Expr *pExpr, char **pzRet ){ return fts5PrintExprNode(db, azCol, pExpr->pRoot, pzRet); } /* ** A user defined function used to test the fts5 expression parser. As follows: ** ** fts5_parse_expr(<tokenizer>, <expr>); */ static void fts5_parse_expr( sqlite4_context *pCtx, int nVal, sqlite4_value **aVal ){ int rc; Fts5Expr *pExpr = 0; Fts5Tokenizer *pTok; sqlite4_tokenizer *p; sqlite4 *db; const char *zTokenizer; const char *zExpr; const char *zTbl; char *zErr = 0; char *zRet = 0; const char **azCol = 0; int nCol = 0; sqlite4_stmt *pStmt = 0; db = sqlite4_context_db_handle(pCtx); assert( nVal==3 ); zTokenizer = (const char *)sqlite4_value_text(aVal[0]); zExpr = (const char *)sqlite4_value_text(aVal[1]); zTbl = (const char *)sqlite4_value_text(aVal[2]); if( sqlite4Strlen30(zTbl)>0 ){ int i; char *zSql = sqlite4MPrintf(db, "SELECT * FROM '%q'", zTbl); rc = sqlite4_prepare(db, zSql, -1, &pStmt, 0); sqlite4DbFree(db, zSql); if( rc!=SQLITE4_OK ){ sqlite4_result_error(pCtx, sqlite4_errmsg(db), -1); sqlite4_result_error_code(pCtx, rc); return; } nCol = sqlite4_column_count(pStmt); azCol = sqlite4DbMallocZero(db, sizeof(char *)*nCol); for(i=0; i<nCol; i++){ azCol[i] = sqlite4_column_name(pStmt, i); } } pTok = fts5FindTokenizer(db, zTokenizer); if( pTok==0 ){ zErr = sqlite4MPrintf(db, "no such tokenizer: %s", zTokenizer); goto fts5_parse_expr_out; }else{ rc = pTok->xCreate(pTok->pCtx, 0, 0, &p); if( rc!=SQLITE4_OK ){ zErr = sqlite4MPrintf(db, "error creating tokenizer: %d", rc); goto fts5_parse_expr_out; } } rc = fts5ParseExpression(db, pTok, p, azCol, nCol, zExpr, &pExpr, &zErr); if( rc!=SQLITE4_OK ){ if( zErr==0 ){ zErr = sqlite4MPrintf(db, "error parsing expression: %d", rc); } goto fts5_parse_expr_out; } fts5PrintExpr(db, azCol, pExpr, &zRet); sqlite4_result_text(pCtx, zRet, -1, SQLITE4_TRANSIENT); fts5ExpressionFree(db, pExpr); sqlite4_free(sqlite4_db_env(db), zRet); fts5_parse_expr_out: sqlite4DbFree(db, azCol); sqlite4_finalize(pStmt); if( zErr ){ sqlite4_result_error(pCtx, zErr, -1); sqlite4DbFree(db, zErr); } } #endif /* ** Register the default FTS5 tokenizer and functions with handle db. */ int sqlite4InitFts5(sqlite4 *db){ #ifdef SQLITE4_TEST int rc = sqlite4_create_function( db, "fts5_parse_expr", 3, SQLITE4_UTF8, 0, fts5_parse_expr, 0, 0 ); if( rc!=SQLITE4_OK ) return rc; #endif return sqlite4InitFts5Func(db); } |
Changes to test/fts5expr1.test.
︙ | ︙ | |||
12 13 14 15 16 17 18 | # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix fts5expr1 foreach {tn expr res} { | < < | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix fts5expr1 foreach {tn expr res} { 1 { abc } {"abc"} 2 { abc AND def } {"abc" AND "def"} 3 { (abc) } {"abc"} 4 { (((abc))) } {"abc"} 5 { one OR two AND three } {"one" OR ("two" AND "three")} 6 { one AND two OR three } {("one" AND "two") OR "three"} |
︙ | ︙ | |||
38 39 40 41 42 43 44 | 15 { a NOT b AND c OR d } {(("a" NOT "b") AND "c") OR "d"} 16 { a OR b AND c NOT d } {"a" OR ("b" AND ("c" NOT "d"))} 17 { (a OR b) AND c NOT d } {("a" OR "b") AND ("c" NOT "d")} } { do_execsql_test 1.$tn { | | > > > > > > > > > > > > | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | 15 { a NOT b AND c OR d } {(("a" NOT "b") AND "c") OR "d"} 16 { a OR b AND c NOT d } {"a" OR ("b" AND ("c" NOT "d"))} 17 { (a OR b) AND c NOT d } {("a" OR "b") AND ("c" NOT "d")} } { do_execsql_test 1.$tn { SELECT fts5_parse_expr('simple', $expr, '') } [list [string trim $res]] } do_execsql_test 2.0 { CREATE TABLE t1(a, b, c); } foreach {tn expr res} { 1 { a : abc } {"a":"abc"} 2 { b : abc + def} {"b":"abc"+"def"} } { do_execsql_test 2.$tn { SELECT fts5_parse_expr('simple', $expr, 't1') } [list [string trim $res]] } finish_test |