/ Check-in [d2ccf7fc]
Login

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

Overview
Comment:Merge in all changes to the trunk through version 3.7.4rc3.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | apple-osx
Files: files | file ages | folders
SHA1: d2ccf7fc0673e875ff7b84cd37b89c65df4bec7f
User & Date: drh 2010-12-07 15:49:03
Context
2011-01-27
18:48
Pull in all the changes from trunk up through the version 3.7.5 release candidate 1. check-in: 09d6c91d user: drh tags: apple-osx
2010-12-07
15:49
Merge in all changes to the trunk through version 3.7.4rc3. check-in: d2ccf7fc user: drh tags: apple-osx
14:59
Version 3.7.4 release candidate 3 check-in: 11c74c0d user: drh tags: trunk
2010-11-19
23:50
Merge all the latest changes from the trunk into the apple-osx branch. check-in: c8bc057c user: drh tags: apple-osx
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to Makefile.in.

372
373
374
375
376
377
378

379
380
381
382
383
384
385
  $(TOP)/src/test_onefile.c \
  $(TOP)/src/test_osinst.c \
  $(TOP)/src/test_pcache.c \
  $(TOP)/src/test_quota.c \
  $(TOP)/src/test_rtree.c \
  $(TOP)/src/test_schema.c \
  $(TOP)/src/test_server.c \

  $(TOP)/src/test_stat.c \
  $(TOP)/src/test_tclvar.c \
  $(TOP)/src/test_thread.c \
  $(TOP)/src/test_vfs.c \
  $(TOP)/src/test_wsd.c

# Source code to the library files needed by the test fixture







>







372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
  $(TOP)/src/test_onefile.c \
  $(TOP)/src/test_osinst.c \
  $(TOP)/src/test_pcache.c \
  $(TOP)/src/test_quota.c \
  $(TOP)/src/test_rtree.c \
  $(TOP)/src/test_schema.c \
  $(TOP)/src/test_server.c \
  $(TOP)/src/test_superlock.c \
  $(TOP)/src/test_stat.c \
  $(TOP)/src/test_tclvar.c \
  $(TOP)/src/test_thread.c \
  $(TOP)/src/test_vfs.c \
  $(TOP)/src/test_wsd.c

# Source code to the library files needed by the test fixture

Changes to ext/fts3/fts3.c.

652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
...
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
...
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
....
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
....
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
....
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
....
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
....
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
....
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
....
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
....
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
....
2294
2295
2296
2297
2298
2299
2300
2301
2302

2303
2304
2305
2306
2307
2308
2309
....
2523
2524
2525
2526
2527
2528
2529


2530

2531
2532
2533
2534
2535
2536
2537
....
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
....
2676
2677
2678
2679
2680
2681
2682

2683
2684




2685
2686
2687
2688
2689
2690
2691
....
2750
2751
2752
2753
2754
2755
2756

2757
2758
2759
2760
2761
2762
2763
....
3269
3270
3271
3272
3273
3274
3275
3276
3277




3278
3279
3280
3281
3282
3283
3284
3285
....
3460
3461
3462
3463
3464
3465
3466

3467
3468
3469
3470
3471
3472
3473
  const char *zCsr = z;

  while( *zCsr!='=' ){
    if( *zCsr=='\0' ) return 0;
    zCsr++;
  }

  *pnKey = zCsr-z;
  zValue = sqlite3_mprintf("%s", &zCsr[1]);
  if( zValue ){
    sqlite3Fts3Dequote(zValue);
  }
  *pzValue = zValue;
  return 1;
}
................................................................................
  );

  nDb = (int)strlen(argv[1]) + 1;
  nName = (int)strlen(argv[2]) + 1;

  aCol = (const char **)sqlite3_malloc(sizeof(const char *) * (argc-2) );
  if( !aCol ) return SQLITE_NOMEM;
  memset(aCol, 0, sizeof(const char *) * (argc-2));

  /* Loop through all of the arguments passed by the user to the FTS3/4
  ** module (i.e. all the column names and special arguments). This loop
  ** does the following:
  **
  **   + Figures out the number of columns the FTSX table will have, and
  **     the number of bytes of space that must be allocated to store copies
................................................................................
  fts3DatabasePageSize(&rc, p);

  /* Declare the table schema to SQLite. */
  fts3DeclareVtab(&rc, p);

