/ Check-in [7ddb8266]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Lift docListMerge() call out of loadSegmentLeavesInt() for prefix search. Doclists from multiple prefix matches will need a union merge function, which will have to logically happen across a segment before doclists are merged between segments. (CVS 3887)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:7ddb82668906e33e2d6a796f2da1795032e036d5
User & Date: shess 2007-04-30 17:52:52
Context
2007-04-30
21:39
Fix a potential segfault following a malloc() failure during a call to sqlite3_prepare() where the nBytes parameter is positive but less than the length of the input SQL string. (CVS 3888) check-in: 27bf3fc3 user: drh tags: trunk
17:52
Lift docListMerge() call out of loadSegmentLeavesInt() for prefix search. Doclists from multiple prefix matches will need a union merge function, which will have to logically happen across a segment before doclists are merged between segments. (CVS 3887) check-in: 7ddb8266 user: shess tags: trunk
16:55
Try to avoid reading pages when moving overflow chains to the free-list. (CVS 3886) check-in: 8cccec68 user: danielk1977 tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to ext/fts2/fts2.c.

5112
5113
5114
5115
5116
5117
5118
5119
5120
5121
5122
5123
5124
5125
5126
5127
5128
5129
5130
5131
5132
5133
5134
5135
5136
5137
5138
5139
5140
....
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
5257
....
5263
5264
5265
5266
5267
5268
5269












































5270
5271
5272
5273
5274
5275
5276
    ** on a better name.  [Meanwhile, break encapsulation rather than
    ** use a confusing name.]
    */
    int rc, c = leafReaderTermCmp(&pReader->leafReader, pTerm, nTerm);
    if( c==0 ){
      const char *pData = leavesReaderData(pReader);
      int nData = leavesReaderDataBytes(pReader);
      if( out->nData==0 ){
        dataBufferReplace(out, pData, nData);
      }else{
        DLReader readers[2];
        DataBuffer result;
        dlrInit(&readers[0], DL_DEFAULT, out->pData, out->nData);
        dlrInit(&readers[1], DL_DEFAULT, pData, nData);
        dataBufferInit(&result, out->nData+nData);
        docListMerge(&result, readers, 2);
        dataBufferDestroy(out);
        *out = result;
        dlrDestroy(&readers[0]);
        dlrDestroy(&readers[1]);
      }
     }
    if( c>=0 ) break;      /* Past any possible matches. */

    rc = leavesReaderStep(v, pReader);
    if( rc!=SQLITE_OK ) return rc;
  }
  return SQLITE_OK;
}
................................................................................
  if( rc==SQLITE_ROW ) return SQLITE_ERROR;
  if( rc!=SQLITE_DONE ) return rc;

  return SQLITE_OK;
}

/* Traverse the tree represented by pData[nData] looking for
** pTerm[nTerm], merging its doclist over *out if found (any duplicate
** doclists read from the segment rooted at pData will overwrite those
** in *out).
*/
static int loadSegment(fulltext_vtab *v, const char *pData, int nData,
                       sqlite_int64 iLeavesEnd,
                       const char *pTerm, int nTerm, DataBuffer *out){
  assert( nData>1 );

  /* This code should never be called with buffered updates. */
  assert( v->nPendingData<0 );

  /* Special case where root is a leaf. */
  if( *pData=='\0' ){
    return loadSegmentLeaf(v, pData, nData, pTerm, nTerm, out);
  }else{
    int rc;
    sqlite_int64 iBlockid;

................................................................................
      rc = loadAndGetChildContaining(v, iBlockid, pTerm, nTerm, &iBlockid);
      if( rc!=SQLITE_OK ) return rc;
    }

    return loadSegmentLeaves(v, iBlockid, iBlockid, pTerm, nTerm, out);
  }
}













































