Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add APIs to allow fts5 to be augmented with ranking and snippet functions. Does not work yet. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | matchinfo |
Files: | files | file ages | folders |
SHA1: |
a235305d42ed0b17be6e18d4932d9704 |
User & Date: | dan 2013-01-01 19:56:04.682 |
Context
2013-01-02
| ||
20:01 | Add an implementation of BM25 to fts5func.c. Other changes to matchinfo related things. check-in: 03f26d8c60 user: dan tags: matchinfo | |
2013-01-01
| ||
19:56 | Add APIs to allow fts5 to be augmented with ranking and snippet functions. Does not work yet. check-in: a235305d42 user: dan tags: matchinfo | |
18:41 | Fix a memory leak in fts5.c. check-in: 7bc0e58875 user: dan tags: trunk | |
Changes
Changes to src/expr.c.
︙ | ︙ | |||
2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 | pColl = sqlite4ExprCollSeq(pParse, pFarg->a[i].pExpr); } } if( pDef->flags & SQLITE4_FUNC_NEEDCOLL ){ if( !pColl ) pColl = db->pDfltColl; sqlite4VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ); } sqlite4VdbeAddOp4(v, OP_Function, constMask, r1, target, (char*)pDef, P4_FUNCDEF); sqlite4VdbeChangeP5(v, (u8)nFarg); if( nFarg ){ sqlite4ReleaseTempRange(pParse, r1, nFarg); } break; | > > > | 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 | pColl = sqlite4ExprCollSeq(pParse, pFarg->a[i].pExpr); } } if( pDef->flags & SQLITE4_FUNC_NEEDCOLL ){ if( !pColl ) pColl = db->pDfltColl; sqlite4VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ); } if( pDef->bMatchinfo ){ sqlite4VdbeAddOp1(v, OP_Mifunction, pFarg->a[0].pExpr->iTable); } sqlite4VdbeAddOp4(v, OP_Function, constMask, r1, target, (char*)pDef, P4_FUNCDEF); sqlite4VdbeChangeP5(v, (u8)nFarg); if( nFarg ){ sqlite4ReleaseTempRange(pParse, r1, nFarg); } break; |
︙ | ︙ |
Changes to src/fts5.c.
︙ | ︙ | |||
76 77 78 79 80 81 82 | ** expr := expr NOT expr ** expr := expr AND expr ** expr := expr OR expr ** expr := LP expr RP */ /* | | | 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | ** expr := expr NOT expr ** expr := expr AND expr ** expr := expr OR expr ** expr := LP expr RP */ /* ** Structure types used by this module. */ typedef struct Fts5Expr Fts5Expr; typedef struct Fts5ExprNode Fts5ExprNode; typedef struct Fts5List Fts5List; typedef struct Fts5Parser Fts5Parser; typedef struct Fts5ParserToken Fts5ParserToken; typedef struct Fts5Phrase Fts5Phrase; |
︙ | ︙ | |||
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 | Fts5ExprNode *pRight; const u8 *aPk; /* Primary key of current entry (or null) */ int nPk; /* Size of aPk[] in bytes */ }; struct Fts5Expr { Fts5ExprNode *pRoot; }; /* ** FTS5 specific cursor data. */ struct Fts5Cursor { sqlite4 *db; Fts5Info *pInfo; Fts5Expr *pExpr; /* MATCH expression for this cursor */ | > > < > > > | 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 | Fts5ExprNode *pRight; const u8 *aPk; /* Primary key of current entry (or null) */ int nPk; /* Size of aPk[] in bytes */ }; struct Fts5Expr { Fts5ExprNode *pRoot; int nPhrase; /* Number of Fts5Str objects in query */ Fts5Str **apPhrase; }; /* ** FTS5 specific cursor data. */ struct Fts5Cursor { sqlite4 *db; Fts5Info *pInfo; Fts5Expr *pExpr; /* MATCH expression for this cursor */ KVByteArray *aKey; /* Buffer for primary key */ int nKeyAlloc; /* Bytes allocated at aKey[] */ KVCursor *pCsr; /* Cursor used to retrive values */ Mem *aMem; /* Array of column values */ }; /* ** This type is used when reading (decoding) an instance-list. */ typedef struct InstanceList InstanceList; struct InstanceList { |
︙ | ︙ | |||
758 759 760 761 762 763 764 765 766 767 768 769 770 771 | int nCol, /* Size of array azCol[] */ const char *zExpr, /* FTS expression text */ Fts5Expr **ppExpr, /* OUT: Expression object */ char **pzErr /* OUT: Error message */ ){ int rc = SQLITE4_OK; Fts5Parser sParse; int nExpr; int i; Fts5Expr *pExpr; int nHier = 0; int nHierAlloc = 0; ExprHier *aHier = 0; | > | 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 | int nCol, /* Size of array azCol[] */ const char *zExpr, /* FTS expression text */ Fts5Expr **ppExpr, /* OUT: Expression object */ char **pzErr /* OUT: Error message */ ){ int rc = SQLITE4_OK; Fts5Parser sParse; int nStr = 0; int nExpr; int i; Fts5Expr *pExpr; int nHier = 0; int nHierAlloc = 0; ExprHier *aHier = 0; |
︙ | ︙ | |||
813 814 815 816 817 818 819 820 821 822 823 824 825 826 | rc = SQLITE4_NOMEM; }else{ pNode->eType = TOKEN_PRIMITIVE; pNode->pPhrase = pPhrase; *pp = pNode; } } break; } case TOKEN_AND: case TOKEN_OR: case TOKEN_NOT: { Fts5ExprNode **pp = aHier[nHier-1].ppNode; | > | 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 | rc = SQLITE4_NOMEM; }else{ pNode->eType = TOKEN_PRIMITIVE; pNode->pPhrase = pPhrase; *pp = pNode; } } nStr++; break; } case TOKEN_AND: case TOKEN_OR: case TOKEN_NOT: { Fts5ExprNode **pp = aHier[nHier-1].ppNode; |
︙ | ︙ | |||
886 887 888 889 890 891 892 893 894 895 896 897 898 899 | if( aHier[i].nOpen>0 ) rc = SQLITE4_ERROR; } if( rc!=SQLITE4_OK ){ fts5ExpressionFree(db, pExpr); *pzErr = sParse.zErr; }else{ *ppExpr = pExpr; } sqlite4DbFree(db, aHier); return rc; } /* | > | 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 | if( aHier[i].nOpen>0 ) rc = SQLITE4_ERROR; } if( rc!=SQLITE4_OK ){ fts5ExpressionFree(db, pExpr); *pzErr = sParse.zErr; }else{ pExpr->nPhrase = nStr; *ppExpr = pExpr; } sqlite4DbFree(db, aHier); return rc; } /* |
︙ | ︙ | |||
2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 | i = putVarint32(pCsr->aKey, iTbl); memcpy(&pCsr->aKey[i], aPk, nPk); *paKey = pCsr->aKey; *pnKey = nReq; return SQLITE4_OK; } /************************************************************************** *************************************************************************** ** Below this point is test code. */ #ifdef SQLITE4_TEST static int fts5PrintExprNode(sqlite4 *, const char **, Fts5ExprNode *, char **); | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 | i = putVarint32(pCsr->aKey, iTbl); memcpy(&pCsr->aKey[i], aPk, nPk); *paKey = pCsr->aKey; *pnKey = nReq; return SQLITE4_OK; } int sqlite4_mi_column_count(sqlite4_context *pCtx, int *pnCol){ int rc = SQLITE4_OK; if( pCtx->pFts ){ *pnCol = pCtx->pFts->pInfo->nCol; }else{ rc = SQLITE4_MISUSE; } return rc; } int sqlite4_mi_column_size(sqlite4_context *pCtx, int iCol, int *pnToken){ int rc = SQLITE4_OK; if( pCtx->pFts ){ }else{ rc = SQLITE4_MISUSE; } return rc; } int sqlite4_mi_column_value( sqlite4_context *pCtx, int iCol, sqlite4_value **ppVal ){ int rc = SQLITE4_OK; if( pCtx->pFts ){ }else{ rc = SQLITE4_MISUSE; } return rc; } int sqlite4_mi_phrase_count(sqlite4_context *pCtx, int *pnPhrase){ int rc = SQLITE4_OK; if( pCtx->pFts ){ *pnPhrase = pCtx->pFts->pExpr->nPhrase; }else{ rc = SQLITE4_MISUSE; } return rc; } int sqlite4_mi_match_count( sqlite4_context *pCtx, int iCol, int iPhrase, int *pnMatch ){ int rc = SQLITE4_OK; if( pCtx->pFts ){ }else{ rc = SQLITE4_MISUSE; } return rc; } int sqlite4_mi_match_offset( sqlite4_context *pCtx, int iCol, int iPhrase, int iMatch, int *piOff ){ } int sqlite4_mi_total_match_count( sqlite4_context *pCtx, int iCol, int iPhrase, int *pnMatch, int *pnDoc ){ } int sqlite4_mi_total_size(sqlite4_context *pCtx, int iCol, int *pnToken){ } int sqlite4_mi_total_count(sqlite4_context *pCtx, int *pnRow){ } /************************************************************************** *************************************************************************** ** Below this point is test code. */ #ifdef SQLITE4_TEST static int fts5PrintExprNode(sqlite4 *, const char **, Fts5ExprNode *, char **); |
︙ | ︙ |
Changes to src/fts5func.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* */ #include "sqliteInt.h" static int fts5SimpleCreate( void *pCtx, const char **azArg, int nArg, sqlite4_tokenizer **pp ){ *pp = (sqlite4_tokenizer *)pCtx; return SQLITE4_OK; } static int fts5SimpleDestroy(sqlite4_tokenizer *p){ return SQLITE4_OK; } | > > > > > | > | < > | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* */ #include "sqliteInt.h" static char fts5Tolower(char c){ if( c>='A' && c<='Z' ) c = c + ('a' - 'A'); return c; } static int fts5SimpleCreate( void *pCtx, const char **azArg, int nArg, sqlite4_tokenizer **pp ){ *pp = (sqlite4_tokenizer *)pCtx; return SQLITE4_OK; } static int fts5SimpleDestroy(sqlite4_tokenizer *p){ return SQLITE4_OK; } static void fts5Rank(sqlite4_context *pCtx, int nArg, sqlite4_value **apArg){ } static void fts5Snippet(sqlite4_context *pCtx, int nArg, sqlite4_value **apArg){ } static int fts5SimpleTokenize( void *pCtx, sqlite4_tokenizer *p, const char *zDoc, int nDoc, |
︙ | ︙ | |||
71 72 73 74 75 76 77 78 79 80 | sqlite4_env *pEnv = sqlite4_db_env(db); rc = sqlite4_create_tokenizer(db, "simple", (void *)pEnv, fts5SimpleCreate, fts5SimpleTokenize, fts5SimpleDestroy ); if( rc!=SQLITE4_OK ) return rc; return rc; } | > > > > > > | 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | sqlite4_env *pEnv = sqlite4_db_env(db); rc = sqlite4_create_tokenizer(db, "simple", (void *)pEnv, fts5SimpleCreate, fts5SimpleTokenize, fts5SimpleDestroy ); if( rc!=SQLITE4_OK ) return rc; rc = sqlite4_create_mi_function(db, "rank", 0, SQLITE4_UTF8, 0, fts5Rank, 0); if( rc!=SQLITE4_OK ) return rc; rc = sqlite4_create_mi_function( db, "snippet", -1, SQLITE4_UTF8, 0, fts5Snippet, 0 ); return rc; } |
Changes to src/main.c.
︙ | ︙ | |||
1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 | if( pArg && pArg->nRef==0 ){ assert( rc!=SQLITE4_OK ); xDestroy(p); sqlite4DbFree(db, pArg); } out: rc = sqlite4ApiExit(db, rc); sqlite4_mutex_leave(db->mutex); return rc; } #ifndef SQLITE4_OMIT_UTF16 int sqlite4_create_function16( | > > > > > > > > > > > > > > > > > > > > > > > > | 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 | if( pArg && pArg->nRef==0 ){ assert( rc!=SQLITE4_OK ); xDestroy(p); sqlite4DbFree(db, pArg); } out: rc = sqlite4ApiExit(db, rc); sqlite4_mutex_leave(db->mutex); return rc; } int sqlite4_create_mi_function( sqlite4 *db, const char *zFunc, int nArg, int enc, void *p, void (*xFunc)(sqlite4_context*,int,sqlite4_value **), void (*xDestroy)(void *) ){ int rc; int n; n = nArg + (nArg>=0); sqlite4_mutex_enter(db->mutex); rc = sqlite4_create_function_v2(db, zFunc, n, enc, p, xFunc, 0,0,xDestroy); if( rc==SQLITE4_OK ){ FuncDef *p = sqlite4FindFunction(db, zFunc, -1, n, enc, 0); p->bMatchinfo = 1; } rc = sqlite4ApiExit(db, rc); sqlite4_mutex_leave(db->mutex); return rc; } #ifndef SQLITE4_OMIT_UTF16 int sqlite4_create_function16( |
︙ | ︙ |
Changes to src/resolve.c.
︙ | ︙ | |||
431 432 433 434 435 436 437 438 439 440 441 442 443 444 | testcase( iCol==BMS ); testcase( iCol==BMS-1 ); pItem->colUsed |= ((Bitmask)1)<<(iCol>=BMS ? BMS-1 : iCol); ExprSetProperty(p, EP_Resolved); } return p; } static void resolveMatch(Parse *pParse, NameContext *pNC, Expr *pExpr){ Expr *pLeft = pExpr->pLeft; SrcList *pSrc = pNC->pSrcList; SrcListItem *pItem; char *zLhs; int i; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 | testcase( iCol==BMS ); testcase( iCol==BMS-1 ); pItem->colUsed |= ((Bitmask)1)<<(iCol>=BMS ? BMS-1 : iCol); ExprSetProperty(p, EP_Resolved); } return p; } static void resolveMatchArg(Parse *pParse, NameContext *pNC, Expr *pExpr){ SrcList *pSrc = pNC->pSrcList; SrcListItem *pItem; char *zLhs; int i; Index *pIdx; if( pExpr->op!=TK_ID || pSrc==0 || pExpr==0 ){ sqlite4ErrorMsg(pParse, "first argument xxx must be a table name"); return; } zLhs = pExpr->u.zToken; for(i=0; i<pSrc->nSrc; i++){ pItem = &pSrc->a[i]; if( pItem->zAlias && sqlite4StrICmp(zLhs, pItem->zAlias)==0 ) break; if( pItem->zAlias==0 && sqlite4StrICmp(zLhs, pItem->zName)==0 ) break; } if( i==pSrc->nSrc ){ sqlite4ErrorMsg(pParse, "no such table: %s", zLhs); return; } pExpr->op = TK_NULL; pExpr->iTable = pItem->iCursor; ExprSetProperty(pExpr, EP_Resolved); } static void resolveMatch(Parse *pParse, NameContext *pNC, Expr *pExpr){ Expr *pLeft = pExpr->pLeft; SrcList *pSrc = pNC->pSrcList; SrcListItem *pItem; char *zLhs; int i; |
︙ | ︙ | |||
612 613 614 615 616 617 618 | nId, zId); pNC->nErr++; } if( is_agg ){ pExpr->op = TK_AGG_FUNCTION; pNC->hasAgg = 1; } | > > > > > | | | > > | 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 | nId, zId); pNC->nErr++; } if( is_agg ){ pExpr->op = TK_AGG_FUNCTION; pNC->hasAgg = 1; } if( pParse->nErr==0 ){ if( pDef->bMatchinfo ){ resolveMatchArg(pParse, pNC, n>0 ? pList->a[0].pExpr : 0); } if( is_agg ) pNC->allowAgg = 0; sqlite4WalkExprList(pWalker, pList); if( is_agg ) pNC->allowAgg = 1; } /* FIX ME: Compute pExpr->affinity based on the expected return ** type of the function */ return WRC_Prune; } #ifndef SQLITE4_OMIT_SUBQUERY case TK_SELECT: |
︙ | ︙ |
Changes to src/sqlite.h.in.
︙ | ︙ | |||
4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 | const char*, int, int(*x)(void *ctx, int iWeight, int iOff, const char *zToken, int nToken, int iSrc, int nSrc) ), int (*xDestroy)(sqlite4_tokenizer *) ); /* ** Undo the hack that converts floating point types to integer for ** builds on processors without floating point support. */ #ifdef SQLITE4_OMIT_FLOATING_POINT # undef double #endif | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 | const char*, int, int(*x)(void *ctx, int iWeight, int iOff, const char *zToken, int nToken, int iSrc, int nSrc) ), int (*xDestroy)(sqlite4_tokenizer *) ); /* ** CAPI4REF: Register a matchinfo function. */ int sqlite4_create_mi_function( sqlite4 *db, const char *zFunc, int nArg, int enc, void *p, void (*xFunc)(sqlite4_context*,int,sqlite4_value **), void (*xDestroy)(void *) ); /* ** Special functions that may be called from within matchinfo UDFs. All ** return an SQLite error code - SQLITE4_OK if successful, or some other ** error code otherwise. ** ** sqlite4_mi_column_count(): ** Set *pnCol to the number of columns in the queried table. ** ** sqlite4_mi_column_size(): ** Set *pnToken to the number of tokens in the value stored in column iCol ** of the current row. ** ** sqlite4_mi_column_value(): ** Set *ppVal to point to an sqlite4_value object containing the value ** read from column iCol of the current row. This object is valid until ** the function callback returns. ** ** sqlite4_mi_phrase_count(): ** Set *pnPhrase to the number of phrases in the query. ** ** sqlite4_mi_match_count(): ** Set *pn to the number of occurences of phrase iPhrase in column iCol of ** the current row. ** ** sqlite4_mi_total_match_count(): ** Set *pnMatch to the total number of occurrences of phrase iPhrase ** in column iCol of all rows in the indexed table. Set *pnDoc to the ** number of rows that contain at least one match for phrase iPhrase in ** column iCol. ** ** sqlite4_mi_match_offset(): ** Set *piOff to the token offset of the iMatch'th instance of phrase ** iPhrase in column iCol of the current row. If any parameter is out ** of range (i.e. too large) it is not an error. In this case *piOff is ** set to -1 before returning. ** ** sqlite4_mi_total_size(): ** Set *pnToken to the total number of tokens in column iCol of all rows ** in the indexed table. ** ** sqlite4_mi_total_count(): ** Set *pnRow to the total number of rows in the indexed table. */ int sqlite4_mi_column_count(sqlite4_context *, int *pnCol); int sqlite4_mi_column_size(sqlite4_context *, int iCol, int *pnToken); int sqlite4_mi_column_value(sqlite4_context *, int iCol, sqlite4_value **ppVal); int sqlite4_mi_phrase_count(sqlite4_context *, int *pnPhrase); int sqlite4_mi_match_count(sqlite4_context *, int iCol, int iPhrase, int *pn); int sqlite4_mi_match_offset( sqlite4_context *, int iCol, int iPhrase, int iMatch, int *piOff); int sqlite4_mi_total_match_count( sqlite4_context *, int iCol, int iPhrase, int *pnMatch, int *pnDoc); int sqlite4_mi_total_size(sqlite4_context *, int iCol, int *pnToken); int sqlite4_mi_total_count(sqlite4_context *, int *pnRow); /* ** Undo the hack that converts floating point types to integer for ** builds on processors without floating point support. */ #ifdef SQLITE4_OMIT_FLOATING_POINT # undef double #endif |
︙ | ︙ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
635 636 637 638 639 640 641 642 643 644 645 646 647 648 | FuncDef *pSameName; /* Next with a different name but the same hash */ void (*xFunc)(sqlite4_context*,int,sqlite4_value**); /* Regular function */ void (*xStep)(sqlite4_context*,int,sqlite4_value**); /* Aggregate step */ void (*xFinalize)(sqlite4_context*); /* Aggregate finalizer */ char *zName; /* SQL name of the function. */ FuncDef *pNextName; /* Next function with a different name */ FuncDestructor *pDestructor; /* Reference counted destructor function */ }; /* ** A table of SQL functions. ** ** The content is a linked list of FuncDef structures with branches. When ** there are two or more FuncDef objects with the same name, they are | > | 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 | FuncDef *pSameName; /* Next with a different name but the same hash */ void (*xFunc)(sqlite4_context*,int,sqlite4_value**); /* Regular function */ void (*xStep)(sqlite4_context*,int,sqlite4_value**); /* Aggregate step */ void (*xFinalize)(sqlite4_context*); /* Aggregate finalizer */ char *zName; /* SQL name of the function. */ FuncDef *pNextName; /* Next function with a different name */ FuncDestructor *pDestructor; /* Reference counted destructor function */ u8 bMatchinfo; /* True for matchinfo function */ }; /* ** A table of SQL functions. ** ** The content is a linked list of FuncDef structures with branches. When ** there are two or more FuncDef objects with the same name, they are |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 | ** to retrieve the collation sequence set by this opcode is not available ** publicly, only to user functions defined in func.c. */ case OP_CollSeq: { assert( pOp->p4type==P4_COLLSEQ ); break; } /* Opcode: Function P1 P2 P3 P4 P5 ** ** Invoke a user function (P4 is a pointer to a Function structure that ** defines the function) with P5 arguments taken from register P2 and ** successors. The result of the function is stored in register P3. ** Register P3 must not be one of the function inputs. | > > > > > > > > | 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 | ** to retrieve the collation sequence set by this opcode is not available ** publicly, only to user functions defined in func.c. */ case OP_CollSeq: { assert( pOp->p4type==P4_COLLSEQ ); break; } /* Opcode: Mifunction P1 */ case OP_Mifunction: { pc++; pOp++; /* fall through to OP_Function */ }; /* Opcode: Function P1 P2 P3 P4 P5 ** ** Invoke a user function (P4 is a pointer to a Function structure that ** defines the function) with P5 arguments taken from register P2 and ** successors. The result of the function is stored in register P3. ** Register P3 must not be one of the function inputs. |
︙ | ︙ | |||
1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 | ctx.pFunc = ctx.pVdbeFunc->pFunc; } ctx.s.flags = MEM_Null; ctx.s.db = db; ctx.s.xDel = 0; ctx.s.zMalloc = 0; /* The output cell may already have a buffer allocated. Move ** the pointer to ctx.s so in case the user-function can use ** the already allocated buffer instead of allocating a new one. */ sqlite4VdbeMemMove(&ctx.s, pOut); MemSetTypeFlag(&ctx.s, MEM_Null); | > > > > > > > | 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 | ctx.pFunc = ctx.pVdbeFunc->pFunc; } ctx.s.flags = MEM_Null; ctx.s.db = db; ctx.s.xDel = 0; ctx.s.zMalloc = 0; if( pOp[-1].opcode==OP_Mifunction ){ ctx.pFts = p->apCsr[pOp[-1].p1]->pFts; apVal++; n--; }else{ ctx.pFts = 0; } /* The output cell may already have a buffer allocated. Move ** the pointer to ctx.s so in case the user-function can use ** the already allocated buffer instead of allocating a new one. */ sqlite4VdbeMemMove(&ctx.s, pOut); MemSetTypeFlag(&ctx.s, MEM_Null); |
︙ | ︙ |
Changes to src/vdbeInt.h.
︙ | ︙ | |||
237 238 239 240 241 242 243 244 245 246 247 248 249 250 | struct sqlite4_context { FuncDef *pFunc; /* Pointer to function information. MUST BE FIRST */ VdbeFunc *pVdbeFunc; /* Auxilary data, if created. */ Mem s; /* The return value is stored here */ Mem *pMem; /* Memory cell used to store aggregate context */ int isError; /* Error code returned by the function. */ CollSeq *pColl; /* Collating sequence */ }; /* ** An Explain object accumulates indented output which is helpful ** in describing recursive data structures. */ struct Explain { | > | 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 | struct sqlite4_context { FuncDef *pFunc; /* Pointer to function information. MUST BE FIRST */ VdbeFunc *pVdbeFunc; /* Auxilary data, if created. */ Mem s; /* The return value is stored here */ Mem *pMem; /* Memory cell used to store aggregate context */ int isError; /* Error code returned by the function. */ CollSeq *pColl; /* Collating sequence */ Fts5Cursor *pFts; /* fts5 cursor for matchinfo functions */ }; /* ** An Explain object accumulates indented output which is helpful ** in describing recursive data structures. */ struct Explain { |
︙ | ︙ |
Changes to src/where.c.
︙ | ︙ | |||
5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 | while( pOp<pEnd ){ if( pOp->p1==pLevel->iTabCur && pOp->opcode==OP_Column ){ pOp->p1 = pLevel->iIdxCur; } pOp++; } } } /* Final cleanup */ pParse->nQueryLoop = pWInfo->savedNQueryLoop; whereInfoFree(db, pWInfo); return; | > > > > > > > > > > > > > > > > > > | 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 | while( pOp<pEnd ){ if( pOp->p1==pLevel->iTabCur && pOp->opcode==OP_Column ){ pOp->p1 = pLevel->iIdxCur; } pOp++; } } if( (pLevel->plan.wsFlags & WHERE_INDEXED) && (pLevel->plan.u.pIdx->eIndexType==SQLITE4_INDEX_FTS5) ){ VdbeOp *pOp; VdbeOp *pEnd; assert( pLevel->iTabCur!=pLevel->iIdxCur ); pOp = sqlite4VdbeGetOp(v, pWInfo->iTop); pEnd = &pOp[sqlite4VdbeCurrentAddr(v) - pWInfo->iTop]; while( pOp<pEnd ){ if( pOp->p1==pLevel->iTabCur && pOp->opcode==OP_Mifunction ){ pOp->p1 = pLevel->iIdxCur; } pOp++; } } } /* Final cleanup */ pParse->nQueryLoop = pWInfo->savedNQueryLoop; whereInfoFree(db, pWInfo); return; |
︙ | ︙ |
Changes to test/fts5create.test.
︙ | ︙ | |||
70 71 72 73 74 75 76 | CREATE INDEX ft ON t2 USING fts5(tukenizer=simple); } {1 {unrecognized argument: "tukenizer"}} do_catchsql_test 2.3 { CREATE INDEX ft ON t2 USING fts5("a b c"); } {1 {unrecognized argument: "a b c"}} | | | 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | CREATE INDEX ft ON t2 USING fts5(tukenizer=simple); } {1 {unrecognized argument: "tukenizer"}} do_catchsql_test 2.3 { CREATE INDEX ft ON t2 USING fts5("a b c"); } {1 {unrecognized argument: "a b c"}} do_catchsql_test 2.4 { CREATE INDEX ft ON t2 USING fts5(tokenizer="nosuch"); } {1 {no such tokenizer: "nosuch"}} finish_test |
Changes to test/fts5query1.test.
︙ | ︙ | |||
130 131 132 133 134 135 136 137 138 139 | 2 {a:a} {1} 3 {b:a} {2} 4 {c:a} {1 2} 5 {a:a*} {1} } { do_execsql_test 7.$tn {SELECT docid FROM t7 WHERE t7 MATCH $expr} $res } finish_test | > > > > > > > > > > > > > | 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | 2 {a:a} {1} 3 {b:a} {2} 4 {c:a} {1 2} 5 {a:a*} {1} } { do_execsql_test 7.$tn {SELECT docid FROM t7 WHERE t7 MATCH $expr} $res } #------------------------------------------------------------------------- # do_execsql_test 8.0 { CREATE TABLE t8(a PRIMARY KEY, b, c); CREATE INDEX i8 ON t8 USING fts5(); INSERT INTO t8 VALUES('one', 'a b c', 'a a a'); INSERT INTO t8 VALUES('two', 'd e f', 'b b b'); } do_execsql_test 8.1 { SELECT rank(t8) FROM t8 WHERE t8 MATCH 'b a' } finish_test |