fts3_init_out:

  sqlite3_free(aCol);
  if( rc!=SQLITE_OK ){
    if( p ){
      fts3DisconnectMethod((sqlite3_vtab *)p);
    }else if( pTokenizer ){
      pTokenizer->pModule->xDestroy(pTokenizer);
    }
  }else{
................................................................................
** If piLast is not NULL, then *piLast is set to the right-most child node
** that heads a sub-tree that may contain a term for which zTerm/nTerm is
** a prefix.
**
** If an OOM error occurs, SQLITE_NOMEM is returned. Otherwise, SQLITE_OK.
*/
static int fts3ScanInteriorNode(
  Fts3Table *p,                   /* Virtual table handle */
  const char *zTerm,              /* Term to select leaves for */
  int nTerm,                      /* Size of term zTerm in bytes */
  const char *zNode,              /* Buffer containing segment interior node */
  int nNode,                      /* Size of buffer at zNode */
  sqlite3_int64 *piFirst,         /* OUT: Selected child node */
  sqlite3_int64 *piLast           /* OUT: Selected child node */
){
................................................................................
  ** either more than 20 bytes of allocated space following the nNode bytes of
  ** contents, or two zero bytes. Or, if the node is read from the %_segments
  ** table, then there are always 20 bytes of zeroed padding following the
  ** nNode bytes of content (see sqlite3Fts3ReadBlock() for details).
  */
  zCsr += sqlite3Fts3GetVarint(zCsr, &iChild);
  zCsr += sqlite3Fts3GetVarint(zCsr, &iChild);
  if( zCsr>=zEnd ){
    return SQLITE_CORRUPT;
  }
  
  while( zCsr<zEnd && (piFirst || piLast) ){
    int cmp;                      /* memcmp() result */
    int nSuffix;                  /* Size of term suffix */
    int nPrefix = 0;              /* Size of term prefix */
................................................................................
){
  int rc;                         /* Return code */
  int iHeight;                    /* Height of this node in tree */

  assert( piLeaf || piLeaf2 );

  sqlite3Fts3GetVarint32(zNode, &iHeight);
  rc = fts3ScanInteriorNode(p, zTerm, nTerm, zNode, nNode, piLeaf, piLeaf2);
  assert( !piLeaf2 || !piLeaf || rc!=SQLITE_OK || (*piLeaf<=*piLeaf2) );

  if( rc==SQLITE_OK && iHeight>1 ){
    char *zBlob = 0;              /* Blob read from %_segments table */
    int nBlob;                    /* Size of zBlob in bytes */

    if( piLeaf && piLeaf2 && (*piLeaf!=*piLeaf2) ){
................................................................................
** Free an Fts3SegReaderArray object. Also free all seg-readers in the
** array (using sqlite3Fts3SegReaderFree()).
*/
static void fts3SegReaderArrayFree(Fts3SegReaderArray *pArray){
  if( pArray ){
    int i;
    for(i=0; i<pArray->nSegment; i++){
      sqlite3Fts3SegReaderFree(0, pArray->apSegment[i]);
    }
    sqlite3_free(pArray);
  }
}

static int fts3SegReaderArrayAdd(
  Fts3SegReaderArray **ppArray, 
................................................................................

  if( !pArray || pArray->nAlloc==pArray->nSegment ){
    int nNew = (pArray ? pArray->nAlloc+16 : 16);
    pArray = (Fts3SegReaderArray *)sqlite3_realloc(pArray, 
        sizeof(Fts3SegReaderArray) + (nNew-1) * sizeof(Fts3SegReader*)
    );
    if( !pArray ){
      sqlite3Fts3SegReaderFree(0, pNew);
      return SQLITE_NOMEM;
    }
    if( nNew==16 ){
      pArray->nSegment = 0;
      pArray->nCost = 0;
    }
    pArray->nAlloc = nNew;
................................................................................
    int nRoot = sqlite3_column_bytes(pStmt, 4);
    char const *zRoot = sqlite3_column_blob(pStmt, 4);
    if( sqlite3_column_int64(pStmt, 1)==0 ){
      /* The entire segment is stored on the root node (which must be a
      ** leaf). Do not bother inspecting any data in this case, just
      ** create a Fts3SegReader to scan the single leaf. 
      */
      rc = sqlite3Fts3SegReaderNew(p, iAge, 0, 0, 0, zRoot, nRoot, &pNew);
    }else{
      sqlite3_int64 i1;           /* First leaf that may contain zTerm */
      sqlite3_int64 i2;           /* Final leaf that may contain zTerm */
      rc = fts3SelectLeaf(p, zTerm, nTerm, zRoot, nRoot, &i1, (isPrefix?&i2:0));
      if( isPrefix==0 ) i2 = i1;
      if( rc==SQLITE_OK ){
        rc = sqlite3Fts3SegReaderNew(p, iAge, i1, i2, 0, 0, 0, &pNew);
      }
    }
    assert( (pNew==0)==(rc!=SQLITE_OK) );

    /* If a new Fts3SegReader was allocated, add it to the array. */
    if( rc==SQLITE_OK ){
      rc = fts3SegReaderArrayAdd(&pArray, pNew);
................................................................................
    while( p<aEnd ){
      sqlite3_int64 delta;
      p += sqlite3Fts3GetVarint(p, &delta);
      fts3PoslistCopy(0, &p);
      pOut += sqlite3Fts3PutVarint(pOut, delta);
    }

    *pnList = (pOut - aList);
  }
}

/* 
** Return a DocList corresponding to the phrase *pPhrase.
**
** If this function returns SQLITE_OK, but *pnOut is set to a negative value,
................................................................................
        if( rc!=SQLITE_OK ) return rc;
      }
    }
  }

  for(ii=0; ii<pPhrase->nToken; ii++){
    Fts3PhraseToken *pTok;        /* Token to find doclist for */
    int iTok;                     /* The token being queried this iteration */
    char *pList;                  /* Pointer to token doclist */
    int nList;                    /* Size of buffer at pList */

    /* Select a token to process. If this is an xFilter() call, then tokens 
    ** are processed in order from least to most costly. Otherwise, tokens 
    ** are processed in the order in which they occur in the phrase.
    */
    if( pCsr->eEvalmode==FTS3_EVAL_MATCHINFO ){
      assert( isReqPos );
................................................................................
        break;
      }
    }

    if( pCsr->eEvalmode==FTS3_EVAL_NEXT && pTok->pDeferred ){
      rc = fts3DeferredTermSelect(pTok->pDeferred, isTermPos, &nList, &pList);
    }else{
      assert( pTok->pArray );
      rc = fts3TermSelect(p, pTok, iCol, isTermPos, &nList, &pList);

      pTok->bFulltext = 1;
    }
    assert( rc!=SQLITE_OK || pCsr->eEvalmode || pTok->pArray==0 );
    if( rc!=SQLITE_OK ) break;

    if( isFirst ){
      pOut = pList;
................................................................................
static int fts3ExprCost(Fts3Expr *pExpr){
  int nCost;                      /* Return value */
  if( pExpr->eType==FTSQUERY_PHRASE ){
    Fts3Phrase *pPhrase = pExpr->pPhrase;
    int ii;
    nCost = 0;
    for(ii=0; ii<pPhrase->nToken; ii++){


      nCost += pPhrase->aToken[ii].pArray->nCost;

    }
  }else{
    nCost = fts3ExprCost(pExpr->pLeft) + fts3ExprCost(pExpr->pRight);
  }
  return nCost;
}

................................................................................
  ExprAndCost **ppExprCost        /* OUT: Write to *ppExprCost */
){
  if( pExpr->eType==FTSQUERY_AND ){
    fts3ExprAssignCosts(pExpr->pLeft, ppExprCost);
    fts3ExprAssignCosts(pExpr->pRight, ppExprCost);
  }else{
    (*ppExprCost)->pExpr = pExpr;
    (*ppExprCost)->nCost = fts3ExprCost(pExpr);;
    (*ppExprCost)++;
  }
}

/*
** Evaluate the full-text expression pExpr against FTS3 table pTab. Store
** the resulting doclist in *paOut and *pnOut. This routine mallocs for
................................................................................
              );
              sqlite3_free(aNew);
            }
          }
        }
      }


      *paOut = aRet;
      *pnOut = nRet;




      sqlite3_free(aExpr);
      fts3ExprFreeSegReaders(pExpr);

    }else{
      char *aLeft;
      char *aRight;
      int nLeft;
................................................................................
          }
        }
      }
      sqlite3_free(aRight);
    }
  }


  return rc;
}

/*
** This function is called from within xNext() for each row visited by
** an FTS3 query. If evaluating the FTS3 query expression within xFilter()
** was able to determine the exact set of matching rows, this function sets
................................................................................
*/
static void fts3MatchinfoFunc(
  sqlite3_context *pContext,      /* SQLite function call context */
  int nVal,                       /* Size of argument array */
  sqlite3_value **apVal           /* Array of arguments */
){
  Fts3Cursor *pCsr;               /* Cursor handle passed through apVal[0] */
  assert( nVal==1 );
  if( SQLITE_OK==fts3FunctionArg(pContext, "matchinfo", apVal[0], &pCsr) ){




    sqlite3Fts3Matchinfo(pContext, pCsr);
  }
}

/*
** This routine implements the xFindFunction method for the FTS3
** virtual table.
*/
................................................................................
  ** module with sqlite.
  */
  if( SQLITE_OK==rc 
   && SQLITE_OK==(rc = sqlite3Fts3InitHashTable(db, pHash, "fts3_tokenizer"))
   && SQLITE_OK==(rc = sqlite3_overload_function(db, "snippet", -1))
   && SQLITE_OK==(rc = sqlite3_overload_function(db, "offsets", 1))
   && SQLITE_OK==(rc = sqlite3_overload_function(db, "matchinfo", 1))

   && SQLITE_OK==(rc = sqlite3_overload_function(db, "optimize", 1))
  ){
    rc = sqlite3_create_module_v2(
        db, "fts3", &fts3Module, (void *)pHash, hashDestroy
    );
    if( rc==SQLITE_OK ){
      rc = sqlite3_create_module_v2(







|







 







|







 







|







 







<







 







|







 







|







 







|







 







|







 







|






|







 







|







 







|
|
|







 







|
|
>







 







>
>
|
>







 







|







 







>
|
|
>
>
>
>







 







>







 







|

>
>
>
>
|







 







>







652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
...
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
...
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
....
1018
1019
1020
1021
1022
1023
1024

1025
1026
1027
1028
1029
1030
1031
....
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
....
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
....
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
....
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
....
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
....
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
....
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
....
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
....
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
....
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
....
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
....
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
....
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
....
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
  const char *zCsr = z;

  while( *zCsr!='=' ){
    if( *zCsr=='\0' ) return 0;
    zCsr++;
  }

  *pnKey = (int)(zCsr-z);
  zValue = sqlite3_mprintf("%s", &zCsr[1]);
  if( zValue ){
    sqlite3Fts3Dequote(zValue);
  }
  *pzValue = zValue;
  return 1;
}
................................................................................
  );

  nDb = (int)strlen(argv[1]) + 1;
  nName = (int)strlen(argv[2]) + 1;

  aCol = (const char **)sqlite3_malloc(sizeof(const char *) * (argc-2) );
  if( !aCol ) return SQLITE_NOMEM;
  memset((void *)aCol, 0, sizeof(const char *) * (argc-2));

  /* Loop through all of the arguments passed by the user to the FTS3/4
  ** module (i.e. all the column names and special arguments). This loop
  ** does the following:
  **
  **   + Figures out the number of columns the FTSX table will have, and
  **     the number of bytes of space that must be allocated to store copies
................................................................................
  fts3DatabasePageSize(&rc, p);

  /* Declare the table schema to SQLite. */
  fts3DeclareVtab(&rc, p);

fts3_init_out:

  sqlite3_free((void *)aCol);
  if( rc!=SQLITE_OK ){
    if( p ){
      fts3DisconnectMethod((sqlite3_vtab *)p);
    }else if( pTokenizer ){
      pTokenizer->pModule->xDestroy(pTokenizer);
    }
  }else{
................................................................................
** If piLast is not NULL, then *piLast is set to the right-most child node
** that heads a sub-tree that may contain a term for which zTerm/nTerm is
** a prefix.
**
** If an OOM error occurs, SQLITE_NOMEM is returned. Otherwise, SQLITE_OK.
*/
static int fts3ScanInteriorNode(

  const char *zTerm,              /* Term to select leaves for */
  int nTerm,                      /* Size of term zTerm in bytes */
  const char *zNode,              /* Buffer containing segment interior node */
  int nNode,                      /* Size of buffer at zNode */
  sqlite3_int64 *piFirst,         /* OUT: Selected child node */
  sqlite3_int64 *piLast           /* OUT: Selected child node */
){
................................................................................
  ** either more than 20 bytes of allocated space following the nNode bytes of
  ** contents, or two zero bytes. Or, if the node is read from the %_segments
  ** table, then there are always 20 bytes of zeroed padding following the
  ** nNode bytes of content (see sqlite3Fts3ReadBlock() for details).
  */
  zCsr += sqlite3Fts3GetVarint(zCsr, &iChild);
  zCsr += sqlite3Fts3GetVarint(zCsr, &iChild);
  if( zCsr>zEnd ){
    return SQLITE_CORRUPT;
  }
  
  while( zCsr<zEnd && (piFirst || piLast) ){
    int cmp;                      /* memcmp() result */
    int nSuffix;                  /* Size of term suffix */
    int nPrefix = 0;              /* Size of term prefix */
................................................................................
){
  int rc;                         /* Return code */
  int iHeight;                    /* Height of this node in tree */

  assert( piLeaf || piLeaf2 );

  sqlite3Fts3GetVarint32(zNode, &iHeight);
  rc = fts3ScanInteriorNode(zTerm, nTerm, zNode, nNode, piLeaf, piLeaf2);
  assert( !piLeaf2 || !piLeaf || rc!=SQLITE_OK || (*piLeaf<=*piLeaf2) );

  if( rc==SQLITE_OK && iHeight>1 ){
    char *zBlob = 0;              /* Blob read from %_segments table */
    int nBlob;                    /* Size of zBlob in bytes */

    if( piLeaf && piLeaf2 && (*piLeaf!=*piLeaf2) ){
................................................................................
** Free an Fts3SegReaderArray object. Also free all seg-readers in the
** array (using sqlite3Fts3SegReaderFree()).
*/
static void fts3SegReaderArrayFree(Fts3SegReaderArray *pArray){
  if( pArray ){
    int i;
    for(i=0; i<pArray->nSegment; i++){
      sqlite3Fts3SegReaderFree(pArray->apSegment[i]);
    }
    sqlite3_free(pArray);
  }
}

static int fts3SegReaderArrayAdd(
  Fts3SegReaderArray **ppArray, 
................................................................................

  if( !pArray || pArray->nAlloc==pArray->nSegment ){
    int nNew = (pArray ? pArray->nAlloc+16 : 16);
    pArray = (Fts3SegReaderArray *)sqlite3_realloc(pArray, 
        sizeof(Fts3SegReaderArray) + (nNew-1) * sizeof(Fts3SegReader*)
    );
    if( !pArray ){
      sqlite3Fts3SegReaderFree(pNew);
      return SQLITE_NOMEM;
    }
    if( nNew==16 ){
      pArray->nSegment = 0;
      pArray->nCost = 0;
    }
    pArray->nAlloc = nNew;
................................................................................
    int nRoot = sqlite3_column_bytes(pStmt, 4);
    char const *zRoot = sqlite3_column_blob(pStmt, 4);
    if( sqlite3_column_int64(pStmt, 1)==0 ){
      /* The entire segment is stored on the root node (which must be a
      ** leaf). Do not bother inspecting any data in this case, just
      ** create a Fts3SegReader to scan the single leaf. 
      */
      rc = sqlite3Fts3SegReaderNew(iAge, 0, 0, 0, zRoot, nRoot, &pNew);
    }else{
      sqlite3_int64 i1;           /* First leaf that may contain zTerm */
      sqlite3_int64 i2;           /* Final leaf that may contain zTerm */
      rc = fts3SelectLeaf(p, zTerm, nTerm, zRoot, nRoot, &i1, (isPrefix?&i2:0));
      if( isPrefix==0 ) i2 = i1;
      if( rc==SQLITE_OK ){
        rc = sqlite3Fts3SegReaderNew(iAge, i1, i2, 0, 0, 0, &pNew);
      }
    }
    assert( (pNew==0)==(rc!=SQLITE_OK) );

    /* If a new Fts3SegReader was allocated, add it to the array. */
    if( rc==SQLITE_OK ){
      rc = fts3SegReaderArrayAdd(&pArray, pNew);
................................................................................
    while( p<aEnd ){
      sqlite3_int64 delta;
      p += sqlite3Fts3GetVarint(p, &delta);
      fts3PoslistCopy(0, &p);
      pOut += sqlite3Fts3PutVarint(pOut, delta);
    }

    *pnList = (int)(pOut - aList);
  }
}

/* 
** Return a DocList corresponding to the phrase *pPhrase.
**
** If this function returns SQLITE_OK, but *pnOut is set to a negative value,
................................................................................
        if( rc!=SQLITE_OK ) return rc;
      }
    }
  }

  for(ii=0; ii<pPhrase->nToken; ii++){
    Fts3PhraseToken *pTok;        /* Token to find doclist for */
    int iTok = 0;                 /* The token being queried this iteration */
    char *pList = 0;              /* Pointer to token doclist */
    int nList = 0;                /* Size of buffer at pList */

    /* Select a token to process. If this is an xFilter() call, then tokens 
    ** are processed in order from least to most costly. Otherwise, tokens 
    ** are processed in the order in which they occur in the phrase.
    */
    if( pCsr->eEvalmode==FTS3_EVAL_MATCHINFO ){
      assert( isReqPos );
................................................................................
        break;
      }
    }

    if( pCsr->eEvalmode==FTS3_EVAL_NEXT && pTok->pDeferred ){
      rc = fts3DeferredTermSelect(pTok->pDeferred, isTermPos, &nList, &pList);
    }else{
      if( pTok->pArray ){
        rc = fts3TermSelect(p, pTok, iCol, isTermPos, &nList, &pList);
      }
      pTok->bFulltext = 1;
    }
    assert( rc!=SQLITE_OK || pCsr->eEvalmode || pTok->pArray==0 );
    if( rc!=SQLITE_OK ) break;

    if( isFirst ){
      pOut = pList;
................................................................................
static int fts3ExprCost(Fts3Expr *pExpr){
  int nCost;                      /* Return value */
  if( pExpr->eType==FTSQUERY_PHRASE ){
    Fts3Phrase *pPhrase = pExpr->pPhrase;
    int ii;
    nCost = 0;
    for(ii=0; ii<pPhrase->nToken; ii++){
      Fts3SegReaderArray *pArray = pPhrase->aToken[ii].pArray;
      if( pArray ){
        nCost += pPhrase->aToken[ii].pArray->nCost;
      }
    }
  }else{
    nCost = fts3ExprCost(pExpr->pLeft) + fts3ExprCost(pExpr->pRight);
  }
  return nCost;
}

................................................................................
  ExprAndCost **ppExprCost        /* OUT: Write to *ppExprCost */
){
  if( pExpr->eType==FTSQUERY_AND ){
    fts3ExprAssignCosts(pExpr->pLeft, ppExprCost);
    fts3ExprAssignCosts(pExpr->pRight, ppExprCost);
  }else{
    (*ppExprCost)->pExpr = pExpr;
    (*ppExprCost)->nCost = fts3ExprCost(pExpr);
    (*ppExprCost)++;
  }
}

/*
** Evaluate the full-text expression pExpr against FTS3 table pTab. Store
** the resulting doclist in *paOut and *pnOut. This routine mallocs for
................................................................................
              );
              sqlite3_free(aNew);
            }
          }
        }
      }

      if( rc==SQLITE_OK ){
        *paOut = aRet;
        *pnOut = nRet;
      }else{
        assert( *paOut==0 );
        sqlite3_free(aRet);
      }
      sqlite3_free(aExpr);
      fts3ExprFreeSegReaders(pExpr);

    }else{
      char *aLeft;
      char *aRight;
      int nLeft;
................................................................................
          }
        }
      }
      sqlite3_free(aRight);
    }
  }

  assert( rc==SQLITE_OK || *paOut==0 );
  return rc;
}

/*
** This function is called from within xNext() for each row visited by
** an FTS3 query. If evaluating the FTS3 query expression within xFilter()
** was able to determine the exact set of matching rows, this function sets
................................................................................
*/
static void fts3MatchinfoFunc(
  sqlite3_context *pContext,      /* SQLite function call context */
  int nVal,                       /* Size of argument array */
  sqlite3_value **apVal           /* Array of arguments */
){
  Fts3Cursor *pCsr;               /* Cursor handle passed through apVal[0] */
  assert( nVal==1 || nVal==2 );
  if( SQLITE_OK==fts3FunctionArg(pContext, "matchinfo", apVal[0], &pCsr) ){
    const char *zArg = 0;
    if( nVal>1 ){
      zArg = (const char *)sqlite3_value_text(apVal[1]);
    }
    sqlite3Fts3Matchinfo(pContext, pCsr, zArg);
  }
}

/*
** This routine implements the xFindFunction method for the FTS3
** virtual table.
*/
................................................................................
  ** module with sqlite.
  */
  if( SQLITE_OK==rc 
   && SQLITE_OK==(rc = sqlite3Fts3InitHashTable(db, pHash, "fts3_tokenizer"))
   && SQLITE_OK==(rc = sqlite3_overload_function(db, "snippet", -1))
   && SQLITE_OK==(rc = sqlite3_overload_function(db, "offsets", 1))
   && SQLITE_OK==(rc = sqlite3_overload_function(db, "matchinfo", 1))
   && SQLITE_OK==(rc = sqlite3_overload_function(db, "matchinfo", 2))
   && SQLITE_OK==(rc = sqlite3_overload_function(db, "optimize", 1))
  ){
    rc = sqlite3_create_module_v2(
        db, "fts3", &fts3Module, (void *)pHash, hashDestroy
    );
    if( rc==SQLITE_OK ){
      rc = sqlite3_create_module_v2(

Changes to ext/fts3/fts3Int.h.

158
159
160
161
162
163
164

165
166
167
168
169
170
171
172
173





174
175
176
177
178
179
180
...
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294



295
296
297
298
299
300
301
...
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
struct Fts3Cursor {
  sqlite3_vtab_cursor base;       /* Base class used by SQLite core */
  i16 eSearch;                    /* Search strategy (see below) */
  u8 isEof;                       /* True if at End Of Results */
  u8 isRequireSeek;               /* True if must seek pStmt to %_content row */
  sqlite3_stmt *pStmt;            /* Prepared statement in use by the cursor */
  Fts3Expr *pExpr;                /* Parsed MATCH query string */

  Fts3DeferredToken *pDeferred;   /* Deferred search tokens, if any */
  sqlite3_int64 iPrevId;          /* Previous id read from aDoclist */
  char *pNextId;                  /* Pointer into the body of aDoclist */
  char *aDoclist;                 /* List of docids for full-text queries */
  int nDoclist;                   /* Size of buffer at aDoclist */
  int isMatchinfoNeeded;          /* True when aMatchinfo[] needs filling in */
  u32 *aMatchinfo;                /* Information about most recent match */
  int eEvalmode;                  /* An FTS3_EVAL_XX constant */
  int nRowAvg;                    /* Average size of database rows, in pages */





};

#define FTS3_EVAL_FILTER    0
#define FTS3_EVAL_NEXT      1
#define FTS3_EVAL_MATCHINFO 2

/*
................................................................................


/* fts3_write.c */
int sqlite3Fts3UpdateMethod(sqlite3_vtab*,int,sqlite3_value**,sqlite3_int64*);
int sqlite3Fts3PendingTermsFlush(Fts3Table *);
void sqlite3Fts3PendingTermsClear(Fts3Table *);
int sqlite3Fts3Optimize(Fts3Table *);
int sqlite3Fts3SegReaderNew(Fts3Table *,int, sqlite3_int64,
  sqlite3_int64, sqlite3_int64, const char *, int, Fts3SegReader**);
int sqlite3Fts3SegReaderPending(Fts3Table*,const char*,int,int,Fts3SegReader**);
void sqlite3Fts3SegReaderFree(Fts3Table *, Fts3SegReader *);
int sqlite3Fts3SegReaderIterate(
  Fts3Table *, Fts3SegReader **, int, Fts3SegFilter *,
  int (*)(Fts3Table *, void *, char *, int, char *, int),  void *
);
int sqlite3Fts3SegReaderCost(Fts3Cursor *, Fts3SegReader *, int *);
int sqlite3Fts3AllSegdirs(Fts3Table*, sqlite3_stmt **);
int sqlite3Fts3MatchinfoDocsizeLocal(Fts3Cursor*, u32*);
int sqlite3Fts3MatchinfoDocsizeGlobal(Fts3Cursor*, u32*);
int sqlite3Fts3ReadLock(Fts3Table *);
int sqlite3Fts3ReadBlock(Fts3Table*, sqlite3_int64, char **, int*);




void sqlite3Fts3FreeDeferredTokens(Fts3Cursor *);
int sqlite3Fts3DeferToken(Fts3Cursor *, Fts3PhraseToken *, int);
int sqlite3Fts3CacheDeferredDoclists(Fts3Cursor *);
void sqlite3Fts3FreeDeferredDoclists(Fts3Cursor *);
char *sqlite3Fts3DeferredDoclist(Fts3DeferredToken *, int *);

void sqlite3Fts3SegmentsClose(Fts3Table *);
................................................................................
int sqlite3Fts3IsIdChar(char);

/* fts3_snippet.c */
void sqlite3Fts3Offsets(sqlite3_context*, Fts3Cursor*);
void sqlite3Fts3Snippet(sqlite3_context *, Fts3Cursor *, const char *,
  const char *, const char *, int, int
);
void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *);

/* fts3_expr.c */
int sqlite3Fts3ExprParse(sqlite3_tokenizer *, 
  char **, int, int, const char *, int, Fts3Expr **
);
void sqlite3Fts3ExprFree(Fts3Expr *);
#ifdef SQLITE_TEST
int sqlite3Fts3ExprInitTestInterface(sqlite3 *db);
#endif

#endif /* _FTSINT_H */







>





<
<


>
>
>
>
>







 







|


|






<
<



>
>
>







 







|











158
159
160
161
162
163
164
165
166
167
168
169
170


171
172
173
174
175
176
177
178
179
180
181
182
183
184
...
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293


294
295
296
297
298
299
300
301
302
303
304
305
306
...
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
struct Fts3Cursor {
  sqlite3_vtab_cursor base;       /* Base class used by SQLite core */
  i16 eSearch;                    /* Search strategy (see below) */
  u8 isEof;                       /* True if at End Of Results */
  u8 isRequireSeek;               /* True if must seek pStmt to %_content row */
  sqlite3_stmt *pStmt;            /* Prepared statement in use by the cursor */
  Fts3Expr *pExpr;                /* Parsed MATCH query string */
  int nPhrase;                    /* Number of matchable phrases in query */
  Fts3DeferredToken *pDeferred;   /* Deferred search tokens, if any */
  sqlite3_int64 iPrevId;          /* Previous id read from aDoclist */
  char *pNextId;                  /* Pointer into the body of aDoclist */
  char *aDoclist;                 /* List of docids for full-text queries */
  int nDoclist;                   /* Size of buffer at aDoclist */


  int eEvalmode;                  /* An FTS3_EVAL_XX constant */
  int nRowAvg;                    /* Average size of database rows, in pages */

  int isMatchinfoNeeded;          /* True when aMatchinfo[] needs filling in */
  u32 *aMatchinfo;                /* Information about most recent match */
  int nMatchinfo;                 /* Number of elements in aMatchinfo[] */
  char *zMatchinfo;               /* Matchinfo specification */
};

#define FTS3_EVAL_FILTER    0
#define FTS3_EVAL_NEXT      1
#define FTS3_EVAL_MATCHINFO 2

/*
................................................................................


/* fts3_write.c */
int sqlite3Fts3UpdateMethod(sqlite3_vtab*,int,sqlite3_value**,sqlite3_int64*);
int sqlite3Fts3PendingTermsFlush(Fts3Table *);
void sqlite3Fts3PendingTermsClear(Fts3Table *);
int sqlite3Fts3Optimize(Fts3Table *);
int sqlite3Fts3SegReaderNew(int, sqlite3_int64,
  sqlite3_int64, sqlite3_int64, const char *, int, Fts3SegReader**);
int sqlite3Fts3SegReaderPending(Fts3Table*,const char*,int,int,Fts3SegReader**);
void sqlite3Fts3SegReaderFree(Fts3SegReader *);
int sqlite3Fts3SegReaderIterate(
  Fts3Table *, Fts3SegReader **, int, Fts3SegFilter *,
  int (*)(Fts3Table *, void *, char *, int, char *, int),  void *
);
int sqlite3Fts3SegReaderCost(Fts3Cursor *, Fts3SegReader *, int *);
int sqlite3Fts3AllSegdirs(Fts3Table*, sqlite3_stmt **);


int sqlite3Fts3ReadLock(Fts3Table *);
int sqlite3Fts3ReadBlock(Fts3Table*, sqlite3_int64, char **, int*);

int sqlite3Fts3SelectDoctotal(Fts3Table *, sqlite3_stmt **);
int sqlite3Fts3SelectDocsize(Fts3Table *, sqlite3_int64, sqlite3_stmt **);

void sqlite3Fts3FreeDeferredTokens(Fts3Cursor *);
int sqlite3Fts3DeferToken(Fts3Cursor *, Fts3PhraseToken *, int);
int sqlite3Fts3CacheDeferredDoclists(Fts3Cursor *);
void sqlite3Fts3FreeDeferredDoclists(Fts3Cursor *);
char *sqlite3Fts3DeferredDoclist(Fts3DeferredToken *, int *);

void sqlite3Fts3SegmentsClose(Fts3Table *);
................................................................................
int sqlite3Fts3IsIdChar(char);

/* fts3_snippet.c */
void sqlite3Fts3Offsets(sqlite3_context*, Fts3Cursor*);
void sqlite3Fts3Snippet(sqlite3_context *, Fts3Cursor *, const char *,
  const char *, const char *, int, int
);
void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *, const char *);

/* fts3_expr.c */
int sqlite3Fts3ExprParse(sqlite3_tokenizer *, 
  char **, int, int, const char *, int, Fts3Expr **
);
void sqlite3Fts3ExprFree(Fts3Expr *);
#ifdef SQLITE_TEST
int sqlite3Fts3ExprInitTestInterface(sqlite3 *db);
#endif

#endif /* _FTSINT_H */

Changes to ext/fts3/fts3_expr.c.

401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
...
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
...
853
854
855
856
857
858
859

860
861
862
863
864
865
866
...
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
    }
  }

  /* Check for an open bracket. */
  if( sqlite3_fts3_enable_parentheses ){
    if( *zInput=='(' ){
      int nConsumed;
      int rc;
      pParse->nNest++;
      rc = fts3ExprParse(pParse, &zInput[1], nInput-1, ppExpr, &nConsumed);
      if( rc==SQLITE_OK && !*ppExpr ){
        rc = SQLITE_DONE;
      }
      *pnConsumed = (int)((zInput - z) + 1 + nConsumed);
      return rc;
................................................................................
    }
  }

  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>, ...);
................................................................................
  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;
................................................................................
  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);
}







<







 







|
|
|
|
>
>
>
>

|




>
|
|
>
|
|
>

|



|


|


|


|



|
|
|
<

<
|
>
>
|
<







 







>







 







|
>
>

<
<
<
<
<
<

<
>
>

>
>







401
402
403
404
405
406
407

408
409
410
411
412
413
414
...
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
...
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
...
901
902
903
904
905
906
907
908
909
910
911






912

913
914
915
916
917
918
919
920
921
922
923
924
    }
  }

  /* Check for an open bracket. */
  if( sqlite3_fts3_enable_parentheses ){
    if( *zInput=='(' ){
      int nConsumed;

      pParse->nNest++;
      rc = fts3ExprParse(pParse, &zInput[1], nInput-1, ppExpr, &nConsumed);
      if( rc==SQLITE_OK && !*ppExpr ){
        rc = SQLITE_DONE;
      }
      *pnConsumed = (int)((zInput - z) + 1 + nConsumed);
      return rc;
................................................................................
    }
  }

  return sqlite3_finalize(pStmt);
}

/*
** Return a pointer to a buffer containing a text representation of the
** expression passed as the first argument. The buffer is obtained from
** sqlite3_malloc(). It is the responsibility of the caller to use 
** sqlite3_free() to release the memory. If an OOM condition is encountered,
** NULL is returned.
**
** If the second argument is not NULL, then its contents are prepended to 
** the returned expression text and then freed using sqlite3_free().
*/
static char *exprToString(Fts3Expr *pExpr, char *zBuf){
  switch( pExpr->eType ){
    case FTSQUERY_PHRASE: {
      Fts3Phrase *pPhrase = pExpr->pPhrase;
      int i;
      zBuf = sqlite3_mprintf(
          "%zPHRASE %d %d", zBuf, pPhrase->iColumn, pPhrase->isNot);
      for(i=0; zBuf && i<pPhrase->nToken; i++){
        zBuf = sqlite3_mprintf("%z %.*s%s", zBuf, 
            pPhrase->aToken[i].n, pPhrase->aToken[i].z,
            (pPhrase->aToken[i].isPrefix?"+":"")
        );
      }
      return zBuf;
    }

    case FTSQUERY_NEAR:
      zBuf = sqlite3_mprintf("%zNEAR/%d ", zBuf, pExpr->nNear);
      break;
    case FTSQUERY_NOT:
      zBuf = sqlite3_mprintf("%zNOT ", zBuf);
      break;
    case FTSQUERY_AND:
      zBuf = sqlite3_mprintf("%zAND ", zBuf);
      break;
    case FTSQUERY_OR:
      zBuf = sqlite3_mprintf("%zOR ", zBuf);
      break;
  }

  if( zBuf ) zBuf = sqlite3_mprintf("%z{", zBuf);
  if( zBuf ) zBuf = exprToString(pExpr->pLeft, zBuf);
  if( zBuf ) zBuf = sqlite3_mprintf("%z} {", zBuf);



  if( zBuf ) zBuf = exprToString(pExpr->pRight, zBuf);
  if( zBuf ) zBuf = sqlite3_mprintf("%z}", zBuf);

  return 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>, ...);
................................................................................
  int rc;
  char **azCol = 0;
  const char *zExpr;
  int nExpr;
  int nCol;
  int ii;
  Fts3Expr *pExpr;
  char *zBuf = 0;
  sqlite3 *db = sqlite3_context_db_handle(context);

  if( argc<3 ){
    sqlite3_result_error(context, 
        "Usage: fts3_exprtest(tokenizer, expr, col1, ...", -1
    );
    return;
................................................................................
  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_OK && rc!=SQLITE_NOMEM ){
    sqlite3_result_error(context, "Error parsing expression", -1);
  }else if( rc==SQLITE_NOMEM || !(zBuf = exprToString(pExpr, 0)) ){
    sqlite3_result_error_nomem(context);






  }else{

    sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
    sqlite3_free(zBuf);
  }

  sqlite3Fts3ExprFree(pExpr);

exprtest_out:
  if( pModule && pTokenizer ){
    rc = pModule->xDestroy(pTokenizer);
  }
  sqlite3_free(azCol);
}

Changes to ext/fts3/fts3_porter.c.

339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
** Stemming never increases the length of the word.  So there is
** no chance of overflowing the zOut buffer.
*/
static void porter_stemmer(const char *zIn, int nIn, char *zOut, int *pnOut){
  int i, j;
  char zReverse[28];
  char *z, *z2;
  if( nIn<3 || nIn>=sizeof(zReverse)-7 ){
    /* The word is too big or too small for the porter stemmer.
    ** Fallback to the copy stemmer */
    copy_stemmer(zIn, nIn, zOut, pnOut);
    return;
  }
  for(i=0, j=sizeof(zReverse)-6; i<nIn; i++, j--){
    char c = zIn[i];







|







339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
** Stemming never increases the length of the word.  So there is
** no chance of overflowing the zOut buffer.
*/
static void porter_stemmer(const char *zIn, int nIn, char *zOut, int *pnOut){
  int i, j;
  char zReverse[28];
  char *z, *z2;
  if( nIn<3 || nIn>=(int)sizeof(zReverse)-7 ){
    /* The word is too big or too small for the porter stemmer.
    ** Fallback to the copy stemmer */
    copy_stemmer(zIn, nIn, zOut, pnOut);
    return;
  }
  for(i=0, j=sizeof(zReverse)-6; i<nIn; i++, j--){
    char c = zIn[i];

Changes to ext/fts3/fts3_snippet.c.

13
14
15
16
17
18
19
















20
21
22
23
24
25
26
..
66
67
68
69
70
71
72


73
74
75
76
77
78
79
...
266
267
268
269
270
271
272












273
274
275
276
277
278
279
...
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
...
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
...
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
....
1207
1208
1209
1210
1211
1212
1213
1214





1215

















1216
1217
1218
1219


1220
1221

1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234

#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)

#include "fts3Int.h"
#include <string.h>
#include <assert.h>


















/*
** Used as an fts3ExprIterate() context when loading phrase doclists to
** Fts3Expr.aDoclist[]/nDoclist.
*/
typedef struct LoadDoclistCtx LoadDoclistCtx;
struct LoadDoclistCtx {
................................................................................
** This type is used as an fts3ExprIterate() context object while 
** accumulating the data returned by the matchinfo() function.
*/
typedef struct MatchInfo MatchInfo;
struct MatchInfo {
  Fts3Cursor *pCursor;            /* FTS3 Cursor */
  int nCol;                       /* Number of columns in table */


  u32 *aMatchinfo;                /* Pre-allocated buffer */
};



/*
** The snippet() and offsets() functions both return text values. An instance
................................................................................
  if( rc==SQLITE_OK ){
    (void)fts3ExprIterate(pCsr->pExpr, fts3ExprLoadDoclistsCb2, 0);
  }
  if( pnPhrase ) *pnPhrase = sCtx.nPhrase;
  if( pnToken ) *pnToken = sCtx.nToken;
  return rc;
}













/*
** Advance the position list iterator specified by the first two 
** arguments so that it points to the first element with a value greater
** than or equal to parameter iNext.
*/
static void fts3SnippetAdvance(char **ppIter, int *piIter, int iNext){
................................................................................
  }
  pCsr++;
  *pp = pCsr;
}

/*
** fts3ExprIterate() callback used to collect the "global" matchinfo stats
** for a single query. The "global" stats are those elements of the matchinfo



** array that are constant for all rows returned by the current query.



















*/
static int fts3ExprGlobalMatchinfoCb(
  Fts3Expr *pExpr,                /* Phrase expression node */
  int iPhrase,                    /* Phrase number (numbered from zero) */
  void *pCtx                      /* Pointer to MatchInfo structure */
){
  MatchInfo *p = (MatchInfo *)pCtx;
  Fts3Cursor *pCsr = p->pCursor;
  char *pIter;
  char *pEnd;
  char *pFree = 0;
  const int iStart = 2 + (iPhrase * p->nCol * 3) + 1;

  assert( pExpr->isLoaded );
  assert( pExpr->eType==FTSQUERY_PHRASE );

  if( pCsr->pDeferred ){
    Fts3Phrase *pPhrase = pExpr->pPhrase;
    int ii;
................................................................................
    if( ii<pPhrase->nToken ){
      int nFree = 0;
      int rc = sqlite3Fts3ExprLoadFtDoclist(pCsr, pExpr, &pFree, &nFree);
      if( rc!=SQLITE_OK ) return rc;
      pIter = pFree;
      pEnd = &pFree[nFree];
    }else{
      int nDoc = p->aMatchinfo[2 + 3*p->nCol*p->aMatchinfo[0]];
      for(ii=0; ii<p->nCol; ii++){
        p->aMatchinfo[iStart + ii*3] = nDoc;
        p->aMatchinfo[iStart + ii*3 + 1] = nDoc;
      }
      return SQLITE_OK;
    }
  }else{
    pIter = pExpr->aDoclist;
    pEnd = &pExpr->aDoclist[pExpr->nDoclist];
  }

  /* Fill in the global hit count matrix row for this phrase. */
  while( pIter<pEnd ){
    while( *pIter++ & 0x80 );      /* Skip past docid. */
    fts3LoadColumnlistCounts(&pIter, &p->aMatchinfo[iStart], 1);
  }

  sqlite3_free(pFree);
  return SQLITE_OK;
}

/*
** fts3ExprIterate() callback used to collect the "local" matchinfo stats
** for a single query. The "local" stats are those elements of the matchinfo
** array that are different for each row returned by the query.
*/
static int fts3ExprLocalMatchinfoCb(
  Fts3Expr *pExpr,                /* Phrase expression node */
  int iPhrase,                    /* Phrase number */
  void *pCtx                      /* Pointer to MatchInfo structure */
){
  MatchInfo *p = (MatchInfo *)pCtx;

  if( pExpr->aDoclist ){
    char *pCsr;
    int iStart = 2 + (iPhrase * p->nCol * 3);
    int i;

    for(i=0; i<p->nCol; i++) p->aMatchinfo[iStart+i*3] = 0;

    pCsr = sqlite3Fts3FindPositions(pExpr, p->pCursor->iPrevId, -1);
    if( pCsr ){
      fts3LoadColumnlistCounts(&pCsr, &p->aMatchinfo[iStart], 0);
    }
  }

  return SQLITE_OK;
}





































































/*


































































































































































































































































** Populate pCsr->aMatchinfo[] with data for the current row. The 
** 'matchinfo' data is an array of 32-bit unsigned integers (C type u32).
*/
static int fts3GetMatchinfo(Fts3Cursor *pCsr){



  MatchInfo sInfo;
  Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
  int rc = SQLITE_OK;



  sInfo.pCursor = pCsr;
  sInfo.nCol = pTab->nColumn;





  if( pCsr->aMatchinfo==0 ){





    /* If Fts3Cursor.aMatchinfo[] is NULL, then this is the first time the
    ** matchinfo function has been called for this query. In this case 
    ** allocate the array used to accumulate the matchinfo data and
    ** initialize those elements that are constant for every row.
    */
    int nPhrase;                  /* Number of phrases */

    int nMatchinfo;               /* Number of u32 elements in match-info */



    /* Load doclists for each phrase in the query. */
    rc = fts3ExprLoadDoclists(pCsr, &nPhrase, 0);
    if( rc!=SQLITE_OK ){
      return rc;



    }
    nMatchinfo = 2 + 3*sInfo.nCol*nPhrase;
    if( pTab->bHasDocsize ){
      nMatchinfo += 1 + 2*pTab->nColumn;



    }



    sInfo.aMatchinfo = (u32 *)sqlite3_malloc(sizeof(u32)*nMatchinfo);
    if( !sInfo.aMatchinfo ){ 
      return SQLITE_NOMEM;
    }



    memset(sInfo.aMatchinfo, 0, sizeof(u32)*nMatchinfo);

    /* First element of match-info is the number of phrases in the query */
    sInfo.aMatchinfo[0] = nPhrase;
    sInfo.aMatchinfo[1] = sInfo.nCol;
    if( pTab->bHasDocsize ){
      int ofst = 2 + 3*sInfo.aMatchinfo[0]*sInfo.aMatchinfo[1];
      rc = sqlite3Fts3MatchinfoDocsizeGlobal(pCsr, &sInfo.aMatchinfo[ofst]);
    }
    (void)fts3ExprIterate(pCsr->pExpr, fts3ExprGlobalMatchinfoCb,(void*)&sInfo);
    pCsr->aMatchinfo = sInfo.aMatchinfo;
    pCsr->isMatchinfoNeeded = 1;

  }

  sInfo.aMatchinfo = pCsr->aMatchinfo;

  if( rc==SQLITE_OK && pCsr->isMatchinfoNeeded ){
    (void)fts3ExprIterate(pCsr->pExpr, fts3ExprLocalMatchinfoCb, (void*)&sInfo);
    if( pTab->bHasDocsize ){
      int ofst = 2 + 3*sInfo.aMatchinfo[0]*sInfo.aMatchinfo[1];
      rc = sqlite3Fts3MatchinfoDocsizeLocal(pCsr, &sInfo.aMatchinfo[ofst]);
    }
    pCsr->isMatchinfoNeeded = 0;
  }

  return SQLITE_OK;
}

/*
** Implementation of snippet() function.
*/
void sqlite3Fts3Snippet(
  sqlite3_context *pCtx,          /* SQLite function call context */
................................................................................
      memset(pFragment, 0, sizeof(*pFragment));

      /* Loop through all columns of the table being considered for snippets.
      ** If the iCol argument to this function was negative, this means all
      ** columns of the FTS3 table. Otherwise, only column iCol is considered.
      */
      for(iRead=0; iRead<pTab->nColumn; iRead++){
        SnippetFragment sF;
        int iS;
        if( iCol>=0 && iRead!=iCol ) continue;

        /* Find the best snippet of nFToken tokens in column iRead. */
        rc = fts3BestSnippet(nFToken, pCsr, iRead, mCovered, &mSeen, &sF, &iS);
        if( rc!=SQLITE_OK ){
          goto snippet_out;
................................................................................
  }
  return;
}

/*
** Implementation of matchinfo() function.
*/
void sqlite3Fts3Matchinfo(sqlite3_context *pContext, Fts3Cursor *pCsr){





  int rc;

















  if( !pCsr->pExpr ){
    sqlite3_result_blob(pContext, "", 0, SQLITE_STATIC);
    return;
  }


  rc = fts3GetMatchinfo(pCsr);
  sqlite3Fts3SegmentsClose((Fts3Table *)pCsr->base.pVtab );

  if( rc!=SQLITE_OK ){
    sqlite3_result_error_code(pContext, rc);
  }else{
    Fts3Table *pTab = (Fts3Table*)pCsr->base.pVtab;
    int n = sizeof(u32)*(2+pCsr->aMatchinfo[0]*pCsr->aMatchinfo[1]*3);
    if( pTab->bHasDocsize ){
      n += sizeof(u32)*(1 + 2*pTab->nColumn);
    }
    sqlite3_result_blob(pContext, pCsr->aMatchinfo, n, SQLITE_TRANSIENT);
  }
}

#endif







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







 







>
>







 







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







 







|
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

|









|







 







|
|
|
|











|







|
|


|








|













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

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



|
>
>
>



>

>



>
>
>
>
|
>
>
>
>
>
|
|
|
|
|
<
>
|
>
>

<
<
<
<
>
>
>
|
<
<
<
>
>
>


>
>
|
<
|
|
>
>
>
|
<
<
<
<
<
<
<
<
<
<

>



>
|
<
|
<
<
<



|







 







|







 







|
>
>
>
>
>

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




>
>
|
|
>



|
<
<
<
<





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
..
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
...
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
...
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
...
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
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
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
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276

1277
1278
1279
1280
1281




1282
1283
1284
1285



1286
1287
1288
1289
1290
1291
1292
1293

1294
1295
1296
1297
1298
1299










1300
1301
1302
1303
1304
1305
1306

1307



1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
....
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
....
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635




1636
1637
1638
1639
1640

#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)

#include "fts3Int.h"
#include <string.h>
#include <assert.h>

/*
** Characters that may appear in the second argument to matchinfo().
*/
#define FTS3_MATCHINFO_NPHRASE   'p'        /* 1 value */
#define FTS3_MATCHINFO_NCOL      'c'        /* 1 value */
#define FTS3_MATCHINFO_NDOC      'n'        /* 1 value */
#define FTS3_MATCHINFO_AVGLENGTH 'a'        /* nCol values */
#define FTS3_MATCHINFO_LENGTH    'l'        /* nCol values */
#define FTS3_MATCHINFO_LCS       's'        /* nCol values */
#define FTS3_MATCHINFO_HITS      'x'        /* 3*nCol*nPhrase values */

/*
** The default value for the second argument to matchinfo(). 
*/
#define FTS3_MATCHINFO_DEFAULT   "pcx"


/*
** Used as an fts3ExprIterate() context when loading phrase doclists to
** Fts3Expr.aDoclist[]/nDoclist.
*/
typedef struct LoadDoclistCtx LoadDoclistCtx;
struct LoadDoclistCtx {
................................................................................
** This type is used as an fts3ExprIterate() context object while 
** accumulating the data returned by the matchinfo() function.
*/
typedef struct MatchInfo MatchInfo;
struct MatchInfo {
  Fts3Cursor *pCursor;            /* FTS3 Cursor */
  int nCol;                       /* Number of columns in table */
  int nPhrase;                    /* Number of matchable phrases in query */
  sqlite3_int64 nDoc;             /* Number of docs in database */
  u32 *aMatchinfo;                /* Pre-allocated buffer */
};



/*
** The snippet() and offsets() functions both return text values. An instance
................................................................................
  if( rc==SQLITE_OK ){
    (void)fts3ExprIterate(pCsr->pExpr, fts3ExprLoadDoclistsCb2, 0);
  }
  if( pnPhrase ) *pnPhrase = sCtx.nPhrase;
  if( pnToken ) *pnToken = sCtx.nToken;
  return rc;
}

static int fts3ExprPhraseCountCb(Fts3Expr *pExpr, int iPhrase, void *ctx){
  (*(int *)ctx)++;
  UNUSED_PARAMETER(pExpr);
  UNUSED_PARAMETER(iPhrase);
  return SQLITE_OK;
}
static int fts3ExprPhraseCount(Fts3Expr *pExpr){
  int nPhrase = 0;
  (void)fts3ExprIterate(pExpr, fts3ExprPhraseCountCb, (void *)&nPhrase);
  return nPhrase;
}

/*
** Advance the position list iterator specified by the first two 
** arguments so that it points to the first element with a value greater
** than or equal to parameter iNext.
*/
static void fts3SnippetAdvance(char **ppIter, int *piIter, int iNext){
................................................................................
  }
  pCsr++;
  *pp = pCsr;
}

/*
** fts3ExprIterate() callback used to collect the "global" matchinfo stats
** for a single query. 
**
** fts3ExprIterate() callback to load the 'global' elements of a
** FTS3_MATCHINFO_HITS matchinfo array. The global stats are those elements 
** of the matchinfo array that are constant for all rows returned by the 
** current query.
**
** Argument pCtx is actually a pointer to a struct of type MatchInfo. This
** function populates Matchinfo.aMatchinfo[] as follows:
**
**   for(iCol=0; iCol<nCol; iCol++){
**     aMatchinfo[3*iPhrase*nCol + 3*iCol + 1] = X;
**     aMatchinfo[3*iPhrase*nCol + 3*iCol + 2] = Y;
**   }
**
** where X is the number of matches for phrase iPhrase is column iCol of all
** rows of the table. Y is the number of rows for which column iCol contains
** at least one instance of phrase iPhrase.
**
** If the phrase pExpr consists entirely of deferred tokens, then all X and
** Y values are set to nDoc, where nDoc is the number of documents in the 
** file system. This is done because the full-text index doclist is required
** to calculate these values properly, and the full-text index doclist is
** not available for deferred tokens.
*/
static int fts3ExprGlobalHitsCb(
  Fts3Expr *pExpr,                /* Phrase expression node */
  int iPhrase,                    /* Phrase number (numbered from zero) */
  void *pCtx                      /* Pointer to MatchInfo structure */
){
  MatchInfo *p = (MatchInfo *)pCtx;
  Fts3Cursor *pCsr = p->pCursor;
  char *pIter;
  char *pEnd;
  char *pFree = 0;
  u32 *aOut = &p->aMatchinfo[3*iPhrase*p->nCol];

  assert( pExpr->isLoaded );
  assert( pExpr->eType==FTSQUERY_PHRASE );

  if( pCsr->pDeferred ){
    Fts3Phrase *pPhrase = pExpr->pPhrase;
    int ii;
................................................................................
    if( ii<pPhrase->nToken ){
      int nFree = 0;
      int rc = sqlite3Fts3ExprLoadFtDoclist(pCsr, pExpr, &pFree, &nFree);
      if( rc!=SQLITE_OK ) return rc;
      pIter = pFree;
      pEnd = &pFree[nFree];
    }else{
      int iCol;                   /* Column index */
      for(iCol=0; iCol<p->nCol; iCol++){
        aOut[iCol*3 + 1] = (u32)p->nDoc;
        aOut[iCol*3 + 2] = (u32)p->nDoc;
      }
      return SQLITE_OK;
    }
  }else{
    pIter = pExpr->aDoclist;
    pEnd = &pExpr->aDoclist[pExpr->nDoclist];
  }

  /* Fill in the global hit count matrix row for this phrase. */
  while( pIter<pEnd ){
    while( *pIter++ & 0x80 );      /* Skip past docid. */
    fts3LoadColumnlistCounts(&pIter, &aOut[1], 1);
  }

  sqlite3_free(pFree);
  return SQLITE_OK;
}

/*
** fts3ExprIterate() callback used to collect the "local" part of the
** FTS3_MATCHINFO_HITS array. The local stats are those elements of the 
** array that are different for each row returned by the query.
*/
static int fts3ExprLocalHitsCb(
  Fts3Expr *pExpr,                /* Phrase expression node */
  int iPhrase,                    /* Phrase number */
  void *pCtx                      /* Pointer to MatchInfo structure */
){
  MatchInfo *p = (MatchInfo *)pCtx;

  if( pExpr->aDoclist ){
    char *pCsr;
    int iStart = iPhrase * p->nCol * 3;
    int i;

    for(i=0; i<p->nCol; i++) p->aMatchinfo[iStart+i*3] = 0;

    pCsr = sqlite3Fts3FindPositions(pExpr, p->pCursor->iPrevId, -1);
    if( pCsr ){
      fts3LoadColumnlistCounts(&pCsr, &p->aMatchinfo[iStart], 0);
    }
  }

  return SQLITE_OK;
}

static int fts3MatchinfoCheck(
  Fts3Table *pTab, 
  char cArg,
  char **pzErr
){
  if( (cArg==FTS3_MATCHINFO_NPHRASE)
   || (cArg==FTS3_MATCHINFO_NCOL)
   || (cArg==FTS3_MATCHINFO_NDOC && pTab->bHasStat)
   || (cArg==FTS3_MATCHINFO_AVGLENGTH && pTab->bHasStat)
   || (cArg==FTS3_MATCHINFO_LENGTH && pTab->bHasDocsize)
   || (cArg==FTS3_MATCHINFO_LCS)
   || (cArg==FTS3_MATCHINFO_HITS)
  ){
    return SQLITE_OK;
  }
  *pzErr = sqlite3_mprintf("unrecognized matchinfo request: %c", cArg);
  return SQLITE_ERROR;
}

static int fts3MatchinfoSize(MatchInfo *pInfo, char cArg){
  int nVal;                       /* Number of integers output by cArg */

  switch( cArg ){
    case FTS3_MATCHINFO_NDOC:
    case FTS3_MATCHINFO_NPHRASE: 
    case FTS3_MATCHINFO_NCOL: 
      nVal = 1;
      break;

    case FTS3_MATCHINFO_AVGLENGTH:
    case FTS3_MATCHINFO_LENGTH:
    case FTS3_MATCHINFO_LCS:
      nVal = pInfo->nCol;
      break;

    default:
      assert( cArg==FTS3_MATCHINFO_HITS );
      nVal = pInfo->nCol * pInfo->nPhrase * 3;
      break;
  }

  return nVal;
}

static int fts3MatchinfoSelectDoctotal(
  Fts3Table *pTab,
  sqlite3_stmt **ppStmt,
  sqlite3_int64 *pnDoc,
  const char **paLen
){
  sqlite3_stmt *pStmt;
  const char *a;
  sqlite3_int64 nDoc;

  if( !*ppStmt ){
    int rc = sqlite3Fts3SelectDoctotal(pTab, ppStmt);
    if( rc!=SQLITE_OK ) return rc;
  }
  pStmt = *ppStmt;

  a = sqlite3_column_blob(pStmt, 0);
  a += sqlite3Fts3GetVarint(a, &nDoc);
  *pnDoc = (u32)nDoc;

  if( paLen ) *paLen = a;
  return SQLITE_OK;
}

/*
** An instance of the following structure is used to store state while 
** iterating through a multi-column position-list corresponding to the
** hits for a single phrase on a single row in order to calculate the
** values for a matchinfo() FTS3_MATCHINFO_LCS request.
*/
typedef struct LcsIterator LcsIterator;
struct LcsIterator {
  Fts3Expr *pExpr;                /* Pointer to phrase expression */
  char *pRead;                    /* Cursor used to iterate through aDoclist */
  int iPosOffset;                 /* Tokens count up to end of this phrase */
  int iCol;                       /* Current column number */
  int iPos;                       /* Current position */
};

/* 
** If LcsIterator.iCol is set to the following value, the iterator has
** finished iterating through all offsets for all columns.
*/
#define LCS_ITERATOR_FINISHED 0x7FFFFFFF;

static int fts3MatchinfoLcsCb(
  Fts3Expr *pExpr,                /* Phrase expression node */
  int iPhrase,                    /* Phrase number (numbered from zero) */
  void *pCtx                      /* Pointer to MatchInfo structure */
){
  LcsIterator *aIter = (LcsIterator *)pCtx;
  aIter[iPhrase].pExpr = pExpr;
  return SQLITE_OK;
}

/*
** Advance the iterator passed as an argument to the next position. Return
** 1 if the iterator is at EOF or if it now points to the start of the
** position list for the next column.
*/
static int fts3LcsIteratorAdvance(LcsIterator *pIter){
  char *pRead = pIter->pRead;
  sqlite3_int64 iRead;
  int rc = 0;

  pRead += sqlite3Fts3GetVarint(pRead, &iRead);
  if( iRead==0 ){
    pIter->iCol = LCS_ITERATOR_FINISHED;
    rc = 1;
  }else{
    if( iRead==1 ){
      pRead += sqlite3Fts3GetVarint(pRead, &iRead);
      pIter->iCol = (int)iRead;
      pIter->iPos = pIter->iPosOffset;
      pRead += sqlite3Fts3GetVarint(pRead, &iRead);
      rc = 1;
    }
    pIter->iPos += (int)(iRead-2);
  }

  pIter->pRead = pRead;
  return rc;
}
  
/*
** This function implements the FTS3_MATCHINFO_LCS matchinfo() flag. 
**
** If the call is successful, the longest-common-substring lengths for each
** column are written into the first nCol elements of the pInfo->aMatchinfo[] 
** array before returning. SQLITE_OK is returned in this case.
**
** Otherwise, if an error occurs, an SQLite error code is returned and the
** data written to the first nCol elements of pInfo->aMatchinfo[] is 
** undefined.
*/
static int fts3MatchinfoLcs(Fts3Cursor *pCsr, MatchInfo *pInfo){
  LcsIterator *aIter;
  int i;
  int iCol;
  int nToken = 0;

  /* Allocate and populate the array of LcsIterator objects. The array
  ** contains one element for each matchable phrase in the query.
  **/
  aIter = sqlite3_malloc(sizeof(LcsIterator) * pCsr->nPhrase);
  if( !aIter ) return SQLITE_NOMEM;
  memset(aIter, 0, sizeof(LcsIterator) * pCsr->nPhrase);
  (void)fts3ExprIterate(pCsr->pExpr, fts3MatchinfoLcsCb, (void*)aIter);
  for(i=0; i<pInfo->nPhrase; i++){
    LcsIterator *pIter = &aIter[i];
    nToken -= pIter->pExpr->pPhrase->nToken;
    pIter->iPosOffset = nToken;
    pIter->pRead = sqlite3Fts3FindPositions(pIter->pExpr, pCsr->iPrevId, -1);
    if( pIter->pRead ){
      pIter->iPos = pIter->iPosOffset;
      fts3LcsIteratorAdvance(&aIter[i]);
    }else{
      pIter->iCol = LCS_ITERATOR_FINISHED;
    }
  }

  for(iCol=0; iCol<pInfo->nCol; iCol++){
    int nLcs = 0;                 /* LCS value for this column */
    int nLive = 0;                /* Number of iterators in aIter not at EOF */

    /* Loop through the iterators in aIter[]. Set nLive to the number of
    ** iterators that point to a position-list corresponding to column iCol.
    */
    for(i=0; i<pInfo->nPhrase; i++){
      assert( aIter[i].iCol>=iCol );
      if( aIter[i].iCol==iCol ) nLive++;
    }

    /* The following loop runs until all iterators in aIter[] have finished
    ** iterating through positions in column iCol. Exactly one of the 
    ** iterators is advanced each time the body of the loop is run.
    */
    while( nLive>0 ){
      LcsIterator *pAdv = 0;      /* The iterator to advance by one position */
      int nThisLcs = 0;           /* LCS for the current iterator positions */

      for(i=0; i<pInfo->nPhrase; i++){
        LcsIterator *pIter = &aIter[i];
        if( iCol!=pIter->iCol ){  
          /* This iterator is already at EOF for this column. */
          nThisLcs = 0;
        }else{
          if( pAdv==0 || pIter->iPos<pAdv->iPos ){
            pAdv = pIter;
          }
          if( nThisLcs==0 || pIter->iPos==pIter[-1].iPos ){
            nThisLcs++;
          }else{
            nThisLcs = 1;
          }
          if( nThisLcs>nLcs ) nLcs = nThisLcs;
        }
      }
      if( fts3LcsIteratorAdvance(pAdv) ) nLive--;
    }

    pInfo->aMatchinfo[iCol] = nLcs;
  }

  sqlite3_free(aIter);
  return SQLITE_OK;
}

/*
** Populate the buffer pInfo->aMatchinfo[] with an array of integers to
** be returned by the matchinfo() function. Argument zArg contains the 
** format string passed as the second argument to matchinfo (or the
** default value "pcx" if no second argument was specified). The format
** string has already been validated and the pInfo->aMatchinfo[] array
** is guaranteed to be large enough for the output.
**
** If bGlobal is true, then populate all fields of the matchinfo() output.
** If it is false, then assume that those fields that do not change between
** rows (i.e. FTS3_MATCHINFO_NPHRASE, NCOL, NDOC, AVGLENGTH and part of HITS)
** have already been populated.
**
** Return SQLITE_OK if successful, or an SQLite error code if an error 
** occurs. If a value other than SQLITE_OK is returned, the state the
** pInfo->aMatchinfo[] buffer is left in is undefined.
*/
static int fts3MatchinfoValues(
  Fts3Cursor *pCsr,               /* FTS3 cursor object */
  int bGlobal,                    /* True to grab the global stats */
  MatchInfo *pInfo,               /* Matchinfo context object */
  const char *zArg                /* Matchinfo format string */
){
  int rc = SQLITE_OK;
  int i;
  Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
  sqlite3_stmt *pSelect = 0;

  for(i=0; rc==SQLITE_OK && zArg[i]; i++){

    switch( zArg[i] ){
      case FTS3_MATCHINFO_NPHRASE:
        if( bGlobal ) pInfo->aMatchinfo[0] = pInfo->nPhrase;
        break;

      case FTS3_MATCHINFO_NCOL:
        if( bGlobal ) pInfo->aMatchinfo[0] = pInfo->nCol;
        break;
        
      case FTS3_MATCHINFO_NDOC:
        if( bGlobal ){
          sqlite3_int64 nDoc;
          rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, 0);
          pInfo->aMatchinfo[0] = (u32)nDoc;
        }
        break;

      case FTS3_MATCHINFO_AVGLENGTH: 
        if( bGlobal ){
          sqlite3_int64 nDoc;     /* Number of rows in table */
          const char *a;          /* Aggregate column length array */

          rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &nDoc, &a);
          if( rc==SQLITE_OK ){
            int iCol;
            for(iCol=0; iCol<pInfo->nCol; iCol++){
              sqlite3_int64 nToken;
              a += sqlite3Fts3GetVarint(a, &nToken);
              pInfo->aMatchinfo[iCol] = (u32)(((u32)(nToken&0xffffffff)+nDoc/2)/nDoc);
            }
          }
        }
        break;

      case FTS3_MATCHINFO_LENGTH: {
        sqlite3_stmt *pSelectDocsize = 0;
        rc = sqlite3Fts3SelectDocsize(pTab, pCsr->iPrevId, &pSelectDocsize);
        if( rc==SQLITE_OK ){
          int iCol;
          const char *a = sqlite3_column_blob(pSelectDocsize, 0);
          for(iCol=0; iCol<pInfo->nCol; iCol++){
            sqlite3_int64 nToken;
            a += sqlite3Fts3GetVarint(a, &nToken);
            pInfo->aMatchinfo[iCol] = (u32)nToken;
          }
        }
        sqlite3_reset(pSelectDocsize);
        break;
      }

      case FTS3_MATCHINFO_LCS:
        rc = fts3ExprLoadDoclists(pCsr, 0, 0);
        if( rc==SQLITE_OK ){
          rc = fts3MatchinfoLcs(pCsr, pInfo);
        }
        break;

      default: {
        Fts3Expr *pExpr;
        assert( zArg[i]==FTS3_MATCHINFO_HITS );
        pExpr = pCsr->pExpr;
        rc = fts3ExprLoadDoclists(pCsr, 0, 0);
        if( rc!=SQLITE_OK ) break;
        if( bGlobal ){
          if( pCsr->pDeferred ){
            rc = fts3MatchinfoSelectDoctotal(pTab, &pSelect, &pInfo->nDoc, 0);
            if( rc!=SQLITE_OK ) break;
          }
          rc = fts3ExprIterate(pExpr, fts3ExprGlobalHitsCb,(void*)pInfo);
          if( rc!=SQLITE_OK ) break;
        }
        (void)fts3ExprIterate(pExpr, fts3ExprLocalHitsCb,(void*)pInfo);
        break;
      }
    }

    pInfo->aMatchinfo += fts3MatchinfoSize(pInfo, zArg[i]);
  }

  sqlite3_reset(pSelect);
  return rc;
}


/*
** Populate pCsr->aMatchinfo[] with data for the current row. The 
** 'matchinfo' data is an array of 32-bit unsigned integers (C type u32).
*/
static int fts3GetMatchinfo(
  Fts3Cursor *pCsr,               /* FTS3 Cursor object */
  const char *zArg                /* Second argument to matchinfo() function */
){
  MatchInfo sInfo;
  Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
  int rc = SQLITE_OK;
  int bGlobal = 0;                /* Collect 'global' stats as well as local */

  memset(&sInfo, 0, sizeof(MatchInfo));
  sInfo.pCursor = pCsr;
  sInfo.nCol = pTab->nColumn;

  /* If there is cached matchinfo() data, but the format string for the 
  ** cache does not match the format string for this request, discard 
  ** the cached data. */
  if( pCsr->zMatchinfo && strcmp(pCsr->zMatchinfo, zArg) ){
    assert( pCsr->aMatchinfo );
    sqlite3_free(pCsr->aMatchinfo);
    pCsr->zMatchinfo = 0;
    pCsr->aMatchinfo = 0;
  }

  /* If Fts3Cursor.aMatchinfo[] is NULL, then this is the first time the
  ** matchinfo function has been called for this query. In this case 
  ** allocate the array used to accumulate the matchinfo data and
  ** initialize those elements that are constant for every row.
  */

  if( pCsr->aMatchinfo==0 ){
    int nMatchinfo = 0;           /* Number of u32 elements in match-info */
    int nArg;                     /* Bytes in zArg */
    int i;                        /* Used to iterate through zArg */





    /* Determine the number of phrases in the query */
    pCsr->nPhrase = fts3ExprPhraseCount(pCsr->pExpr);
    sInfo.nPhrase = pCsr->nPhrase;




    /* Determine the number of integers in the buffer returned by this call. */
    for(i=0; zArg[i]; i++){
      nMatchinfo += fts3MatchinfoSize(&sInfo, zArg[i]);
    }

    /* Allocate space for Fts3Cursor.aMatchinfo[] and Fts3Cursor.zMatchinfo. */
    nArg = (int)strlen(zArg);
    pCsr->aMatchinfo = (u32 *)sqlite3_malloc(sizeof(u32)*nMatchinfo + nArg + 1);

    if( !pCsr->aMatchinfo ) return SQLITE_NOMEM;

    pCsr->zMatchinfo = (char *)&pCsr->aMatchinfo[nMatchinfo];
    pCsr->nMatchinfo = nMatchinfo;
    memcpy(pCsr->zMatchinfo, zArg, nArg+1);
    memset(pCsr->aMatchinfo, 0, sizeof(u32)*nMatchinfo);










    pCsr->isMatchinfoNeeded = 1;
    bGlobal = 1;
  }

  sInfo.aMatchinfo = pCsr->aMatchinfo;
  sInfo.nPhrase = pCsr->nPhrase;
  if( pCsr->isMatchinfoNeeded ){

    rc = fts3MatchinfoValues(pCsr, bGlobal, &sInfo, zArg);



    pCsr->isMatchinfoNeeded = 0;
  }

  return rc;
}

/*
** Implementation of snippet() function.
*/
void sqlite3Fts3Snippet(
  sqlite3_context *pCtx,          /* SQLite function call context */
................................................................................
      memset(pFragment, 0, sizeof(*pFragment));

      /* Loop through all columns of the table being considered for snippets.
      ** If the iCol argument to this function was negative, this means all
      ** columns of the FTS3 table. Otherwise, only column iCol is considered.
      */
      for(iRead=0; iRead<pTab->nColumn; iRead++){
        SnippetFragment sF = {0, 0, 0, 0};
        int iS;
        if( iCol>=0 && iRead!=iCol ) continue;

        /* Find the best snippet of nFToken tokens in column iRead. */
        rc = fts3BestSnippet(nFToken, pCsr, iRead, mCovered, &mSeen, &sF, &iS);
        if( rc!=SQLITE_OK ){
          goto snippet_out;
................................................................................
  }
  return;
}

/*
** Implementation of matchinfo() function.
*/
void sqlite3Fts3Matchinfo(
  sqlite3_context *pContext,      /* Function call context */
  Fts3Cursor *pCsr,               /* FTS3 table cursor */
  const char *zArg                /* Second arg to matchinfo() function */
){
  Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
  int rc;
  int i;
  const char *zFormat;

  if( zArg ){
    for(i=0; zArg[i]; i++){
      char *zErr = 0;
      if( fts3MatchinfoCheck(pTab, zArg[i], &zErr) ){
        sqlite3_result_error(pContext, zErr, -1);
        sqlite3_free(zErr);
        return;
      }
    }
    zFormat = zArg;
  }else{
    zFormat = FTS3_MATCHINFO_DEFAULT;
  }

  if( !pCsr->pExpr ){
    sqlite3_result_blob(pContext, "", 0, SQLITE_STATIC);
    return;
  }

  /* Retrieve matchinfo() data. */
  rc = fts3GetMatchinfo(pCsr, zFormat);
  sqlite3Fts3SegmentsClose(pTab);

  if( rc!=SQLITE_OK ){
    sqlite3_result_error_code(pContext, rc);
  }else{
    int n = pCsr->nMatchinfo * sizeof(u32);




    sqlite3_result_blob(pContext, pCsr->aMatchinfo, n, SQLITE_TRANSIENT);
  }
}

#endif

Changes to ext/fts3/fts3_tokenizer.c.

461
462
463
464
465
466
467
468
469


470

471

472


473


474

475
476
477
478
479
480
481
482
483
484
485
486
  zTest = sqlite3_mprintf("%s_test", zName);
  zTest2 = sqlite3_mprintf("%s_internal_test", zName);
  if( !zTest || !zTest2 ){
    rc = SQLITE_NOMEM;
  }
#endif

  if( SQLITE_OK!=rc
   || SQLITE_OK!=(rc = sqlite3_create_function(db, zName, 1, any, p, scalarFunc, 0, 0))


   || SQLITE_OK!=(rc = sqlite3_create_function(db, zName, 2, any, p, scalarFunc, 0, 0))

#ifdef SQLITE_TEST

   || SQLITE_OK!=(rc = sqlite3_create_function(db, zTest, 2, any, p, testFunc, 0, 0))


   || SQLITE_OK!=(rc = sqlite3_create_function(db, zTest, 3, any, p, testFunc, 0, 0))


   || SQLITE_OK!=(rc = sqlite3_create_function(db, zTest2, 0, any, pdb, intTestFunc, 0, 0))

#endif
   );

#ifdef SQLITE_TEST
  sqlite3_free(zTest);
  sqlite3_free(zTest2);
#endif

  return rc;
}

#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */







|
|
>
>
|
>

>
|
>
>
|
>
>
|
>

<










461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484

485
486
487
488
489
490
491
492
493
494
  zTest = sqlite3_mprintf("%s_test", zName);
  zTest2 = sqlite3_mprintf("%s_internal_test", zName);
  if( !zTest || !zTest2 ){
    rc = SQLITE_NOMEM;
  }
#endif

  if( SQLITE_OK==rc ){
    rc = sqlite3_create_function(db, zName, 1, any, p, scalarFunc, 0, 0);
  }
  if( SQLITE_OK==rc ){
    rc = sqlite3_create_function(db, zName, 2, any, p, scalarFunc, 0, 0);
  }
#ifdef SQLITE_TEST
  if( SQLITE_OK==rc ){
    rc = sqlite3_create_function(db, zTest, 2, any, p, testFunc, 0, 0);
  }
  if( SQLITE_OK==rc ){
    rc = sqlite3_create_function(db, zTest, 3, any, p, testFunc, 0, 0);
  }
  if( SQLITE_OK==rc ){
    rc = sqlite3_create_function(db, zTest2, 0, any, pdb, intTestFunc, 0, 0);
  }
#endif


#ifdef SQLITE_TEST
  sqlite3_free(zTest);
  sqlite3_free(zTest2);
#endif

  return rc;
}

#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */

Changes to ext/fts3/fts3_write.c.

278
279
280
281
282
283
284













































285
286
287
288
289
290
291
....
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
....
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
....
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
....
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
....
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
....
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
....
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
....
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
    for(i=0; rc==SQLITE_OK && i<nParam; i++){
      rc = sqlite3_bind_value(pStmt, i+1, apVal[i]);
    }
  }
  *pp = pStmt;
  return rc;
}














































/*
** Similar to fts3SqlStmt(). Except, after binding the parameters in
** array apVal[] to the SQL statement identified by eStmt, the statement
** is executed.
**
** Returns SQLITE_OK if the statement is successfully executed, or an
................................................................................
          const char *pEnd = &a[sqlite3_column_bytes(pStmt, 0)];
          a += sqlite3Fts3GetVarint(a, &nDoc);
          while( a<pEnd ){
            a += sqlite3Fts3GetVarint(a, &nByte);
          }
        }

        pCsr->nRowAvg = (((nByte / nDoc) + pgsz - 1) / pgsz);
      }
      rc = sqlite3_reset(pStmt);
      if( rc!=SQLITE_OK || pCsr->nRowAvg==0 ) return rc;
    }

    /* Assume that a blob flows over onto overflow pages if it is larger
    ** than (pgsz-35) bytes in size (the file-format documentation
................................................................................
  return rc;
}

/*
** Free all allocations associated with the iterator passed as the 
** second argument.
*/
void sqlite3Fts3SegReaderFree(Fts3Table *p, Fts3SegReader *pReader){
  if( pReader && !fts3SegReaderIsPending(pReader) ){
    sqlite3_free(pReader->zTerm);
    if( !fts3SegReaderIsRootOnly(pReader) ){
      sqlite3_free(pReader->aNode);
    }
  }
  sqlite3_free(pReader);
}

/*
** Allocate a new SegReader object.
*/
int sqlite3Fts3SegReaderNew(
  Fts3Table *p,                   /* Virtual table handle */
  int iAge,                       /* Segment "age". */
  sqlite3_int64 iStartLeaf,       /* First leaf to traverse */
  sqlite3_int64 iEndLeaf,         /* Final leaf to traverse */
  sqlite3_int64 iEndBlock,        /* Final block of segment */
  const char *zRoot,              /* Buffer containing root node */
  int nRoot,                      /* Size of buffer containing root node */
  Fts3SegReader **ppReader        /* OUT: Allocated Fts3SegReader */
................................................................................
  }else{
    pReader->iCurrentBlock = iStartLeaf-1;
  }

  if( rc==SQLITE_OK ){
    *ppReader = pReader;
  }else{
    sqlite3Fts3SegReaderFree(p, pReader);
  }
  return rc;
}

/*
** This is a comparison function used as a qsort() callback when sorting
** an array of pending terms by term. This occurs as part of flushing
................................................................................
** current row that pStmt is pointing to. 
**
** If successful, the Fts3SegReader is left pointing to the first term
** in the segment and SQLITE_OK is returned. Otherwise, an SQLite error
** code is returned.
*/
static int fts3SegReaderNew(
  Fts3Table *p,                   /* Virtual table handle */
  sqlite3_stmt *pStmt,            /* See above */
  int iAge,                       /* Segment "age". */
  Fts3SegReader **ppReader        /* OUT: Allocated Fts3SegReader */
){
  return sqlite3Fts3SegReaderNew(p, iAge, 
      sqlite3_column_int64(pStmt, 1),
      sqlite3_column_int64(pStmt, 2),
      sqlite3_column_int64(pStmt, 3),
      sqlite3_column_blob(pStmt, 4),
      sqlite3_column_bytes(pStmt, 4),
      ppReader
  );
................................................................................
  ** entries on all leaves of a single segment. 
  */
  assert( SQL_SELECT_LEVEL+1==SQL_SELECT_ALL_LEVEL);
  rc = fts3SqlStmt(p, SQL_SELECT_LEVEL+(iLevel<0), &pStmt, 0);
  if( rc!=SQLITE_OK ) goto finished;
  sqlite3_bind_int(pStmt, 1, iLevel);
  for(i=0; SQLITE_ROW==(sqlite3_step(pStmt)); i++){
    rc = fts3SegReaderNew(p, pStmt, i, &apSegment[i]);
    if( rc!=SQLITE_OK ){
      goto finished;
    }
  }
  rc = sqlite3_reset(pStmt);
  if( pPending ){
    apSegment[i] = pPending;
................................................................................
    rc = fts3SegWriterFlush(p, pWriter, iNewLevel, iIdx);
  }

 finished:
  fts3SegWriterFree(pWriter);
  if( apSegment ){
    for(i=0; i<nSegment; i++){
      sqlite3Fts3SegReaderFree(p, apSegment[i]);
    }
    sqlite3_free(apSegment);
  }
  sqlite3Fts3SegReaderFree(p, pPending);
  sqlite3_reset(pStmt);
  return rc;
}


/* 
** Flush the contents of pendingTerms to a level 0 segment.
................................................................................
  ** database. Then delete the SegmentWriter and Fts3SegReader objects
  ** allocated by this function.
  */
  if( rc==SQLITE_OK ){
    rc = fts3SegWriterFlush(p, pWriter, 0, idx);
  }
  fts3SegWriterFree(pWriter);
  sqlite3Fts3SegReaderFree(p, pReader);

  if( rc==SQLITE_OK ){
    sqlite3Fts3PendingTermsClear(p);
  }
  return rc;
}

................................................................................
    sqlite3_int64 x;
    j += sqlite3Fts3GetVarint(&zBuf[j], &x);
    assert(j<=nBuf);
    a[i] = (u32)(x & 0xffffffff);
  }
}

