Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(393)

Side by Side Diff: third_party/sqlite/sqlite-src-3100200/ext/fts5/fts5_test_mi.c

Issue 1610543003: [sql] Import reference version of SQLite 3.10.2. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 ** 2015 Aug 04
3 **
4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
6 **
7 ** May you do good and not evil.
8 ** May you find forgiveness for yourself and forgive others.
9 ** May you share freely, never taking more than you give.
10 **
11 ******************************************************************************
12 **
13 ** This file contains test code only, it is not included in release
14 ** versions of FTS5. It contains the implementation of an FTS5 auxiliary
15 ** function very similar to the FTS4 function matchinfo():
16 **
17 ** https://www.sqlite.org/fts3.html#matchinfo
18 **
19 ** Known differences are that:
20 **
21 ** 1) this function uses the FTS5 definition of "matchable phrase", which
22 ** excludes any phrases that are part of an expression sub-tree that
23 ** does not match the current row. This comes up for MATCH queries
24 ** such as:
25 **
26 ** "a OR (b AND c)"
27 **
28 ** In FTS4, if a single row contains instances of tokens "a" and "c",
29 ** but not "b", all instances of "c" are considered matches. In FTS5,
30 ** they are not (as the "b AND c" sub-tree does not match the current
31 ** row.
32 **
33 ** 2) For the values returned by 'x' that apply to all rows of the table,
34 ** NEAR constraints are not considered. But for the number of hits in
35 ** the current row, they are.
36 **
37 ** This file exports a single function that may be called to register the
38 ** matchinfo() implementation with a database handle:
39 **
40 ** int sqlite3Fts5TestRegisterMatchinfo(sqlite3 *db);
41 */
42
43
44 #ifdef SQLITE_TEST
45 #ifdef SQLITE_ENABLE_FTS5
46
47 #include "fts5.h"
48 #include <tcl.h>
49 #include <assert.h>
50 #include <string.h>
51
52 typedef struct Fts5MatchinfoCtx Fts5MatchinfoCtx;
53 typedef unsigned int u32;
54
55 struct Fts5MatchinfoCtx {
56 int nCol; /* Number of cols in FTS5 table */
57 int nPhrase; /* Number of phrases in FTS5 query */
58 char *zArg; /* nul-term'd copy of 2nd arg */
59 int nRet; /* Number of elements in aRet[] */
60 u32 *aRet; /* Array of 32-bit unsigned ints to return */
61 };
62
63
64
65 /*
66 ** Return a pointer to the fts5_api pointer for database connection db.
67 ** If an error occurs, return NULL and leave an error in the database
68 ** handle (accessible using sqlite3_errcode()/errmsg()).
69 */
70 static fts5_api *fts5_api_from_db(sqlite3 *db){
71 fts5_api *pRet = 0;
72 sqlite3_stmt *pStmt = 0;
73
74 if( SQLITE_OK==sqlite3_prepare(db, "SELECT fts5()", -1, &pStmt, 0)
75 && SQLITE_ROW==sqlite3_step(pStmt)
76 && sizeof(pRet)==sqlite3_column_bytes(pStmt, 0)
77 ){
78 memcpy(&pRet, sqlite3_column_blob(pStmt, 0), sizeof(pRet));
79 }
80 sqlite3_finalize(pStmt);
81 return pRet;
82 }
83
84
85 /*
86 ** Argument f should be a flag accepted by matchinfo() (a valid character
87 ** in the string passed as the second argument). If it is not, -1 is
88 ** returned. Otherwise, if f is a valid matchinfo flag, the value returned
89 ** is the number of 32-bit integers added to the output array if the
90 ** table has nCol columns and the query nPhrase phrases.
91 */
92 static int fts5MatchinfoFlagsize(int nCol, int nPhrase, char f){
93 int ret = -1;
94 switch( f ){
95 case 'p': ret = 1; break;
96 case 'c': ret = 1; break;
97 case 'x': ret = 3 * nCol * nPhrase; break;
98 case 'y': ret = nCol * nPhrase; break;
99 case 'b': ret = ((nCol + 31) / 32) * nPhrase; break;
100 case 'n': ret = 1; break;
101 case 'a': ret = nCol; break;
102 case 'l': ret = nCol; break;
103 case 's': ret = nCol; break;
104 }
105 return ret;
106 }
107
108 static int fts5MatchinfoIter(
109 const Fts5ExtensionApi *pApi, /* API offered by current FTS version */
110 Fts5Context *pFts, /* First arg to pass to pApi functions */
111 Fts5MatchinfoCtx *p,
112 int(*x)(const Fts5ExtensionApi*,Fts5Context*,Fts5MatchinfoCtx*,char,u32*)
113 ){
114 int i;
115 int n = 0;
116 int rc = SQLITE_OK;
117 char f;
118 for(i=0; (f = p->zArg[i]); i++){
119 rc = x(pApi, pFts, p, f, &p->aRet[n]);
120 if( rc!=SQLITE_OK ) break;
121 n += fts5MatchinfoFlagsize(p->nCol, p->nPhrase, f);
122 }
123 return rc;
124 }
125
126 static int fts5MatchinfoXCb(
127 const Fts5ExtensionApi *pApi,
128 Fts5Context *pFts,
129 void *pUserData
130 ){
131 Fts5PhraseIter iter;
132 int iCol, iOff;
133 u32 *aOut = (u32*)pUserData;
134 int iPrev = -1;
135
136 for(pApi->xPhraseFirst(pFts, 0, &iter, &iCol, &iOff);
137 iOff>=0;
138 pApi->xPhraseNext(pFts, &iter, &iCol, &iOff)
139 ){
140 aOut[iCol*3+1]++;
141 if( iCol!=iPrev ) aOut[iCol*3 + 2]++;
142 iPrev = iCol;
143 }
144
145 return SQLITE_OK;
146 }
147
148 static int fts5MatchinfoGlobalCb(
149 const Fts5ExtensionApi *pApi,
150 Fts5Context *pFts,
151 Fts5MatchinfoCtx *p,
152 char f,
153 u32 *aOut
154 ){
155 int rc = SQLITE_OK;
156 switch( f ){
157 case 'p':
158 aOut[0] = p->nPhrase;
159 break;
160
161 case 'c':
162 aOut[0] = p->nCol;
163 break;
164
165 case 'x': {
166 int i;
167 for(i=0; i<p->nPhrase && rc==SQLITE_OK; i++){
168 void *pPtr = (void*)&aOut[i * p->nCol * 3];
169 rc = pApi->xQueryPhrase(pFts, i, pPtr, fts5MatchinfoXCb);
170 }
171 break;
172 }
173
174 case 'n': {
175 sqlite3_int64 nRow;
176 rc = pApi->xRowCount(pFts, &nRow);
177 aOut[0] = (u32)nRow;
178 break;
179 }
180
181 case 'a': {
182 sqlite3_int64 nRow = 0;
183 rc = pApi->xRowCount(pFts, &nRow);
184 if( nRow==0 ){
185 memset(aOut, 0, sizeof(u32) * p->nCol);
186 }else{
187 int i;
188 for(i=0; rc==SQLITE_OK && i<p->nCol; i++){
189 sqlite3_int64 nToken;
190 rc = pApi->xColumnTotalSize(pFts, i, &nToken);
191 if( rc==SQLITE_OK){
192 aOut[i] = (u32)((2*nToken + nRow) / (2*nRow));
193 }
194 }
195 }
196 break;
197 }
198
199 }
200 return rc;
201 }
202
203 static int fts5MatchinfoLocalCb(
204 const Fts5ExtensionApi *pApi,
205 Fts5Context *pFts,
206 Fts5MatchinfoCtx *p,
207 char f,
208 u32 *aOut
209 ){
210 int i;
211 int rc = SQLITE_OK;
212
213 switch( f ){
214 case 'b':
215 case 'x':
216 case 'y': {
217 int nMul = (f=='x' ? 3 : 1);
218 int iPhrase;
219
220 if( f=='b' ){
221 int nInt = ((p->nCol + 31) / 32) * p->nPhrase;
222 for(i=0; i<nInt; i++) aOut[i] = 0;
223 }else{
224 for(i=0; i<(p->nCol*p->nPhrase); i++) aOut[i*nMul] = 0;
225 }
226
227 for(iPhrase=0; iPhrase<p->nPhrase; iPhrase++){
228 Fts5PhraseIter iter;
229 int iOff, iCol;
230 for(pApi->xPhraseFirst(pFts, iPhrase, &iter, &iCol, &iOff);
231 iOff>=0;
232 pApi->xPhraseNext(pFts, &iter, &iCol, &iOff)
233 ){
234 if( f=='b' ){
235 aOut[iPhrase * ((p->nCol+31)/32) + iCol/32] |= ((u32)1 << iCol%32);
236 }else{
237 aOut[nMul * (iCol + iPhrase * p->nCol)]++;
238 }
239 }
240 }
241
242 break;
243 }
244
245 case 'l': {
246 for(i=0; rc==SQLITE_OK && i<p->nCol; i++){
247 int nToken;
248 rc = pApi->xColumnSize(pFts, i, &nToken);
249 aOut[i] = (u32)nToken;
250 }
251 break;
252 }
253
254 case 's': {
255 int nInst;
256
257 memset(aOut, 0, sizeof(u32) * p->nCol);
258
259 rc = pApi->xInstCount(pFts, &nInst);
260 for(i=0; rc==SQLITE_OK && i<nInst; i++){
261 int iPhrase, iOff, iCol = 0;
262 int iNextPhrase;
263 int iNextOff;
264 u32 nSeq = 1;
265 int j;
266
267 rc = pApi->xInst(pFts, i, &iPhrase, &iCol, &iOff);
268 iNextPhrase = iPhrase+1;
269 iNextOff = iOff+pApi->xPhraseSize(pFts, 0);
270 for(j=i+1; rc==SQLITE_OK && j<nInst; j++){
271 int ip, ic, io;
272 rc = pApi->xInst(pFts, j, &ip, &ic, &io);
273 if( ic!=iCol || io>iNextOff ) break;
274 if( ip==iNextPhrase && io==iNextOff ){
275 nSeq++;
276 iNextPhrase = ip+1;
277 iNextOff = io + pApi->xPhraseSize(pFts, ip);
278 }
279 }
280
281 if( nSeq>aOut[iCol] ) aOut[iCol] = nSeq;
282 }
283
284 break;
285 }
286 }
287 return rc;
288 }
289
290 static Fts5MatchinfoCtx *fts5MatchinfoNew(
291 const Fts5ExtensionApi *pApi, /* API offered by current FTS version */
292 Fts5Context *pFts, /* First arg to pass to pApi functions */
293 sqlite3_context *pCtx, /* Context for returning error message */
294 const char *zArg /* Matchinfo flag string */
295 ){
296 Fts5MatchinfoCtx *p;
297 int nCol;
298 int nPhrase;
299 int i;
300 int nInt;
301 int nByte;
302 int rc;
303
304 nCol = pApi->xColumnCount(pFts);
305 nPhrase = pApi->xPhraseCount(pFts);
306
307 nInt = 0;
308 for(i=0; zArg[i]; i++){
309 int n = fts5MatchinfoFlagsize(nCol, nPhrase, zArg[i]);
310 if( n<0 ){
311 char *zErr = sqlite3_mprintf("unrecognized matchinfo flag: %c", zArg[i]);
312 sqlite3_result_error(pCtx, zErr, -1);
313 sqlite3_free(zErr);
314 return 0;
315 }
316 nInt += n;
317 }
318
319 nByte = sizeof(Fts5MatchinfoCtx) /* The struct itself */
320 + sizeof(u32) * nInt /* The p->aRet[] array */
321 + (i+1); /* The p->zArg string */
322 p = (Fts5MatchinfoCtx*)sqlite3_malloc(nByte);
323 if( p==0 ){
324 sqlite3_result_error_nomem(pCtx);
325 return 0;
326 }
327 memset(p, 0, nByte);
328
329 p->nCol = nCol;
330 p->nPhrase = nPhrase;
331 p->aRet = (u32*)&p[1];
332 p->nRet = nInt;
333 p->zArg = (char*)&p->aRet[nInt];
334 memcpy(p->zArg, zArg, i);
335
336 rc = fts5MatchinfoIter(pApi, pFts, p, fts5MatchinfoGlobalCb);
337 if( rc!=SQLITE_OK ){
338 sqlite3_result_error_code(pCtx, rc);
339 sqlite3_free(p);
340 p = 0;
341 }
342
343 return p;
344 }
345
346 static void fts5MatchinfoFunc(
347 const Fts5ExtensionApi *pApi, /* API offered by current FTS version */
348 Fts5Context *pFts, /* First arg to pass to pApi functions */
349 sqlite3_context *pCtx, /* Context for returning result/error */
350 int nVal, /* Number of values in apVal[] array */
351 sqlite3_value **apVal /* Array of trailing arguments */
352 ){
353 const char *zArg;
354 Fts5MatchinfoCtx *p;
355 int rc = SQLITE_OK;
356
357 if( nVal>0 ){
358 zArg = (const char*)sqlite3_value_text(apVal[0]);
359 }else{
360 zArg = "pcx";
361 }
362
363 p = (Fts5MatchinfoCtx*)pApi->xGetAuxdata(pFts, 0);
364 if( p==0 || sqlite3_stricmp(zArg, p->zArg) ){
365 p = fts5MatchinfoNew(pApi, pFts, pCtx, zArg);
366 if( p==0 ){
367 rc = SQLITE_NOMEM;
368 }else{
369 rc = pApi->xSetAuxdata(pFts, p, sqlite3_free);
370 }
371 }
372
373 if( rc==SQLITE_OK ){
374 rc = fts5MatchinfoIter(pApi, pFts, p, fts5MatchinfoLocalCb);
375 }
376 if( rc!=SQLITE_OK ){
377 sqlite3_result_error_code(pCtx, rc);
378 }else{
379 /* No errors has occured, so return a copy of the array of integers. */
380 int nByte = p->nRet * sizeof(u32);
381 sqlite3_result_blob(pCtx, (void*)p->aRet, nByte, SQLITE_TRANSIENT);
382 }
383 }
384
385 int sqlite3Fts5TestRegisterMatchinfo(sqlite3 *db){
386 int rc; /* Return code */
387 fts5_api *pApi; /* FTS5 API functions */
388
389 /* Extract the FTS5 API pointer from the database handle. The
390 ** fts5_api_from_db() function above is copied verbatim from the
391 ** FTS5 documentation. Refer there for details. */
392 pApi = fts5_api_from_db(db);
393
394 /* If fts5_api_from_db() returns NULL, then either FTS5 is not registered
395 ** with this database handle, or an error (OOM perhaps?) has occurred.
396 **
397 ** Also check that the fts5_api object is version 2 or newer.
398 */
399 if( pApi==0 || pApi->iVersion<1 ){
400 return SQLITE_ERROR;
401 }
402
403 /* Register the implementation of matchinfo() */
404 rc = pApi->xCreateFunction(pApi, "matchinfo", 0, fts5MatchinfoFunc, 0);
405
406 return rc;
407 }
408
409 #endif /* SQLITE_ENABLE_FTS5 */
410 #endif /* SQLITE_TEST */
411
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698