/* Scan the database and merge together the posting lists for the term
** into *out.
*/
static int termSelect(fulltext_vtab *v, int iColumn,
                      const char *pTerm, int nTerm,
                      DocListType iType, DataBuffer *out){







|
|
<
<
<
<
<
<
<
<
<
<
<
|
<







 







|
|
<

|
|
|
<
<
<
<
<







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







5112
5113
5114
5115
5116
5117
5118
5119
5120











5121

5122
5123
5124
5125
5126
5127
5128
....
5220
5221
5222
5223
5224
5225
5226
5227
5228

5229
5230
5231
5232





5233
5234
5235
5236
5237
5238
5239
....
5245
5246
5247
5248
5249
5250
5251
5252
5253
5254
5255
5256
5257
5258
5259
5260
5261
5262
5263
5264
5265
5266
5267
5268
5269
5270
5271
5272
5273
5274
5275
5276
5277
5278
5279
5280
5281
5282
5283
5284
5285
5286
5287
5288
5289
5290
5291
5292
5293
5294
5295
5296
5297
5298
5299
5300
5301
5302
    ** on a better name.  [Meanwhile, break encapsulation rather than
    ** use a confusing name.]
    */
    int rc, c = leafReaderTermCmp(&pReader->leafReader, pTerm, nTerm);
    if( c==0 ){
      const char *pData = leavesReaderData(pReader);
      int nData = leavesReaderDataBytes(pReader);
      assert( out->nData==0 );
      dataBufferReplace(out, pData, nData);











    }

    if( c>=0 ) break;      /* Past any possible matches. */

    rc = leavesReaderStep(v, pReader);
    if( rc!=SQLITE_OK ) return rc;
  }
  return SQLITE_OK;
}
................................................................................
  if( rc==SQLITE_ROW ) return SQLITE_ERROR;
  if( rc!=SQLITE_DONE ) return rc;

  return SQLITE_OK;
}

/* Traverse the tree represented by pData[nData] looking for
** pTerm[nTerm], placing its doclist into *out.  This is internal to
** loadSegment() to make error-handling cleaner.

*/
static int loadSegmentInt(fulltext_vtab *v, const char *pData, int nData,
                          sqlite_int64 iLeavesEnd,
                          const char *pTerm, int nTerm, DataBuffer *out){





  /* Special case where root is a leaf. */
  if( *pData=='\0' ){
    return loadSegmentLeaf(v, pData, nData, pTerm, nTerm, out);
  }else{
    int rc;
    sqlite_int64 iBlockid;

................................................................................
      rc = loadAndGetChildContaining(v, iBlockid, pTerm, nTerm, &iBlockid);
      if( rc!=SQLITE_OK ) return rc;
    }

    return loadSegmentLeaves(v, iBlockid, iBlockid, pTerm, nTerm, out);
  }
}

/* Call loadSegmentInt() to collect the doclist for pTerm/nTerm, then
** merge its doclist over *out (any duplicate doclists read from the
** segment rooted at pData will overwrite those in *out).
*/
/* NOTE(shess) Previous code passed out down to sub-routines for use
** in docListMerge().  This version deoptimizes things slightly, but
** prefix searches require a different merge function entirely.
*/
static int loadSegment(fulltext_vtab *v, const char *pData, int nData,
                       sqlite_int64 iLeavesEnd,
                       const char *pTerm, int nTerm, DataBuffer *out){
  DataBuffer result;
  int rc;

  assert( nData>1 );

  /* This code should never be called with buffered updates. */
  assert( v->nPendingData<0 );

  dataBufferInit(&result, 0);
  rc = loadSegmentInt(v, pData, nData, iLeavesEnd, pTerm, nTerm, &result);
  if( rc==SQLITE_OK && result.nData>0 ){
    if( out->nData==0 ){
      DataBuffer tmp = *out;
      *out = result;
      result = tmp;
    }else{
      DataBuffer merged;
      DLReader readers[2];

      dlrInit(&readers[0], DL_DEFAULT, out->pData, out->nData);
      dlrInit(&readers[1], DL_DEFAULT, result.pData, result.nData);
      dataBufferInit(&merged, out->nData+result.nData);
      docListMerge(&merged, readers, 2);
      dataBufferDestroy(out);
      *out = merged;
      dlrDestroy(&readers[0]);
      dlrDestroy(&readers[1]);
    }
  }
  dataBufferDestroy(&result);
  return rc;
}

/* Scan the database and merge together the posting lists for the term
** into *out.
*/
static int termSelect(fulltext_vtab *v, int iColumn,
                      const char *pTerm, int nTerm,
                      DocListType iType, DataBuffer *out){