/*
** Fill in the document size auxiliary information for the matchinfo
** structure.  The auxiliary information is:
**
**    N     Total number of documents in the full-text index
**    a0    Average length of column 0 over the whole index
**    n0    Length of column 0 on the matching row
**    ...
**    aM    Average length of column M over the whole index
**    nM    Length of column M on the matching row
**
** The fts3MatchinfoDocsizeLocal() routine fills in the nX values.
** The fts3MatchinfoDocsizeGlobal() routine fills in N and the aX values.
*/
int sqlite3Fts3MatchinfoDocsizeLocal(Fts3Cursor *pCur, u32 *a){
  const char *pBlob;       /* The BLOB holding %_docsize info */
  int nBlob;               /* Size of the BLOB */
  sqlite3_stmt *pStmt;     /* Statement for reading and writing */
  int i, j;                /* Loop counters */
  sqlite3_int64 x;         /* Varint value */
  int rc;                  /* Result code from subfunctions */
  Fts3Table *p;            /* The FTS table */

  p = (Fts3Table*)pCur->base.pVtab;
  rc = fts3SqlStmt(p, SQL_SELECT_DOCSIZE, &pStmt, 0);
  if( rc ){
    return rc;
  }
  sqlite3_bind_int64(pStmt, 1, pCur->iPrevId);
  if( sqlite3_step(pStmt)==SQLITE_ROW ){
    nBlob = sqlite3_column_bytes(pStmt, 0);
    pBlob = (const char*)sqlite3_column_blob(pStmt, 0);
    for(i=j=0; i<p->nColumn && j<nBlob; i++){
      j = sqlite3Fts3GetVarint(&pBlob[j], &x);
      a[2+i*2] = (u32)(x & 0xffffffff);
    }
  }
  sqlite3_reset(pStmt);
  return SQLITE_OK; 
}
int sqlite3Fts3MatchinfoDocsizeGlobal(Fts3Cursor *pCur, u32 *a){
  const char *pBlob;       /* The BLOB holding %_stat info */
  int nBlob;               /* Size of the BLOB */
  sqlite3_stmt *pStmt;     /* Statement for reading and writing */
  int i, j;                /* Loop counters */
  sqlite3_int64 x;         /* Varint value */
  int nDoc;                /* Number of documents */
  int rc;                  /* Result code from subfunctions */
  Fts3Table *p;            /* The FTS table */

  p = (Fts3Table*)pCur->base.pVtab;
  rc = fts3SqlStmt(p, SQL_SELECT_DOCTOTAL, &pStmt, 0);
  if( rc ){
    return rc;
  }
  if( sqlite3_step(pStmt)==SQLITE_ROW ){
    nBlob = sqlite3_column_bytes(pStmt, 0);
    pBlob = (const char*)sqlite3_column_blob(pStmt, 0);
    j = sqlite3Fts3GetVarint(pBlob, &x);
    a[0] = nDoc = (u32)(x & 0xffffffff);
    for(i=0; i<p->nColumn && j<nBlob; i++){
      j = sqlite3Fts3GetVarint(&pBlob[j], &x);
      a[1+i*2] = ((u32)(x & 0xffffffff) + nDoc/2)/nDoc;
    }
  }
  sqlite3_reset(pStmt);
  return SQLITE_OK; 
}

/*
** Insert the sizes (in tokens) for each column of the document
** with docid equal to p->iPrevDocid.  The sizes are encoded as
** a blob of varints.
*/
static void fts3InsertDocsize(
  int *pRC,         /* Result code */







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







 







|







 







|













<







 







|







 







<




|







 







|







 







|



|







 







|







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
....
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
....
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160

1161
1162
1163
1164
1165
1166
1167
....
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
....
1317
1318
1319
1320
1321
1322
1323

1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
....
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
....
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
....
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
....
2482
2483
2484
2485
2486
2487
2488





































































2489
2490
2491
2492
2493
2494
2495
    for(i=0; rc==SQLITE_OK && i<nParam; i++){
      rc = sqlite3_bind_value(pStmt, i+1, apVal[i]);
    }
  }
  *pp = pStmt;
  return rc;
}

static int fts3SelectDocsize(
  Fts3Table *pTab,                /* FTS3 table handle */
  int eStmt,                      /* Either SQL_SELECT_DOCSIZE or DOCTOTAL */
  sqlite3_int64 iDocid,           /* Docid to bind for SQL_SELECT_DOCSIZE */
  sqlite3_stmt **ppStmt           /* OUT: Statement handle */
){
  sqlite3_stmt *pStmt = 0;        /* Statement requested from fts3SqlStmt() */
  int rc;                         /* Return code */

  assert( eStmt==SQL_SELECT_DOCSIZE || eStmt==SQL_SELECT_DOCTOTAL );

  rc = fts3SqlStmt(pTab, eStmt, &pStmt, 0);
  if( rc==SQLITE_OK ){
    if( eStmt==SQL_SELECT_DOCSIZE ){
      sqlite3_bind_int64(pStmt, 1, iDocid);
    }
    rc = sqlite3_step(pStmt);
    if( rc!=SQLITE_ROW ){
      rc = sqlite3_reset(pStmt);
      if( rc==SQLITE_OK ) rc = SQLITE_CORRUPT;
      pStmt = 0;
    }else{
      rc = SQLITE_OK;
    }
  }

  *ppStmt = pStmt;
  return rc;
}

int sqlite3Fts3SelectDoctotal(
  Fts3Table *pTab,                /* Fts3 table handle */
  sqlite3_stmt **ppStmt           /* OUT: Statement handle */
){
  return fts3SelectDocsize(pTab, SQL_SELECT_DOCTOTAL, 0, ppStmt);
}

int sqlite3Fts3SelectDocsize(
  Fts3Table *pTab,                /* Fts3 table handle */
  sqlite3_int64 iDocid,           /* Docid to read size data for */
  sqlite3_stmt **ppStmt           /* OUT: Statement handle */
){
  return fts3SelectDocsize(pTab, SQL_SELECT_DOCSIZE, iDocid, ppStmt);
}

/*
** Similar to fts3SqlStmt(). Except, after binding the parameters in
** array apVal[] to the SQL statement identified by eStmt, the statement
** is executed.
**
** Returns SQLITE_OK if the statement is successfully executed, or an
................................................................................
          const char *pEnd = &a[sqlite3_column_bytes(pStmt, 0)];
          a += sqlite3Fts3GetVarint(a, &nDoc);
          while( a<pEnd ){
            a += sqlite3Fts3GetVarint(a, &nByte);
          }
        }

        pCsr->nRowAvg = (int)(((nByte / nDoc) + pgsz - 1) / pgsz);
      }
      rc = sqlite3_reset(pStmt);
      if( rc!=SQLITE_OK || pCsr->nRowAvg==0 ) return rc;
    }

    /* Assume that a blob flows over onto overflow pages if it is larger
    ** than (pgsz-35) bytes in size (the file-format documentation
................................................................................
  return rc;
}

/*
** Free all allocations associated with the iterator passed as the 
** second argument.
*/
void sqlite3Fts3SegReaderFree(Fts3SegReader *pReader){
  if( pReader && !fts3SegReaderIsPending(pReader) ){
    sqlite3_free(pReader->zTerm);
    if( !fts3SegReaderIsRootOnly(pReader) ){
      sqlite3_free(pReader->aNode);
    }
  }
  sqlite3_free(pReader);
}

/*
** Allocate a new SegReader object.
*/
int sqlite3Fts3SegReaderNew(

  int iAge,                       /* Segment "age". */
  sqlite3_int64 iStartLeaf,       /* First leaf to traverse */
  sqlite3_int64 iEndLeaf,         /* Final leaf to traverse */
  sqlite3_int64 iEndBlock,        /* Final block of segment */
  const char *zRoot,              /* Buffer containing root node */
  int nRoot,                      /* Size of buffer containing root node */
  Fts3SegReader **ppReader        /* OUT: Allocated Fts3SegReader */
................................................................................
  }else{
    pReader->iCurrentBlock = iStartLeaf-1;
  }

  if( rc==SQLITE_OK ){
    *ppReader = pReader;
  }else{
    sqlite3Fts3SegReaderFree(pReader);
  }
  return rc;
}

/*
** This is a comparison function used as a qsort() callback when sorting
** an array of pending terms by term. This occurs as part of flushing
................................................................................
** current row that pStmt is pointing to. 
**
** If successful, the Fts3SegReader is left pointing to the first term
** in the segment and SQLITE_OK is returned. Otherwise, an SQLite error
** code is returned.
*/
static int fts3SegReaderNew(

  sqlite3_stmt *pStmt,            /* See above */
  int iAge,                       /* Segment "age". */
  Fts3SegReader **ppReader        /* OUT: Allocated Fts3SegReader */
){
  return sqlite3Fts3SegReaderNew(iAge, 
      sqlite3_column_int64(pStmt, 1),
      sqlite3_column_int64(pStmt, 2),
      sqlite3_column_int64(pStmt, 3),
      sqlite3_column_blob(pStmt, 4),
      sqlite3_column_bytes(pStmt, 4),
      ppReader
  );
................................................................................
  ** entries on all leaves of a single segment. 
  */
  assert( SQL_SELECT_LEVEL+1==SQL_SELECT_ALL_LEVEL);
  rc = fts3SqlStmt(p, SQL_SELECT_LEVEL+(iLevel<0), &pStmt, 0);
  if( rc!=SQLITE_OK ) goto finished;
  sqlite3_bind_int(pStmt, 1, iLevel);
  for(i=0; SQLITE_ROW==(sqlite3_step(pStmt)); i++){
    rc = fts3SegReaderNew(pStmt, i, &apSegment[i]);
    if( rc!=SQLITE_OK ){
      goto finished;
    }
  }
  rc = sqlite3_reset(pStmt);
  if( pPending ){
    apSegment[i] = pPending;
................................................................................
    rc = fts3SegWriterFlush(p, pWriter, iNewLevel, iIdx);
  }

 finished:
  fts3SegWriterFree(pWriter);
  if( apSegment ){
    for(i=0; i<nSegment; i++){
      sqlite3Fts3SegReaderFree(apSegment[i]);
    }
    sqlite3_free(apSegment);
  }
  sqlite3Fts3SegReaderFree(pPending);
  sqlite3_reset(pStmt);
  return rc;
}


/* 
** Flush the contents of pendingTerms to a level 0 segment.
................................................................................
  ** database. Then delete the SegmentWriter and Fts3SegReader objects
  ** allocated by this function.
  */
  if( rc==SQLITE_OK ){
    rc = fts3SegWriterFlush(p, pWriter, 0, idx);
  }
  fts3SegWriterFree(pWriter);
  sqlite3Fts3SegReaderFree(pReader);

  if( rc==SQLITE_OK ){
    sqlite3Fts3PendingTermsClear(p);
  }
  return rc;
}

................................................................................
    sqlite3_int64 x;
    j += sqlite3Fts3GetVarint(&zBuf[j], &x);
    assert(j<=nBuf);
    a[i] = (u32)(x & 0xffffffff);
  }
}






































































/*
** Insert the sizes (in tokens) for each column of the document
** with docid equal to p->iPrevDocid.  The sizes are encoded as
** a blob of varints.
*/
static void fts3InsertDocsize(
  int *pRC,         /* Result code */

Changes to ext/rtree/rtree.c.

109
110
111
112
113
114
115






116
117
118
119
120
121
122
...
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
...
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
...
884
885
886
887
888
889
890

891
892
893
894
895
896
897
...
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
....
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040

1041
1042
1043
1044
1045
1046
1047
1048
1049
....
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
....
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
....
1352
1353
1354
1355
1356
1357
1358

1359
1360
1361
1362
1363
1364
1365
....
1525
1526
1527
1528
1529
1530
1531

1532
1533
1534
1535
1536
1537
1538
....
3111
3112
3113
3114
3115
3116
3117

3118
3119
3120
3121
3122
3123
3124
....
3144
3145
3146
3147
3148
3149
3150

3151
3152
3153
3154
3155
3156
3157
....
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179

#ifndef SQLITE_AMALGAMATION
#include "sqlite3rtree.h"
typedef sqlite3_int64 i64;
typedef unsigned char u8;
typedef unsigned int u32;
#endif







typedef struct Rtree Rtree;
typedef struct RtreeCursor RtreeCursor;
typedef struct RtreeNode RtreeNode;
typedef struct RtreeCell RtreeCell;
typedef struct RtreeConstraint RtreeConstraint;
typedef struct RtreeMatchArg RtreeMatchArg;
................................................................................
** If an R*-tree "Reinsert" operation is required, the same number of
** cells are removed from the overfull node and reinserted into the tree.
*/
#define RTREE_MINCELLS(p) ((((p)->iNodeSize-4)/(p)->nBytesPerCell)/3)
#define RTREE_REINSERT(p) RTREE_MINCELLS(p)
#define RTREE_MAXCELLS 51

/* 
** The smallest possible node-size is (512-64)==448 bytes. And the largest
** supported cell size is 48 bytes (8 byte rowid + ten 4 byte coordinates).
** Therefore all non-root nodes must contain at least 3 entries. Since 
** 2^40 is greater than 2^64, an r-tree structure always has a depth of
** 40 or less.
*/
#define RTREE_MAX_DEPTH 40
................................................................................
** record (i.e if the scan has finished), or zero otherwise.
*/
static int rtreeEof(sqlite3_vtab_cursor *cur){
  RtreeCursor *pCsr = (RtreeCursor *)cur;
  return (pCsr->pNode==0);
}

/* 
** The r-tree constraint passed as the second argument to this function is
** guaranteed to be a MATCH constraint.
*/
static int testRtreeGeom(
  Rtree *pRtree,                  /* R-Tree object */
  RtreeConstraint *pConstraint,   /* MATCH constraint to test */
  RtreeCell *pCell,               /* Cell to test */
................................................................................
** Return SQLITE_OK if successful or an SQLite error code if an error
** occurs within a geometry callback.
*/
static int testRtreeCell(Rtree *pRtree, RtreeCursor *pCursor, int *pbEof){
  RtreeCell cell;
  int ii;
  int bRes = 0;


  nodeGetCell(pRtree, pCursor->pNode, pCursor->iCell, &cell);
  for(ii=0; bRes==0 && ii<pCursor->nConstraint; ii++){
    RtreeConstraint *p = &pCursor->aConstraint[ii];
    double cell_min = DCOORD(cell.aCoord[(p->iCoord>>1)*2]);
    double cell_max = DCOORD(cell.aCoord[(p->iCoord>>1)*2+1]);

................................................................................
        bRes = p->rValue<cell_min; 
        break;

      case RTREE_GE: case RTREE_GT: 
        bRes = p->rValue>cell_max; 
        break;

      case RTREE_EQ: 
        bRes = (p->rValue>cell_max || p->rValue<cell_min);
        break;

      default: {
        int rc;
        assert( p->op==RTREE_MATCH );
        rc = testRtreeGeom(pRtree, p, &cell, &bRes);
        if( rc!=SQLITE_OK ){
          return rc;
        }
        bRes = !bRes;
        break;
      }
    }
  }

  *pbEof = bRes;
  return SQLITE_OK;
}

/* 
** Test if the cell that cursor pCursor currently points to
** would be filtered (excluded) by the constraints in the 
** pCursor->aConstraint[] array. If so, set *pbEof to true before
** returning. If the cell is not filtered (excluded) by the constraints,
................................................................................

  if( iHeight==0 ){
    rc = testRtreeEntry(pRtree, pCursor, &isEof);
  }else{
    rc = testRtreeCell(pRtree, pCursor, &isEof);
  }
  if( rc!=SQLITE_OK || isEof || iHeight==0 ){
    *pEof = isEof;
    return rc;
  }

  iRowid = nodeGetRowid(pRtree, pCursor->pNode, pCursor->iCell);
  rc = nodeAcquire(pRtree, iRowid, pCursor->pNode, &pChild);
  if( rc!=SQLITE_OK ){
    return rc;
  }

  nodeRelease(pRtree, pCursor->pNode);
  pCursor->pNode = pChild;
  isEof = 1;
  for(ii=0; isEof && ii<NCELL(pChild); ii++){
    pCursor->iCell = ii;
    rc = descendToCell(pRtree, pCursor, iHeight-1, &isEof);
    if( rc!=SQLITE_OK ){
      return rc;
    }
  }

  if( isEof ){
    assert( pCursor->pNode==pChild );
    nodeReference(pSavedNode);
    nodeRelease(pRtree, pChild);
    pCursor->pNode = pSavedNode;
    pCursor->iCell = iSavedCell;
  }


  *pEof = isEof;
  return SQLITE_OK;
}

/*
** One of the cells in node pNode is guaranteed to have a 64-bit 
** integer value equal to iRowid. Return the index of this cell.
*/
static int nodeRowidIndex(
................................................................................
  int nBlob;

  /* Check that value is actually a blob. */
  if( !sqlite3_value_type(pValue)==SQLITE_BLOB ) return SQLITE_ERROR;

  /* Check that the blob is roughly the right size. */
  nBlob = sqlite3_value_bytes(pValue);
  if( nBlob<sizeof(RtreeMatchArg) 
   || ((nBlob-sizeof(RtreeMatchArg))%sizeof(double))!=0
  ){
    return SQLITE_ERROR;
  }

  pGeom = (sqlite3_rtree_geometry *)sqlite3_malloc(
      sizeof(sqlite3_rtree_geometry) + nBlob
................................................................................
  );
  if( !pGeom ) return SQLITE_NOMEM;
  memset(pGeom, 0, sizeof(sqlite3_rtree_geometry));
  p = (RtreeMatchArg *)&pGeom[1];

  memcpy(p, sqlite3_value_blob(pValue), nBlob);
  if( p->magic!=RTREE_GEOMETRY_MAGIC 
   || nBlob!=(sizeof(RtreeMatchArg) + (p->nParam-1)*sizeof(double))
  ){
    sqlite3_free(pGeom);
    return SQLITE_ERROR;
  }

  pGeom->pContext = p->pContext;
  pGeom->nParam = p->nParam;
................................................................................
static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
  int rc = SQLITE_OK;
  int ii, cCol;

  int iIdx = 0;
  char zIdxStr[RTREE_MAX_DIMENSIONS*8+1];
  memset(zIdxStr, 0, sizeof(zIdxStr));


  assert( pIdxInfo->idxStr==0 );
  for(ii=0; ii<pIdxInfo->nConstraint; ii++){
    struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii];

    if( p->usable && p->iColumn==0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){
      /* We have an equality constraint on the rowid. Use strategy 1. */
................................................................................
  int ii;
  float overlap = 0.0;
  for(ii=0; ii<nCell; ii++){
#if VARIANT_RSTARTREE_CHOOSESUBTREE
    if( ii!=iExclude )
#else
    assert( iExclude==-1 );

#endif
    {
      int jj;
      float o = 1.0;
      for(jj=0; jj<(pRtree->nDim*2); jj+=2){
        double x1;
        double x2;
................................................................................
*/
static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
  char *zText = 0;
  RtreeNode node;
  Rtree tree;
  int ii;


  memset(&node, 0, sizeof(RtreeNode));
  memset(&tree, 0, sizeof(Rtree));
  tree.nDim = sqlite3_value_int(apArg[0]);
  tree.nBytesPerCell = 8 + 8 * tree.nDim;
  node.zData = (u8 *)sqlite3_value_blob(apArg[1]);

  for(ii=0; ii<NCELL(&node); ii++){
................................................................................
    }
  }
  
  sqlite3_result_text(ctx, zText, -1, sqlite3_free);
}

static void rtreedepth(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){

  if( sqlite3_value_type(apArg[0])!=SQLITE_BLOB 
   || sqlite3_value_bytes(apArg[0])<2
  ){
    sqlite3_result_error(ctx, "Invalid argument to rtreedepth()", -1); 
  }else{
    u8 *zBlob = (u8 *)sqlite3_value_blob(apArg[0]);
    sqlite3_result_int(ctx, readInt16(zBlob));
................................................................................
*/
int sqlite3RtreeInit(sqlite3 *db){
  const int utf8 = SQLITE_UTF8;
  int rc;

  rc = sqlite3_create_function(db, "rtreenode", 2, utf8, 0, rtreenode, 0, 0);
  if( rc==SQLITE_OK ){
    int utf8 = SQLITE_UTF8;
    rc = sqlite3_create_function(db, "rtreedepth", 1, utf8, 0,rtreedepth, 0, 0);
  }
  if( rc==SQLITE_OK ){
    void *c = (void *)RTREE_COORD_REAL32;
    rc = sqlite3_create_module_v2(db, "rtree", &rtreeModule, c, 0);
  }
  if( rc==SQLITE_OK ){







>
>
>
>
>
>







 







|







 







|







 







>







 







|




<


<
<
<







|







 







|
<





|









|











>

|







 







|







 







|







 







>







 







>







 







>







 







>







 







<







109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
...
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
...
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
...
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
...
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
....
1008
1009
1010
1011
1012
1013
1014
1015

1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
....
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
....
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
....
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
....
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
....
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
....
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
....
3172
3173
3174
3175
3176
3177
3178

3179
3180
3181
3182
3183
3184
3185

#ifndef SQLITE_AMALGAMATION
#include "sqlite3rtree.h"
typedef sqlite3_int64 i64;
typedef unsigned char u8;
typedef unsigned int u32;
#endif

/*  The following macro is used to suppress compiler warnings.
*/
#ifndef UNUSED_PARAMETER
# define UNUSED_PARAMETER(x) (void)(x)
#endif

typedef struct Rtree Rtree;
typedef struct RtreeCursor RtreeCursor;
typedef struct RtreeNode RtreeNode;
typedef struct RtreeCell RtreeCell;
typedef struct RtreeConstraint RtreeConstraint;
typedef struct RtreeMatchArg RtreeMatchArg;
................................................................................
** If an R*-tree "Reinsert" operation is required, the same number of
** cells are removed from the overfull node and reinserted into the tree.
*/
#define RTREE_MINCELLS(p) ((((p)->iNodeSize-4)/(p)->nBytesPerCell)/3)
#define RTREE_REINSERT(p) RTREE_MINCELLS(p)
#define RTREE_MAXCELLS 51

/*
** The smallest possible node-size is (512-64)==448 bytes. And the largest
** supported cell size is 48 bytes (8 byte rowid + ten 4 byte coordinates).
** Therefore all non-root nodes must contain at least 3 entries. Since 
** 2^40 is greater than 2^64, an r-tree structure always has a depth of
** 40 or less.
*/
#define RTREE_MAX_DEPTH 40
................................................................................
** record (i.e if the scan has finished), or zero otherwise.
*/
static int rtreeEof(sqlite3_vtab_cursor *cur){
  RtreeCursor *pCsr = (RtreeCursor *)cur;
  return (pCsr->pNode==0);
}

/*
** The r-tree constraint passed as the second argument to this function is
** guaranteed to be a MATCH constraint.
*/
static int testRtreeGeom(
  Rtree *pRtree,                  /* R-Tree object */
  RtreeConstraint *pConstraint,   /* MATCH constraint to test */
  RtreeCell *pCell,               /* Cell to test */
................................................................................
** Return SQLITE_OK if successful or an SQLite error code if an error
** occurs within a geometry callback.
*/
static int testRtreeCell(Rtree *pRtree, RtreeCursor *pCursor, int *pbEof){
  RtreeCell cell;
  int ii;
  int bRes = 0;
  int rc = SQLITE_OK;

  nodeGetCell(pRtree, pCursor->pNode, pCursor->iCell, &cell);
  for(ii=0; bRes==0 && ii<pCursor->nConstraint; ii++){
    RtreeConstraint *p = &pCursor->aConstraint[ii];
    double cell_min = DCOORD(cell.aCoord[(p->iCoord>>1)*2]);
    double cell_max = DCOORD(cell.aCoord[(p->iCoord>>1)*2+1]);

................................................................................
        bRes = p->rValue<cell_min; 
        break;

      case RTREE_GE: case RTREE_GT: 
        bRes = p->rValue>cell_max; 
        break;

      case RTREE_EQ:
        bRes = (p->rValue>cell_max || p->rValue<cell_min);
        break;

      default: {

        assert( p->op==RTREE_MATCH );
        rc = testRtreeGeom(pRtree, p, &cell, &bRes);



        bRes = !bRes;
        break;
      }
    }
  }

  *pbEof = bRes;
  return rc;
}

/* 
** Test if the cell that cursor pCursor currently points to
** would be filtered (excluded) by the constraints in the 
** pCursor->aConstraint[] array. If so, set *pbEof to true before
** returning. If the cell is not filtered (excluded) by the constraints,
................................................................................

  if( iHeight==0 ){
    rc = testRtreeEntry(pRtree, pCursor, &isEof);
  }else{
    rc = testRtreeCell(pRtree, pCursor, &isEof);
  }
  if( rc!=SQLITE_OK || isEof || iHeight==0 ){
    goto descend_to_cell_out;

  }

  iRowid = nodeGetRowid(pRtree, pCursor->pNode, pCursor->iCell);
  rc = nodeAcquire(pRtree, iRowid, pCursor->pNode, &pChild);
  if( rc!=SQLITE_OK ){
    goto descend_to_cell_out;
  }

  nodeRelease(pRtree, pCursor->pNode);
  pCursor->pNode = pChild;
  isEof = 1;
  for(ii=0; isEof && ii<NCELL(pChild); ii++){
    pCursor->iCell = ii;
    rc = descendToCell(pRtree, pCursor, iHeight-1, &isEof);
    if( rc!=SQLITE_OK ){
      goto descend_to_cell_out;
    }
  }

  if( isEof ){
    assert( pCursor->pNode==pChild );
    nodeReference(pSavedNode);
    nodeRelease(pRtree, pChild);
    pCursor->pNode = pSavedNode;
    pCursor->iCell = iSavedCell;
  }

descend_to_cell_out:
  *pEof = isEof;
  return rc;
}

/*
** One of the cells in node pNode is guaranteed to have a 64-bit 
** integer value equal to iRowid. Return the index of this cell.
*/
static int nodeRowidIndex(
................................................................................
  int nBlob;

  /* Check that value is actually a blob. */
  if( !sqlite3_value_type(pValue)==SQLITE_BLOB ) return SQLITE_ERROR;

  /* Check that the blob is roughly the right size. */
  nBlob = sqlite3_value_bytes(pValue);
  if( nBlob<(int)sizeof(RtreeMatchArg) 
   || ((nBlob-sizeof(RtreeMatchArg))%sizeof(double))!=0
  ){
    return SQLITE_ERROR;
  }

  pGeom = (sqlite3_rtree_geometry *)sqlite3_malloc(
      sizeof(sqlite3_rtree_geometry) + nBlob
................................................................................
  );
  if( !pGeom ) return SQLITE_NOMEM;
  memset(pGeom, 0, sizeof(sqlite3_rtree_geometry));
  p = (RtreeMatchArg *)&pGeom[1];

  memcpy(p, sqlite3_value_blob(pValue), nBlob);
  if( p->magic!=RTREE_GEOMETRY_MAGIC 
   || nBlob!=(int)(sizeof(RtreeMatchArg) + (p->nParam-1)*sizeof(double))
  ){
    sqlite3_free(pGeom);
    return SQLITE_ERROR;
  }

  pGeom->pContext = p->pContext;
  pGeom->nParam = p->nParam;
................................................................................
static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
  int rc = SQLITE_OK;
  int ii, cCol;

  int iIdx = 0;
  char zIdxStr[RTREE_MAX_DIMENSIONS*8+1];
  memset(zIdxStr, 0, sizeof(zIdxStr));
  UNUSED_PARAMETER(tab);

  assert( pIdxInfo->idxStr==0 );
  for(ii=0; ii<pIdxInfo->nConstraint; ii++){
    struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii];

    if( p->usable && p->iColumn==0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){
      /* We have an equality constraint on the rowid. Use strategy 1. */
................................................................................
  int ii;
  float overlap = 0.0;
  for(ii=0; ii<nCell; ii++){
#if VARIANT_RSTARTREE_CHOOSESUBTREE
    if( ii!=iExclude )
#else
    assert( iExclude==-1 );
    UNUSED_PARAMETER(iExclude);
#endif
    {
      int jj;
      float o = 1.0;
      for(jj=0; jj<(pRtree->nDim*2); jj+=2){
        double x1;
        double x2;
................................................................................
*/
static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
  char *zText = 0;
  RtreeNode node;
  Rtree tree;
  int ii;

  UNUSED_PARAMETER(nArg);
  memset(&node, 0, sizeof(RtreeNode));
  memset(&tree, 0, sizeof(Rtree));
  tree.nDim = sqlite3_value_int(apArg[0]);
  tree.nBytesPerCell = 8 + 8 * tree.nDim;
  node.zData = (u8 *)sqlite3_value_blob(apArg[1]);

  for(ii=0; ii<NCELL(&node); ii++){
................................................................................
    }
  }
  
  sqlite3_result_text(ctx, zText, -1, sqlite3_free);
}

static void rtreedepth(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
  UNUSED_PARAMETER(nArg);
  if( sqlite3_value_type(apArg[0])!=SQLITE_BLOB 
   || sqlite3_value_bytes(apArg[0])<2
  ){
    sqlite3_result_error(ctx, "Invalid argument to rtreedepth()", -1); 
  }else{
    u8 *zBlob = (u8 *)sqlite3_value_blob(apArg[0]);
    sqlite3_result_int(ctx, readInt16(zBlob));
................................................................................
*/
int sqlite3RtreeInit(sqlite3 *db){
  const int utf8 = SQLITE_UTF8;
  int rc;

  rc = sqlite3_create_function(db, "rtreenode", 2, utf8, 0, rtreenode, 0, 0);
  if( rc==SQLITE_OK ){

    rc = sqlite3_create_function(db, "rtreedepth", 1, utf8, 0,rtreedepth, 0, 0);
  }
  if( rc==SQLITE_OK ){
    void *c = (void *)RTREE_COORD_REAL32;
    rc = sqlite3_create_module_v2(db, "rtree", &rtreeModule, c, 0);
  }
  if( rc==SQLITE_OK ){

Changes to src/btree.c.

1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
  u8 nReserve;                   /* Byte of unused space on each page */
  unsigned char zDbHeader[100];  /* Database header content */

  /* True if opening an ephemeral, temporary database */
  const int isTempDb = zFilename==0 || zFilename[0]==0;

  /* Set the variable isMemdb to true for an in-memory database, or 
  ** false for a file-based database. This symbol is only required if
  ** either of the shared-data or autovacuum features are compiled 
  ** into the library.
  */
#if !defined(SQLITE_OMIT_SHARED_CACHE) || !defined(SQLITE_OMIT_AUTOVACUUM)
  #ifdef SQLITE_OMIT_MEMORYDB
    const int isMemdb = 0;
  #else
    const int isMemdb = (zFilename && strcmp(zFilename, ":memory:")==0)
                         || (isTempDb && sqlite3TempInMemory(db));
  #endif
#endif

  assert( db!=0 );
  assert( sqlite3_mutex_held(db->mutex) );
  assert( (flags&0xff)==flags );   /* flags fit in 8 bits */

  /* Only a BTREE_SINGLE database can be BTREE_UNORDERED */







|
<
<

<
|
|
|
|
|
<







1707
1708
1709
1710
1711
1712
1713
1714


1715

1716
1717
1718
1719
1720

1721
1722
1723
1724
1725
1726
1727
  u8 nReserve;                   /* Byte of unused space on each page */
  unsigned char zDbHeader[100];  /* Database header content */

  /* True if opening an ephemeral, temporary database */
  const int isTempDb = zFilename==0 || zFilename[0]==0;

  /* Set the variable isMemdb to true for an in-memory database, or 
  ** false for a file-based database.


  */

#ifdef SQLITE_OMIT_MEMORYDB
  const int isMemdb = 0;
#else
  const int isMemdb = (zFilename && strcmp(zFilename, ":memory:")==0)
                       || (isTempDb && sqlite3TempInMemory(db));

#endif

  assert( db!=0 );
  assert( sqlite3_mutex_held(db->mutex) );
  assert( (flags&0xff)==flags );   /* flags fit in 8 bits */

  /* Only a BTREE_SINGLE database can be BTREE_UNORDERED */

Changes to src/expr.c.

1651
1652
1653
1654
1655
1656
1657

1658
1659
1660
1661
1662
1663
1664
....
1751
1752
1753
1754
1755
1756
1757

1758
1759
1760
1761
1762
1763
1764
....
3034
3035
3036
3037
3038
3039
3040











3041
3042
3043


3044
3045
3046
3047
3048
3049
3050
        SelectDest dest;
        ExprList *pEList;

        assert( !isRowid );
        sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
        dest.affinity = (u8)affinity;
        assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );

        if( sqlite3Select(pParse, pExpr->x.pSelect, &dest) ){
          return 0;
        }
        pEList = pExpr->x.pSelect->pEList;
        if( ALWAYS(pEList!=0 && pEList->nExpr>0) ){ 
          keyInfo.aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft,
              pEList->a[0].pExpr);
................................................................................
        dest.eDest = SRT_Exists;
        sqlite3VdbeAddOp2(v, OP_Integer, 0, dest.iParm);
        VdbeComment((v, "Init EXISTS result"));
      }
      sqlite3ExprDelete(pParse->db, pSel->pLimit);
      pSel->pLimit = sqlite3PExpr(pParse, TK_INTEGER, 0, 0,
                                  &sqlite3IntTokens[1]);

      if( sqlite3Select(pParse, pSel, &dest) ){
        return 0;
      }
      rReg = dest.iParm;
      ExprSetIrreducible(pExpr);
      break;
    }
................................................................................
  return WRC_Continue;
}

/*
** Preevaluate constant subexpressions within pExpr and store the
** results in registers.  Modify pExpr so that the constant subexpresions
** are TK_REGISTER opcodes that refer to the precomputed values.











*/
void sqlite3ExprCodeConstants(Parse *pParse, Expr *pExpr){
  Walker w;


  w.xExprCallback = evalConstExpr;
  w.xSelectCallback = 0;
  w.pParse = pParse;
  sqlite3WalkExpr(&w, pExpr);
}









>







 







>







 







>
>
>
>
>
>
>
>
>
>
>



>
>







1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
....
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
....
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
        SelectDest dest;
        ExprList *pEList;

        assert( !isRowid );
        sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);
        dest.affinity = (u8)affinity;
        assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
        pExpr->x.pSelect->iLimit = 0;
        if( sqlite3Select(pParse, pExpr->x.pSelect, &dest) ){
          return 0;
        }
        pEList = pExpr->x.pSelect->pEList;
        if( ALWAYS(pEList!=0 && pEList->nExpr>0) ){ 
          keyInfo.aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft,
              pEList->a[0].pExpr);
................................................................................
        dest.eDest = SRT_Exists;
        sqlite3VdbeAddOp2(v, OP_Integer, 0, dest.iParm);
        VdbeComment((v, "Init EXISTS result"));
      }
      sqlite3ExprDelete(pParse->db, pSel->pLimit);
      pSel->pLimit = sqlite3PExpr(pParse, TK_INTEGER, 0, 0,
                                  &sqlite3IntTokens[1]);
      pSel->iLimit = 0;
      if( sqlite3Select(pParse, pSel, &dest) ){
        return 0;
      }
      rReg = dest.iParm;
      ExprSetIrreducible(pExpr);
      break;
    }
................................................................................
  return WRC_Continue;
}

/*
** Preevaluate constant subexpressions within pExpr and store the
** results in registers.  Modify pExpr so that the constant subexpresions
** are TK_REGISTER opcodes that refer to the precomputed values.
**
** This routine is a no-op if the jump to the cookie-check code has
** already occur.  Since the cookie-check jump is generated prior to
** any other serious processing, this check ensures that there is no
** way to accidently bypass the constant initializations.
**
** This routine is also a no-op if the SQLITE_FactorOutConst optimization
** is disabled via the sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS)
** interface.  This allows test logic to verify that the same answer is
** obtained for queries regardless of whether or not constants are
** precomputed into registers or if they are inserted in-line.
*/
void sqlite3ExprCodeConstants(Parse *pParse, Expr *pExpr){
  Walker w;
  if( pParse->cookieGoto ) return;
  if( (pParse->db->flags & SQLITE_FactorOutConst)!=0 ) return;
  w.xExprCallback = evalConstExpr;
  w.xSelectCallback = 0;
  w.pParse = pParse;
  sqlite3WalkExpr(&w, pExpr);
}


Changes to src/os_unix.c.

5102
5103
5104
5105
5106
5107
5108
5109
5110
5111
5112
5113
5114
5115
5116
....
5239
5240
5241
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251
5252
5253
....
5719
5720
5721
5722
5723
5724
5725
5726
5727
5728
5729
5730
5731
5732
5733
5734
5735
5736
5737
5738
5739
5740
5741
5742
5743
5744
5745
5746
5747
5748
5749
5750
5751
5752
5753
** SQLite calls this function immediately after a call to unixDlSym() or
** unixDlOpen() fails (returns a null pointer). If a more detailed error
** message is available, it is written to zBufOut. If no error message
** is available, zBufOut is left unmodified and SQLite uses a default
** error message.
*/
static void unixDlError(sqlite3_vfs *NotUsed, int nBuf, char *zBufOut){
  char *zErr;
  UNUSED_PARAMETER(NotUsed);
  unixEnterMutex();
  zErr = dlerror();
  if( zErr ){
    sqlite3_snprintf(nBuf, zBufOut, "%s", zErr);
  }
  unixLeaveMutex();
................................................................................
** On success, return 0.  Return 1 if the time and date cannot be found.
*/
static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){
  static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
#if defined(NO_GETTOD)
  time_t t;
  time(&t);
  *piNow = ((sqlite3_int64)i)*1000 + unixEpoch;
#elif OS_VXWORKS
  struct timespec sNow;
  clock_gettime(CLOCK_REALTIME, &sNow);
  *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_nsec/1000000;
#else
  struct timeval sNow;
  gettimeofday(&sNow, 0);
................................................................................
  int rc = -1;
  UNUSED_PARAMETER(myHostID);

  /* create a new path by replace the trailing '-conch' with '-break' */
  pathLen = strlcpy(tPath, cPath, MAXPATHLEN);
  if( pathLen>MAXPATHLEN || pathLen<6 || 
     (strlcpy(&tPath[pathLen-5], "break", 6) != 5) ){
    sprintf(errmsg, "path error (len %d)", (int)pathLen);
    goto end_breaklock;
  }
  /* read the conch content */
  readLen = pread(conchFile->h, buf, PROXY_MAXCONCHLEN, 0);
  if( readLen<PROXY_PATHINDEX ){
    sprintf(errmsg, "read error (len %d)", (int)readLen);
    goto end_breaklock;
  }
  /* write it out to the temporary break file */
  fd = open(tPath, (O_RDWR|O_CREAT|O_EXCL), SQLITE_DEFAULT_FILE_PERMISSIONS);
  if( fd<0 ){
    sprintf(errmsg, "create failed (%d)", errno);
    goto end_breaklock;
  }
  if( pwrite(fd, buf, readLen, 0) != (ssize_t)readLen ){
    sprintf(errmsg, "write failed (%d)", errno);
    goto end_breaklock;
  }
  if( rename(tPath, cPath) ){
    sprintf(errmsg, "rename failed (%d)", errno);
    goto end_breaklock;
  }
  rc = 0;
  fprintf(stderr, "broke stale lock on %s\n", cPath);
  close(conchFile->h);
  conchFile->h = fd;
  conchFile->openFlags = O_RDWR | O_CREAT;







|







 







|







 







|





|





|



|



|







5102
5103
5104
5105
5106
5107
5108
5109
5110
5111
5112
5113
5114
5115
5116
....
5239
5240
5241
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251
5252
5253
....
5719
5720
5721
5722
5723
5724
5725
5726
5727
5728
5729
5730
5731
5732
5733
5734
5735
5736
5737
5738
5739
5740
5741
5742
5743
5744
5745
5746
5747
5748
5749
5750
5751
5752
5753
** SQLite calls this function immediately after a call to unixDlSym() or
** unixDlOpen() fails (returns a null pointer). If a more detailed error
** message is available, it is written to zBufOut. If no error message
** is available, zBufOut is left unmodified and SQLite uses a default
** error message.
*/
static void unixDlError(sqlite3_vfs *NotUsed, int nBuf, char *zBufOut){
  const char *zErr;
  UNUSED_PARAMETER(NotUsed);
  unixEnterMutex();
  zErr = dlerror();
  if( zErr ){
    sqlite3_snprintf(nBuf, zBufOut, "%s", zErr);
  }
  unixLeaveMutex();
................................................................................
** On success, return 0.  Return 1 if the time and date cannot be found.
*/
static int unixCurrentTimeInt64(sqlite3_vfs *NotUsed, sqlite3_int64 *piNow){
  static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000;
#if defined(NO_GETTOD)
  time_t t;
  time(&t);
  *piNow = ((sqlite3_int64)t)*1000 + unixEpoch;
#elif OS_VXWORKS
  struct timespec sNow;
  clock_gettime(CLOCK_REALTIME, &sNow);
  *piNow = unixEpoch + 1000*(sqlite3_int64)sNow.tv_sec + sNow.tv_nsec/1000000;
#else
  struct timeval sNow;
  gettimeofday(&sNow, 0);
................................................................................
  int rc = -1;
  UNUSED_PARAMETER(myHostID);

  /* create a new path by replace the trailing '-conch' with '-break' */
  pathLen = strlcpy(tPath, cPath, MAXPATHLEN);
  if( pathLen>MAXPATHLEN || pathLen<6 || 
     (strlcpy(&tPath[pathLen-5], "break", 6) != 5) ){
    sqlite3_snprintf(sizeof(errmsg),errmsg,"path error (len %d)",(int)pathLen);
    goto end_breaklock;
  }
  /* read the conch content */
  readLen = pread(conchFile->h, buf, PROXY_MAXCONCHLEN, 0);
  if( readLen<PROXY_PATHINDEX ){
    sqlite3_snprintf(sizeof(errmsg),errmsg,"read error (len %d)",(int)readLen);
    goto end_breaklock;
  }
  /* write it out to the temporary break file */
  fd = open(tPath, (O_RDWR|O_CREAT|O_EXCL), SQLITE_DEFAULT_FILE_PERMISSIONS);
  if( fd<0 ){
    sqlite3_snprintf(sizeof(errmsg), errmsg, "create failed (%d)", errno);
    goto end_breaklock;
  }
  if( pwrite(fd, buf, readLen, 0) != (ssize_t)readLen ){
    sqlite3_snprintf(sizeof(errmsg), errmsg, "write failed (%d)", errno);
    goto end_breaklock;
  }
  if( rename(tPath, cPath) ){
    sqlite3_snprintf(sizeof(errmsg), errmsg, "rename failed (%d)", errno);
    goto end_breaklock;
  }
  rc = 0;
  fprintf(stderr, "broke stale lock on %s\n", cPath);
  close(conchFile->h);
  conchFile->h = fd;
  conchFile->openFlags = O_RDWR | O_CREAT;

Changes to src/pager.c.

3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
**
** Regardless of mxPage, return the current maximum page count.
*/
int sqlite3PagerMaxPageCount(Pager *pPager, int mxPage){
  if( mxPage>0 ){
    pPager->mxPgno = mxPage;
  }
  if( pPager->eState!=PAGER_OPEN && pPager->mxPgno<pPager->dbSize ){
    pPager->mxPgno = pPager->dbSize;
  }
  return pPager->mxPgno;
}

/*
** The following set of routines are used to disable the simulated
** I/O error mechanism.  These routines are used to avoid simulated
** errors in places where we do not care about errors.







|
|
<







3479
3480
3481
3482
3483
3484
3485
3486
3487

3488
3489
3490
3491
3492
3493
3494
**
** Regardless of mxPage, return the current maximum page count.
*/
int sqlite3PagerMaxPageCount(Pager *pPager, int mxPage){
  if( mxPage>0 ){
    pPager->mxPgno = mxPage;
  }
  assert( pPager->eState!=PAGER_OPEN );      /* Called only by OP_MaxPgcnt */
  assert( pPager->mxPgno>=pPager->dbSize );  /* OP_MaxPgcnt enforces this */

  return pPager->mxPgno;
}

/*
** The following set of routines are used to disable the simulated
** I/O error mechanism.  These routines are used to avoid simulated
** errors in places where we do not care about errors.

Changes to src/pragma.c.

31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
..
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
...
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
...
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
...
465
466
467
468
469
470
471








472
473
474
475
476


477
478
479
480

481



482
483
484
485
486
487
488
489
490
491
...
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
....
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
....
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
....
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
                             /* 123456789 123456789 */
  static const char zText[] = "onoffalseyestruefull";
  static const u8 iOffset[] = {0, 1, 2, 4, 9, 12, 16};
  static const u8 iLength[] = {2, 2, 3, 5, 3, 4, 4};
  static const u8 iValue[] =  {1, 0, 0, 0, 1, 1, 2};
  int i, n;
  if( sqlite3Isdigit(*z) ){
    return (u8)atoi(z);
  }
  n = sqlite3Strlen30(z);
  for(i=0; i<ArraySize(iLength); i++){
    if( iLength[i]==n && sqlite3StrNICmp(&zText[iOffset[i]],z,n)==0 ){
      return iValue[i];
    }
  }
................................................................................
** acceptable, as are their numeric equivalents: 0, 1 and 2 respectively.
*/
static int getAutoVacuum(const char *z){
  int i;
  if( 0==sqlite3StrICmp(z, "none") ) return BTREE_AUTOVACUUM_NONE;
  if( 0==sqlite3StrICmp(z, "full") ) return BTREE_AUTOVACUUM_FULL;
  if( 0==sqlite3StrICmp(z, "incremental") ) return BTREE_AUTOVACUUM_INCR;
  i = atoi(z);
  return (u8)((i>=0&&i<=2)?i:0);
}
#endif /* ifndef SQLITE_OMIT_AUTOVACUUM */

#ifndef SQLITE_OMIT_PAGER_PRAGMAS
/*
** Interpret the given string as a temp db location. Return 1 for file
................................................................................
      sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cache_size", SQLITE_STATIC);
      pParse->nMem += 2;
      addr = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize);
      sqlite3VdbeChangeP1(v, addr, iDb);
      sqlite3VdbeChangeP1(v, addr+1, iDb);
      sqlite3VdbeChangeP1(v, addr+6, SQLITE_DEFAULT_CACHE_SIZE);
    }else{
      int size = atoi(zRight);
      if( size<0 ) size = -size;
      sqlite3BeginWriteOperation(pParse, 0, iDb);
      sqlite3VdbeAddOp2(v, OP_Integer, size, 1);
      sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_DEFAULT_CACHE_SIZE, 1);
      pDb->pSchema->cache_size = size;
      sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
    }
................................................................................
    if( !zRight ){
      i64 size = ALWAYS(pBt) ? sqlite3BtreeGetPageSize(pBt) : 0;
      returnSingleInt(pParse, "page_size", &size);
    }else{
      /* Malloc may fail when setting the page-size, as there is an internal
      ** buffer that the pager module resizes using sqlite3_realloc().
      */
      db->nextPagesize = atoi(zRight);
      if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, -1, 0) ){
        db->mallocFailed = 1;
      }
    }
  }else

  /*
  **  PRAGMA [database.]max_page_count
  **  PRAGMA [database.]max_page_count=N
  **
  ** The first form reports the current setting for the
  ** maximum number of pages in the database file.  The 
  ** second form attempts to change this setting.  Both
  ** forms return the current setting.
  */
  if( sqlite3StrICmp(zLeft,"max_page_count")==0 ){
    Btree *pBt = pDb->pBt;
    i64 newMax = 0;
    assert( pBt!=0 );
    if( zRight ){
      newMax = atoi(zRight);
    }
    if( ALWAYS(pBt) ){
      newMax = sqlite3BtreeMaxPageCount(pBt, (int)newMax);
    }
    returnSingleInt(pParse, "max_page_count", &newMax);
  }else

  /*
  **  PRAGMA [database.]secure_delete
  **  PRAGMA [database.]secure_delete=ON/OFF
  **
  ** The first form reports the current setting for the
  ** secure_delete flag.  The second form changes the secure_delete
  ** flag setting and reports thenew value.
................................................................................
      }
    }
    b = sqlite3BtreeSecureDelete(pBt, b);
    returnSingleInt(pParse, "secure_delete", &b);
  }else

  /*








  **  PRAGMA [database.]page_count
  **
  ** Return the number of pages in the specified database.
  */
  if( sqlite3StrICmp(zLeft,"page_count")==0 ){


    int iReg;
    if( sqlite3ReadSchema(pParse) ) goto pragma_out;
    sqlite3CodeVerifySchema(pParse, iDb);
    iReg = ++pParse->nMem;

    sqlite3VdbeAddOp2(v, OP_Pagecount, iDb, iReg);



    sqlite3VdbeAddOp2(v, OP_ResultRow, iReg, 1);
    sqlite3VdbeSetNumCols(v, 1);
    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "page_count", SQLITE_STATIC);
  }else

  /*
  **  PRAGMA [database.]locking_mode
  **  PRAGMA [database.]locking_mode = (normal|exclusive)
  */
  if( sqlite3StrICmp(zLeft,"locking_mode")==0 ){
................................................................................
  */
  if( sqlite3StrICmp(zLeft,"cache_size")==0 ){
    if( sqlite3ReadSchema(pParse) ) goto pragma_out;
    if( !zRight ){
      i64 cacheSize = pDb->pSchema->cache_size;
      returnSingleInt(pParse, "cache_size", &cacheSize);
    }else{
      int size = atoi(zRight);
      if( size<0 ) size = -size;
      pDb->pSchema->cache_size = size;
      sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
    }
  }else

  /*
................................................................................
    pParse->nMem = 6;
    sqlite3VdbeSetNumCols(v, 1);
    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "integrity_check", SQLITE_STATIC);

    /* Set the maximum error count */
    mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
    if( zRight ){
      mxErr = atoi(zRight);
      if( mxErr<=0 ){
        mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
      }
    }
    sqlite3VdbeAddOp2(v, OP_Integer, mxErr, 1);  /* reg[1] holds errors left */

    /* Do an integrity check on each database file */
................................................................................
      static const VdbeOpList setCookie[] = {
        { OP_Transaction,    0,  1,  0},    /* 0 */
        { OP_Integer,        0,  1,  0},    /* 1 */
        { OP_SetCookie,      0,  0,  1},    /* 2 */
      };
      int addr = sqlite3VdbeAddOpList(v, ArraySize(setCookie), setCookie);
      sqlite3VdbeChangeP1(v, addr, iDb);
      sqlite3VdbeChangeP1(v, addr+1, atoi(zRight));
      sqlite3VdbeChangeP1(v, addr+2, iDb);
      sqlite3VdbeChangeP2(v, addr+2, iCookie);
    }else{
      /* Read the specified cookie value */
      static const VdbeOpList readCookie[] = {
        { OP_Transaction,     0,  0,  0},    /* 0 */
        { OP_ReadCookie,      0,  1,  0},    /* 1 */
................................................................................
  ** Configure a database connection to automatically checkpoint a database
  ** after accumulating N frames in the log. Or query for the current value
  ** of N.
  */
  if( sqlite3StrICmp(zLeft, "wal_autocheckpoint")==0 ){
    i64 walArg = 0;
    if( zRight ){
      int nAuto = atoi(zRight);
      sqlite3_wal_autocheckpoint(db, nAuto);
    }
    if( db->xWalCallback==sqlite3WalDefaultHook ){
      walArg = SQLITE_PTR_TO_INT(db->pWalArg);
    }
    returnSingleInt(pParse, "wal_autocheckpoint", &walArg);
  }else
#endif







|







 







|







 







|







 







|






<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







>
>
>
>
>
>
>
>




|
>
>




>
|
>
>
>


|







 







|







 







|







 







|







 







<
|







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
..
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
...
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
...
410
411
412
413
414
415
416
417
418
419
420
421
422
423






















424
425
426
427
428
429
430
...
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
473
474
475
476
477
478
479
480
481
482
483
...
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
....
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
....
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
....
1406
1407
1408
1409
1410
1411
1412

1413
1414
1415
1416
1417
1418
1419
1420
                             /* 123456789 123456789 */
  static const char zText[] = "onoffalseyestruefull";
  static const u8 iOffset[] = {0, 1, 2, 4, 9, 12, 16};
  static const u8 iLength[] = {2, 2, 3, 5, 3, 4, 4};
  static const u8 iValue[] =  {1, 0, 0, 0, 1, 1, 2};
  int i, n;
  if( sqlite3Isdigit(*z) ){
    return (u8)sqlite3Atoi(z);
  }
  n = sqlite3Strlen30(z);
  for(i=0; i<ArraySize(iLength); i++){
    if( iLength[i]==n && sqlite3StrNICmp(&zText[iOffset[i]],z,n)==0 ){
      return iValue[i];
    }
  }
................................................................................
** acceptable, as are their numeric equivalents: 0, 1 and 2 respectively.
*/
static int getAutoVacuum(const char *z){
  int i;
  if( 0==sqlite3StrICmp(z, "none") ) return BTREE_AUTOVACUUM_NONE;
  if( 0==sqlite3StrICmp(z, "full") ) return BTREE_AUTOVACUUM_FULL;
  if( 0==sqlite3StrICmp(z, "incremental") ) return BTREE_AUTOVACUUM_INCR;
  i = sqlite3Atoi(z);
  return (u8)((i>=0&&i<=2)?i:0);
}
#endif /* ifndef SQLITE_OMIT_AUTOVACUUM */

#ifndef SQLITE_OMIT_PAGER_PRAGMAS
/*
** Interpret the given string as a temp db location. Return 1 for file
................................................................................
      sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "cache_size", SQLITE_STATIC);
      pParse->nMem += 2;
      addr = sqlite3VdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize);
      sqlite3VdbeChangeP1(v, addr, iDb);
      sqlite3VdbeChangeP1(v, addr+1, iDb);
      sqlite3VdbeChangeP1(v, addr+6, SQLITE_DEFAULT_CACHE_SIZE);
    }else{
      int size = sqlite3Atoi(zRight);
      if( size<0 ) size = -size;
      sqlite3BeginWriteOperation(pParse, 0, iDb);
      sqlite3VdbeAddOp2(v, OP_Integer, size, 1);
      sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, BTREE_DEFAULT_CACHE_SIZE, 1);
      pDb->pSchema->cache_size = size;
      sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
    }
................................................................................
    if( !zRight ){
      i64 size = ALWAYS(pBt) ? sqlite3BtreeGetPageSize(pBt) : 0;
      returnSingleInt(pParse, "page_size", &size);
    }else{
      /* Malloc may fail when setting the page-size, as there is an internal
      ** buffer that the pager module resizes using sqlite3_realloc().
      */
      db->nextPagesize = sqlite3Atoi(zRight);
      if( SQLITE_NOMEM==sqlite3BtreeSetPageSize(pBt, db->nextPagesize, -1, 0) ){
        db->mallocFailed = 1;
      }
    }
  }else























  /*
  **  PRAGMA [database.]secure_delete
  **  PRAGMA [database.]secure_delete=ON/OFF
  **
  ** The first form reports the current setting for the
  ** secure_delete flag.  The second form changes the secure_delete
  ** flag setting and reports thenew value.
................................................................................
      }
    }
    b = sqlite3BtreeSecureDelete(pBt, b);
    returnSingleInt(pParse, "secure_delete", &b);
  }else

  /*
  **  PRAGMA [database.]max_page_count
  **  PRAGMA [database.]max_page_count=N
  **
  ** The first form reports the current setting for the
  ** maximum number of pages in the database file.  The 
  ** second form attempts to change this setting.  Both
  ** forms return the current setting.
  **
  **  PRAGMA [database.]page_count
  **
  ** Return the number of pages in the specified database.
  */
  if( sqlite3StrICmp(zLeft,"page_count")==0
   || sqlite3StrICmp(zLeft,"max_page_count")==0
  ){
    int iReg;
    if( sqlite3ReadSchema(pParse) ) goto pragma_out;
    sqlite3CodeVerifySchema(pParse, iDb);
    iReg = ++pParse->nMem;
    if( zLeft[0]=='p' ){
      sqlite3VdbeAddOp2(v, OP_Pagecount, iDb, iReg);
    }else{
      sqlite3VdbeAddOp3(v, OP_MaxPgcnt, iDb, iReg, sqlite3Atoi(zRight));
    }
    sqlite3VdbeAddOp2(v, OP_ResultRow, iReg, 1);
    sqlite3VdbeSetNumCols(v, 1);
    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, SQLITE_TRANSIENT);
  }else

  /*
  **  PRAGMA [database.]locking_mode
  **  PRAGMA [database.]locking_mode = (normal|exclusive)
  */
  if( sqlite3StrICmp(zLeft,"locking_mode")==0 ){
................................................................................
  */
  if( sqlite3StrICmp(zLeft,"cache_size")==0 ){
    if( sqlite3ReadSchema(pParse) ) goto pragma_out;
    if( !zRight ){
      i64 cacheSize = pDb->pSchema->cache_size;
      returnSingleInt(pParse, "cache_size", &cacheSize);
    }else{
      int size = sqlite3Atoi(zRight);
      if( size<0 ) size = -size;
      pDb->pSchema->cache_size = size;
      sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size);
    }
  }else

  /*
................................................................................
    pParse->nMem = 6;
    sqlite3VdbeSetNumCols(v, 1);
    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "integrity_check", SQLITE_STATIC);

    /* Set the maximum error count */
    mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
    if( zRight ){
      sqlite3GetInt32(zRight, &mxErr);
      if( mxErr<=0 ){
        mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
      }
    }
    sqlite3VdbeAddOp2(v, OP_Integer, mxErr, 1);  /* reg[1] holds errors left */

    /* Do an integrity check on each database file */
................................................................................
      static const VdbeOpList setCookie[] = {
        { OP_Transaction,    0,  1,  0},    /* 0 */
        { OP_Integer,        0,  1,  0},    /* 1 */
        { OP_SetCookie,      0,  0,  1},    /* 2 */
      };
      int addr = sqlite3VdbeAddOpList(v, ArraySize(setCookie), setCookie);
      sqlite3VdbeChangeP1(v, addr, iDb);
      sqlite3VdbeChangeP1(v, addr+1, sqlite3Atoi(zRight));
      sqlite3VdbeChangeP1(v, addr+2, iDb);
      sqlite3VdbeChangeP2(v, addr+2, iCookie);
    }else{
      /* Read the specified cookie value */
      static const VdbeOpList readCookie[] = {
        { OP_Transaction,     0,  0,  0},    /* 0 */
        { OP_ReadCookie,      0,  1,  0},    /* 1 */
................................................................................
  ** Configure a database connection to automatically checkpoint a database
  ** after accumulating N frames in the log. Or query for the current value
  ** of N.
  */
  if( sqlite3StrICmp(zLeft, "wal_autocheckpoint")==0 ){
    i64 walArg = 0;
    if( zRight ){

      sqlite3_wal_autocheckpoint(db, sqlite3Atoi(zRight));
    }
    if( db->xWalCallback==sqlite3WalDefaultHook ){
      walArg = SQLITE_PTR_TO_INT(db->pWalArg);
    }
    returnSingleInt(pParse, "wal_autocheckpoint", &walArg);
  }else
#endif

Changes to src/prepare.c.

78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
    */
    int rc;
    sqlite3_stmt *pStmt;
    TESTONLY(int rcp);            /* Return code from sqlite3_prepare() */

    assert( db->init.busy );
    db->init.iDb = iDb;
    db->init.newTnum = atoi(argv[1]);
    db->init.orphanTrigger = 0;
    TESTONLY(rcp = ) sqlite3_prepare(db, argv[2], -1, &pStmt, 0);
    rc = db->errCode;
    assert( (rc&0xFF)==(rcp&0xFF) );
    db->init.iDb = 0;
    if( SQLITE_OK!=rc ){
      if( db->init.orphanTrigger ){







|







78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
    */
    int rc;
    sqlite3_stmt *pStmt;
    TESTONLY(int rcp);            /* Return code from sqlite3_prepare() */

    assert( db->init.busy );
    db->init.iDb = iDb;
    db->init.newTnum = sqlite3Atoi(argv[1]);
    db->init.orphanTrigger = 0;
    TESTONLY(rcp = ) sqlite3_prepare(db, argv[2], -1, &pStmt, 0);
    rc = db->errCode;
    assert( (rc&0xFF)==(rcp&0xFF) );
    db->init.iDb = 0;
    if( SQLITE_OK!=rc ){
      if( db->init.orphanTrigger ){

Changes to src/select.c.

3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
        isAgg = 1;
        p->selFlags |= SF_Aggregate;
      }
      i = -1;
    }else{
      sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
      assert( pItem->isPopulated==0 );
      explainSetInteger(pItem->iSelectId, pParse->iNextSelectId);
      sqlite3Select(pParse, pSub, &dest);
      pItem->isPopulated = 1;
      pItem->pTab->nRowEst = (unsigned)pSub->nSelectRow;
    }
    if( /*pParse->nErr ||*/ db->mallocFailed ){
      goto select_end;
    }







|







3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
        isAgg = 1;
        p->selFlags |= SF_Aggregate;
      }
      i = -1;
    }else{
      sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor);
      assert( pItem->isPopulated==0 );
      explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId);
      sqlite3Select(pParse, pSub, &dest);
      pItem->isPopulated = 1;
      pItem->pTab->nRowEst = (unsigned)pSub->nSelectRow;
    }
    if( /*pParse->nErr ||*/ db->mallocFailed ){
      goto select_end;
    }

Changes to src/sqlite.h.in.

4831
4832
4833
4834
4835
4836
4837
4838

4839
4840
4841
4842
4843
4844
4845
** ^(The new row must meet the same criteria as for [sqlite3_blob_open()] -
** it must exist and there must be either a blob or text value stored in
** the nominated column.)^ ^If the new row is not present in the table, or if
** it does not contain a blob or text value, or if another error occurs, an
** SQLite error code is returned and the blob handle is considered aborted.
** ^All subsequent calls to [sqlite3_blob_read()], [sqlite3_blob_write()] or
** [sqlite3_blob_reopen()] on an aborted blob handle immediately return
** SQLITE_ABORT.

**
** ^This function sets the database handle error code and message.
*/
SQLITE_EXPERIMENTAL int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);

/*
** CAPI3REF: Close A BLOB Handle







|
>







4831
4832
4833
4834
4835
4836
4837
4838
4839
4840
4841
4842
4843
4844
4845
4846
** ^(The new row must meet the same criteria as for [sqlite3_blob_open()] -
** it must exist and there must be either a blob or text value stored in
** the nominated column.)^ ^If the new row is not present in the table, or if
** it does not contain a blob or text value, or if another error occurs, an
** SQLite error code is returned and the blob handle is considered aborted.
** ^All subsequent calls to [sqlite3_blob_read()], [sqlite3_blob_write()] or
** [sqlite3_blob_reopen()] on an aborted blob handle immediately return
** SQLITE_ABORT. ^Calling [sqlite3_blob_bytes()] on an aborted blob handle
** always returns zero.
**
** ^This function sets the database handle error code and message.
*/
SQLITE_EXPERIMENTAL int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);

/*
** CAPI3REF: Close A BLOB Handle

Changes to src/sqliteInt.h.

930
931
932
933
934
935
936

937
938
939
940
941
942
943
....
1818
1819
1820
1821
1822
1823
1824



1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
....
2836
2837
2838
2839
2840
2841
2842

2843
2844
2845
2846
2847
2848
2849
*/
#define SQLITE_QueryFlattener 0x01        /* Disable query flattening */
#define SQLITE_ColumnCache    0x02        /* Disable the column cache */
#define SQLITE_IndexSort      0x04        /* Disable indexes for sorting */
#define SQLITE_IndexSearch    0x08        /* Disable indexes for searching */
#define SQLITE_IndexCover     0x10        /* Disable index covering table */
#define SQLITE_GroupByOrder   0x20        /* Disable GROUPBY cover of ORDERBY */

#define SQLITE_OptMask        0xff        /* Mask of all disablable opts */

/*
** Possible values for the sqlite.magic field.
** The numbers are obtained at random and have no special meaning, other
** than being distinct from one another.
*/
................................................................................
    char *zName;      /* Name of the table */
    char *zAlias;     /* The "B" part of a "A AS B" phrase.  zName is the "A" */
    Table *pTab;      /* An SQL table corresponding to zName */
    Select *pSelect;  /* A SELECT statement used in place of a table name */
    u8 isPopulated;   /* Temporary table associated with SELECT is populated */
    u8 jointype;      /* Type of join between this able and the previous */
    u8 notIndexed;    /* True if there is a NOT INDEXED clause */



    int iCursor;      /* The VDBE cursor number used to access this table */
    Expr *pOn;        /* The ON clause of a join */
    IdList *pUsing;   /* The USING clause of a join */
    Bitmask colUsed;  /* Bit N (1<<N) set if column N of pTab is used */
    char *zIndex;     /* Identifier from "INDEXED BY <zIndex>" clause */
    Index *pIndex;    /* Index structure corresponding to zIndex, if any */
#ifndef SQLITE_OMIT_EXPLAIN
    int iSelectId;    /* If pSelect!=0, the id of the sub-select in EQP */
#endif
  } a[1];             /* One entry for each identifier on the list */
};

/*
** Permitted values of the SrcList.a.jointype field
*/
#define JT_INNER     0x0001    /* Any kind of inner or cross join */
................................................................................
int sqlite3FixSrcList(DbFixer*, SrcList*);
int sqlite3FixSelect(DbFixer*, Select*);
int sqlite3FixExpr(DbFixer*, Expr*);
int sqlite3FixExprList(DbFixer*, ExprList*);
int sqlite3FixTriggerStep(DbFixer*, TriggerStep*);
int sqlite3AtoF(const char *z, double*, int, u8);
int sqlite3GetInt32(const char *, int*);

int sqlite3Utf16ByteLen(const void *pData, int nChar);
int sqlite3Utf8CharLen(const char *pData, int nByte);
int sqlite3Utf8Read(const u8*, const u8**);

/*
** Routines to read and write variable-length integers.  These used to
** be defined locally, but now we use the varint routines in the util.c







>







 







>
>
>






<
<
<







 







>







930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
....
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834



1835
1836
1837
1838
1839
1840
1841
....
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
*/
#define SQLITE_QueryFlattener 0x01        /* Disable query flattening */
#define SQLITE_ColumnCache    0x02        /* Disable the column cache */
#define SQLITE_IndexSort      0x04        /* Disable indexes for sorting */
#define SQLITE_IndexSearch    0x08        /* Disable indexes for searching */
#define SQLITE_IndexCover     0x10        /* Disable index covering table */
#define SQLITE_GroupByOrder   0x20        /* Disable GROUPBY cover of ORDERBY */
#define SQLITE_FactorOutConst 0x40        /* Disable factoring out constants */
#define SQLITE_OptMask        0xff        /* Mask of all disablable opts */

/*
** Possible values for the sqlite.magic field.
** The numbers are obtained at random and have no special meaning, other
** than being distinct from one another.
*/
................................................................................
    char *zName;      /* Name of the table */
    char *zAlias;     /* The "B" part of a "A AS B" phrase.  zName is the "A" */
    Table *pTab;      /* An SQL table corresponding to zName */
    Select *pSelect;  /* A SELECT statement used in place of a table name */
    u8 isPopulated;   /* Temporary table associated with SELECT is populated */
    u8 jointype;      /* Type of join between this able and the previous */
    u8 notIndexed;    /* True if there is a NOT INDEXED clause */
#ifndef SQLITE_OMIT_EXPLAIN
    u8 iSelectId;     /* If pSelect!=0, the id of the sub-select in EQP */
#endif
    int iCursor;      /* The VDBE cursor number used to access this table */
    Expr *pOn;        /* The ON clause of a join */
    IdList *pUsing;   /* The USING clause of a join */
    Bitmask colUsed;  /* Bit N (1<<N) set if column N of pTab is used */
    char *zIndex;     /* Identifier from "INDEXED BY <zIndex>" clause */
    Index *pIndex;    /* Index structure corresponding to zIndex, if any */



  } a[1];             /* One entry for each identifier on the list */
};

/*
** Permitted values of the SrcList.a.jointype field
*/
#define JT_INNER     0x0001    /* Any kind of inner or cross join */
................................................................................
int sqlite3FixSrcList(DbFixer*, SrcList*);
int sqlite3FixSelect(DbFixer*, Select*);
int sqlite3FixExpr(DbFixer*, Expr*);
int sqlite3FixExprList(DbFixer*, ExprList*);
int sqlite3FixTriggerStep(DbFixer*, TriggerStep*);
int sqlite3AtoF(const char *z, double*, int, u8);
int sqlite3GetInt32(const char *, int*);
int sqlite3Atoi(const char*);
int sqlite3Utf16ByteLen(const void *pData, int nChar);
int sqlite3Utf8CharLen(const char *pData, int nByte);
int sqlite3Utf8Read(const u8*, const u8**);

/*
** Routines to read and write variable-length integers.  These used to
** be defined locally, but now we use the varint routines in the util.c

Changes to src/test1.c.

5421
5422
5423
5424
5425
5426
5427


























































5428
5429
5430
5431
5432
5433
5434
....
5540
5541
5542
5543
5544
5545
5546

5547
5548
5549
5550
5551
5552
5553
  }
  if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
  rc = printExplainQueryPlan(pStmt);
  Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0);
  return TCL_OK;
}
#endif /* SQLITE_OMIT_EXPLAIN */



























































/*
** Register commands with the TCL interpreter.
*/
int Sqlitetest1_Init(Tcl_Interp *interp){
  extern int sqlite3_search_count;
  extern int sqlite3_found_count;
................................................................................
     { "sqlite3_enable_load_extension", test_enable_load,        0},
     { "sqlite3_extended_result_codes", test_extended_result_codes, 0},
     { "sqlite3_limit",                 test_limit,                 0},

     { "save_prng_state",               save_prng_state,    0 },
     { "restore_prng_state",            restore_prng_state, 0 },
     { "reset_prng_state",              reset_prng_state,   0 },

     { "tcl_objproc",                   runAsObjProc,       0 },

     /* sqlite3_column_*() API */
     { "sqlite3_column_count",          test_column_count  ,0 },
     { "sqlite3_data_count",            test_data_count    ,0 },
     { "sqlite3_column_type",           test_column_type   ,0 },
     { "sqlite3_column_blob",           test_column_blob   ,0 },







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







 







>







5421
5422
5423
5424
5425
5426
5427
5428
5429
5430
5431
5432
5433
5434
5435
5436
5437
5438
5439
5440
5441
5442
5443
5444
5445
5446
5447
5448
5449
5450
5451
5452
5453
5454
5455
5456
5457
5458
5459
5460
5461
5462
5463
5464
5465
5466
5467
5468
5469
5470
5471
5472
5473
5474
5475
5476
5477
5478
5479
5480
5481
5482
5483
5484
5485
5486
5487
5488
5489
5490
5491
5492
....
5598
5599
5600
5601
5602
5603
5604
5605
5606
5607
5608
5609
5610
5611
5612
  }
  if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
  rc = printExplainQueryPlan(pStmt);
  Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0);
  return TCL_OK;
}
#endif /* SQLITE_OMIT_EXPLAIN */

/*
**      optimization_control DB OPT BOOLEAN
**
** Enable or disable query optimizations using the sqlite3_test_control()
** interface.  Disable if BOOLEAN is false and enable if BOOLEAN is true.
** OPT is the name of the optimization to be disabled.
*/
static int optimization_control(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  int i;
  sqlite3 *db;
  const char *zOpt;
  int onoff;
  int mask;
  static const struct {
    const char *zOptName;
    int mask;
  } aOpt[] = {
    { "all",              SQLITE_OptMask        },
    { "query-flattener",  SQLITE_QueryFlattener },
    { "column-cache",     SQLITE_ColumnCache    },
    { "index-sort",       SQLITE_IndexSort      },
    { "index-search",     SQLITE_IndexSearch    },
    { "index-cover",      SQLITE_IndexCover     },
    { "groupby-order",    SQLITE_GroupByOrder   },
    { "factor-constants", SQLITE_FactorOutConst },
  };

  if( objc!=4 ){
    Tcl_WrongNumArgs(interp, 1, objv, "DB OPT BOOLEAN");
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
  if( Tcl_GetBooleanFromObj(interp, objv[3], &onoff) ) return TCL_ERROR;
  zOpt = Tcl_GetString(objv[2]);
  for(i=0; i<sizeof(aOpt)/sizeof(aOpt[0]); i++){
    if( strcmp(zOpt, aOpt[i].zOptName)==0 ){
      mask = aOpt[i].mask;
      break;
    }
  }
  if( onoff ) mask = ~mask;
  if( i>=sizeof(aOpt)/sizeof(aOpt[0]) ){
    Tcl_AppendResult(interp, "unknown optimization - should be one of:",
                     (char*)0);
    for(i=0; i<sizeof(aOpt)/sizeof(aOpt[0]); i++){
      Tcl_AppendResult(interp, " ", aOpt[i].zOptName);
    }
    return TCL_ERROR;
  }
  sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS, db, mask);
  return TCL_OK;
}

/*
** Register commands with the TCL interpreter.
*/
int Sqlitetest1_Init(Tcl_Interp *interp){
  extern int sqlite3_search_count;
  extern int sqlite3_found_count;
................................................................................
     { "sqlite3_enable_load_extension", test_enable_load,        0},
     { "sqlite3_extended_result_codes", test_extended_result_codes, 0},
     { "sqlite3_limit",                 test_limit,                 0},

     { "save_prng_state",               save_prng_state,    0 },
     { "restore_prng_state",            restore_prng_state, 0 },
     { "reset_prng_state",              reset_prng_state,   0 },
     { "optimization_control",          optimization_control,0},
     { "tcl_objproc",                   runAsObjProc,       0 },

     /* sqlite3_column_*() API */
     { "sqlite3_column_count",          test_column_count  ,0 },
     { "sqlite3_data_count",            test_data_count    ,0 },
     { "sqlite3_column_type",           test_column_type   ,0 },
     { "sqlite3_column_blob",           test_column_blob   ,0 },

Changes to src/test_multiplex.c.

541
542
543
544
545
546
547



548
549
550
551
552
553
554
555
556
    }
    if( pSubOpen ){
      sqlite3_int64 sz;
      rc2 = pSubOpen->pMethods->xFileSize(pSubOpen, &sz);
      if( rc2!=SQLITE_OK ){
        rc = rc2;
      }else{



        *pSize += sz;
        assert(sz<=gMultiplex.nChunkSize);
      }
    }else{
      break;
    }
  }
  multiplexLeave();
  return rc;







>
>
>

<







541
542
543
544
545
546
547
548
549
550
551

552
553
554
555
556
557
558
    }
    if( pSubOpen ){
      sqlite3_int64 sz;
      rc2 = pSubOpen->pMethods->xFileSize(pSubOpen, &sz);
      if( rc2!=SQLITE_OK ){
        rc = rc2;
      }else{
        if( sz>gMultiplex.nChunkSize ){
          rc = SQLITE_IOERR_FSTAT;
        }
        *pSize += sz;

      }
    }else{
      break;
    }
  }
  multiplexLeave();
  return rc;

Changes to src/test_superlock.c.

98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
...
307
308
309
310
311
312
313

314
315
316
317
318
319
320
static int superlockWalLock(
  sqlite3 *db,                    /* Database handle open on WAL database */
  SuperlockBusy *pBusy            /* Busy handler wrapper object */
){
  int rc;                         /* Return code */
  sqlite3_file *fd = 0;           /* Main database file handle */
  void volatile *p = 0;           /* Pointer to first page of shared memory */
  int nBusy = 0;                  /* Number of calls already made to xBusy */

  /* Obtain a pointer to the sqlite3_file object open on the main db file. */
  rc = sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, (void *)&fd);
  if( rc!=SQLITE_OK ) return rc;

  /* Obtain the "recovery" lock. Normally, this lock is only obtained by
  ** clients running database recovery.  
................................................................................
  }

  rc = sqlite3demo_superlock(zPath, zVfs, xBusy, &busy, &pLock);
  assert( rc==SQLITE_OK || pLock==0 );
  assert( rc!=SQLITE_OK || pLock!=0 );

  if( rc!=SQLITE_OK ){

    Tcl_ResetResult(interp);
    Tcl_AppendResult(interp, sqlite3ErrStr(rc), 0);
    return TCL_ERROR;
  }

  Tcl_CreateObjCommand(
      interp, Tcl_GetString(objv[1]), superunlock_cmd, pLock, superunlock_del







<







 







>







98
99
100
101
102
103
104

105
106
107
108
109
110
111
...
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
static int superlockWalLock(
  sqlite3 *db,                    /* Database handle open on WAL database */
  SuperlockBusy *pBusy            /* Busy handler wrapper object */
){
  int rc;                         /* Return code */
  sqlite3_file *fd = 0;           /* Main database file handle */
  void volatile *p = 0;           /* Pointer to first page of shared memory */


  /* Obtain a pointer to the sqlite3_file object open on the main db file. */
  rc = sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, (void *)&fd);
  if( rc!=SQLITE_OK ) return rc;

  /* Obtain the "recovery" lock. Normally, this lock is only obtained by
  ** clients running database recovery.  
................................................................................
  }

  rc = sqlite3demo_superlock(zPath, zVfs, xBusy, &busy, &pLock);
  assert( rc==SQLITE_OK || pLock==0 );
  assert( rc!=SQLITE_OK || pLock!=0 );

  if( rc!=SQLITE_OK ){
    extern const char *sqlite3ErrStr(int);
    Tcl_ResetResult(interp);
    Tcl_AppendResult(interp, sqlite3ErrStr(rc), 0);
    return TCL_ERROR;
  }

  Tcl_CreateObjCommand(
      interp, Tcl_GetString(objv[1]), superunlock_cmd, pLock, superunlock_del

Changes to src/util.c.

536
537
538
539
540
541
542










543
544
545
546
547
548
549
  }
  if( neg ){
    v = -v;
  }
  *pValue = (int)v;
  return 1;
}











/*
** The variable-length integer encoding is as follows:
**
** KEY:
**         A = 0xxxxxxx    7 bits of data and one flag bit
**         B = 1xxxxxxx    7 bits of data and one flag bit







>
>
>
>
>
>
>
>
>
>







536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
  }
  if( neg ){
    v = -v;
  }
  *pValue = (int)v;
  return 1;
}

/*
** Return a 32-bit integer value extracted from a string.  If the
** string is not an integer, just return 0.
*/
int sqlite3Atoi(const char *z){
  int x = 0;
  if( z ) sqlite3GetInt32(z, &x);
  return x;
}

/*
** The variable-length integer encoding is as follows:
**
** KEY:
**         A = 0xxxxxxx    7 bits of data and one flag bit
**         B = 1xxxxxxx    7 bits of data and one flag bit

Changes to src/vdbe.c.

1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
....
5783
5784
5785
5786
5787
5788
5789


























5790
5791
5792
5793
5794
5795
5796
** Force the value in register P1 to be an integer.  If the value
** in P1 is not an integer and cannot be converted into an integer
** without data loss, then jump immediately to P2, or if P2==0
** raise an SQLITE_MISMATCH exception.
*/
case OP_MustBeInt: {            /* jump, in1 */
  pIn1 = &aMem[pOp->p1];
  memAboutToChange(p, pIn1);
  applyAffinity(pIn1, SQLITE_AFF_NUMERIC, encoding);
  if( (pIn1->flags & MEM_Int)==0 ){
    if( pOp->p2==0 ){
      rc = SQLITE_MISMATCH;
      goto abort_due_to_error;
    }else{
      pc = pOp->p2 - 1;
................................................................................
** Write the current number of pages in database P1 to memory cell P2.
*/
case OP_Pagecount: {            /* out2-prerelease */
  pOut->u.i = sqlite3BtreeLastPage(db->aDb[pOp->p1].pBt);
  break;
}
#endif



























#ifndef SQLITE_OMIT_TRACE
/* Opcode: Trace * * * P4 *
**
** If tracing is enabled (by the sqlite3_trace()) interface, then
** the UTF-8 string contained in P4 is emitted on the trace callback.
*/







<







 







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







1510
1511
1512
1513
1514
1515
1516

1517
1518
1519
1520
1521
1522
1523
....
5782
5783
5784
5785
5786
5787
5788
5789
5790
5791
5792
5793
5794
5795
5796
5797
5798
5799
5800
5801
5802
5803
5804
5805
5806
5807
5808
5809
5810
5811
5812
5813
5814
5815
5816
5817
5818
5819
5820
5821
** Force the value in register P1 to be an integer.  If the value
** in P1 is not an integer and cannot be converted into an integer
** without data loss, then jump immediately to P2, or if P2==0
** raise an SQLITE_MISMATCH exception.
*/
case OP_MustBeInt: {            /* jump, in1 */
  pIn1 = &aMem[pOp->p1];

  applyAffinity(pIn1, SQLITE_AFF_NUMERIC, encoding);
  if( (pIn1->flags & MEM_Int)==0 ){
    if( pOp->p2==0 ){
      rc = SQLITE_MISMATCH;
      goto abort_due_to_error;
    }else{
      pc = pOp->p2 - 1;
................................................................................
** Write the current number of pages in database P1 to memory cell P2.
*/
case OP_Pagecount: {            /* out2-prerelease */
  pOut->u.i = sqlite3BtreeLastPage(db->aDb[pOp->p1].pBt);
  break;
}
#endif


#ifndef  SQLITE_OMIT_PAGER_PRAGMAS
/* Opcode: MaxPgcnt P1 P2 P3 * *
**
** Try to set the maximum page count for database P1 to the value in P3.
** Do not let the maximum page count fall below the current page count and
** do not change the maximum page count value if P3==0.
**
** Store the maximum page count after the change in register P2.
*/
case OP_MaxPgcnt: {            /* out2-prerelease */
  unsigned int newMax;
  Btree *pBt;

  pBt = db->aDb[pOp->p1].pBt;
  newMax = 0;
  if( pOp->p3 ){
    newMax = sqlite3BtreeLastPage(pBt);
    if( newMax < (unsigned)pOp->p3 ) newMax = (unsigned)pOp->p3;
  }
  pOut->u.i = sqlite3BtreeMaxPageCount(pBt, newMax);
  break;
}
#endif


#ifndef SQLITE_OMIT_TRACE
/* Opcode: Trace * * * P4 *
**
** If tracing is enabled (by the sqlite3_trace()) interface, then
** the UTF-8 string contained in P4 is emitted on the trace callback.
*/

Changes to src/vdbeInt.h.

93
94
95
96
97
98
99
100
101
102








103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
...
329
330
331
332
333
334
335

336
337
338
339
340
341
342
** is allocated to store the current value of the program counter, as
** well as the current memory cell array and various other frame specific
** values stored in the Vdbe struct. When the sub-program is finished, 
** these values are copied back to the Vdbe from the VdbeFrame structure,
** restoring the state of the VM to as it was before the sub-program
** began executing.
**
** Frames are stored in a linked list headed at Vdbe.pParent. Vdbe.pParent
** is the parent of the current frame, or zero if the current frame
** is the main Vdbe program.








*/
typedef struct VdbeFrame VdbeFrame;
struct VdbeFrame {
  Vdbe *v;                /* VM this frame belongs to */
  int pc;                 /* Program Counter */
  Op *aOp;                /* Program instructions */
  int nOp;                /* Size of aOp array */
  Mem *aMem;              /* Array of memory cells */
  int nMem;               /* Number of entries in aMem */
  VdbeCursor **apCsr;     /* Element of Vdbe cursors */
  u16 nCursor;            /* Number of entries in apCsr */
  void *token;            /* Copy of SubProgram.token */
  int nChildMem;          /* Number of memory cells for child frame */
  int nChildCsr;          /* Number of cursors for child frame */
  i64 lastRowid;          /* Last insert rowid (sqlite3.lastRowid) */
  int nChange;            /* Statement changes (Vdbe.nChanges)     */
  VdbeFrame *pParent;     /* Parent of this frame */
};

#define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))])

/*
** A value for VdbeCursor.cacheValid that means the cache is always invalid.
*/
................................................................................
  i64 nFkConstraint;      /* Number of imm. FK constraints this VM */
  i64 nStmtDefCons;       /* Number of def. constraints when stmt started */
  int iStatement;         /* Statement number (or 0 if has not opened stmt) */
#ifdef SQLITE_DEBUG
  FILE *trace;            /* Write an execution trace here, if not NULL */
#endif
  VdbeFrame *pFrame;      /* Parent frame */

  int nFrame;             /* Number of frames in pFrame list */
  u32 expmask;            /* Binding to these vars invalidates VM */
  SubProgram *pProgram;   /* Linked list of all sub-programs used by VM */
};

/*
** The following are allowed values for Vdbe.magic







|
|
|
>
>
>
>
>
>
>
>




|
|

|

|






|







 







>







93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
...
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
** is allocated to store the current value of the program counter, as
** well as the current memory cell array and various other frame specific
** values stored in the Vdbe struct. When the sub-program is finished, 
** these values are copied back to the Vdbe from the VdbeFrame structure,
** restoring the state of the VM to as it was before the sub-program
** began executing.
**
** The memory for a VdbeFrame object is allocated and managed by a memory
** cell in the parent (calling) frame. When the memory cell is deleted or
** overwritten, the VdbeFrame object is not freed immediately. Instead, it
** is linked into the Vdbe.pDelFrame list. The contents of the Vdbe.pDelFrame
** list is deleted when the VM is reset in VdbeHalt(). The reason for doing
** this instead of deleting the VdbeFrame immediately is to avoid recursive
** calls to sqlite3VdbeMemRelease() when the memory cells belonging to the
** child frame are released.
**
** The currently executing frame is stored in Vdbe.pFrame. Vdbe.pFrame is
** set to NULL if the currently executing frame is the main program.
*/
typedef struct VdbeFrame VdbeFrame;
struct VdbeFrame {
  Vdbe *v;                /* VM this frame belongs to */
  int pc;                 /* Program Counter in parent (calling) frame */
  Op *aOp;                /* Program instructions for parent frame */
  int nOp;                /* Size of aOp array */
  Mem *aMem;              /* Array of memory cells for parent frame */
  int nMem;               /* Number of entries in aMem */
  VdbeCursor **apCsr;     /* Array of Vdbe cursors for parent frame */
  u16 nCursor;            /* Number of entries in apCsr */
  void *token;            /* Copy of SubProgram.token */
  int nChildMem;          /* Number of memory cells for child frame */
  int nChildCsr;          /* Number of cursors for child frame */
  i64 lastRowid;          /* Last insert rowid (sqlite3.lastRowid) */
  int nChange;            /* Statement changes (Vdbe.nChanges)     */
  VdbeFrame *pParent;     /* Parent of this frame, or NULL if parent is main */
};

#define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))])

/*
** A value for VdbeCursor.cacheValid that means the cache is always invalid.
*/
................................................................................
  i64 nFkConstraint;      /* Number of imm. FK constraints this VM */
  i64 nStmtDefCons;       /* Number of def. constraints when stmt started */
  int iStatement;         /* Statement number (or 0 if has not opened stmt) */
#ifdef SQLITE_DEBUG
  FILE *trace;            /* Write an execution trace here, if not NULL */
#endif
  VdbeFrame *pFrame;      /* Parent frame */
  VdbeFrame *pDelFrame;   /* List of frame objects to free on VM reset */
  int nFrame;             /* Number of frames in pFrame list */
  u32 expmask;            /* Binding to these vars invalidates VM */
  SubProgram *pProgram;   /* Linked list of all sub-programs used by VM */
};

/*
** The following are allowed values for Vdbe.magic

Changes to src/vdbeaux.c.

1533
1534
1535
1536
1537
1538
1539





1540
1541
1542
1543
1544
1545
1546
        p->apCsr[i] = 0;
      }
    }
  }
  if( p->aMem ){
    releaseMemArray(&p->aMem[1], p->nMem);
  }





}

/*
** Clean up the VM after execution.
**
** This routine will automatically close any cursors, lists, and/or
** sorters that were left open.  It also deletes the values of







>
>
>
>
>







1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
        p->apCsr[i] = 0;
      }
    }
  }
  if( p->aMem ){
    releaseMemArray(&p->aMem[1], p->nMem);
  }
  while( p->pDelFrame ){
    VdbeFrame *pDel = p->pDelFrame;
    p->pDelFrame = pDel->pParent;
    sqlite3VdbeFrameDelete(pDel);
  }
}

/*
** Clean up the VM after execution.
**
** This routine will automatically close any cursors, lists, and/or
** sorters that were left open.  It also deletes the values of

Changes to src/vdbeblob.c.

415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
...
453
454
455
456
457
458
459

460
461
462
463
464
** Query a blob handle for the size of the data.
**
** The Incrblob.nByte field is fixed for the lifetime of the Incrblob
** so no mutex is required for access.
*/
int sqlite3_blob_bytes(sqlite3_blob *pBlob){
  Incrblob *p = (Incrblob *)pBlob;
  return p ? p->nByte : 0;
}

/*
** Move an existing blob handle to point to a different row of the same
** database table.
**
** If an error occurs, or if the specified row does not exist or does not
................................................................................
      sqlite3Error(db, rc, (zErr ? "%s" : 0), zErr);
      sqlite3DbFree(db, zErr);
    }
    assert( rc!=SQLITE_SCHEMA );
  }

  rc = sqlite3ApiExit(db, rc);

  sqlite3_mutex_leave(db->mutex);
  return rc;
}

#endif /* #ifndef SQLITE_OMIT_INCRBLOB */







|







 







>





415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
...
453
454
455
456
457
458
459
460
461
462
463
464
465
** Query a blob handle for the size of the data.
**
** The Incrblob.nByte field is fixed for the lifetime of the Incrblob
** so no mutex is required for access.
*/
int sqlite3_blob_bytes(sqlite3_blob *pBlob){
  Incrblob *p = (Incrblob *)pBlob;
  return (p && p->pStmt) ? p->nByte : 0;
}

/*
** Move an existing blob handle to point to a different row of the same
** database table.
**
** If an error occurs, or if the specified row does not exist or does not
................................................................................
      sqlite3Error(db, rc, (zErr ? "%s" : 0), zErr);
      sqlite3DbFree(db, zErr);
    }
    assert( rc!=SQLITE_SCHEMA );
  }

  rc = sqlite3ApiExit(db, rc);
  assert( rc==SQLITE_OK || p->pStmt==0 );
  sqlite3_mutex_leave(db->mutex);
  return rc;
}

#endif /* #ifndef SQLITE_OMIT_INCRBLOB */

Changes to src/vdbemem.c.

483
484
485
486
487
488
489
490


491
492
493
494
495
496
497
}

/*
** Delete any previous value and set the value stored in *pMem to NULL.
*/
void sqlite3VdbeMemSetNull(Mem *pMem){
  if( pMem->flags & MEM_Frame ){
    sqlite3VdbeFrameDelete(pMem->u.pFrame);


  }
  if( pMem->flags & MEM_RowSet ){
    sqlite3RowSetClear(pMem->u.pRowSet);
  }
  MemSetTypeFlag(pMem, MEM_Null);
  pMem->type = SQLITE_NULL;
}







|
>
>







483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
}

/*
** Delete any previous value and set the value stored in *pMem to NULL.
*/
void sqlite3VdbeMemSetNull(Mem *pMem){
  if( pMem->flags & MEM_Frame ){
    VdbeFrame *pFrame = pMem->u.pFrame;
    pFrame->pParent = pFrame->v->pDelFrame;
    pFrame->v->pDelFrame = pFrame;
  }
  if( pMem->flags & MEM_RowSet ){
    sqlite3RowSetClear(pMem->u.pRowSet);
  }
  MemSetTypeFlag(pMem, MEM_Null);
  pMem->type = SQLITE_NULL;
}

Changes to test/all.test.

12
13
14
15
16
17
18

19
20
21
22
23
24
25
#

set testdir [file dirname $argv0]
source $testdir/permutations.test

run_test_suite full


run_test_suite memsubsys1 
run_test_suite memsubsys2 
run_test_suite singlethread 
run_test_suite multithread 
run_test_suite onefile 
run_test_suite utf16 
run_test_suite exclusive







>







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#

set testdir [file dirname $argv0]
source $testdir/permutations.test

run_test_suite full

run_test_suite no_optimization 
run_test_suite memsubsys1 
run_test_suite memsubsys2 
run_test_suite singlethread 
run_test_suite multithread 
run_test_suite onefile 
run_test_suite utf16 
run_test_suite exclusive

Changes to test/backcompat.test.

266
267
268
269
270
271
272
273


































































































274
      SELECT * FROM t1;
    } } {I 1 II 2 III 3}
    do_test backcompat-2.1.4 { sql1 {
      SELECT * FROM t1;
    } } {I 1 II 2 III 3}
  }
}



































































































finish_test








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

266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
      SELECT * FROM t1;
    } } {I 1 II 2 III 3}
    do_test backcompat-2.1.4 { sql1 {
      SELECT * FROM t1;
    } } {I 1 II 2 III 3}
  }
}

#-------------------------------------------------------------------------
# Test that FTS3 tables may be read/written by different versions of 
# SQLite. 
#
set contents {
  CREATE VIRTUAL TABLE t1 USING fts3(a, b);
}
foreach {num doc} {
  one "jk zm jk eczkjblu urvysbnykk sk gnl jk ttvgf hmjf"
  two "jk bnhc jjrxpjkb mjpavjuhw fibokdry igju jk zm zm xh"
  three "wxe ogttbykvt uhzq xr iaf zf urvysbnykk aayxpmve oacaxgjoo mjpavjuhw"
  four "gazrt jk ephknonq myjp uenvbm wuvajhwqz jk zm xnxhf nvfasfh"
  five "zm aayxpmve csjqxhgj xnxhf xr jk aayxpmve xnxhf zm zm"
  six "sokcyf zm ogyavjvv jk zm fibokdry zm jk igju igju"
  seven "vgsld bvgimjik xuprtlyle jk akmikrqyt jk aayxpmve hkfoudzftq ddjj"
  eight "zm uhzq ovkyevlgv zk uenvbm csjqxhgj jk vgsld pgybs jk"
  nine  "zm agmckuiu zexh fibokdry jk uhzq bu tugflixoex xnxhf sk"
} {
  append contents "INSERT INTO t1 VALUES('$num', '$doc');"
}
do_allbackcompat_test {
  if {[code1 {set ::sqlite_options(fts3)}]
   && [code2 {set ::sqlite_options(fts3)}]
  } {

    do_test backcompat-3.1 { sql1 $contents } {}

    foreach {n q} {
      1    "SELECT * FROM t1 ORDER BY a, b"
      2    "SELECT rowid FROM t1 WHERE a MATCH 'five'"
      3    "SELECT * FROM t1 WHERE a MATCH 'five'"
      4    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'jk'"
      5    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'tug* OR eight'"
    } {
      do_test backcompat-3.2 [list sql1 $q] [sql2 $q]
    }

    do_test backcompat-3.3 { sql1 {
      INSERT INTO t1 SELECT * FROM t1;
      INSERT INTO t1 SELECT * FROM t1;
      INSERT INTO t1 SELECT * FROM t1;
      INSERT INTO t1 SELECT * FROM t1;
      INSERT INTO t1 SELECT * FROM t1;
      INSERT INTO t1 SELECT * FROM t1;
      INSERT INTO t1 SELECT * FROM t1;
      INSERT INTO t1 SELECT * FROM t1;
    } } {}

    foreach {n q} {
      1    "SELECT * FROM t1 ORDER BY a, b"
      2    "SELECT rowid FROM t1 WHERE a MATCH 'five'"
      3    "SELECT * FROM t1 WHERE a MATCH 'five'"
      4    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'jk'"
      5    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'tug* OR eight'"
    } {
      do_test backcompat-3.4 [list sql1 $q] [sql2 $q]
    }

    set alphabet "a b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4"
    for {set i 0} {$i < 900} {incr i} {
      set term "[lindex $alphabet [expr $i/30]][lindex $alphabet [expr $i%30]] "
      sql1 "INSERT INTO t1 VALUES($i, '[string repeat $term 14]')"
    }

    foreach {n q} {
      1    "SELECT * FROM t1 ORDER BY a, b"
      2    "SELECT rowid FROM t1 WHERE a MATCH 'five'"
      3    "SELECT * FROM t1 WHERE a MATCH 'five'"
      4    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'jk'"
      5    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'tug* OR eight'"

      6    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'aa'"
      7    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH '44'"
      8    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'a*'"
    } {
      do_test backcompat-3.5 [list sql1 $q] [sql2 $q]
    }

    do_test backcompat-3.6 { 
      sql1 "SELECT optimize(t1) FROM t1 LIMIT 1" 
    } {{Index optimized}}

    foreach {n q} {
      1    "SELECT * FROM t1 ORDER BY a, b"
      2    "SELECT rowid FROM t1 WHERE a MATCH 'five'"
      3    "SELECT * FROM t1 WHERE a MATCH 'five'"
      4    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'jk'"
      5    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'tug* OR eight'"

      6    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'aa'"
      7    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH '44'"
      8    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'a*'"
    } {
      do_test backcompat-3.7 [list sql1 $q] [sql2 $q]
    }
  }
}

finish_test

Changes to test/cache.test.

47
48
49
50
51
52
53
54
55
56
57
58
59
60
61


62












































































63
# 2000 pages by default).
#
# This tests that once the pager-cache is initialised, it can be locked
# and unlocked repeatedly without internally allocating any new pages.
#
set cache_size [pager_cache_size db]
for {set ii 0} {$ii < 10} {incr ii} {

  do_test cache-1.3.$ii {
    execsql {SELECT * FROM abc}
    pager_cache_size db
  } $::cache_size

}
sqlite3_soft_heap_limit $cmdlinearg(soft-heap-limit)















































































finish_test







<




|
|
|
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

47
48
49
50
51
52
53

54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# 2000 pages by default).
#
# This tests that once the pager-cache is initialised, it can be locked
# and unlocked repeatedly without internally allocating any new pages.
#
set cache_size [pager_cache_size db]
for {set ii 0} {$ii < 10} {incr ii} {

  do_test cache-1.3.$ii {
    execsql {SELECT * FROM abc}
    pager_cache_size db
  } $::cache_size
}

#-------------------------------------------------------------------------
# This block of tests checks that it is possible to set the cache_size of a
# database to a small (< 10) value. More specifically:
#
#   cache-2.1.*: Test that "PRAGMA cache_size" appears to work with small 
#                values.
#   cache-2.2.*: Test that "PRAGMA main.cache_size" appears to work with 
#                small values.
#   cache-2.3.*: Test cache_size=1 correctly spills/flushes the cache. 
#   cache-2.4.*: Test cache_size=0 correctly spills/flushes the cache. 
#
#
db_delete_and_reopen
do_execsql_test cache-2.0 {
  PRAGMA auto_vacuum=OFF;
  PRAGMA journal_mode=DELETE;
  CREATE TABLE t1(a, b);
  CREATE TABLE t2(c, d);
  INSERT INTO t1 VALUES('x', 'y');
  INSERT INTO t2 VALUES('i', 'j');
} {delete}

for {set i 0} {$i < 20} {incr i} {
  do_execsql_test cache-2.1.$i.1 "PRAGMA cache_size = $i"
  do_execsql_test cache-2.1.$i.2 "PRAGMA cache_size" $i
  do_execsql_test cache-2.1.$i.3 "SELECT * FROM t1" {x y}
  do_execsql_test cache-2.1.$i.4 "PRAGMA cache_size" $i
}
for {set i 0} {$i < 20} {incr i} {
  do_execsql_test cache-2.2.$i.1 "PRAGMA main.cache_size = $i"
  do_execsql_test cache-2.2.$i.2 "PRAGMA main.cache_size" $i
  do_execsql_test cache-2.2.$i.3 "SELECT * FROM t1" {x y}
  do_execsql_test cache-2.2.$i.4 "PRAGMA main.cache_size" $i
}

# Tests for cache_size = 1.
#
do_execsql_test cache-2.3.1 {
  PRAGMA cache_size = 1;
  BEGIN;
    INSERT INTO t1 VALUES(1, 2);
    PRAGMA lock_status;
} {main reserved temp closed}
do_test cache-2.3.2 { pager_cache_size db } 2
do_execsql_test cache-2.3.3 {
    INSERT INTO t2 VALUES(1, 2);
    PRAGMA lock_status;
} {main exclusive temp closed}
do_test cache-2.3.4 { pager_cache_size db } 2
do_execsql_test cache-2.3.5 COMMIT
do_test cache-2.3.6 { pager_cache_size db } 1

do_execsql_test cache-2.3.7 {
  SELECT * FROM t1 UNION SELECT * FROM t2;
} {1 2 i j x y}
do_test cache-2.3.8 { pager_cache_size db } 1

# Tests for cache_size = 0.
#
do_execsql_test cache-2.4.1 {
  PRAGMA cache_size = 0;
  BEGIN;
    INSERT INTO t1 VALUES(1, 2);
    PRAGMA lock_status;
} {main reserved temp closed}
do_test cache-2.4.2 { pager_cache_size db } 2
do_execsql_test cache-2.4.3 {
    INSERT INTO t2 VALUES(1, 2);
    PRAGMA lock_status;
} {main exclusive temp closed}
do_test cache-2.4.4 { pager_cache_size db } 2
do_execsql_test cache-2.4.5 COMMIT

do_test cache-2.4.6 { pager_cache_size db } 0
do_execsql_test cache-2.4.7 {
  SELECT * FROM t1 UNION SELECT * FROM t2;
} {1 2 i j x y}
do_test cache-2.4.8 { pager_cache_size db } 0

sqlite3_soft_heap_limit $cmdlinearg(soft-heap-limit)
finish_test

Added test/e_droptrigger.test.





















































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
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
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
# 2010 November 29
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
# This file implements tests to verify that the "testable statements" in 
# the lang_droptrigger.html document are correct.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set ::testprefix e_droptrigger

ifcapable !trigger { finish_test ; return }

proc do_droptrigger_tests {nm args} {
  uplevel do_select_tests [list e_createtable-$nm] $args
}

proc list_all_triggers {{db db}} {
  set res [list]
  $db eval { PRAGMA database_list } {
    if {$name == "temp"} {
      set tbl sqlite_temp_master
    } else {
      set tbl "$name.sqlite_master"
    }
    lappend res {*}[
      db eval "SELECT '$name.' || name FROM $tbl WHERE type = 'trigger'"
    ]
  }
  set res
}


proc droptrigger_reopen_db {{event INSERT}} {
  db close
  forcedelete test.db test.db2
  sqlite3 db test.db

  set ::triggers_fired [list]
  proc r {x} { lappend ::triggers_fired $x }
  db func r r

  db eval "
    ATTACH 'test.db2' AS aux;

    CREATE TEMP TABLE t1(a, b);
    INSERT INTO t1 VALUES('a', 'b');
    CREATE TRIGGER tr1 AFTER $event ON t1 BEGIN SELECT r('temp.tr1') ; END;

    CREATE TABLE t2(a, b);
    INSERT INTO t2 VALUES('a', 'b');
    CREATE TRIGGER tr1 BEFORE $event ON t2 BEGIN SELECT r('main.tr1') ; END;
    CREATE TRIGGER tr2 AFTER  $event ON t2 BEGIN SELECT r('main.tr2') ; END;

    CREATE TABLE aux.t3(a, b);
    INSERT INTO t3 VALUES('a', 'b');
    CREATE TRIGGER aux.tr1 BEFORE $event ON t3 BEGIN SELECT r('aux.tr1') ; END;
    CREATE TRIGGER aux.tr2 AFTER  $event ON t3 BEGIN SELECT r('aux.tr2') ; END;
    CREATE TRIGGER aux.tr3 AFTER  $event ON t3 BEGIN SELECT r('aux.tr3') ; END;
  "
}


# EVIDENCE-OF: R-52650-16855 -- syntax diagram drop-trigger-stmt
#
do_droptrigger_tests 1.1 -repair {
  droptrigger_reopen_db
} -tclquery {
  list_all_triggers 
} {
  1   "DROP TRIGGER main.tr1"            
      {main.tr2 temp.tr1 aux.tr1 aux.tr2 aux.tr3}
  2   "DROP TRIGGER IF EXISTS main.tr1"  
      {main.tr2 temp.tr1 aux.tr1 aux.tr2 aux.tr3}
  3   "DROP TRIGGER tr1"                 
      {main.tr1 main.tr2 aux.tr1 aux.tr2 aux.tr3}
  4   "DROP TRIGGER IF EXISTS tr1"       
      {main.tr1 main.tr2 aux.tr1 aux.tr2 aux.tr3}

  5   "DROP TRIGGER aux.tr1"             
      {main.tr1 main.tr2 temp.tr1 aux.tr2 aux.tr3}
  6   "DROP TRIGGER IF EXISTS aux.tr1"   
      {main.tr1 main.tr2 temp.tr1 aux.tr2 aux.tr3}

  7   "DROP TRIGGER IF EXISTS aux.xxx"   
      {main.tr1 main.tr2 temp.tr1 aux.tr1 aux.tr2 aux.tr3}
  8   "DROP TRIGGER IF EXISTS aux.xxx"   
      {main.tr1 main.tr2 temp.tr1 aux.tr1 aux.tr2 aux.tr3}
}

# EVIDENCE-OF: R-61172-15671 The DROP TRIGGER statement removes a
# trigger created by the CREATE TRIGGER statement.
#
foreach {tn tbl droptrigger before after} {
  1   t1  "DROP TRIGGER tr1" {temp.tr1}                {}
  2   t2  "DROP TRIGGER tr1" {main.tr1 main.tr2}       {main.tr1 main.tr2}
  3   t3  "DROP TRIGGER tr1" {aux.tr1 aux.tr3 aux.tr2} {aux.tr1 aux.tr3 aux.tr2}

  4   t1  "DROP TRIGGER tr2" {temp.tr1}                {temp.tr1}
  5   t2  "DROP TRIGGER tr2" {main.tr1 main.tr2}       {main.tr1}
  6   t3  "DROP TRIGGER tr2" {aux.tr1 aux.tr3 aux.tr2} {aux.tr1 aux.tr3 aux.tr2}

  7   t1  "DROP TRIGGER tr3" {temp.tr1}                {temp.tr1}
  8   t2  "DROP TRIGGER tr3" {main.tr1 main.tr2}       {main.tr1 main.tr2}
  9   t3  "DROP TRIGGER tr3" {aux.tr1 aux.tr3 aux.tr2} {aux.tr1 aux.tr2}
} {

  do_test 2.$tn.1 {
    droptrigger_reopen_db
    execsql " INSERT INTO $tbl VALUES('1', '2') "
    set ::triggers_fired
  } $before

  do_test 2.$tn.2 {
    droptrigger_reopen_db
    execsql $droptrigger
    execsql " INSERT INTO $tbl VALUES('1', '2') "
    set ::triggers_fired
  } $after
}

# EVIDENCE-OF: R-50239-29811 Once removed, the trigger definition is no
# longer present in the sqlite_master (or sqlite_temp_master) table and
# is not fired by any subsequent INSERT, UPDATE or DELETE statements.
#
#   Test cases e_droptrigger-1.* test the first part of this statement
#   (that dropped triggers do not appear in the schema table), and tests
#   droptrigger-2.* test that dropped triggers are not fired by INSERT
#   statements. The following tests verify that they are not fired by
#   UPDATE or DELETE statements.
#
foreach {tn tbl droptrigger before after} {
  1   t1  "DROP TRIGGER tr1" {temp.tr1}                {}
  2   t2  "DROP TRIGGER tr1" {main.tr1 main.tr2}       {main.tr1 main.tr2}
  3   t3  "DROP TRIGGER tr1" {aux.tr1 aux.tr3 aux.tr2} {aux.tr1 aux.tr3 aux.tr2}

  4   t1  "DROP TRIGGER tr2" {temp.tr1}                {temp.tr1}
  5   t2  "DROP TRIGGER tr2" {main.tr1 main.tr2}       {main.tr1}
  6   t3  "DROP TRIGGER tr2" {aux.tr1 aux.tr3 aux.tr2} {aux.tr1 aux.tr3 aux.tr2}

  7   t1  "DROP TRIGGER tr3" {temp.tr1}                {temp.tr1}
  8   t2  "DROP TRIGGER tr3" {main.tr1 main.tr2}       {main.tr1 main.tr2}
  9   t3  "DROP TRIGGER tr3" {aux.tr1 aux.tr3 aux.tr2} {aux.tr1 aux.tr2}
} {

  do_test 3.1.$tn.1 {
    droptrigger_reopen_db UPDATE
    execsql "UPDATE $tbl SET a = 'abc'"
    set ::triggers_fired
  } $before

  do_test 3.1.$tn.2 {
    droptrigger_reopen_db UPDATE
    execsql $droptrigger
    execsql "UPDATE $tbl SET a = 'abc'"
    set ::triggers_fired
  } $after
}
foreach {tn tbl droptrigger before after} {
  1   t1  "DROP TRIGGER tr1" {temp.tr1}                {}
  2   t2  "DROP TRIGGER tr1" {main.tr1 main.tr2}       {main.tr1 main.tr2}
  3   t3  "DROP TRIGGER tr1" {aux.tr1 aux.tr3 aux.tr2} {aux.tr1 aux.tr3 aux.tr2}

  4   t1  "DROP TRIGGER tr2" {temp.tr1}                {temp.tr1}
  5   t2  "DROP TRIGGER tr2" {main.tr1 main.tr2}       {main.tr1}
  6   t3  "DROP TRIGGER tr2" {aux.tr1 aux.tr3 aux.tr2} {aux.tr1 aux.tr3 aux.tr2}

  7   t1  "DROP TRIGGER tr3" {temp.tr1}                {temp.tr1}
  8   t2  "DROP TRIGGER tr3" {main.tr1 main.tr2}       {main.tr1 main.tr2}
  9   t3  "DROP TRIGGER tr3" {aux.tr1 aux.tr3 aux.tr2} {aux.tr1 aux.tr2}
} {

  do_test 3.2.$tn.1 {
    droptrigger_reopen_db DELETE
    execsql "DELETE FROM $tbl"
    set ::triggers_fired
  } $before

  do_test 3.2.$tn.2 {
    droptrigger_reopen_db DELETE
    execsql $droptrigger
    execsql "DELETE FROM $tbl"
    set ::triggers_fired
  } $after
}

# EVIDENCE-OF: R-37808-62273 Note that triggers are automatically
# dropped when the associated table is dropped.
#
do_test 4.1 {
  droptrigger_reopen_db
  list_all_triggers
} {main.tr1 main.tr2 temp.tr1 aux.tr1 aux.tr2 aux.tr3}
do_test 4.2 {
  droptrigger_reopen_db
  execsql "DROP TABLE t1"
  list_all_triggers
} {main.tr1 main.tr2 aux.tr1 aux.tr2 aux.tr3}
do_test 4.3 {
  droptrigger_reopen_db
  execsql "DROP TABLE t1"
  list_all_triggers
} {main.tr1 main.tr2 aux.tr1 aux.tr2 aux.tr3}
do_test 4.4 {
  droptrigger_reopen_db
  execsql "DROP TABLE t1"
  list_all_triggers
} {main.tr1 main.tr2 aux.tr1 aux.tr2 aux.tr3}

finish_test

Added test/e_dropview.test.

































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# 2010 November 30
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
# This file implements tests to verify that the "testable statements" in 
# the lang_dropview.html document are correct.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set ::testprefix e_dropview

proc dropview_reopen_db {} {
  db close
  forcedelete test.db test.db2
  sqlite3 db test.db

  db eval {
    ATTACH 'test.db2' AS aux;
    CREATE TABLE t1(a, b); 
    INSERT INTO t1 VALUES('a main', 'b main');
    CREATE VIEW v1 AS SELECT * FROM t1;
    CREATE VIEW v2 AS SELECT * FROM t1;

    CREATE TEMP TABLE t1(a, b);
    INSERT INTO temp.t1 VALUES('a temp', 'b temp');
    CREATE VIEW temp.v1 AS SELECT * FROM t1;

    CREATE TABLE aux.t1(a, b);
    INSERT INTO aux.t1 VALUES('a aux', 'b aux');
    CREATE VIEW aux.v1 AS SELECT * FROM t1;
    CREATE VIEW aux.v2 AS SELECT * FROM t1;
    CREATE VIEW aux.v3 AS SELECT * FROM t1;
  }
}

proc list_all_views {{db db}} {
  set res [list]
  $db eval { PRAGMA database_list } {
    set tbl "$name.sqlite_master"
    if {$name == "temp"} { set tbl sqlite_temp_master }

    set sql "SELECT '$name.' || name FROM $tbl WHERE type = 'view'"
    lappend res {*}[$db eval $sql]
  }
  set res
}

proc list_all_data {{db db}} {
  set res [list]
  $db eval { PRAGMA database_list } {
    set tbl "$name.sqlite_master"
    if {$name == "temp"} { set tbl sqlite_temp_master }

    db eval "SELECT '$name.' || name AS x FROM $tbl WHERE type = 'table'" {
      lappend res [list $x [db eval "SELECT * FROM $x"]]
    }
  }
  set res
}

proc do_dropview_tests {nm args} {
  uplevel do_select_tests $nm $args
}

# EVIDENCE-OF: R-21739-51207 -- syntax diagram drop-view-stmt
#
# All paths in the syntax diagram for DROP VIEW are tested by tests 1.*.
#
do_dropview_tests 1 -repair {
  dropview_reopen_db
} -tclquery {
  list_all_views
} {
  1   "DROP VIEW v1"                  {main.v1 main.v2 aux.v1 aux.v2 aux.v3}
  2   "DROP VIEW v2"                  {main.v1 temp.v1 aux.v1 aux.v2 aux.v3}
  3   "DROP VIEW main.v1"             {main.v2 temp.v1 aux.v1 aux.v2 aux.v3}
  4   "DROP VIEW main.v2"             {main.v1 temp.v1 aux.v1 aux.v2 aux.v3}
  5   "DROP VIEW IF EXISTS v1"        {main.v1 main.v2 aux.v1 aux.v2 aux.v3}
  6   "DROP VIEW IF EXISTS v2"        {main.v1 temp.v1 aux.v1 aux.v2 aux.v3}
  7   "DROP VIEW IF EXISTS main.v1"   {main.v2 temp.v1 aux.v1 aux.v2 aux.v3}
  8   "DROP VIEW IF EXISTS main.v2"   {main.v1 temp.v1 aux.v1 aux.v2 aux.v3}
}

# EVIDENCE-OF: R-27002-52307 The DROP VIEW statement removes a view
# created by the CREATE VIEW statement.
#
dropview_reopen_db
do_execsql_test 2.1 {
  CREATE VIEW "new view" AS SELECT * FROM t1 AS x, t1 AS y;
  SELECT * FROM "new view";
} {{a main} {b main} {a main} {b main}}
do_execsql_test 2.2 {;
  SELECT * FROM sqlite_master WHERE name = 'new view';
} {
  view {new view} {new view} 0 
  {CREATE VIEW "new view" AS SELECT * FROM t1 AS x, t1 AS y}
}
do_execsql_test 2.3 {
  DROP VIEW "new view";
  SELECT * FROM sqlite_master WHERE name = 'new view';
} {}
do_catchsql_test 2.4 {
  SELECT * FROM "new view"
} {1 {no such table: new view}}

# EVIDENCE-OF: R-00359-41639 The view definition is removed from the
# database schema, but no actual data in the underlying base tables is
# modified.
#
#     For each view in the database, check that it can be queried. Then drop
#     it. Check that it can no longer be queried and is no longer listed
#     in any schema table. Then check that the contents of the db tables have 
#     not changed
#
set databasedata [list_all_data]

do_execsql_test  3.1.0 { SELECT * FROM temp.v1 } {{a temp} {b temp}}
do_execsql_test  3.1.1 { DROP VIEW temp.v1 } {}
do_catchsql_test 3.1.2 { SELECT * FROM temp.v1 } {1 {no such table: temp.v1}}
do_test          3.1.3 { list_all_views } {main.v1 main.v2 aux.v1 aux.v2 aux.v3}
do_test          3.1.4 { list_all_data  } $databasedata

do_execsql_test  3.2.0 { SELECT * FROM v1 } {{a main} {b main}}
do_execsql_test  3.2.1 { DROP VIEW v1 } {}
do_catchsql_test 3.2.2 { SELECT * FROM main.v1 } {1 {no such table: main.v1}}
do_test          3.2.3 { list_all_views } {main.v2 aux.v1 aux.v2 aux.v3}
do_test          3.2.4 { list_all_data  } $databasedata

do_execsql_test  3.3.0 { SELECT * FROM v2 } {{a main} {b main}}
do_execsql_test  3.3.1 { DROP VIEW v2 } {}
do_catchsql_test 3.3.2 { SELECT * FROM main.v2 } {1 {no such table: main.v2}}
do_test          3.3.3 { list_all_views } {aux.v1 aux.v2 aux.v3}
do_test          3.3.4 { list_all_data  } $databasedata

do_execsql_test  3.4.0 { SELECT * FROM v1 } {{a aux} {b aux}}
do_execsql_test  3.4.1 { DROP VIEW v1 } {}
do_catchsql_test 3.4.2 { SELECT * FROM v1 } {1 {no such table: v1}}
do_test          3.4.3 { list_all_views } {aux.v2 aux.v3}
do_test          3.4.4 { list_all_data  } $databasedata

do_execsql_test  3.4.0 { SELECT * FROM aux.v2 } {{a aux} {b aux}}
do_execsql_test  3.4.1 { DROP VIEW aux.v2 } {}
do_catchsql_test 3.4.2 { SELECT * FROM aux.v2 } {1 {no such table: aux.v2}}
do_test          3.4.3 { list_all_views } {aux.v3}
do_test          3.4.4 { list_all_data  } $databasedata

do_execsql_test  3.5.0 { SELECT * FROM v3 } {{a aux} {b aux}}
do_execsql_test  3.5.1 { DROP VIEW v3 } {}
do_catchsql_test 3.5.2 { SELECT * FROM v3 } {1 {no such table: v3}}
do_test          3.5.3 { list_all_views } {}
do_test          3.5.4 { list_all_data  } $databasedata

# EVIDENCE-OF: R-25558-37487 If the specified view cannot be found and
# the IF EXISTS clause is not present, it is an error.
#
do_dropview_tests 4 -repair {
  dropview_reopen_db 
} -errorformat {
  no such view: %s
} {
  1   "DROP VIEW xx"                  xx
  2   "DROP VIEW main.xx"             main.xx
  3   "DROP VIEW temp.v2"             temp.v2
}

# EVIDENCE-OF: R-07490-32536 If the specified view cannot be found and
# an IF EXISTS clause is present in the DROP VIEW statement, then the
# statement is a no-op.
#
do_dropview_tests 5 -repair {
  dropview_reopen_db
} -tclquery {
  list_all_views
  expr {[list_all_views] == "main.v1 main.v2 temp.v1 aux.v1 aux.v2 aux.v3"}
} {
  1    "DROP VIEW IF EXISTS xx"       1
  2    "DROP VIEW IF EXISTS main.xx"  1
  3    "DROP VIEW IF EXISTS temp.v2"  1
}




finish_test

Added test/e_resolve.test.















































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# 2010 November 30
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
# This file implements tests to verify that the "testable statements" in 
# the lang_naming.html document are correct.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set ::testprefix e_resolve

# An example database schema for testing name resolution:
#
set schema {
  ATTACH 'test.db2' AS at1;
  ATTACH 'test.db3' AS at2;

  CREATE TABLE   temp.n1(x, y); INSERT INTO temp.n1 VALUES('temp', 'n1');
  CREATE TRIGGER temp.n3 AFTER INSERT ON n1 BEGIN SELECT 1; END;
  CREATE INDEX   temp.n4 ON n1(x, y);

  CREATE TABLE   main.n1(x, y); INSERT INTO main.n1 VALUES('main', 'n1');
  CREATE TABLE   main.n2(x, y); INSERT INTO main.n2 VALUES('main', 'n2');
  CREATE INDEX   main.n3 ON n2(y, x);
  CREATE TRIGGER main.n4 BEFORE INSERT ON n2 BEGIN SELECT 1; END;

  CREATE TABLE   at1.n1(x, y);  INSERT INTO at1.n1 VALUES('at1', 'n1');
  CREATE TABLE   at1.n2(x, y);  INSERT INTO at1.n2 VALUES('at1', 'n2');
  CREATE TABLE   at1.n3(x, y);  INSERT INTO at1.n3 VALUES('at1', 'n3');

  CREATE TABLE   at2.n1(x, y);  INSERT INTO at2.n1 VALUES('at2', 'n1');
  CREATE TABLE   at2.n2(x, y);  INSERT INTO at2.n2 VALUES('at2', 'n2');
  CREATE TABLE   at2.n3(x, y);  INSERT INTO at2.n3 VALUES('at2', 'n3');
  CREATE TABLE   at2.n4(x, y);  INSERT INTO at2.n4 VALUES('at2', 'n4');
  CREATE TRIGGER at2.n4 BEFORE INSERT ON n4 BEGIN SELECT 1; END;
}

proc resolve_reopen_db {} {
  db close
  forcedelete test.db test.db2 test.db3
  sqlite3 db test.db
  db eval $::schema
}



# EVIDENCE-OF: R-33528-20612 If no database is specified as part of the
# object reference, then SQLite searches the main, temp and all attached
# databases for an object with a matching name. The temp database is
# searched first, followed by the main database, followed all attached
# databases in the order that they were attached. The reference resolves
# to the first match found.
#
resolve_reopen_db
do_execsql_test 1.1 { SELECT * FROM n1 } {temp n1}
do_execsql_test 1.2 { SELECT * FROM n2 } {main n2}
do_execsql_test 1.3 { SELECT * FROM n3 } {at1  n3}
do_execsql_test 1.4 { SELECT * FROM n4 } {at2  n4}

# EVIDENCE-OF: R-54577-28142 If a database name is specified as part of
# an object reference, it must be either "main", or "temp" or the name
# of an attached database.
#
#   Or else it is a "no such table: xxx" error.
#
resolve_reopen_db
do_execsql_test 2.1.1 { SELECT * FROM main.n1 } {main n1}
do_execsql_test 2.1.2 { SELECT * FROM temp.n1 } {temp n1}
do_execsql_test 2.1.3 { SELECT * FROM at1.n1 } {at1 n1}
do_execsql_test 2.1.4 { SELECT * FROM at2.n1 } {at2 n1}

do_catchsql_test 2.2 { SELECT * FROM xxx.n1 } {1 {no such table: xxx.n1}}

# EVIDENCE-OF: R-26223-47623 Like other SQL identifiers, database names
# are case-insensitive.
#
resolve_reopen_db
do_execsql_test 3.1 { SELECT * FROM MAIN.n1 } {main n1}
do_execsql_test 3.2 { SELECT * FROM tEmP.n1 } {temp n1}
do_execsql_test 3.3 { SELECT * FROM aT1.n1 } {at1 n1}
do_execsql_test 3.4 { SELECT * FROM At2.n1 } {at2 n1}

# EVIDENCE-OF: R-15639-28392 If a database name is specified, then only
# the named database is searched for the named object.
#
do_catchsql_test 4.1 { SELECT * FROM temp.n2 } {1 {no such table: temp.n2}}
do_catchsql_test 4.2 { SELECT * FROM main.n2 } {0 {main n2}}
do_catchsql_test 4.3 { SELECT * FROM at1.n2 }  {0 {at1 n2}}
do_catchsql_test 4.4 { SELECT * FROM at2.n2 }  {0 {at2 n2}}

# EVIDENCE-OF: R-08951-19801 When searching database schemas for a named
# object, objects of types that cannot be used in the context of the
# reference are always ignored.
#
#   In this case, "types that cannot be used" are triggers and indexes.
#   The temp and main databases both contain triggers and indexes named
#   "n3" and "n4". Database "at2" contains a trigger called "n4". And yet:
#
do_execsql_test 5.1 { SELECT * FROM n3 } {at1  n3}
do_execsql_test 5.2 { SELECT * FROM n4 } {at2  n4}

#-------------------------------------------------------------------------
# EVIDENCE-OF: R-37286-42536 
#
db close
forcedelete test.db file.db
sqlite3 db test.db
do_execsql_test 6.1 {
  ATTACH 'file.db' AS aux;
  CREATE TABLE t1(x, y);
  CREATE TEMP TABLE t1(x, y);
  CREATE TABLE aux.t1(x, y);
}

do_execsql_test  6.2.0 { DROP TABLE t1 }
do_catchsql_test 6.2.1 { SELECT * FROM temp.t1 } {1 {no such table: temp.t1}}
do_catchsql_test 6.2.2 { SELECT * FROM main.t1 } {0 {}}
do_catchsql_test 6.2.3 { SELECT * FROM aux.t1  } {0 {}}

do_execsql_test  6.3.0 { DROP TABLE t1 }
do_catchsql_test 6.3.1 { SELECT * FROM main.t1 } {1 {no such table: main.t1}}
do_catchsql_test 6.3.3 { SELECT * FROM aux.t1  } {0 {}}

do_execsql_test  6.4.0 { DROP TABLE t1 }
do_catchsql_test 6.4.1 { SELECT * FROM aux.t1 } {1 {no such table: aux.t1}}

finish_test

Changes to test/fts3aa.test.

192
193
194
195
196
197
198
199
200
201
202
203























204

} {{four five}}
do_test fts3aa-6.2 {
  execsql {INSERT INTO t1(rowid, content) VALUES(-1, 'three four')}
} {}
do_test fts3aa-6.3 {
  execsql {SELECT content FROM t1 WHERE rowid = -1}
} {{three four}}
breakpoint
do_test fts3aa-6.4 {
  execsql {SELECT rowid FROM t1 WHERE t1 MATCH 'four'}
} {-1 0 8 9 10 11 12 13 14 15 24 25 26 27 28 29 30 31}
























finish_test








<




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

>
192
193
194
195
196
197
198

199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
} {{four five}}
do_test fts3aa-6.2 {
  execsql {INSERT INTO t1(rowid, content) VALUES(-1, 'three four')}
} {}
do_test fts3aa-6.3 {
  execsql {SELECT content FROM t1 WHERE rowid = -1}
} {{three four}}

do_test fts3aa-6.4 {
  execsql {SELECT rowid FROM t1 WHERE t1 MATCH 'four'}
} {-1 0 8 9 10 11 12 13 14 15 24 25 26 27 28 29 30 31}

# Test creation of FTS3 and FTS4 tables with columns that contain
# an "=" character.
#
do_execsql_test fts3aa-7.1 {
  CREATE VIRTUAL TABLE t2 USING fts3(xyz=abc);
  SELECT xyz FROM t2;
} {}
do_catchsql_test fts3aa-7.2 {
  CREATE VIRTUAL TABLE t3 USING fts4(xyz=abc);
} {1 {unrecognized parameter: xyz=abc}}
do_catchsql_test fts3aa-7.3 {
  CREATE VIRTUAL TABLE t3 USING fts4(xyz = abc);
} {1 {unrecognized parameter: xyz = abc}}

do_execsql_test fts3aa-7.4 {
  CREATE VIRTUAL TABLE t3 USING fts3(tokenize=simple, tokenize=simple);
  SELECT tokenize FROM t3;
} {}
do_catchsql_test fts3aa-7.5 {
  CREATE VIRTUAL TABLE t4 USING fts4(tokenize=simple, tokenize=simple);
} {1 {unrecognized parameter: tokenize=simple}}


finish_test

Changes to test/fts3defer2.test.

49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
..
87
88
89
90
91
92
93

94
95
96
97
98
99
100
101
102
...
120
121
122
123
124
125
126
127
128
129
130
131
132
133
} {2}

do_execsql_test 1.2.1 {
  SELECT content FROM t1 WHERE t1 MATCH 'f (e NEAR/2 a)';
} {{a b c d e f a x y}}

do_execsql_test 1.2.2 {
  SELECT snippet(t1, '[', ']'), offsets(t1), mit(matchinfo(t1))
  FROM t1 WHERE t1 MATCH 'f (e NEAR/2 a)';
} [list                              \
   {a b c d [e] [f] [a] x y}         \
   {0 1 8 1 0 0 10 1 0 2 12 1}       \
   [list 3 1   1 1 1   1 8 8   1 8 8   8 5001 9]
]

do_execsql_test 1.2.3 {
  SELECT snippet(t1, '[', ']'), offsets(t1), mit(matchinfo(t1))
  FROM t1 WHERE t1 MATCH 'f (e NEAR/3 a)';
} [list                                 \
   {[a] b c d [e] [f] [a] x y}          \
   {0 2 0 1 0 1 8 1 0 0 10 1 0 2 12 1}  \
   [list 3 1   1 1 1   1 8 8   2 8 8   8 5001 9]
]

................................................................................
  1 {}
  2 { INSERT INTO t2(t2) VALUES('optimize') }
  3 { UPDATE t2_segments SET block = zeroblob(length(block)) 
      WHERE length(block)>10000;
  }
} {
  execsql $sql

  do_execsql_test 2.2.$tn {
    SELECT mit(matchinfo(t2)) FROM t2 WHERE t2 MATCH 'a b';
  } [list                                          \
    [list 2 1  1 54 54  1 3 3  54 372 7]        \
    [list 2 1  1 54 54  1 3 3  54 372 7]        \
  ]
}

do_execsql_test 2.3.1 {
................................................................................
  2 { INSERT INTO t3(t3) VALUES('optimize') }
  3 { UPDATE t3_segments SET block = zeroblob(length(block)) 
      WHERE length(block)>10000;
  }
} {
  execsql $sql
  do_execsql_test 2.4.$tn {
    SELECT docid, mit(matchinfo(t3)) FROM t3 WHERE t3 MATCH '"a b c"';
  } {1 {1 1 1 4 4 11 912 6} 3 {1 1 1 4 4 11 912 6}}
}


finish_test








|








|







 







>

|







 







|






49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
..
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
...
121
122
123
124
125
126
127
128
129
130
131
132
133
134
} {2}

do_execsql_test 1.2.1 {
  SELECT content FROM t1 WHERE t1 MATCH 'f (e NEAR/2 a)';
} {{a b c d e f a x y}}

do_execsql_test 1.2.2 {
  SELECT snippet(t1, '[', ']'), offsets(t1), mit(matchinfo(t1, 'pcxnal'))
  FROM t1 WHERE t1 MATCH 'f (e NEAR/2 a)';
} [list                              \
   {a b c d [e] [f] [a] x y}         \
   {0 1 8 1 0 0 10 1 0 2 12 1}       \
   [list 3 1   1 1 1   1 8 8   1 8 8   8 5001 9]
]

do_execsql_test 1.2.3 {
  SELECT snippet(t1, '[', ']'), offsets(t1), mit(matchinfo(t1, 'pcxnal'))
  FROM t1 WHERE t1 MATCH 'f (e NEAR/3 a)';
} [list                                 \
   {[a] b c d [e] [f] [a] x y}          \
   {0 2 0 1 0 1 8 1 0 0 10 1 0 2 12 1}  \
   [list 3 1   1 1 1   1 8 8   2 8 8   8 5001 9]
]

................................................................................
  1 {}
  2 { INSERT INTO t2(t2) VALUES('optimize') }
  3 { UPDATE t2_segments SET block = zeroblob(length(block)) 
      WHERE length(block)>10000;
  }
} {
  execsql $sql

  do_execsql_test 2.2.$tn {
    SELECT mit(matchinfo(t2, 'pcxnal')) FROM t2 WHERE t2 MATCH 'a b';
  } [list                                          \
    [list 2 1  1 54 54  1 3 3  54 372 7]        \
    [list 2 1  1 54 54  1 3 3  54 372 7]        \
  ]
}

do_execsql_test 2.3.1 {
................................................................................
  2 { INSERT INTO t3(t3) VALUES('optimize') }
  3 { UPDATE t3_segments SET block = zeroblob(length(block)) 
      WHERE length(block)>10000;
  }
} {
  execsql $sql
  do_execsql_test 2.4.$tn {
    SELECT docid, mit(matchinfo(t3, 'pcxnal')) FROM t3 WHERE t3 MATCH '"a b c"';
  } {1 {1 1 1 4 4 11 912 6} 3 {1 1 1 4 4 11 912 6}}
}


finish_test

Changes to test/fts3fault.test.

13
14
15
16
17
18
19


20
21
22
23
24
25
26
...
150
151
152
153
154
155
156
157









































































158
set testdir [file dirname $argv0]
source $testdir/tester.tcl

set ::testprefix fts3fault

# If SQLITE_ENABLE_FTS3 is not defined, omit this file.
ifcapable !fts3 { finish_test ; return }



# Test error handling in the sqlite3Fts3Init() function. This is the 
# function that registers the FTS3 module and various support functions
# with SQLite.
#
do_faultsim_test 1 -body { 
  sqlite3 db test.db 
................................................................................
  faultsim_delete_and_reopen
} -body {
  execsql { CREATE VIRTUAL TABLE t1 USING fts4(a, b, matchnfo=fts3) }
} -test {
  faultsim_test_result {1 {unrecognized parameter: matchnfo=fts3}} \
                       {1 {vtable constructor failed: t1}}
}










































































finish_test







>
>







 








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

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
...
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
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
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
set testdir [file dirname $argv0]
source $testdir/tester.tcl

set ::testprefix fts3fault

# If SQLITE_ENABLE_FTS3 is not defined, omit this file.
ifcapable !fts3 { finish_test ; return }

if 1 {

# Test error handling in the sqlite3Fts3Init() function. This is the 
# function that registers the FTS3 module and various support functions
# with SQLite.
#
do_faultsim_test 1 -body { 
  sqlite3 db test.db 
................................................................................
  faultsim_delete_and_reopen
} -body {
  execsql { CREATE VIRTUAL TABLE t1 USING fts4(a, b, matchnfo=fts3) }
} -test {
  faultsim_test_result {1 {unrecognized parameter: matchnfo=fts3}} \
                       {1 {vtable constructor failed: t1}}
}

}

proc mit {blob} {
  set scan(littleEndian) i*
  set scan(bigEndian) I*
  binary scan $blob $scan($::tcl_platform(byteOrder)) r
  return $r
}

do_test 8.0 {
  faultsim_delete_and_reopen
  execsql { CREATE VIRTUAL TABLE t8 USING fts4 }
  execsql "INSERT INTO t8 VALUES('a b c')"
  execsql "INSERT INTO t8 VALUES('b b b')"
  execsql "INSERT INTO t8 VALUES('[string repeat {c } 50000]')"
  execsql "INSERT INTO t8 VALUES('d d d')"
  execsql "INSERT INTO t8 VALUES('e e e')"
  execsql "INSERT INTO t8(t8) VALUES('optimize')"
  faultsim_save_and_close
} {}

do_faultsim_test 8.1 -prep { 
  faultsim_restore_and_reopen
  db func mit mit
} -body {
  execsql { SELECT mit(matchinfo(t8, 'x')) FROM t8 WHERE t8 MATCH 'a b c' }
} -test {
  faultsim_test_result {0 {{1 1 1 1 4 2 1 5 5}}}
}
do_faultsim_test 8.2 -faults oom-t* -prep { 
  faultsim_restore_and_reopen
  db func mit mit
} -body {
  execsql { SELECT mit(matchinfo(t8, 's')) FROM t8 WHERE t8 MATCH 'a b c' }
} -test {
  faultsim_test_result {0 3}
}
do_faultsim_test 8.3 -prep { 
  faultsim_restore_and_reopen
  db func mit mit
} -body {
  execsql { SELECT mit(matchinfo(t8, 'a')) FROM t8 WHERE t8 MATCH 'a b c' }
} -test {
  faultsim_test_result {0 10002}
}
do_faultsim_test 8.4 -prep { 
  faultsim_restore_and_reopen
  db func mit mit
} -body {
  execsql { SELECT mit(matchinfo(t8, 'l')) FROM t8 WHERE t8 MATCH 'a b c' }
} -test {
  faultsim_test_result {0 3}
}

do_test 9.0 {
  faultsim_delete_and_reopen
  execsql {
    CREATE VIRTUAL TABLE t9 USING fts4(tokenize=porter);
    INSERT INTO t9 VALUES(
      'this record is used toooooooooooooooooooooooooooooooooooooo try to'
    );
    SELECT offsets(t9) FROM t9 WHERE t9 MATCH 'to*';
  }
  faultsim_save_and_close
} {}
do_faultsim_test 9.1 -prep {
  faultsim_restore_and_reopen
} -body {
  execsql { SELECT offsets(t9) FROM t9 WHERE t9 MATCH 'to*' }
} -test {
  faultsim_test_result {0 {{0 0 20 39 0 0 64 2}}}
}

finish_test

Changes to test/fts3matchinfo.test.

37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
..
63
64
65
66
67
68
69
70
















































































































































































































































































71

  INSERT INTO t1(content) VALUES('I wandered lonely as a cloud');
  INSERT INTO t1(content) VALUES('That floats on high o''er vales and hills,');
  INSERT INTO t1(content) VALUES('When all at once I saw a crowd,');
  INSERT INTO t1(content) VALUES('A host, of golden daffodils,');
  SELECT mit(matchinfo(t1)) FROM t1 WHERE t1 MATCH 'I';
} {{1 1 1 2 2} {1 1 1 2 2}}

# Now create an FTS4 table that does not specify matchinfo=fts3. The 
# %_docsize table is created in this case and the array of integers returned
# by matchinfo() includes the extra data.
#
do_execsql_test 1.2 {
  CREATE VIRTUAL TABLE t2 USING fts4;
  INSERT INTO t2 SELECT * FROM t1;
  SELECT mit(matchinfo(t2)) FROM t2 WHERE t2 MATCH 'I';
} {{1 1 1 2 2 4 7 6} {1 1 1 2 2 4 7 8}}

# Test some syntax-error handling.
#
do_catchsql_test 2.0 {
  CREATE VIRTUAL TABLE x1 USING fts4(matchinfo=fs3);
} {1 {unrecognized matchinfo: fs3}}
do_catchsql_test 2.1 {
................................................................................
# Check that with fts3, the "=" character is permitted in column definitions.
#
do_execsql_test 3.1 {
  CREATE VIRTUAL TABLE t3 USING fts3(mtchinfo=fts3);
  INSERT INTO t3(mtchinfo) VALUES('Beside the lake, beneath the trees');
  SELECT mtchinfo FROM t3;
} {{Beside the lake, beneath the trees}}

















































































































































































































































































finish_test








|
<
<





|







 








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

>
37
38
39
40
41
42
43
44


45
46
47
48
49
50
51
52
53
54
55
56
57
..
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
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
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
  INSERT INTO t1(content) VALUES('I wandered lonely as a cloud');
  INSERT INTO t1(content) VALUES('That floats on high o''er vales and hills,');
  INSERT INTO t1(content) VALUES('When all at once I saw a crowd,');
  INSERT INTO t1(content) VALUES('A host, of golden daffodils,');
  SELECT mit(matchinfo(t1)) FROM t1 WHERE t1 MATCH 'I';
} {{1 1 1 2 2} {1 1 1 2 2}}

# Now create an FTS4 table that does not specify matchinfo=fts3.


#
do_execsql_test 1.2 {
  CREATE VIRTUAL TABLE t2 USING fts4;
  INSERT INTO t2 SELECT * FROM t1;
  SELECT mit(matchinfo(t2)) FROM t2 WHERE t2 MATCH 'I';
} {{1 1 1 2 2} {1 1 1 2 2}}

# Test some syntax-error handling.
#
do_catchsql_test 2.0 {
  CREATE VIRTUAL TABLE x1 USING fts4(matchinfo=fs3);
} {1 {unrecognized matchinfo: fs3}}
do_catchsql_test 2.1 {
................................................................................
# Check that with fts3, the "=" character is permitted in column definitions.
#
do_execsql_test 3.1 {
  CREATE VIRTUAL TABLE t3 USING fts3(mtchinfo=fts3);
  INSERT INTO t3(mtchinfo) VALUES('Beside the lake, beneath the trees');
  SELECT mtchinfo FROM t3;
} {{Beside the lake, beneath the trees}}

do_execsql_test 3.2 {
  CREATE VIRTUAL TABLE xx USING FTS4;
  SELECT * FROM xx WHERE xx MATCH 'abc';
  SELECT * FROM xx WHERE xx MATCH 'a b c';
}


#--------------------------------------------------------------------------
# Proc [do_matchinfo_test] is used to test the FTSX matchinfo() function.
#
# The first argument - $tn - is a test identifier. This may be either a
# full identifier (i.e. "fts3matchinfo-1.1") or, if global var $testprefix
# is set, just the numeric component (i.e. "1.1").
#
# The second argument is the name of an FTSX table. The third is the 
# full text of a WHERE/MATCH expression to query the table for 
# (i.e. "t1 MATCH 'abc'"). The final argument - $results - should be a
# key-value list (serialized array) with matchinfo() format specifiers
# as keys, and the results of executing the statement:
#
#   SELECT matchinfo($tbl, '$key') FROM $tbl WHERE $expr
#
# For example:
#
#   CREATE VIRTUAL TABLE t1 USING fts4;
#   INSERT INTO t1 VALUES('abc');
#   INSERT INTO t1 VALUES('def');
#   INSERT INTO t1 VALUES('abc abc');
#
#   do_matchinfo_test 1.1 t1 "t1 MATCH 'abc'" {
#     n {3 3}
#     p {1 1}
#     c {1 1}
#     x {{1 3 2} {2 3 2}}
#   }
#
# If the $results list contains keys mapped to "-" instead of a matchinfo()
# result, then this command computes the expected results based on other
# mappings to test the matchinfo() function. For example, the command above
# could be changed to:
#
#   do_matchinfo_test 1.1 t1 "t1 MATCH 'abc'" {
#     n {3 3} p {1 1} c {1 1} x {{1 3 2} {2 3 2}}
#     pcx -
#   }
#
# And this command would compute the expected results for matchinfo(t1, 'pcx')
# based on the results of matchinfo(t1, 'p'), matchinfo(t1, 'c') and 
# matchinfo(t1, 'x') in order to test 'pcx'.
#
proc do_matchinfo_test {tn tbl expr results} {

  foreach {fmt res} $results {
    if {$res == "-"} continue
    set resarray($fmt) $res
  }

  set nRow 0
  foreach {fmt res} [array get resarray] {
    if {[llength $res]>$nRow} { set nRow [llength $res] }
  }

  # Construct expected results for any formats for which the caller 
  # supplied result is "-".
  #
  foreach {fmt res} $results {
    if {$res == "-"} {
      set res [list]
      for {set iRow 0} {$iRow<$nRow} {incr iRow} {
        set rowres [list]
        foreach c [split $fmt ""] {
          set rowres [concat $rowres [lindex $resarray($c) $iRow]]
        }
        lappend res $rowres
      }
      set resarray($fmt) $res
    }
  }

  # Test each matchinfo() request individually.
  #
  foreach {fmt res} [array get resarray] {
    set sql "SELECT mit(matchinfo($tbl, '$fmt')) FROM $tbl WHERE $expr"
    do_execsql_test $tn.$fmt $sql [normalize2 $res]
  }

  # Test them all executed together (multiple invocations of matchinfo()).
  #
  set exprlist [list]
  foreach {format res} [array get resarray] {
    lappend exprlist "mit(matchinfo($tbl, '$format'))"
  }
  set allres [list]
  for {set iRow 0} {$iRow<$nRow} {incr iRow} {
    foreach {format res} [array get resarray] {
      lappend allres [lindex $res $iRow]
    }
  }
  set sql "SELECT [join $exprlist ,] FROM $tbl WHERE $expr"
  do_execsql_test $tn.multi $sql [normalize2 $allres]
}
proc normalize2 {list_of_lists} {
  set res [list]
  foreach elem $list_of_lists {
    lappend res [list {*}$elem]
  }
  return $res
}


do_execsql_test 4.1.0 {
  CREATE VIRTUAL TABLE t4 USING fts4(x, y);
  INSERT INTO t4 VALUES('a b c d e', 'f g h i j');
  INSERT INTO t4 VALUES('f g h i j', 'a b c d e');
}

do_matchinfo_test 4.1.1 t4 {t4 MATCH 'a b c'} {
  p {3 3}
  c {2 2}
  x {
    {1 1 1   0 1 1   1 1 1   0 1 1   1 1 1   0 1 1}
    {0 1 1   1 1 1   0 1 1   1 1 1   0 1 1   1 1 1}
  }
  n {2 2}
  l {{5 5} {5 5}}
  a {{5 5} {5 5}}

  s {{3 0} {0 3}}

  xxxxxxxxxxxxxxxxxx - pcx - xpc - ccc - pppxpcpcx - laxnpc -
  xpxsscplax -
}

do_matchinfo_test 4.1.2 t4 {t4 MATCH '"g h i"'} {
  p {1 1}
  c {2 2}
  x {
    {0 1 1   1 1 1}
    {1 1 1   0 1 1}
  }
  n {2 2}
  l {{5 5} {5 5}}
  a {{5 5} {5 5}}

  s {{0 1} {1 0}}

  xxxxxxxxxxxxxxxxxx - pcx - xpc - ccc - pppxpcpcx - laxnpc -
  sxsxs -
}

do_matchinfo_test 4.1.3 t4 {t4 MATCH 'a b'}     { s {{2 0} {0 2}} }
do_matchinfo_test 4.1.4 t4 {t4 MATCH '"a b" c'} { s {{2 0} {0 2}} }
do_matchinfo_test 4.1.5 t4 {t4 MATCH 'a "b c"'} { s {{2 0} {0 2}} }
do_matchinfo_test 4.1.6 t4 {t4 MATCH 'd d'}     { s {{1 0} {0 1}} }

do_execsql_test 4.2.0 {
  CREATE VIRTUAL TABLE t5 USING fts4;
  INSERT INTO t5 VALUES('a a a a a');
  INSERT INTO t5 VALUES('a b a b a');
  INSERT INTO t5 VALUES('c b c b c');
  INSERT INTO t5 VALUES('x x x x x');
}
do_matchinfo_test 4.2.1 t5 {t5 MATCH 'a a'}         { 
  x {{5 8 2   5 8 2} {3 8 2   3 8 2}}
  s {2 1} 
}
do_matchinfo_test 4.2.2 t5 {t5 MATCH 'a b'}         { s {2} }
do_matchinfo_test 4.2.3 t5 {t5 MATCH 'a b a'}       { s {3} }
do_matchinfo_test 4.2.4 t5 {t5 MATCH 'a a a'}       { s {3 1} }
do_matchinfo_test 4.2.5 t5 {t5 MATCH '"a b" "a b"'} { s {2} }
do_matchinfo_test 4.2.6 t5 {t5 MATCH 'a OR b'}      { s {1 2 1} }

do_execsql_test 4.3.0 "INSERT INTO t5 VALUES('x y [string repeat {b } 50000]')";

do_matchinfo_test 4.3.1 t5 {t5 MATCH 'a a'} { 
  x {{5 8 2   5 5 5} {3 8 2   3 5 5}}
  s {2 1} 
}

do_matchinfo_test 4.3.2 t5 {t5 MATCH 'a b'}         { s {2} }
do_matchinfo_test 4.3.3 t5 {t5 MATCH 'a b a'}       { s {3} }
do_matchinfo_test 4.3.4 t5 {t5 MATCH 'a a a'}       { s {3 1} }
do_matchinfo_test 4.3.5 t5 {t5 MATCH '"a b" "a b"'} { s {2} }
do_matchinfo_test 4.3.6 t5 {t5 MATCH 'a OR b'}      { s {1 2 1 1} }

do_execsql_test 4.4.0 {
  INSERT INTO t5(t5) VALUES('optimize');
  UPDATE t5_segments 
  SET block = zeroblob(length(block)) 
  WHERE length(block)>10000;
}

do_matchinfo_test 4.4.2 t5 {t5 MATCH 'a b'}         { s {2} }
do_matchinfo_test 4.4.1 t5 {t5 MATCH 'a a'}         { s {2 1} }
do_matchinfo_test 4.4.2 t5 {t5 MATCH 'a b'}         { s {2} }
do_matchinfo_test 4.4.3 t5 {t5 MATCH 'a b a'}       { s {3} }
do_matchinfo_test 4.4.4 t5 {t5 MATCH 'a a a'}       { s {3 1} }
do_matchinfo_test 4.4.5 t5 {t5 MATCH '"a b" "a b"'} { s {2} }

do_execsql_test 4.5.0 {
  CREATE VIRTUAL TABLE t6 USING fts4(a, b, c);
  INSERT INTO t6 VALUES('a', 'b', 'c');
}
do_matchinfo_test 4.5.1 t6 {t6 MATCH 'a b c'}       { s {{1 1 1}} }


#-------------------------------------------------------------------------
# Check the following restrictions:
#
#   + Matchinfo flags 'a', 'l' and 'n' can only be used with fts4, not fts3.
#   + Matchinfo flag 'l' cannot be used with matchinfo=fts3.
#
do_execsql_test 5.1 {
  CREATE VIRTUAL TABLE t7 USING fts3(a, b);
  INSERT INTO t7 VALUES('u v w', 'x y z');

  CREATE VIRTUAL TABLE t8 USING fts4(a, b, matchinfo=fts3);
  INSERT INTO t8 VALUES('u v w', 'x y z');
}

do_catchsql_test 5.2.1 { 
  SELECT matchinfo(t7, 'a') FROM t7 WHERE t7 MATCH 'x y'
} {1 {unrecognized matchinfo request: a}}
do_catchsql_test 5.2.2 { 
  SELECT matchinfo(t7, 'l') FROM t7 WHERE t7 MATCH 'x y'
} {1 {unrecognized matchinfo request: l}}
do_catchsql_test 5.2.3 { 
  SELECT matchinfo(t7, 'n') FROM t7 WHERE t7 MATCH 'x y'
} {1 {unrecognized matchinfo request: n}}

do_catchsql_test 5.3.1 { 
  SELECT matchinfo(t8, 'l') FROM t8 WHERE t8 MATCH 'x y'
} {1 {unrecognized matchinfo request: l}}

#-------------------------------------------------------------------------
# Test that the offsets() function handles corruption in the %_content
# table correctly.
#
do_execsql_test 6.1 {
  CREATE VIRTUAL TABLE t9 USING fts4;
  INSERT INTO t9 VALUES(
    'this record is used to try to dectect corruption'
  );
  SELECT offsets(t9) FROM t9 WHERE t9 MATCH 'to';
} {{0 0 20 2 0 0 27 2}}

do_catchsql_test 6.2 {
  UPDATE t9_content SET c0content = 'this record is used to'; 
  SELECT offsets(t9) FROM t9 WHERE t9 MATCH 'to';
} {1 {database disk image is malformed}}

#-------------------------------------------------------------------------
# Test the outcome of matchinfo() when used within a query that does not
# use the full-text index (i.e. lookup by rowid or full-table scan).
#
do_execsql_test 7.1 {
  CREATE VIRTUAL TABLE t10 USING fts4;
  INSERT INTO t10 VALUES('first record');
  INSERT INTO t10 VALUES('second record');
}
do_execsql_test 7.2 {
  SELECT typeof(matchinfo(t10)), length(matchinfo(t10)) FROM t10;
} {blob 0 blob 0}
do_execsql_test 7.3 {
  SELECT typeof(matchinfo(t10)), length(matchinfo(t10)) FROM t10 WHERE docid=1;
} {blob 0}
do_execsql_test 7.4 {
  SELECT typeof(matchinfo(t10)), length(matchinfo(t10)) 
  FROM t10 WHERE t10 MATCH 'record'
} {blob 20 blob 20}


finish_test

Changes to test/fts3query.test.

148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
...
170
171
172
173
174
175
176




177

178
179
180
181
182
183
184
  CREATE VIRTUAL TABLE t2 USING FTS4;
  INSERT INTO t2 VALUES('it was the first time in history');
}
do_select_tests 5.2 -errorformat {
  wrong number of arguments to function %s()
} {
  1 "SELECT matchinfo() FROM t2 WHERE t2 MATCH 'history'"       matchinfo
  2 "SELECT matchinfo(t2, t2) FROM t2 WHERE t2 MATCH 'history'" matchinfo

  3 "SELECT snippet(t2, 1, 2, 3, 4, 5, 6) FROM t2 WHERE t2 MATCH 'history'" 
    snippet
}
do_select_tests 5.3 -errorformat {
  illegal first argument to %s
} {
  1 "SELECT matchinfo(content) FROM t2 WHERE t2 MATCH 'history'" matchinfo
................................................................................
  illegal first argument to %s
} {
  1 "SELECT matchinfo(content) FROM t2 WHERE t2 MATCH 'history'" matchinfo
  2 "SELECT offsets(content) FROM t2 WHERE t2 MATCH 'history'"   offsets
  3 "SELECT snippet(content) FROM t2 WHERE t2 MATCH 'history'"   snippet
  4 "SELECT optimize(content) FROM t2 WHERE t2 MATCH 'history'"  optimize
}




do_execsql_test 5.5 { DROP TABLE t2 }


# Test the snippet() function with 1 to 6 arguments.
# 
do_execsql_test 6.1 {
  CREATE VIRTUAL TABLE t3 USING FTS4(a, b);
  INSERT INTO t3 VALUES('no gestures', 'another intriguing discovery by observing the hand gestures (called beats) people make while speaking. Research has shown that such gestures do more than add visual emphasis to our words (many people gesture while they''re on the telephone, for example); it seems they actually help our brains find words');
}







<
<







 







>
>
>
>

>







148
149
150
151
152
153
154


155
156
157
158
159
160
161
...
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
  CREATE VIRTUAL TABLE t2 USING FTS4;
  INSERT INTO t2 VALUES('it was the first time in history');
}
do_select_tests 5.2 -errorformat {
  wrong number of arguments to function %s()
} {
  1 "SELECT matchinfo() FROM t2 WHERE t2 MATCH 'history'"       matchinfo


  3 "SELECT snippet(t2, 1, 2, 3, 4, 5, 6) FROM t2 WHERE t2 MATCH 'history'" 
    snippet
}
do_select_tests 5.3 -errorformat {
  illegal first argument to %s
} {
  1 "SELECT matchinfo(content) FROM t2 WHERE t2 MATCH 'history'" matchinfo
................................................................................
  illegal first argument to %s
} {
  1 "SELECT matchinfo(content) FROM t2 WHERE t2 MATCH 'history'" matchinfo
  2 "SELECT offsets(content) FROM t2 WHERE t2 MATCH 'history'"   offsets
  3 "SELECT snippet(content) FROM t2 WHERE t2 MATCH 'history'"   snippet
  4 "SELECT optimize(content) FROM t2 WHERE t2 MATCH 'history'"  optimize
}
do_catchsql_test 5.5.1 {
  SELECT matchinfo(t2, 'abc') FROM t2 WHERE t2 MATCH 'history'
} {1 {unrecognized matchinfo request: b}}

do_execsql_test 5.5 { DROP TABLE t2 }


# Test the snippet() function with 1 to 6 arguments.
# 
do_execsql_test 6.1 {
  CREATE VIRTUAL TABLE t3 USING FTS4(a, b);
  INSERT INTO t3 VALUES('no gestures', 'another intriguing discovery by observing the hand gestures (called beats) people make while speaking. Research has shown that such gestures do more than add visual emphasis to our words (many people gesture while they''re on the telephone, for example); it seems they actually help our brains find words');
}

Changes to test/fts3rnd.test.

301
302
303
304
305
306
307




308
309
310
311
312
313
314
...
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
      set iInsert [expr {int(rand()*1000000)}]
    }
    execsql BEGIN
      insert_row $iInsert
      update_row $iUpdate
      delete_row $iDelete
    if {0==($iTest%2)} { execsql COMMIT }





    # Pick 10 terms from the vocabulary. Check that the results of querying
    # the database for the set of documents containing each of these terms
    # is the same as the result obtained by scanning the contents of the Tcl 
    # array for each term.
    #
    for {set i 0} {$i < 10} {incr i} {
................................................................................

    # A 3-way NEAR query with terms as the arguments.
    #
    for {set i 0} {$i < $nRep} {incr i} {
      set terms [list [random_term] [random_term] [random_term]]
      set nNear 11
      set match [join $terms " NEAR/$nNear "]
      set fts3 [execsql { SELECT docid FROM t1 WHERE t1 MATCH $match }]
      do_select_test fts3rnd-1.$nodesize.$iTest.7.$i {
        SELECT docid FROM t1 WHERE t1 MATCH $match
      } [simple_near $terms $nNear]
    }
    
    # Set operations on simple term queries.
    #







>
>
>
>







 







<







301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
...
379
380
381
382
383
384
385

386
387
388
389
390
391
392
      set iInsert [expr {int(rand()*1000000)}]
    }
    execsql BEGIN
      insert_row $iInsert
      update_row $iUpdate
      delete_row $iDelete
    if {0==($iTest%2)} { execsql COMMIT }

    if {0==($iTest%2)} { 
      do_test fts3rnd-1.$nodesize.$iTest.0 { fts3_integrity_check t1 } ok 
    }

    # Pick 10 terms from the vocabulary. Check that the results of querying
    # the database for the set of documents containing each of these terms
    # is the same as the result obtained by scanning the contents of the Tcl 
    # array for each term.
    #
    for {set i 0} {$i < 10} {incr i} {
................................................................................

    # A 3-way NEAR query with terms as the arguments.
    #
    for {set i 0} {$i < $nRep} {incr i} {
      set terms [list [random_term] [random_term] [random_term]]
      set nNear 11
      set match [join $terms " NEAR/$nNear "]

      do_select_test fts3rnd-1.$nodesize.$iTest.7.$i {
        SELECT docid FROM t1 WHERE t1 MATCH $match
      } [simple_near $terms $nNear]
    }
    
    # Set operations on simple term queries.
    #

Changes to test/incrblob3.test.

88
89
90
91
92
93
94



95
96
97
98
99
100
101
102
103
  } {1 SQLITE_ABORT}
  do_test incrblob3-2.2.$tn.4 {
    list [catch {sqlite3_blob_read $::blob 0 10} msg] $msg
  } {1 SQLITE_ABORT}
  do_test incrblob3-2.2.$tn.5 {
    list [catch {sqlite3_blob_write $::blob 0 "abcd"} msg] $msg
  } {1 SQLITE_ABORT}




  do_test incrblob3-2.2.$tn.4 { close $::blob } {}
}

# Test that passing NULL to sqlite3_blob_XXX() APIs returns SQLITE_MISUSE.
#
#   incrblob3-3.1: sqlite3_blob_reopen()
#   incrblob3-3.2: sqlite3_blob_read()
#   incrblob3-3.3: sqlite3_blob_write()







>
>
>

|







88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
  } {1 SQLITE_ABORT}
  do_test incrblob3-2.2.$tn.4 {
    list [catch {sqlite3_blob_read $::blob 0 10} msg] $msg
  } {1 SQLITE_ABORT}
  do_test incrblob3-2.2.$tn.5 {
    list [catch {sqlite3_blob_write $::blob 0 "abcd"} msg] $msg
  } {1 SQLITE_ABORT}
  do_test incrblob3-2.2.$tn.6 {
    sqlite3_blob_bytes $::blob
  } {0}

  do_test incrblob3-2.2.$tn.7 { close $::blob } {}
}

# Test that passing NULL to sqlite3_blob_XXX() APIs returns SQLITE_MISUSE.
#
#   incrblob3-3.1: sqlite3_blob_reopen()
#   incrblob3-3.2: sqlite3_blob_read()
#   incrblob3-3.3: sqlite3_blob_write()

Changes to test/lock_common.tcl.

12
13
14
15
16
17
18

19
20
21
22
23
24
25
# code in this file allows testfixture to control another process (or
# processes) to test locking.
#

proc do_multiclient_test {varname script} {

  foreach code [list {

    set ::code2_chan [launch_testfixture]
    set ::code3_chan [launch_testfixture]
    proc code2 {tcl} { testfixture $::code2_chan $tcl }
    proc code3 {tcl} { testfixture $::code3_chan $tcl }
    set tn 1
  } {
    proc code2 {tcl} { uplevel #0 $tcl }







>







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# code in this file allows testfixture to control another process (or
# processes) to test locking.
#

proc do_multiclient_test {varname script} {

  foreach code [list {
    if {[info exists ::G(valgrind)]} { db close ; continue }
    set ::code2_chan [launch_testfixture]
    set ::code3_chan [launch_testfixture]
    proc code2 {tcl} { testfixture $::code2_chan $tcl }
    proc code3 {tcl} { testfixture $::code3_chan $tcl }
    set tn 1
  } {
    proc code2 {tcl} { uplevel #0 $tcl }

Changes to test/malloc_common.tcl.

130
131
132
133
134
135
136

137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
  }

  set testspec [list -prep $O(-prep) -body $O(-body) -test $O(-test)]
  foreach f [lsort -unique $faultlist] {
    eval do_one_faultsim_test "$name-$f" $FAULTSIM($f) $testspec
  }
}


#-------------------------------------------------------------------------
# Procedures to save and restore the current file-system state:
#
#   faultsim_save
#   faultsim_restore
#   faultsim_save_and_close
#   faultsim_restore_and_reopen
#   faultsim_delete_and_reopen
#
proc faultsim_save {} {
  foreach f [glob -nocomplain sv_test.db*] { forcedelete $f }
  foreach f [glob -nocomplain test.db*] {
    set f2 "sv_$f"
    file copy -force $f $f2
  }
}
proc faultsim_save_and_close {} {
  faultsim_save
  catch { db close }
  return ""
}
proc faultsim_restore {} {
  foreach f [glob -nocomplain test.db*] { forcedelete $f }
  foreach f2 [glob -nocomplain sv_test.db*] {
    set f [string range $f2 3 end]
    file copy -force $f2 $f
  }
}
proc faultsim_restore_and_reopen {{dbfile test.db}} {
  catch { db close }
  faultsim_restore
  sqlite3 db $dbfile
  sqlite3_extended_result_codes db 1
  sqlite3_db_config_lookaside db 0 0 0
}

proc faultsim_integrity_check {{db db}} {
  set ic [$db eval { PRAGMA integrity_check }]
  if {$ic != "ok"} { error "Integrity check: $ic" }
}

proc faultsim_delete_and_reopen {{file test.db}} {
  catch { db close }
  foreach f [glob -nocomplain test.db*] { file delete -force $f }
  sqlite3 db $file
}


# The following procs are used as [do_one_faultsim_test] callbacks when 
# injecting OOM faults into test cases.
#
proc oom_injectstart {nRepeat iFail} {
  sqlite3_memdebug_fail [expr $iFail-1] -repeat $nRepeat
}







>










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









<
<
<
<
<
<







130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157













158
159
160
161
162
163
164
165
166






167
168
169
170
171
172
173
  }

  set testspec [list -prep $O(-prep) -body $O(-body) -test $O(-test)]
  foreach f [lsort -unique $faultlist] {
    eval do_one_faultsim_test "$name-$f" $FAULTSIM($f) $testspec
  }
}


#-------------------------------------------------------------------------
# Procedures to save and restore the current file-system state:
#
#   faultsim_save
#   faultsim_restore
#   faultsim_save_and_close
#   faultsim_restore_and_reopen
#   faultsim_delete_and_reopen
#
proc faultsim_save {args} { uplevel db_save $args }
proc faultsim_save_and_close {args} { uplevel db_save_and_close $args }
proc faultsim_restore {args} { uplevel db_restore $args }
proc faultsim_restore_and_reopen {args} { 
  uplevel db_restore_and_reopen $args 
  sqlite3_extended_result_codes db 1
  sqlite3_db_config_lookaside db 0 0 0
}
proc faultsim_delete_and_reopen {args} {
  uplevel db_delete_and_reopen $args 













  sqlite3_extended_result_codes db 1
  sqlite3_db_config_lookaside db 0 0 0
}

proc faultsim_integrity_check {{db db}} {
  set ic [$db eval { PRAGMA integrity_check }]
  if {$ic != "ok"} { error "Integrity check: $ic" }
}








# The following procs are used as [do_one_faultsim_test] callbacks when 
# injecting OOM faults into test cases.
#
proc oom_injectstart {nRepeat iFail} {
  sqlite3_memdebug_fail [expr $iFail-1] -repeat $nRepeat
}

Changes to test/misc7.test.

255
256
257
258
259
260
261
262
263
264
265
266
267


268
269
270
271
272


273
274
275
276
277


278
279
280
281
282
283
284
285
286

db close
file delete -force test.db
file delete -force test.db-journal
sqlite3 db test.db

ifcapable explain {
  do_test misc7-14.1 {
    execsql {
      CREATE TABLE abc(a PRIMARY KEY, b, c);
    }
    execsql {
      EXPLAIN QUERY PLAN SELECT * FROM abc AS t2 WHERE rowid = 1;


    }
  } {0 0 {TABLE abc AS t2 USING PRIMARY KEY}}
  do_test misc7-14.2 {
    execsql {
      EXPLAIN QUERY PLAN SELECT * FROM abc AS t2 WHERE a = 1;


    }
  } {0 0 {TABLE abc AS t2 WITH INDEX sqlite_autoindex_abc_1}}
  do_test misc7-14.3 {
    execsql {
      EXPLAIN QUERY PLAN SELECT * FROM abc AS t2 ORDER BY a;


    }
  } {0 0 {TABLE abc AS t2 WITH INDEX sqlite_autoindex_abc_1 ORDER BY}}
}

db close
file delete -force test.db
file delete -force test.db-journal
sqlite3 db test.db








|
<
|
<
<
|
>
>
|
<
|
<
|
>
>
|
<
|
<
|
>
>
|
<







255
256
257
258
259
260
261
262

263


264
265
266
267

268

269
270
271
272

273

274
275
276
277

278
279
280
281
282
283
284

db close
file delete -force test.db
file delete -force test.db-journal
sqlite3 db test.db

ifcapable explain {
  do_execsql_test misc7-14.1 {

    CREATE TABLE abc(a PRIMARY KEY, b, c);


    EXPLAIN QUERY PLAN SELECT * FROM abc AS t2 WHERE rowid = 1;
  } {
    0 0 0 {SEARCH TABLE abc AS t2 USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)}
  }

  do_execsql_test misc7-14.2 {

    EXPLAIN QUERY PLAN SELECT * FROM abc AS t2 WHERE a = 1;
  } {0 0 0 
     {SEARCH TABLE abc AS t2 USING INDEX sqlite_autoindex_abc_1 (a=?) (~1 rows)}
  }

  do_execsql_test misc7-14.3 {

    EXPLAIN QUERY PLAN SELECT * FROM abc AS t2 ORDER BY a;
  } {0 0 0 
     {SCAN TABLE abc AS t2 USING INDEX sqlite_autoindex_abc_1 (~1000000 rows)}
  }

}

db close
file delete -force test.db
file delete -force test.db-journal
sqlite3 db test.db

Changes to test/multiplex.test.

50
51
52
53
54
55
56



57
58
59
60
61
62
63
...
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
...
443
444
445
446
447
448
449
450












































451
452
    forcedelete [multiplex_name $name-journal $i]
    forcedelete [multiplex_name $name-wal $i]
  }
}

db close




#-------------------------------------------------------------------------
#   multiplex-1.1.*: Test initialize and shutdown.

do_test multiplex-1.1 { sqlite3_multiplex_initialize nosuchvfs 1 } {SQLITE_ERROR}
do_test multiplex-1.2 { sqlite3_multiplex_initialize "" 1 }        {SQLITE_OK}
do_test multiplex-1.3 { sqlite3_multiplex_initialize "" 1 }        {SQLITE_MISUSE}
do_test multiplex-1.4 { sqlite3_multiplex_shutdown }               {SQLITE_OK}
................................................................................

do_test multiplex-2.2.1 {
  execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) }
} {}
do_test multiplex-2.2.3 { file size [multiplex_name test.db 0] } {6144}

do_test multiplex-2.3.1 {
  sqlite3 db2 bak.db
  db2 close
} {}

do_test multiplex-2.4.1 {
  sqlite3_multiplex_shutdown
} {SQLITE_MISUSE}
do_test multiplex-2.4.2 {
................................................................................

do_faultsim_test multiplex-5.5 -prep {
  catch { sqlite3_multiplex_shutdown }
} -body {
  sqlite3_multiplex_initialize "" 1
  multiplex_set 32768 16
}













































catch { sqlite3_multiplex_shutdown }
finish_test







>
>
>







 







|







 








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


50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
...
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
...
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
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
    forcedelete [multiplex_name $name-journal $i]
    forcedelete [multiplex_name $name-wal $i]
  }
}

db close

multiplex_delete test.db
multiplex_delete test2.db

#-------------------------------------------------------------------------
#   multiplex-1.1.*: Test initialize and shutdown.

do_test multiplex-1.1 { sqlite3_multiplex_initialize nosuchvfs 1 } {SQLITE_ERROR}
do_test multiplex-1.2 { sqlite3_multiplex_initialize "" 1 }        {SQLITE_OK}
do_test multiplex-1.3 { sqlite3_multiplex_initialize "" 1 }        {SQLITE_MISUSE}
do_test multiplex-1.4 { sqlite3_multiplex_shutdown }               {SQLITE_OK}
................................................................................

do_test multiplex-2.2.1 {
  execsql { INSERT INTO t1 VALUES(3, randomblob(1100)) }
} {}
do_test multiplex-2.2.3 { file size [multiplex_name test.db 0] } {6144}

do_test multiplex-2.3.1 {
  sqlite3 db2 test2.db
  db2 close
} {}

do_test multiplex-2.4.1 {
  sqlite3_multiplex_shutdown
} {SQLITE_MISUSE}
do_test multiplex-2.4.2 {
................................................................................

do_faultsim_test multiplex-5.5 -prep {
  catch { sqlite3_multiplex_shutdown }
} -body {
  sqlite3_multiplex_initialize "" 1
  multiplex_set 32768 16
}

# test that mismatch filesize is detected
#
# Do not run this test if $::G(perm:presql) is set. If it is set, then the
# expected IO error will occur within the Tcl [sqlite3] wrapper, not within
# the first SQL statement executed below. This breaks the test case.
#
if {0==[info exists ::G(perm:presql)] || $::G(perm:presql) == ""} {
  set all_journal_modes {delete persist truncate memory off}
  foreach jmode $all_journal_modes {
    do_test multiplex-5.6.1.$jmode {
      sqlite3_multiplex_shutdown
      multiplex_delete test.db
      sqlite3 db test.db
      db eval {
        PRAGMA page_size = 1024;
        PRAGMA auto_vacuum = off;
      }
      db eval "PRAGMA journal_mode = $jmode;"
    } $jmode
    do_test multiplex-5.6.2.$jmode {
      execsql {
        CREATE TABLE t1(a, b);
        INSERT INTO t1 VALUES(1, randomblob(1100));
        INSERT INTO t1 VALUES(2, randomblob(1100));
        INSERT INTO t1 VALUES(3, randomblob(1100));
        INSERT INTO t1 VALUES(4, randomblob(1100));
        INSERT INTO t1 VALUES(5, randomblob(1100));
      }
      db close
      sqlite3_multiplex_initialize "" 1
      multiplex_set 4096 16
      sqlite3 db test.db
    } {}
    do_test multiplex-5.6.3.$jmode {
      catchsql {
        INSERT INTO t1 VALUES(6, randomblob(1100));
      }
    } {1 {disk I/O error}}
    do_test multiplex-5.6.4.$jmode {
      db close
    } {}
  }
}

catch { sqlite3_multiplex_shutdown }
finish_test

Changes to test/pager1.test.

1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
} {13}
do_execsql_test pager1-6.8 {
    INSERT INTO t11 VALUES(3, 4);
    PRAGMA max_page_count = 10;
} {11}
do_execsql_test pager1-6.9 { COMMIT } {}

do_execsql_test pager1-6.10 { PRAGMA max_page_count = 10 } {10}
do_execsql_test pager1-6.11 { SELECT * FROM t11 }          {1 2 3 4}
do_execsql_test pager1-6.12 { PRAGMA max_page_count }      {11}


#-------------------------------------------------------------------------
# The following tests work with "PRAGMA journal_mode=TRUNCATE" and
# "PRAGMA locking_mode=EXCLUSIVE".







|







1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
} {13}
do_execsql_test pager1-6.8 {
    INSERT INTO t11 VALUES(3, 4);
    PRAGMA max_page_count = 10;
} {11}
do_execsql_test pager1-6.9 { COMMIT } {}

do_execsql_test pager1-6.10 { PRAGMA max_page_count = 10 } {11}
do_execsql_test pager1-6.11 { SELECT * FROM t11 }          {1 2 3 4}
do_execsql_test pager1-6.12 { PRAGMA max_page_count }      {11}


#-------------------------------------------------------------------------
# The following tests work with "PRAGMA journal_mode=TRUNCATE" and
# "PRAGMA locking_mode=EXCLUSIVE".

Changes to test/permutations.test.

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
46
47
48
49
50
51
52
53
54
55
56
57
58
...
132
133
134
135
136
137
138











139
140
141
142
143
144
145
...
742
743
744
745
746
747
748













749
750
751
752
753
754
755
...
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
#
#       -description TITLE                  (default "")
#       -initialize  SCRIPT                 (default "")
#       -shutdown    SCRIPT                 (default "")
#       -presql      SQL                    (default "")
#       -files       LIST-OF-FILES          (default $::ALLTESTS)
#       -prefix      NAME                   (default "$::NAME.")

#
proc test_suite {name args} {

  set default(-shutdown)    ""
  set default(-initialize)  ""
  set default(-presql)      ""
  set default(-description) "no description supplied (fixme)"
  set default(-files)       ""
  set default(-prefix)      "${name}."


  array set options [array get default]
  if {[llength $args]%2} {
    error "uneven number of options/switches passed to test_suite"
  }
  foreach {k v} $args {
    set o [array names options ${k}*]
................................................................................
    if {[llength $o]>1}  { error "ambiguous option: $k" }
    if {[llength $o]==0} { error "unknown option: $k" }
    set options([lindex $o 0]) $v
  }

  set     ::testspec($name) [array get options]
  lappend ::testsuitelist $name

}

#-------------------------------------------------------------------------
# test_set ARGS...
#
proc test_set {args} {
  set isExclude 0
................................................................................
test_suite "veryquick" -prefix "" -description {
  "Very" quick test suite. Runs in less than 5 minutes on a workstation. 
  This test suite is the same as the "quick" tests, except that some files
  that test malloc and IO errors are omitted.
} -files [
  test_set $allquicktests -exclude *malloc* *ioerr* *fault*
]












test_suite "quick" -prefix "" -description {
  Quick test suite. Runs in around 10 minutes on a workstation.
} -files [
  test_set $allquicktests
]

................................................................................
  fts3am.test  fts3an.test  fts3ao.test  fts3b.test
  fts3c.test   fts3d.test   fts3e.test   fts3query.test 
}

test_suite "rtree" -description {
  All R-tree related tests. Provides coverage of source file rtree.c.
} -files [glob -nocomplain $::testdir/../ext/rtree/*.test]














# End of tests
#############################################################################

# run_tests NAME OPTIONS
#
# where available options are:  
................................................................................
proc run_tests {name args} {
  array set options $args

  set ::G(perm:name)         $name
  set ::G(perm:prefix)       $options(-prefix)
  set ::G(perm:presql)       $options(-presql)
  set ::G(isquick)           1


  uplevel $options(-initialize)

  foreach file [lsort $options(-files)] {
    if {[file tail $file] == $file} { set file [file join $::testdir $file] }
    slave_test_file $file
  }

  uplevel $options(-shutdown)

  unset ::G(perm:name)
  unset ::G(perm:prefix)
  unset ::G(perm:presql)

}

proc run_test_suite {name} {
  if {[info exists ::testspec($name)]==0} {
    error "No such test suite: $name"
  }
  uplevel run_tests $name $::testspec($name)







>









>







 







<







 







>
>
>
>
>
>
>
>
>
>
>







 







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







 







>













>







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
..
46
47
48
49
50
51
52

53
54
55
56
57
58
59
...
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
...
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
...
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
#
#       -description TITLE                  (default "")
#       -initialize  SCRIPT                 (default "")
#       -shutdown    SCRIPT                 (default "")
#       -presql      SQL                    (default "")
#       -files       LIST-OF-FILES          (default $::ALLTESTS)
#       -prefix      NAME                   (default "$::NAME.")
#       -dbconfig    SCRIPT                 (default "")
#
proc test_suite {name args} {

  set default(-shutdown)    ""
  set default(-initialize)  ""
  set default(-presql)      ""
  set default(-description) "no description supplied (fixme)"
  set default(-files)       ""
  set default(-prefix)      "${name}."
  set default(-dbconfig)    ""

  array set options [array get default]
  if {[llength $args]%2} {
    error "uneven number of options/switches passed to test_suite"
  }
  foreach {k v} $args {
    set o [array names options ${k}*]
................................................................................
    if {[llength $o]>1}  { error "ambiguous option: $k" }
    if {[llength $o]==0} { error "unknown option: $k" }
    set options([lindex $o 0]) $v
  }

  set     ::testspec($name) [array get options]
  lappend ::testsuitelist $name

}

#-------------------------------------------------------------------------
# test_set ARGS...
#
proc test_set {args} {
  set isExclude 0
................................................................................
test_suite "veryquick" -prefix "" -description {
  "Very" quick test suite. Runs in less than 5 minutes on a workstation. 
  This test suite is the same as the "quick" tests, except that some files
  that test malloc and IO errors are omitted.
} -files [
  test_set $allquicktests -exclude *malloc* *ioerr* *fault*
]

test_suite "valgrind" -prefix "" -description {
  Run the "veryquick" test suite with a couple of multi-process tests (that
  fail under valgrind) omitted.
} -files [
  test_set $allquicktests -exclude *malloc* *ioerr* *fault*
] -initialize {
  set ::G(valgrind) 1
} -shutdown {
  unset -nocomplain ::G(valgrind)
}

test_suite "quick" -prefix "" -description {
  Quick test suite. Runs in around 10 minutes on a workstation.
} -files [
  test_set $allquicktests
]

................................................................................
  fts3am.test  fts3an.test  fts3ao.test  fts3b.test
  fts3c.test   fts3d.test   fts3e.test   fts3query.test 
}

test_suite "rtree" -description {
  All R-tree related tests. Provides coverage of source file rtree.c.
} -files [glob -nocomplain $::testdir/../ext/rtree/*.test]

test_suite "no_optimization" -description {
  Run test scripts with optimizations disabled using the
  sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS) interface.
} -files {
  where.test where2.test where3.test where4.test where5.test
  where6.test where7.test where8.test where9.test
  whereA.test whereB.test wherelimit.test
  select1.test select2.test select3.test select4.test select5.test
  select7.test select8.test selectA.test selectC.test
} -dbconfig {
  optimization_control $::dbhandle all 0
}

# End of tests
#############################################################################

# run_tests NAME OPTIONS
#
# where available options are:  
................................................................................
proc run_tests {name args} {
  array set options $args

  set ::G(perm:name)         $name
  set ::G(perm:prefix)       $options(-prefix)
  set ::G(perm:presql)       $options(-presql)
  set ::G(isquick)           1
  set ::G(perm:dbconfig)     $options(-dbconfig)

  uplevel $options(-initialize)

  foreach file [lsort $options(-files)] {
    if {[file tail $file] == $file} { set file [file join $::testdir $file] }
    slave_test_file $file
  }

  uplevel $options(-shutdown)

  unset ::G(perm:name)
  unset ::G(perm:prefix)
  unset ::G(perm:presql)
  unset ::G(perm:dbconfig)
}

proc run_test_suite {name} {
  if {[info exists ::testspec($name)]==0} {
    error "No such test suite: $name"
  }
  uplevel run_tests $name $::testspec($name)

Changes to test/superlock.test.

11
12
13
14
15
16
17


























18
19
20
21
22
23
24
..
50
51
52
53
54
55
56

57
58
59
60
61
62
63
..
88
89
90
91
92
93
94
95
96





97














































































































98
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/lock_common.tcl

set testprefix superlock



























do_execsql_test 1.1 {
  CREATE TABLE t1(a, b);
  INSERT INTO t1 VALUES(1, 2);
  PRAGMA journal_mode = DELETE;
} {delete}

................................................................................
do_test 4.2 { sqlite3demo_superlock unlock test.db } {unlock}
do_catchsql_test 4.3 { SELECT * FROM t1 }           {1 {database is locked}}
do_catchsql_test 4.4 { INSERT INTO t1 VALUES(5, 6)} {1 {database is locked}}
do_catchsql_test 4.5 { PRAGMA wal_checkpoint }      {1 {database is locked}}
do_test 4.6 { unlock } {}

do_multiclient_test tn {

  proc busyhandler {x} {
    switch -- $x {
      1 { sql1 "COMMIT" }
      2 { sql2 "COMMIT" }
      3 { sql3 "COMMIT" }
    }
    lappend ::busylist $x
................................................................................
  do_test 5.$tn.4 { csql2 { SELECT * FROM t1 } } {1 {database is locked}}
  do_test 5.$tn.5 { 
    csql3 { INSERT INTO t1 VALUES(5, 6) } 
  } {1 {database is locked}}
  do_test 5.$tn.6 { csql1 "PRAGMA wal_checkpoint" } {1 {database is locked}}

  do_test 5.$tn.7 { unlock } {}
}





















































































































finish_test







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







 







>







 







|
|
>
>
>
>
>

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

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
46
47
48
49
50
..
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
...
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
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
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/lock_common.tcl

set testprefix superlock

# Test organization:
#
#   1.*: Test superlock on a rollback database. Test that once the db is
#        superlocked, it is not possible for a second client to read from
#        it.
#
#   2.*: Test superlock on a WAL database with zero frames in the WAL file.
#        Test that once the db is superlocked, it is not possible to read,
#        write or checkpoint the db.
#
#   3.*: As 2.*, for WAL databases with one or more frames in the WAL.
#
#   4.*: As 2.*, for WAL databases with one or more checkpointed frames 
#        in the WAL.
#
#   5.*: Test that a call to sqlite3demo_superlock() uses the busy handler
#        correctly to wait for existing clients to clear on a WAL database.
#        And returns SQLITE_BUSY if no busy handler is defined or the busy
#        handler returns 0 before said clients relinquish their locks.
#
#   6.*: Test that if a superlocked WAL database is overwritten, existing
#        clients run the recovery to build the new wal-index after the 
#        superlock is released.
#        
#

do_execsql_test 1.1 {
  CREATE TABLE t1(a, b);
  INSERT INTO t1 VALUES(1, 2);
  PRAGMA journal_mode = DELETE;
} {delete}

................................................................................
do_test 4.2 { sqlite3demo_superlock unlock test.db } {unlock}
do_catchsql_test 4.3 { SELECT * FROM t1 }           {1 {database is locked}}
do_catchsql_test 4.4 { INSERT INTO t1 VALUES(5, 6)} {1 {database is locked}}
do_catchsql_test 4.5 { PRAGMA wal_checkpoint }      {1 {database is locked}}
do_test 4.6 { unlock } {}

do_multiclient_test tn {

  proc busyhandler {x} {
    switch -- $x {
      1 { sql1 "COMMIT" }
      2 { sql2 "COMMIT" }
      3 { sql3 "COMMIT" }
    }
    lappend ::busylist $x
................................................................................
  do_test 5.$tn.4 { csql2 { SELECT * FROM t1 } } {1 {database is locked}}
  do_test 5.$tn.5 { 
    csql3 { INSERT INTO t1 VALUES(5, 6) } 
  } {1 {database is locked}}
  do_test 5.$tn.6 { csql1 "PRAGMA wal_checkpoint" } {1 {database is locked}}

  do_test 5.$tn.7 { unlock } {}

  
  do_test 5.$tn.8 {
    sql1 { BEGIN ; SELECT * FROM t1 }
    sql2 { BEGIN ; INSERT INTO t1 VALUES(5, 6) }
    sql3 { BEGIN ; SELECT * FROM t1 }
  } {1 2 3 4}

  do_test 5.$tn.9 { 
    list [catch {sqlite3demo_superlock unlock test.db} msg] $msg
  } {1 {database is locked}}
  do_test 5.$tn.10 { 
    sql1 COMMIT
    list [catch {sqlite3demo_superlock unlock test.db} msg] $msg
  } {1 {database is locked}}
  do_test 5.$tn.11 { 
    sql2 COMMIT
    list [catch {sqlite3demo_superlock unlock test.db} msg] $msg
  } {1 {database is locked}}
  do_test 5.$tn.12 { 
    sql3 COMMIT
    list [catch {sqlite3demo_superlock unlock test.db} msg] $msg
  } {0 unlock}
  unlock
}

proc read_content {file} {
  if {[file exists $file]==0} {return ""}
  set fd [open $file]
  fconfigure $fd -encoding binary -translation binary
  set content [read $fd]
  close $fd
  return $content
}

proc write_content {file content} {
  set fd [open $file w+]
  fconfigure $fd -encoding binary -translation binary
  puts -nonewline $fd $content
  close $fd
}

# Both $file1 and $file2 are database files. This function takes a 
# superlock on each, then exchanges the content of the two files (i.e.
# overwrites $file1 with the initial contents of $file2, and overwrites
# $file2 with the initial contents of $file1). The contents of any WAL 
# file is also exchanged.
#
proc db_swap {file1 file2} {
  sqlite3demo_superlock unlock1 $file1
  sqlite3demo_superlock unlock2 $file2

  set db1 [read_content $file1]
  set db2 [read_content $file2]
  write_content $file1 $db2
  write_content $file2 $db1

  set wal1 [read_content ${file1}-wal]
  set wal2 [read_content ${file2}-wal]
  write_content ${file1}-wal $wal2
  write_content ${file2}-wal $wal1

  unlock1
  unlock2
}

forcedelete test.db
sqlite3 db  test.db
do_execsql_test 6.1 {
  ATTACH 'test.db2' AS aux;
  PRAGMA aux.journal_mode = wal;
  CREATE TABLE aux.t2(x, y);
  INSERT INTO aux.t2 VALUES('a', 'b');
  PRAGMA schema_version = 450;
  DETACH aux;

  PRAGMA main.journal_mode = wal;
  CREATE TABLE t1(a, b);
  INSERT INTO t1 VALUES(1, 2);
  INSERT INTO t1 VALUES(3, 4);
  SELECT * FROM t1;
} {wal wal 1 2 3 4}


db_swap test.db2 test.db
do_catchsql_test 6.2 { SELECT * FROM t1 } {1 {no such table: t1}}
do_catchsql_test 6.3 { SELECT * FROM t2 } {0 {a b}}

db_swap test.db2 test.db
do_catchsql_test 6.4 { SELECT * FROM t1 } {0 {1 2 3 4}}
do_catchsql_test 6.5 { SELECT * FROM t2 } {1 {no such table: t2}}

do_execsql_test  6.6 { PRAGMA wal_checkpoint }

db_swap test.db2 test.db
do_catchsql_test 6.7 { SELECT * FROM t1 } {1 {no such table: t1}}
do_catchsql_test 6.8 { SELECT * FROM t2 } {0 {a b}}

db_swap test.db2 test.db
do_catchsql_test 6.9 { SELECT * FROM t1 } {0 {1 2 3 4}}
do_catchsql_test 6.10 { SELECT * FROM t2 } {1 {no such table: t2}}

do_execsql_test  6.11 { 
  PRAGMA journal_mode = delete;
  PRAGMA page_size = 512;
  VACUUM;
  PRAGMA journal_mode = wal;
  INSERT INTO t1 VALUES(5, 6);
} {delete wal}

db_swap test.db2 test.db
do_catchsql_test 6.12 { SELECT * FROM t1 } {1 {no such table: t1}}
do_catchsql_test 6.13 { SELECT * FROM t2 } {0 {a b}}

db_swap test.db2 test.db
do_catchsql_test 6.14 { SELECT * FROM t1 } {0 {1 2 3 4 5 6}}
do_catchsql_test 6.15 { SELECT * FROM t2 } {1 {no such table: t2}}

finish_test

Changes to test/tester.tcl.

105
106
107
108
109
110
111




112
113
114
115
116
117
118
...
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
....
1403
1404
1405
1406
1407
1408
1409






























1410
1411
1412
1413
1414
1415
1416
        lappend args -key {xyzzy}
      }

      set res [uplevel 1 sqlite_orig $args]
      if {[info exists ::G(perm:presql)]} {
        [lindex $args 0] eval $::G(perm:presql)
      }




      set res
    } else {
      # This command is not opening a new database connection. Pass the 
      # arguments through to the C implemenation as the are.
      #
      uplevel 1 sqlite_orig $args
    }
................................................................................
    puts "\nExpected: \[$expected\]\n     Got: \[$result\]"
    fail_test $name
  } else {
    puts " Ok"
  }
  flush stdout
}
    
proc fix_testname {varname} {
  upvar $varname testname
  if {[info exists ::testprefix] 
   && [string is digit [string range $testname 0 0]]
  } {
    set testname "${::testprefix}-$testname"
  }
................................................................................
  catch { db36231 func a_string a_string }
  execsql $sql db36231
  db36231 close
  hexio_write test.db 28 $A
  hexio_write test.db 92 $B
  return ""
}































# If the library is compiled with the SQLITE_DEFAULT_AUTOVACUUM macro set
# to non-zero, then set the global variable $AUTOVACUUM to 1.
set AUTOVACUUM $sqlite_options(default_autovacuum)

source $testdir/thread_common.tcl
source $testdir/malloc_common.tcl







>
>
>
>







 







|







 







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







105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
...
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
....
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
        lappend args -key {xyzzy}
      }

      set res [uplevel 1 sqlite_orig $args]
      if {[info exists ::G(perm:presql)]} {
        [lindex $args 0] eval $::G(perm:presql)
      }
      if {[info exists ::G(perm:dbconfig)]} {
        set ::dbhandle [lindex $args 0]
        uplevel #0 $::G(perm:dbconfig)
      }
      set res
    } else {
      # This command is not opening a new database connection. Pass the 
      # arguments through to the C implemenation as the are.
      #
      uplevel 1 sqlite_orig $args
    }
................................................................................
    puts "\nExpected: \[$expected\]\n     Got: \[$result\]"
    fail_test $name
  } else {
    puts " Ok"
  }
  flush stdout
}

proc fix_testname {varname} {
  upvar $varname testname
  if {[info exists ::testprefix] 
   && [string is digit [string range $testname 0 0]]
  } {
    set testname "${::testprefix}-$testname"
  }
................................................................................
  catch { db36231 func a_string a_string }
  execsql $sql db36231
  db36231 close
  hexio_write test.db 28 $A
  hexio_write test.db 92 $B
  return ""
}

proc db_save {} {
  foreach f [glob -nocomplain sv_test.db*] { forcedelete $f }
  foreach f [glob -nocomplain test.db*] {
    set f2 "sv_$f"
    file copy -force $f $f2
  }
}
proc db_save_and_close {} {
  db_save
  catch { db close }
  return ""
}
proc db_restore {} {
  foreach f [glob -nocomplain test.db*] { forcedelete $f }
  foreach f2 [glob -nocomplain sv_test.db*] {
    set f [string range $f2 3 end]
    file copy -force $f2 $f
  }
}
proc db_restore_and_reopen {{dbfile test.db}} {
  catch { db close }
  db_restore
  sqlite3 db $dbfile
}
proc db_delete_and_reopen {{file test.db}} {
  catch { db close }
  foreach f [glob -nocomplain test.db*] { file delete -force $f }
  sqlite3 db $file
}

# If the library is compiled with the SQLITE_DEFAULT_AUTOVACUUM macro set
# to non-zero, then set the global variable $AUTOVACUUM to 1.
set AUTOVACUUM $sqlite_options(default_autovacuum)

source $testdir/thread_common.tcl
source $testdir/malloc_common.tcl

Added test/tkt-80ba201079.test.































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# 2010 December 6
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library. Specifically,
# it tests that ticket [80ba201079ea608071d22a57856b940ea3ac53ce] is
# resolved.  That ticket is about an incorrect result that appears when
# an index is added.  The root cause is that a constant is being used
# without initialization when the OR optimization applies in the WHERE clause.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set ::testprefix tkt-80ba2

do_test tkt-80ba2-100 {
  db eval {
    CREATE TABLE t1(a);
    INSERT INTO t1 VALUES('A');
    CREATE TABLE t2(b);
    INSERT INTO t2 VALUES('B');
    CREATE TABLE t3(c);
    INSERT INTO t3 VALUES('C');
    SELECT * FROM t1, t2
     WHERE (a='A' AND b='X')
        OR (a='A' AND EXISTS (SELECT * FROM t3 WHERE c='C'));
  }
} {A B}
do_test tkt-80ba2-101 {
  db eval {
    CREATE INDEX i1 ON t1(a);
    SELECT * FROM t1, t2
     WHERE (a='A' AND b='X')
        OR (a='A' AND EXISTS (SELECT * FROM t3 WHERE c='C'));
  }
} {A B}
do_test tkt-80ba2-102 {
  optimization_control db factor-constants 0
  db cache flush
  db eval {
    SELECT * FROM t1, t2
     WHERE (a='A' AND b='X')
        OR (a='A' AND EXISTS (SELECT * FROM t3 WHERE c='C'));
  }
} {A B}
optimization_control db all 1

# Verify that the optimization_control command is actually working
#
do_test tkt-80ba2-150 {
  optimization_control db factor-constants 1
  db cache flush
  set x1 [db eval {EXPLAIN 
    SELECT * FROM t1, t2
     WHERE (a='A' AND b='X')
        OR (a='A' AND EXISTS (SELECT * FROM t3 WHERE c='C'));}]
  optimization_control db factor-constants 0
  db cache flush
  set x2 [db eval {EXPLAIN 
    SELECT * FROM t1, t2
     WHERE (a='A' AND b='X')
        OR (a='A' AND EXISTS (SELECT * FROM t3 WHERE c='C'));}]

  expr {$x1==$x2}
} {0}

do_test tkt-80ba2-200 {
  db eval {
    CREATE TABLE entry_types (
                        id     integer primary key,
                        name   text
                    );
    INSERT INTO "entry_types" VALUES(100,'cli_command');
    INSERT INTO "entry_types" VALUES(300,'object_change');
    CREATE TABLE object_changes (
                        change_id    integer primary key,
                        system_id    int,
                        obj_id       int,
                        obj_context  text,
                        change_type  int,
                        command_id   int
                    );
    INSERT INTO "object_changes" VALUES(1551,1,114608,'exported_pools',1,2114);
    INSERT INTO "object_changes" VALUES(2048,1,114608,'exported_pools',2,2319);
    CREATE TABLE timeline (
                        rowid        integer primary key,
                        timestamp    text,
                        system_id    int,
                        entry_type   int,
                        entry_id     int
                    );
    INSERT INTO "timeline" VALUES(6735,'2010-11-21 17:08:27.000',1,300,2048);
    INSERT INTO "timeline" VALUES(6825,'2010-11-21 17:09:21.000',1,300,2114);
    SELECT entry_type,
           entry_types.name,
           entry_id
      FROM timeline JOIN entry_types ON entry_type = entry_types.id
     WHERE (entry_types.name = 'cli_command' AND entry_id=2114)
        OR (entry_types.name = 'object_change'
             AND entry_id IN (SELECT change_id
                              FROM object_changes
                               WHERE obj_context = 'exported_pools'));
  }
} {300 object_change 2048}
do_test tkt-80ba2-201 {
  db eval {
    CREATE INDEX timeline_entry_id_idx on timeline(entry_id);
    SELECT entry_type,
           entry_types.name,
           entry_id
      FROM timeline JOIN entry_types ON entry_type = entry_types.id
     WHERE (entry_types.name = 'cli_command' AND entry_id=2114)
        OR (entry_types.name = 'object_change'
             AND entry_id IN (SELECT change_id
                              FROM object_changes
                               WHERE obj_context = 'exported_pools'));
  }
} {300 object_change 2048}
do_test tkt-80ba2-202 {
  optimization_control db factor-constants 0
  db cache flush
  db eval {
    SELECT entry_type,
           entry_types.name,
           entry_id
      FROM timeline JOIN entry_types ON entry_type = entry_types.id
     WHERE (entry_types.name = 'cli_command' AND entry_id=2114)
        OR (entry_types.name = 'object_change'
             AND entry_id IN (SELECT change_id
                              FROM object_changes
                               WHERE obj_context = 'exported_pools'));
  }
} {300 object_change 2048}

#-------------------------------------------------------------------------
#

drop_all_tables
do_execsql_test 301 {
  CREATE TABLE t1(a, b, c);
  CREATE INDEX i1 ON t1(a);
  CREATE INDEX i2 ON t1(b);
  CREATE TABLE t2(d, e);

  INSERT INTO t1 VALUES('A', 'B', 'C');
  INSERT INTO t2 VALUES('D', 'E');
}

do_execsql_test 302 {
  SELECT * FROM t1, t2 WHERE
    (a='A' AND d='E') OR
    (b='B' AND c IN ('C', 'D', 'E'))
} {A B C D E}

do_execsql_test 303 {
  SELECT * FROM t1, t2 WHERE
    (a='A' AND d='E') OR
    (b='B' AND c IN (SELECT c FROM t1))
} {A B C D E}

do_execsql_test 304 {
  SELECT * FROM t1, t2 WHERE
    (a='A' AND d='E') OR
    (b='B' AND c IN (SELECT 'B' UNION SELECT 'C' UNION SELECT 'D'))
} {A B C D E}

do_execsql_test 305 {
  SELECT * FROM t1, t2 WHERE
    (b='B' AND c IN ('C', 'D', 'E')) OR
    (a='A' AND d='E')
} {A B C D E}

do_execsql_test 306 {
  SELECT * FROM t1, t2 WHERE
    (b='B' AND c IN (SELECT c FROM t1)) OR
    (a='A' AND d='E')
} {A B C D E}

do_execsql_test 307 {
  SELECT * FROM t1, t2 WHERE
    (b='B' AND c IN (SELECT 'B' UNION SELECT 'C' UNION SELECT 'D')) OR
    (a='A' AND d='E')
} {A B C D E}

finish_test

Changes to test/triggerC.test.

933
934
935
936
937
938
939












940
941
942
do_test triggerC-12.2 {
  db eval { SELECT * FROM t1 } {
    if {$a == 3} { execsql { DROP TRIGGER tr1 } }
  }
  execsql { SELECT count(*) FROM sqlite_master }
} {1}















finish_test







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



933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
do_test triggerC-12.2 {
  db eval { SELECT * FROM t1 } {
    if {$a == 3} { execsql { DROP TRIGGER tr1 } }
  }
  execsql { SELECT count(*) FROM sqlite_master }
} {1}

do_execsql_test triggerC-13.1 {
  PRAGMA recursive_triggers = ON;
  CREATE TABLE t12(a, b);
  INSERT INTO t12 VALUES(1, 2);
  CREATE TRIGGER tr12 AFTER UPDATE ON t12 BEGIN
    UPDATE t12 SET a=new.a+1, b=new.b+1;
  END;
} {}
do_catchsql_test triggerC-13.2 {
  UPDATE t12 SET a=a+1, b=b+1;
} {1 {too many levels of trigger recursion}}



finish_test

Changes to test/wal2.test.

14
15
16
17
18
19
20


21
22
23
24
25
26
27
....
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
....
1206
1207
1208
1209
1210
1211
1212
1213

1214



1215






























































1216
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/lock_common.tcl
source $testdir/malloc_common.tcl
source $testdir/wal_common.tcl



ifcapable !wal {finish_test ; return }
if { ![wal_is_ok] || [path_is_dos "."]} {
  finish_test 
  return 
}

................................................................................
      set b(1,1) {0 {}}
      do_test wal2-13.$tn.4 {
        catchsql { INSERT INTO t1 DEFAULT VALUES }
      } $b($can_read,$can_write)
    }
    catch { db close }
  }
}

#-------------------------------------------------------------------------
# Test that "PRAGMA checkpoint_fullsync" appears to be working.
#
foreach {tn sql reslist} {
  1 { }                                 {8 0 3 0 5 0}
  2 { PRAGMA checkpoint_fullfsync = 1 } {8 4 3 2 5 2}
................................................................................
    execsql { INSERT INTO t1 VALUES(9, 10) }
    execsql { INSERT INTO t1 VALUES(11, 12) }
    execsql { INSERT INTO t1 VALUES(13, 14) }
    db close
    list $sqlite_sync_count $sqlite_fullsync_count
  } [lrange $reslist 4 5]
}





































































finish_test







>
>







 







|







 








>

>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
....
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
....
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/lock_common.tcl
source $testdir/malloc_common.tcl
source $testdir/wal_common.tcl

set testprefix wal2

ifcapable !wal {finish_test ; return }
if { ![wal_is_ok] || [path_is_dos "."]} {
  finish_test 
  return 
}

................................................................................
      set b(1,1) {0 {}}
      do_test wal2-13.$tn.4 {
        catchsql { INSERT INTO t1 DEFAULT VALUES }
      } $b($can_read,$can_write)
    }
    catch { db close }
  }
} 

#-------------------------------------------------------------------------
# Test that "PRAGMA checkpoint_fullsync" appears to be working.
#
foreach {tn sql reslist} {
  1 { }                                 {8 0 3 0 5 0}
  2 { PRAGMA checkpoint_fullfsync = 1 } {8 4 3 2 5 2}
................................................................................
    execsql { INSERT INTO t1 VALUES(9, 10) }
    execsql { INSERT INTO t1 VALUES(11, 12) }
    execsql { INSERT INTO t1 VALUES(13, 14) }
    db close
    list $sqlite_sync_count $sqlite_fullsync_count
  } [lrange $reslist 4 5]
}

catch { db close }

# PRAGMA checkpoint_fullsync
# PRAGMA fullfsync
# PRAGMA synchronous
#
foreach {tn settings commit_sync ckpt_sync} {
  1  {0 0 off}     {0 0}  {0 0}
  2  {0 0 normal}  {0 0}  {2 0}
  3  {0 0 full}    {1 0}  {2 0}

  4  {0 1 off}     {0 0}  {0 0}
  5  {0 1 normal}  {0 0}  {0 2}
  6  {0 1 full}    {0 1}  {0 2}

  7  {1 0 off}     {0 0}  {0 0}
  8  {1 0 normal}  {0 0}  {0 2}
  9  {1 0 full}    {1 0}  {0 2}

  10 {1 1 off}     {0 0}  {0 0}
  11 {1 1 normal}  {0 0}  {0 2}
  12 {1 1 full}    {0 1}  {0 2}
} {
  forcedelete test.db

  testvfs tvfs -default 1
  tvfs filter xSync
  tvfs script xSyncCb
  proc xSyncCb {method file fileid flags} {
    incr ::sync($flags)
  }

  sqlite3 db test.db
  do_execsql_test 15.$tn.1 "
    CREATE TABLE t1(x);
    PRAGMA journal_mode = WAL;
    PRAGMA checkpoint_fullfsync = [lindex $settings 0];
    PRAGMA fullfsync = [lindex $settings 1];
    PRAGMA synchronous = [lindex $settings 2];
  " {wal}

  do_test 15.$tn.2 {
    set sync(normal) 0
    set sync(full) 0
    execsql { INSERT INTO t1 VALUES('abc') }
    list $::sync(normal) $::sync(full)
  } $commit_sync

  do_test 15.$tn.3 {
    set sync(normal) 0
    set sync(full) 0
    execsql { INSERT INTO t1 VALUES('def') }
    list $::sync(normal) $::sync(full)
  } $commit_sync

  do_test 15.$tn.4 {
    set sync(normal) 0
    set sync(full) 0
    execsql { PRAGMA wal_checkpoint }
    list $::sync(normal) $::sync(full)
  } $ckpt_sync
  
  db close
  tvfs delete
}



finish_test

Changes to test/wal3.test.

703
704
705
706
707
708
709


710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
# transaction.
#
# This test case verifies that if an exclusive lock cannot be obtained
# on any aReadMark[] slot (because there are already several readers),
# the client takes a shared-lock on a slot without modifying the value
# and continues.
#


do_test wal3-9.0 {
  file delete -force test.db test.db-journal test.db wal
  sqlite3 db test.db
  execsql {
    PRAGMA page_size = 1024;
    PRAGMA journal_mode = WAL;
    CREATE TABLE whoami(x);
    INSERT INTO whoami VALUES('nobody');
  }
} {wal}
for {set i 0} {$i < 50} {incr i} {
  set c db$i
  do_test wal3-9.1.$i {
    sqlite3 $c test.db
    execsql { UPDATE whoami SET x = $c }
    execsql {
      BEGIN;
      SELECT * FROM whoami
    } $c
  } $c
}
for {set i 0} {$i < 50} {incr i} {
  set c db$i
  do_test wal3-9.2.$i {
    execsql { SELECT * FROM whoami } $c
  } $c
}

set sz [expr 1024 * (2+$AUTOVACUUM)]
do_test wal3-9.3 {
  for {set i 0} {$i < 49} {incr i} { db$i close }
  execsql { PRAGMA wal_checkpoint } 
  byte_is_zero test.db [expr $sz-1024]
} {1}
do_test wal3-9.4 {
  db49 close
  execsql { PRAGMA wal_checkpoint } 
  set sz2 [file size test.db]
  byte_is_zero test.db [expr $sz-1024]
} {0}

do_multiclient_test tn {
  do_test wal3-10.$tn.1 {







>
>










|










|








|




|







703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
# transaction.
#
# This test case verifies that if an exclusive lock cannot be obtained
# on any aReadMark[] slot (because there are already several readers),
# the client takes a shared-lock on a slot without modifying the value
# and continues.
#
set nConn 50
if { [string match *BSD $tcl_platform(os)] } { set nConn 35 }
do_test wal3-9.0 {
  file delete -force test.db test.db-journal test.db wal
  sqlite3 db test.db
  execsql {
    PRAGMA page_size = 1024;
    PRAGMA journal_mode = WAL;
    CREATE TABLE whoami(x);
    INSERT INTO whoami VALUES('nobody');
  }
} {wal}
for {set i 0} {$i < $nConn} {incr i} {
  set c db$i
  do_test wal3-9.1.$i {
    sqlite3 $c test.db
    execsql { UPDATE whoami SET x = $c }
    execsql {
      BEGIN;
      SELECT * FROM whoami
    } $c
  } $c
}
for {set i 0} {$i < $nConn} {incr i} {
  set c db$i
  do_test wal3-9.2.$i {
    execsql { SELECT * FROM whoami } $c
  } $c
}

set sz [expr 1024 * (2+$AUTOVACUUM)]
do_test wal3-9.3 {
  for {set i 0} {$i < ($nConn-1)} {incr i} { db$i close }
  execsql { PRAGMA wal_checkpoint } 
  byte_is_zero test.db [expr $sz-1024]
} {1}
do_test wal3-9.4 {
  db[expr $nConn-1] close
  execsql { PRAGMA wal_checkpoint } 
  set sz2 [file size test.db]
  byte_is_zero test.db [expr $sz-1024]
} {0}

do_multiclient_test tn {
  do_test wal3-10.$tn.1 {

Added test/wal6.test.





















































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# 2010 December 1
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing the operation of the library in
# "PRAGMA journal_mode=WAL" mode.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/lock_common.tcl
source $testdir/wal_common.tcl
source $testdir/malloc_common.tcl
ifcapable !wal {finish_test ; return }

#-------------------------------------------------------------------------
# Changing to WAL mode in one connection forces the change in others.
#
db close
forcedelete test.db

set all_journal_modes {delete persist truncate memory off}
foreach jmode $all_journal_modes {

	do_test wal6-1.0.$jmode {
    sqlite3 db test.db
    execsql "PRAGMA journal_mode = $jmode;"
	} $jmode

	do_test wal6-1.1.$jmode {
	  execsql {
	    CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
	    INSERT INTO t1 VALUES(1,2);
	    SELECT * FROM t1;
	  }
	} {1 2}

# Under Windows, you'll get an error trying to delete
# a file this is already opened.  For now, make sure 
# we get that error, then close the first connection
# so the other tests work.
if {$tcl_platform(platform)=="windows"} {
  if {$jmode=="persist" || $jmode=="truncate"} {
	  do_test wal6-1.2.$jmode.win {
	    sqlite3 db2 test.db
	    catchsql {
		    PRAGMA journal_mode=WAL;
	    } db2
	  } {1 {disk I/O error}}
  	db2 close
	  db close
  }
}

	do_test wal6-1.2.$jmode {
	  sqlite3 db2 test.db
	  execsql {
		PRAGMA journal_mode=WAL;
		INSERT INTO t1 VALUES(3,4);
		SELECT * FROM t1 ORDER BY a;
	  } db2
	} {wal 1 2 3 4}

if {$tcl_platform(platform)=="windows"} {
  if {$jmode=="persist" || $jmode=="truncate"} {
	  sqlite3 db test.db
  }
}

	do_test wal6-1.3.$jmode {
	  execsql {
		  SELECT * FROM t1 ORDER BY a;
	  }
	} {1 2 3 4}

	db close
	db2 close
  forcedelete test.db

}

finish_test

Changes to tool/lemon.c.

16
17
18
19
20
21
22



23



24
25
26
27
28
29
30
....
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
#ifndef __WIN32__
#   if defined(_WIN32) || defined(WIN32)
#	define __WIN32__
#   endif
#endif

#ifdef __WIN32__



extern int access();



#else
#include <unistd.h>
#endif

/* #define PRIVATE static */
#define PRIVATE

................................................................................
  if( n<=0 ){
    if( n<0 ){
      used += n;
      assert( used>=0 );
    }
    n = lemonStrlen(zText);
  }
  if( n+sizeof(zInt)*2+used >= alloced ){
    alloced = n + sizeof(zInt)*2 + used + 200;
    z = (char *) realloc(z,  alloced);
  }
  if( z==0 ) return empty;
  while( n-- > 0 ){
    c = *(zText++);
    if( c=='%' && n>0 && zText[0]=='d' ){







>
>
>
|
>
>
>







 







|







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
....
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
#ifndef __WIN32__
#   if defined(_WIN32) || defined(WIN32)
#	define __WIN32__
#   endif
#endif

#ifdef __WIN32__
#ifdef __cplusplus
extern "C" {
#endif
extern int access(const char *path, int mode);
#ifdef __cplusplus
}
#endif
#else
#include <unistd.h>
#endif

/* #define PRIVATE static */
#define PRIVATE

................................................................................
  if( n<=0 ){
    if( n<0 ){
      used += n;
      assert( used>=0 );
    }
    n = lemonStrlen(zText);
  }
  if( (int) (n+sizeof(zInt)*2+used) >= alloced ){
    alloced = n + sizeof(zInt)*2 + used + 200;
    z = (char *) realloc(z,  alloced);
  }
  if( z==0 ) return empty;
  while( n-- > 0 ){
    c = *(zText++);
    if( c=='%' && n>0 && zText[0]=='d' ){