Fossil SCM

Merged/resolved trunk [4092208afca3ff]. Accommodated changes in text_diff() signature.

stephan 2011-10-22 16:00 json-multitag-test merge
Commit acc253f44cfb783ad6dcf311da78fb51716f59b4
+266 -10
--- src/diff.c
+++ src/diff.c
@@ -21,10 +21,22 @@
2121
#include "config.h"
2222
#include "diff.h"
2323
#include <assert.h>
2424
2525
26
+#if INTERFACE
27
+/*
28
+** Allowed flag parameters to the text_diff() and html_sbsdiff() funtions:
29
+*/
30
+#define DIFF_CONTEXT_MASK 0x0000fff /* Lines of context. Default if 0 */
31
+#define DIFF_WIDTH_MASK 0x00ff000 /* side-by-side column width */
32
+#define DIFF_IGNORE_EOLWS 0x0100000 /* Ignore end-of-line whitespace */
33
+#define DIFF_SIDEBYSIDE 0x0200000 /* Generate a side-by-side diff */
34
+#define DIFF_NEWFILE 0x0400000 /* Missing files are as empty files */
35
+
36
+#endif /* INTERFACE */
37
+
2638
/*
2739
** Maximum length of a line in a text file. (8192)
2840
*/
2941
#define LENGTH_MASK_SZ 13
3042
#define LENGTH_MASK ((1<<LENGTH_MASK_SZ)-1)
@@ -285,10 +297,196 @@
285297
for(j=0; j<m; j++){
286298
appendDiffLine(pOut, " ", &B[b+j]);
287299
}
288300
}
289301
}
302
+
303
+/*
304
+** Write a 6-digit line number into the buffer z[]. z[] is guaranteed to
305
+** have space for at least 7 characters.
306
+*/
307
+static void sbsWriteLineno(char *z, int ln){
308
+ sqlite3_snprintf(7, z, "%6d", ln+1);
309
+ z[6] = ' ';
310
+}
311
+
312
+/*
313
+** Write up to width characters of pLine into z[]. Translate tabs into
314
+** spaces. If trunc is true, then append \n\000 after the last character
315
+** written.
316
+*/
317
+static int sbsWriteText(char *z, DLine *pLine, int width, int trunc){
318
+ int n = pLine->h & LENGTH_MASK;
319
+ int i, j;
320
+ const char *zIn = pLine->z;
321
+ for(i=j=0; i<n && j<width; i++){
322
+ char c = zIn[i];
323
+ if( c=='\t' ){
324
+ z[j++] = ' ';
325
+ while( (j&7)!=0 && j<width ) z[j++] = ' ';
326
+ }else if( c=='\r' || c=='\f' ){
327
+ z[j++] = ' ';
328
+ }else{
329
+ z[j++] = c;
330
+ }
331
+ }
332
+ if( trunc ){
333
+ z[j++] = '\n';
334
+ z[j] = 0;
335
+ }
336
+ return j;
337
+}
338
+
339
+
340
+/*
341
+** Given a diff context in which the aEdit[] array has been filled
342
+** in, compute a side-by-side diff into pOut.
343
+*/
344
+static void sbsDiff(DContext *p, Blob *pOut, int nContext, int width){
345
+ DLine *A; /* Left side of the diff */
346
+ DLine *B; /* Right side of the diff */
347
+ int a = 0; /* Index of next line in A[] */
348
+ int b = 0; /* Index of next line in B[] */
349
+ int *R; /* Array of COPY/DELETE/INSERT triples */
350
+ int r; /* Index into R[] */
351
+ int nr; /* Number of COPY/DELETE/INSERT triples to process */
352
+ int mxr; /* Maximum value for r */
353
+ int na, nb; /* Number of lines shown from A and B */
354
+ int i, j; /* Loop counters */
355
+ int m, ma, mb;/* Number of lines to output */
356
+ int skip; /* Number of lines to skip */
357
+ int mxLine; /* Length of a line of text */
358
+ char *zLine; /* A line of text being formatted */
359
+ int len; /* Length of an output line */
360
+
361
+ mxLine = width*2 + 2*7 + 3 + 1;
362
+ zLine = fossil_malloc( mxLine + 1 );
363
+ if( zLine==0 ) return;
364
+ zLine[mxLine] = 0;
365
+ A = p->aFrom;
366
+ B = p->aTo;
367
+ R = p->aEdit;
368
+ mxr = p->nEdit;
369
+ while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
370
+ for(r=0; r<mxr; r += 3*nr){
371
+ /* Figure out how many triples to show in a single block */
372
+ for(nr=1; R[r+nr*3]>0 && R[r+nr*3]<nContext*2; nr++){}
373
+ /* printf("r=%d nr=%d\n", r, nr); */
374
+
375
+ /* For the current block comprising nr triples, figure out
376
+ ** how many lines of A and B are to be displayed
377
+ */
378
+ if( R[r]>nContext ){
379
+ na = nb = nContext;
380
+ skip = R[r] - nContext;
381
+ }else{
382
+ na = nb = R[r];
383
+ skip = 0;
384
+ }
385
+ for(i=0; i<nr; i++){
386
+ na += R[r+i*3+1];
387
+ nb += R[r+i*3+2];
388
+ }
389
+ if( R[r+nr*3]>nContext ){
390
+ na += nContext;
391
+ nb += nContext;
392
+ }else{
393
+ na += R[r+nr*3];
394
+ nb += R[r+nr*3];
395
+ }
396
+ for(i=1; i<nr; i++){
397
+ na += R[r+i*3];
398
+ nb += R[r+i*3];
399
+ }
400
+ /*
401
+ * If the patch changes an empty file or results in an empty file,
402
+ * the block header must use 0,0 as position indicator and not 1,0.
403
+ * Otherwise, patch would be confused and may reject the diff.
404
+ */
405
+ if( r>0 ) blob_appendf(pOut,"%.*c\n", width*2+16, '.');
406
+
407
+ /* Show the initial common area */
408
+ a += skip;
409
+ b += skip;
410
+ m = R[r] - skip;
411
+ for(j=0; j<m; j++){
412
+ memset(zLine, ' ', mxLine);
413
+ sbsWriteLineno(zLine, a+j);
414
+ sbsWriteText(&zLine[7], &A[a+j], width, 0);
415
+ sbsWriteLineno(&zLine[width+10], b+j);
416
+ len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
417
+ blob_append(pOut, zLine, len+width+17);
418
+ }
419
+ a += m;
420
+ b += m;
421
+
422
+ /* Show the differences */
423
+ for(i=0; i<nr; i++){
424
+ ma = R[r+i*3+1];
425
+ mb = R[r+i*3+2];
426
+ m = ma<mb ? ma : mb;
427
+ for(j=0; j<m; j++){
428
+ memset(zLine, ' ', mxLine);
429
+ sbsWriteLineno(zLine, a+j);
430
+ sbsWriteText(&zLine[7], &A[a+j], width, 0);
431
+ zLine[width+8] = '|';
432
+ sbsWriteLineno(&zLine[width+10], b+j);
433
+ len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
434
+ blob_append(pOut, zLine, len+width+17);
435
+ }
436
+ a += m;
437
+ b += m;
438
+ ma -= m;
439
+ mb -= m;
440
+ for(j=0; j<ma; j++){
441
+ memset(zLine, ' ', width+7);
442
+ sbsWriteLineno(zLine, a+j);
443
+ sbsWriteText(&zLine[7], &A[a+j], width, 0);
444
+ zLine[width+8] = '<';
445
+ zLine[width+9] = '\n';
446
+ zLine[width+10] = 0;
447
+ blob_append(pOut, zLine, width+10);
448
+ }
449
+ a += ma;
450
+ for(j=0; j<mb; j++){
451
+ memset(zLine, ' ', mxLine);
452
+ zLine[width+8] = '>';
453
+ sbsWriteLineno(&zLine[width+10], b+j);
454
+ len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
455
+ blob_append(pOut, zLine, len+width+17);
456
+ }
457
+ b += mb;
458
+ if( i<nr-1 ){
459
+ m = R[r+i*3+3];
460
+ for(j=0; j<m; j++){
461
+ memset(zLine, ' ', mxLine);
462
+ sbsWriteLineno(zLine, a+j);
463
+ sbsWriteText(&zLine[7], &A[a+j], width, 0);
464
+ sbsWriteLineno(&zLine[width+10], b+j);
465
+ len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
466
+ blob_append(pOut, zLine, len+width+17);
467
+ }
468
+ b += m;
469
+ a += m;
470
+ }
471
+ }
472
+
473
+ /* Show the final common area */
474
+ assert( nr==i );
475
+ m = R[r+nr*3];
476
+ if( m>nContext ) m = nContext;
477
+ for(j=0; j<m; j++){
478
+ memset(zLine, ' ', mxLine);
479
+ sbsWriteLineno(zLine, a+j);
480
+ sbsWriteText(&zLine[7], &A[a+j], width, 0);
481
+ sbsWriteLineno(&zLine[width+10], b+j);
482
+ len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
483
+ blob_append(pOut, zLine, len+width+17);
484
+ }
485
+ }
486
+ free(zLine);
487
+}
290488
291489
/*
292490
** Compute the optimal longest common subsequence (LCS) using an
293491
** exhaustive search. This version of the LCS is only used for
294492
** shorter input strings since runtime is O(N*N) where N is the
@@ -520,10 +718,30 @@
520718
p->aEdit[p->nEdit++] = 0;
521719
p->aEdit[p->nEdit++] = 0;
522720
p->aEdit[p->nEdit++] = 0;
523721
}
524722
}
723
+
724
+/*
725
+** Extract the number of lines of context from diffFlags. Supply an
726
+** appropriate default if no context width is specified.
727
+*/
728
+int diff_context_lines(int diffFlags){
729
+ int n = diffFlags & DIFF_CONTEXT_MASK;
730
+ if( n==0 ) n = 5;
731
+ return n;
732
+}
733
+
734
+/*
735
+** Extract the width of columns for side-by-side diff. Supply an
736
+** appropriate default if no width is given.
737
+*/
738
+int diff_width(int diffFlags){
739
+ int w = (diffFlags & DIFF_WIDTH_MASK)/(DIFF_CONTEXT_MASK+1);
740
+ if( w==0 ) w = 80;
741
+ return w;
742
+}
525743
526744
/*
527745
** Generate a report of the differences between files pA and pB.
528746
** If pOut is not NULL then a unified diff is appended there. It
529747
** is assumed that pOut has already been initialized. If pOut is
@@ -538,16 +756,20 @@
538756
** text "cannot compute difference between binary files".
539757
*/
540758
int *text_diff(
541759
Blob *pA_Blob, /* FROM file */
542760
Blob *pB_Blob, /* TO file */
543
- Blob *pOut, /* Write unified diff here if not NULL */
544
- int nContext, /* Amount of context to unified diff */
545
- int ignoreEolWs /* Ignore whitespace at the end of lines */
761
+ Blob *pOut, /* Write diff here if not NULL */
762
+ int diffFlags /* DIFF_* flags defined above */
546763
){
764
+ int ignoreEolWs; /* Ignore whitespace at the end of lines */
765
+ int nContext; /* Amount of context to display */
547766
DContext c;
548
-
767
+
768
+ nContext = diff_context_lines(diffFlags);
769
+ ignoreEolWs = (diffFlags & DIFF_IGNORE_EOLWS)!=0;
770
+
549771
/* Prepare the input files */
550772
memset(&c, 0, sizeof(c));
551773
c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob),
552774
&c.nFrom, ignoreEolWs);
553775
c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob),
@@ -563,12 +785,17 @@
563785
564786
/* Compute the difference */
565787
diff_all(&c);
566788
567789
if( pOut ){
568
- /* Compute a context diff if requested */
569
- contextDiff(&c, pOut, nContext);
790
+ /* Compute a context or side-by-side diff into pOut */
791
+ if( diffFlags & DIFF_SIDEBYSIDE ){
792
+ int width = diff_width(diffFlags);
793
+ sbsDiff(&c, pOut, nContext, width);
794
+ }else{
795
+ contextDiff(&c, pOut, nContext);
796
+ }
570797
free(c.aFrom);
571798
free(c.aTo);
572799
free(c.aEdit);
573800
return 0;
574801
}else{
@@ -588,11 +815,11 @@
588815
static char *copylimline(char *out, DLine *dl, int lim){
589816
int len;
590817
len = dl->h & LENGTH_MASK;
591818
if( lim && len > lim ){
592819
memcpy(out, dl->z, lim-3);
593
- strcpy(&out[lim-3], "...");
820
+ memcpy(&out[lim-3], "...", 4);
594821
}else{
595822
memcpy(out, dl->z, len);
596823
out[len] = '\0';
597824
}
598825
return out;
@@ -660,11 +887,11 @@
660887
while( i<c.nEdit ){
661888
int j;
662889
/* Copied lines */
663890
for( j=0; j<c.aEdit[i]; j++){
664891
/* Hide lines which are copied and are further away from block boundaries
665
- ** than nConext lines. For each block with hidden lines, show a row
892
+ ** than nContext lines. For each block with hidden lines, show a row
666893
** notifying the user about the hidden rows.
667894
*/
668895
if( j<nContext || j>c.aEdit[i]-nContext-1 ){
669896
@ <tr>
670897
}else if( j==nContext && j<c.aEdit[i]-nContext-1 ){
@@ -776,29 +1003,58 @@
7761003
if( g.argc<4 ) usage("FILE1 FILE2 ...");
7771004
blob_read_from_file(&a, g.argv[2]);
7781005
for(i=3; i<g.argc; i++){
7791006
if( i>3 ) fossil_print("-------------------------------\n");
7801007
blob_read_from_file(&b, g.argv[i]);
781
- R = text_diff(&a, &b, 0, 0, 0);
1008
+ R = text_diff(&a, &b, 0, 0);
7821009
for(r=0; R[r] || R[r+1] || R[r+2]; r += 3){
7831010
fossil_print(" copy %4d delete %4d insert %4d\n", R[r], R[r+1], R[r+2]);
7841011
}
7851012
/* free(R); */
7861013
blob_reset(&b);
7871014
}
7881015
}
1016
+
1017
+/*
1018
+** Process diff-related command-line options and return an appropriate
1019
+** "diffFlags" integer.
1020
+**
1021
+** --side-by-side|-y Side-by-side diff. DIFF_SIDEBYSIDE
1022
+** --context|-c N N lines of context. DIFF_CONTEXT_MASK
1023
+** --width|-W N N character lines. DIFF_WIDTH_MASK
1024
+*/
1025
+int diff_options(void){
1026
+ int diffFlags = 0;
1027
+ const char *z;
1028
+ int f;
1029
+ if( find_option("side-by-side","y",0)!=0 ) diffFlags |= DIFF_SIDEBYSIDE;
1030
+ if( (z = find_option("context","c",1))!=0 && (f = atoi(z))>0 ){
1031
+ if( f > DIFF_CONTEXT_MASK ) f = DIFF_CONTEXT_MASK;
1032
+ diffFlags |= f;
1033
+ }
1034
+ if( (z = find_option("width","W",1))!=0 && (f = atoi(z))>0 ){
1035
+ f *= DIFF_CONTEXT_MASK+1;
1036
+ if( f > DIFF_WIDTH_MASK ) f = DIFF_CONTEXT_MASK;
1037
+ diffFlags |= f;
1038
+ }
1039
+ return diffFlags;
1040
+}
7891041
7901042
/*
7911043
** COMMAND: test-udiff
1044
+**
1045
+** Print the difference between two files. The usual diff options apply.
7921046
*/
7931047
void test_udiff_cmd(void){
7941048
Blob a, b, out;
1049
+ int diffFlag = diff_options();
1050
+
7951051
if( g.argc!=4 ) usage("FILE1 FILE2");
7961052
blob_read_from_file(&a, g.argv[2]);
7971053
blob_read_from_file(&b, g.argv[3]);
7981054
blob_zero(&out);
799
- text_diff(&a, &b, &out, 3, 0);
1055
+ text_diff(&a, &b, &out, diffFlag);
8001056
blob_write_to_file(&out, "-");
8011057
}
8021058
8031059
/**************************************************************************
8041060
** The basic difference engine is above. What follows is the annotation
8051061
--- src/diff.c
+++ src/diff.c
@@ -21,10 +21,22 @@
21 #include "config.h"
22 #include "diff.h"
23 #include <assert.h>
24
25
 
 
 
 
 
 
 
 
 
 
 
 
26 /*
27 ** Maximum length of a line in a text file. (8192)
28 */
29 #define LENGTH_MASK_SZ 13
30 #define LENGTH_MASK ((1<<LENGTH_MASK_SZ)-1)
@@ -285,10 +297,196 @@
285 for(j=0; j<m; j++){
286 appendDiffLine(pOut, " ", &B[b+j]);
287 }
288 }
289 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
290
291 /*
292 ** Compute the optimal longest common subsequence (LCS) using an
293 ** exhaustive search. This version of the LCS is only used for
294 ** shorter input strings since runtime is O(N*N) where N is the
@@ -520,10 +718,30 @@
520 p->aEdit[p->nEdit++] = 0;
521 p->aEdit[p->nEdit++] = 0;
522 p->aEdit[p->nEdit++] = 0;
523 }
524 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
525
526 /*
527 ** Generate a report of the differences between files pA and pB.
528 ** If pOut is not NULL then a unified diff is appended there. It
529 ** is assumed that pOut has already been initialized. If pOut is
@@ -538,16 +756,20 @@
538 ** text "cannot compute difference between binary files".
539 */
540 int *text_diff(
541 Blob *pA_Blob, /* FROM file */
542 Blob *pB_Blob, /* TO file */
543 Blob *pOut, /* Write unified diff here if not NULL */
544 int nContext, /* Amount of context to unified diff */
545 int ignoreEolWs /* Ignore whitespace at the end of lines */
546 ){
 
 
547 DContext c;
548
 
 
 
549 /* Prepare the input files */
550 memset(&c, 0, sizeof(c));
551 c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob),
552 &c.nFrom, ignoreEolWs);
553 c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob),
@@ -563,12 +785,17 @@
563
564 /* Compute the difference */
565 diff_all(&c);
566
567 if( pOut ){
568 /* Compute a context diff if requested */
569 contextDiff(&c, pOut, nContext);
 
 
 
 
 
570 free(c.aFrom);
571 free(c.aTo);
572 free(c.aEdit);
573 return 0;
574 }else{
@@ -588,11 +815,11 @@
588 static char *copylimline(char *out, DLine *dl, int lim){
589 int len;
590 len = dl->h & LENGTH_MASK;
591 if( lim && len > lim ){
592 memcpy(out, dl->z, lim-3);
593 strcpy(&out[lim-3], "...");
594 }else{
595 memcpy(out, dl->z, len);
596 out[len] = '\0';
597 }
598 return out;
@@ -660,11 +887,11 @@
660 while( i<c.nEdit ){
661 int j;
662 /* Copied lines */
663 for( j=0; j<c.aEdit[i]; j++){
664 /* Hide lines which are copied and are further away from block boundaries
665 ** than nConext lines. For each block with hidden lines, show a row
666 ** notifying the user about the hidden rows.
667 */
668 if( j<nContext || j>c.aEdit[i]-nContext-1 ){
669 @ <tr>
670 }else if( j==nContext && j<c.aEdit[i]-nContext-1 ){
@@ -776,29 +1003,58 @@
776 if( g.argc<4 ) usage("FILE1 FILE2 ...");
777 blob_read_from_file(&a, g.argv[2]);
778 for(i=3; i<g.argc; i++){
779 if( i>3 ) fossil_print("-------------------------------\n");
780 blob_read_from_file(&b, g.argv[i]);
781 R = text_diff(&a, &b, 0, 0, 0);
782 for(r=0; R[r] || R[r+1] || R[r+2]; r += 3){
783 fossil_print(" copy %4d delete %4d insert %4d\n", R[r], R[r+1], R[r+2]);
784 }
785 /* free(R); */
786 blob_reset(&b);
787 }
788 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
789
790 /*
791 ** COMMAND: test-udiff
 
 
792 */
793 void test_udiff_cmd(void){
794 Blob a, b, out;
 
 
795 if( g.argc!=4 ) usage("FILE1 FILE2");
796 blob_read_from_file(&a, g.argv[2]);
797 blob_read_from_file(&b, g.argv[3]);
798 blob_zero(&out);
799 text_diff(&a, &b, &out, 3, 0);
800 blob_write_to_file(&out, "-");
801 }
802
803 /**************************************************************************
804 ** The basic difference engine is above. What follows is the annotation
805
--- src/diff.c
+++ src/diff.c
@@ -21,10 +21,22 @@
21 #include "config.h"
22 #include "diff.h"
23 #include <assert.h>
24
25
26 #if INTERFACE
27 /*
28 ** Allowed flag parameters to the text_diff() and html_sbsdiff() funtions:
29 */
30 #define DIFF_CONTEXT_MASK 0x0000fff /* Lines of context. Default if 0 */
31 #define DIFF_WIDTH_MASK 0x00ff000 /* side-by-side column width */
32 #define DIFF_IGNORE_EOLWS 0x0100000 /* Ignore end-of-line whitespace */
33 #define DIFF_SIDEBYSIDE 0x0200000 /* Generate a side-by-side diff */
34 #define DIFF_NEWFILE 0x0400000 /* Missing files are as empty files */
35
36 #endif /* INTERFACE */
37
38 /*
39 ** Maximum length of a line in a text file. (8192)
40 */
41 #define LENGTH_MASK_SZ 13
42 #define LENGTH_MASK ((1<<LENGTH_MASK_SZ)-1)
@@ -285,10 +297,196 @@
297 for(j=0; j<m; j++){
298 appendDiffLine(pOut, " ", &B[b+j]);
299 }
300 }
301 }
302
303 /*
304 ** Write a 6-digit line number into the buffer z[]. z[] is guaranteed to
305 ** have space for at least 7 characters.
306 */
307 static void sbsWriteLineno(char *z, int ln){
308 sqlite3_snprintf(7, z, "%6d", ln+1);
309 z[6] = ' ';
310 }
311
312 /*
313 ** Write up to width characters of pLine into z[]. Translate tabs into
314 ** spaces. If trunc is true, then append \n\000 after the last character
315 ** written.
316 */
317 static int sbsWriteText(char *z, DLine *pLine, int width, int trunc){
318 int n = pLine->h & LENGTH_MASK;
319 int i, j;
320 const char *zIn = pLine->z;
321 for(i=j=0; i<n && j<width; i++){
322 char c = zIn[i];
323 if( c=='\t' ){
324 z[j++] = ' ';
325 while( (j&7)!=0 && j<width ) z[j++] = ' ';
326 }else if( c=='\r' || c=='\f' ){
327 z[j++] = ' ';
328 }else{
329 z[j++] = c;
330 }
331 }
332 if( trunc ){
333 z[j++] = '\n';
334 z[j] = 0;
335 }
336 return j;
337 }
338
339
340 /*
341 ** Given a diff context in which the aEdit[] array has been filled
342 ** in, compute a side-by-side diff into pOut.
343 */
344 static void sbsDiff(DContext *p, Blob *pOut, int nContext, int width){
345 DLine *A; /* Left side of the diff */
346 DLine *B; /* Right side of the diff */
347 int a = 0; /* Index of next line in A[] */
348 int b = 0; /* Index of next line in B[] */
349 int *R; /* Array of COPY/DELETE/INSERT triples */
350 int r; /* Index into R[] */
351 int nr; /* Number of COPY/DELETE/INSERT triples to process */
352 int mxr; /* Maximum value for r */
353 int na, nb; /* Number of lines shown from A and B */
354 int i, j; /* Loop counters */
355 int m, ma, mb;/* Number of lines to output */
356 int skip; /* Number of lines to skip */
357 int mxLine; /* Length of a line of text */
358 char *zLine; /* A line of text being formatted */
359 int len; /* Length of an output line */
360
361 mxLine = width*2 + 2*7 + 3 + 1;
362 zLine = fossil_malloc( mxLine + 1 );
363 if( zLine==0 ) return;
364 zLine[mxLine] = 0;
365 A = p->aFrom;
366 B = p->aTo;
367 R = p->aEdit;
368 mxr = p->nEdit;
369 while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
370 for(r=0; r<mxr; r += 3*nr){
371 /* Figure out how many triples to show in a single block */
372 for(nr=1; R[r+nr*3]>0 && R[r+nr*3]<nContext*2; nr++){}
373 /* printf("r=%d nr=%d\n", r, nr); */
374
375 /* For the current block comprising nr triples, figure out
376 ** how many lines of A and B are to be displayed
377 */
378 if( R[r]>nContext ){
379 na = nb = nContext;
380 skip = R[r] - nContext;
381 }else{
382 na = nb = R[r];
383 skip = 0;
384 }
385 for(i=0; i<nr; i++){
386 na += R[r+i*3+1];
387 nb += R[r+i*3+2];
388 }
389 if( R[r+nr*3]>nContext ){
390 na += nContext;
391 nb += nContext;
392 }else{
393 na += R[r+nr*3];
394 nb += R[r+nr*3];
395 }
396 for(i=1; i<nr; i++){
397 na += R[r+i*3];
398 nb += R[r+i*3];
399 }
400 /*
401 * If the patch changes an empty file or results in an empty file,
402 * the block header must use 0,0 as position indicator and not 1,0.
403 * Otherwise, patch would be confused and may reject the diff.
404 */
405 if( r>0 ) blob_appendf(pOut,"%.*c\n", width*2+16, '.');
406
407 /* Show the initial common area */
408 a += skip;
409 b += skip;
410 m = R[r] - skip;
411 for(j=0; j<m; j++){
412 memset(zLine, ' ', mxLine);
413 sbsWriteLineno(zLine, a+j);
414 sbsWriteText(&zLine[7], &A[a+j], width, 0);
415 sbsWriteLineno(&zLine[width+10], b+j);
416 len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
417 blob_append(pOut, zLine, len+width+17);
418 }
419 a += m;
420 b += m;
421
422 /* Show the differences */
423 for(i=0; i<nr; i++){
424 ma = R[r+i*3+1];
425 mb = R[r+i*3+2];
426 m = ma<mb ? ma : mb;
427 for(j=0; j<m; j++){
428 memset(zLine, ' ', mxLine);
429 sbsWriteLineno(zLine, a+j);
430 sbsWriteText(&zLine[7], &A[a+j], width, 0);
431 zLine[width+8] = '|';
432 sbsWriteLineno(&zLine[width+10], b+j);
433 len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
434 blob_append(pOut, zLine, len+width+17);
435 }
436 a += m;
437 b += m;
438 ma -= m;
439 mb -= m;
440 for(j=0; j<ma; j++){
441 memset(zLine, ' ', width+7);
442 sbsWriteLineno(zLine, a+j);
443 sbsWriteText(&zLine[7], &A[a+j], width, 0);
444 zLine[width+8] = '<';
445 zLine[width+9] = '\n';
446 zLine[width+10] = 0;
447 blob_append(pOut, zLine, width+10);
448 }
449 a += ma;
450 for(j=0; j<mb; j++){
451 memset(zLine, ' ', mxLine);
452 zLine[width+8] = '>';
453 sbsWriteLineno(&zLine[width+10], b+j);
454 len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
455 blob_append(pOut, zLine, len+width+17);
456 }
457 b += mb;
458 if( i<nr-1 ){
459 m = R[r+i*3+3];
460 for(j=0; j<m; j++){
461 memset(zLine, ' ', mxLine);
462 sbsWriteLineno(zLine, a+j);
463 sbsWriteText(&zLine[7], &A[a+j], width, 0);
464 sbsWriteLineno(&zLine[width+10], b+j);
465 len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
466 blob_append(pOut, zLine, len+width+17);
467 }
468 b += m;
469 a += m;
470 }
471 }
472
473 /* Show the final common area */
474 assert( nr==i );
475 m = R[r+nr*3];
476 if( m>nContext ) m = nContext;
477 for(j=0; j<m; j++){
478 memset(zLine, ' ', mxLine);
479 sbsWriteLineno(zLine, a+j);
480 sbsWriteText(&zLine[7], &A[a+j], width, 0);
481 sbsWriteLineno(&zLine[width+10], b+j);
482 len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
483 blob_append(pOut, zLine, len+width+17);
484 }
485 }
486 free(zLine);
487 }
488
489 /*
490 ** Compute the optimal longest common subsequence (LCS) using an
491 ** exhaustive search. This version of the LCS is only used for
492 ** shorter input strings since runtime is O(N*N) where N is the
@@ -520,10 +718,30 @@
718 p->aEdit[p->nEdit++] = 0;
719 p->aEdit[p->nEdit++] = 0;
720 p->aEdit[p->nEdit++] = 0;
721 }
722 }
723
724 /*
725 ** Extract the number of lines of context from diffFlags. Supply an
726 ** appropriate default if no context width is specified.
727 */
728 int diff_context_lines(int diffFlags){
729 int n = diffFlags & DIFF_CONTEXT_MASK;
730 if( n==0 ) n = 5;
731 return n;
732 }
733
734 /*
735 ** Extract the width of columns for side-by-side diff. Supply an
736 ** appropriate default if no width is given.
737 */
738 int diff_width(int diffFlags){
739 int w = (diffFlags & DIFF_WIDTH_MASK)/(DIFF_CONTEXT_MASK+1);
740 if( w==0 ) w = 80;
741 return w;
742 }
743
744 /*
745 ** Generate a report of the differences between files pA and pB.
746 ** If pOut is not NULL then a unified diff is appended there. It
747 ** is assumed that pOut has already been initialized. If pOut is
@@ -538,16 +756,20 @@
756 ** text "cannot compute difference between binary files".
757 */
758 int *text_diff(
759 Blob *pA_Blob, /* FROM file */
760 Blob *pB_Blob, /* TO file */
761 Blob *pOut, /* Write diff here if not NULL */
762 int diffFlags /* DIFF_* flags defined above */
 
763 ){
764 int ignoreEolWs; /* Ignore whitespace at the end of lines */
765 int nContext; /* Amount of context to display */
766 DContext c;
767
768 nContext = diff_context_lines(diffFlags);
769 ignoreEolWs = (diffFlags & DIFF_IGNORE_EOLWS)!=0;
770
771 /* Prepare the input files */
772 memset(&c, 0, sizeof(c));
773 c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob),
774 &c.nFrom, ignoreEolWs);
775 c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob),
@@ -563,12 +785,17 @@
785
786 /* Compute the difference */
787 diff_all(&c);
788
789 if( pOut ){
790 /* Compute a context or side-by-side diff into pOut */
791 if( diffFlags & DIFF_SIDEBYSIDE ){
792 int width = diff_width(diffFlags);
793 sbsDiff(&c, pOut, nContext, width);
794 }else{
795 contextDiff(&c, pOut, nContext);
796 }
797 free(c.aFrom);
798 free(c.aTo);
799 free(c.aEdit);
800 return 0;
801 }else{
@@ -588,11 +815,11 @@
815 static char *copylimline(char *out, DLine *dl, int lim){
816 int len;
817 len = dl->h & LENGTH_MASK;
818 if( lim && len > lim ){
819 memcpy(out, dl->z, lim-3);
820 memcpy(&out[lim-3], "...", 4);
821 }else{
822 memcpy(out, dl->z, len);
823 out[len] = '\0';
824 }
825 return out;
@@ -660,11 +887,11 @@
887 while( i<c.nEdit ){
888 int j;
889 /* Copied lines */
890 for( j=0; j<c.aEdit[i]; j++){
891 /* Hide lines which are copied and are further away from block boundaries
892 ** than nContext lines. For each block with hidden lines, show a row
893 ** notifying the user about the hidden rows.
894 */
895 if( j<nContext || j>c.aEdit[i]-nContext-1 ){
896 @ <tr>
897 }else if( j==nContext && j<c.aEdit[i]-nContext-1 ){
@@ -776,29 +1003,58 @@
1003 if( g.argc<4 ) usage("FILE1 FILE2 ...");
1004 blob_read_from_file(&a, g.argv[2]);
1005 for(i=3; i<g.argc; i++){
1006 if( i>3 ) fossil_print("-------------------------------\n");
1007 blob_read_from_file(&b, g.argv[i]);
1008 R = text_diff(&a, &b, 0, 0);
1009 for(r=0; R[r] || R[r+1] || R[r+2]; r += 3){
1010 fossil_print(" copy %4d delete %4d insert %4d\n", R[r], R[r+1], R[r+2]);
1011 }
1012 /* free(R); */
1013 blob_reset(&b);
1014 }
1015 }
1016
1017 /*
1018 ** Process diff-related command-line options and return an appropriate
1019 ** "diffFlags" integer.
1020 **
1021 ** --side-by-side|-y Side-by-side diff. DIFF_SIDEBYSIDE
1022 ** --context|-c N N lines of context. DIFF_CONTEXT_MASK
1023 ** --width|-W N N character lines. DIFF_WIDTH_MASK
1024 */
1025 int diff_options(void){
1026 int diffFlags = 0;
1027 const char *z;
1028 int f;
1029 if( find_option("side-by-side","y",0)!=0 ) diffFlags |= DIFF_SIDEBYSIDE;
1030 if( (z = find_option("context","c",1))!=0 && (f = atoi(z))>0 ){
1031 if( f > DIFF_CONTEXT_MASK ) f = DIFF_CONTEXT_MASK;
1032 diffFlags |= f;
1033 }
1034 if( (z = find_option("width","W",1))!=0 && (f = atoi(z))>0 ){
1035 f *= DIFF_CONTEXT_MASK+1;
1036 if( f > DIFF_WIDTH_MASK ) f = DIFF_CONTEXT_MASK;
1037 diffFlags |= f;
1038 }
1039 return diffFlags;
1040 }
1041
1042 /*
1043 ** COMMAND: test-udiff
1044 **
1045 ** Print the difference between two files. The usual diff options apply.
1046 */
1047 void test_udiff_cmd(void){
1048 Blob a, b, out;
1049 int diffFlag = diff_options();
1050
1051 if( g.argc!=4 ) usage("FILE1 FILE2");
1052 blob_read_from_file(&a, g.argv[2]);
1053 blob_read_from_file(&b, g.argv[3]);
1054 blob_zero(&out);
1055 text_diff(&a, &b, &out, diffFlag);
1056 blob_write_to_file(&out, "-");
1057 }
1058
1059 /**************************************************************************
1060 ** The basic difference engine is above. What follows is the annotation
1061
+55 -38
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -19,16 +19,10 @@
1919
*/
2020
#include "config.h"
2121
#include "diffcmd.h"
2222
#include <assert.h>
2323
24
-/*
25
-** Diff option flags
26
-*/
27
-#define DIFF_NEWFILE 0x01 /* Treat non-existing fails as empty files */
28
-#define DIFF_NOEOLWS 0x02 /* Ignore whitespace at the end of lines */
29
-
3024
/*
3125
** Output the results of a diff. Output goes to stdout for command-line
3226
** or to the CGI/HTTP result buffer for web pages.
3327
*/
3428
static void diff_printf(const char *zFormat, ...){
@@ -41,15 +35,38 @@
4135
}
4236
va_end(ap);
4337
}
4438
4539
/*
46
-** Print the "Index:" message that patch wants to see at the top of a diff.
40
+** Print the "Index:" message that patches wants to see at the top of a diff.
41
+*/
42
+void diff_print_index(const char *zFile, int diffFlags){
43
+ if( (diffFlags & DIFF_SIDEBYSIDE)==0 ){
44
+ char *z = mprintf("Index: %s\n%.66c\n", zFile, '=');
45
+ diff_printf("%s", z);
46
+ fossil_free(z);
47
+ }
48
+}
49
+
50
+/*
51
+** Print the +++/--- filename lines for a diff operation.
4752
*/
48
-void diff_print_index(const char *zFile){
49
- diff_printf("Index: %s\n======================================="
50
- "============================\n", zFile);
53
+void diff_print_filenames(const char *zLeft, const char *zRight, int diffFlags){
54
+ char *z = 0;
55
+ if( diffFlags & DIFF_SIDEBYSIDE ){
56
+ int w = diff_width(diffFlags);
57
+ int n1 = strlen(zLeft);
58
+ int x;
59
+ if( n1>w*2 ) n1 = w*2;
60
+ x = w*2+17 - (n1+2);
61
+ z = mprintf("%.*c %.*s %.*c\n",
62
+ x/2, '=', n1, zLeft, (x+1)/2, '=');
63
+ }else{
64
+ z = mprintf("--- %s\n+++ %s\n", zLeft, zRight);
65
+ }
66
+ diff_printf("%s", z);
67
+ fossil_free(z);
5168
}
5269
5370
/*
5471
** Show the difference between two files, one in memory and one on disk.
5572
**
@@ -62,11 +79,11 @@
6279
void diff_file(
6380
Blob *pFile1, /* In memory content to compare from */
6481
const char *zFile2, /* On disk content to compare to */
6582
const char *zName, /* Display name of the file */
6683
const char *zDiffCmd, /* Command for comparison */
67
- int ignoreEolWs /* Ignore whitespace at end of line */
84
+ int diffFlags /* Flags to control the diff */
6885
){
6986
if( zDiffCmd==0 ){
7087
Blob out; /* Diff output text */
7188
Blob file2; /* Content of zFile2 */
7289
const char *zName2; /* Name of zFile2 for display */
@@ -84,13 +101,13 @@
84101
zName2 = zName;
85102
}
86103
87104
/* Compute and output the differences */
88105
blob_zero(&out);
89
- text_diff(pFile1, &file2, &out, 5, ignoreEolWs);
106
+ text_diff(pFile1, &file2, &out, diffFlags);
90107
if( blob_size(&out) ){
91
- diff_printf("--- %s\n+++ %s\n", zName, zName2);
108
+ diff_print_filenames(zName, zName2, diffFlags);
92109
diff_printf("%s\n", blob_str(&out));
93110
}
94111
95112
/* Release memory resources */
96113
blob_reset(&file2);
@@ -138,18 +155,18 @@
138155
void diff_file_mem(
139156
Blob *pFile1, /* In memory content to compare from */
140157
Blob *pFile2, /* In memory content to compare to */
141158
const char *zName, /* Display name of the file */
142159
const char *zDiffCmd, /* Command for comparison */
143
- int ignoreEolWs /* Ignore whitespace at end of lines */
160
+ int diffFlags /* Diff flags */
144161
){
145162
if( zDiffCmd==0 ){
146163
Blob out; /* Diff output text */
147164
148165
blob_zero(&out);
149
- text_diff(pFile1, pFile2, &out, 5, ignoreEolWs);
150
- diff_printf("--- %s\n+++ %s\n", zName, zName);
166
+ text_diff(pFile1, pFile2, &out, diffFlags);
167
+ diff_print_filenames(zName, zName, diffFlags);
151168
diff_printf("%s\n", blob_str(&out));
152169
153170
/* Release memory resources */
154171
blob_reset(&out);
155172
}else{
@@ -185,11 +202,11 @@
185202
** against the same file on disk.
186203
*/
187204
static void diff_one_against_disk(
188205
const char *zFrom, /* Name of file */
189206
const char *zDiffCmd, /* Use this "diff" command */
190
- int ignoreEolWs, /* Ignore whitespace changes at end of lines */
207
+ int diffFlags, /* Diff control flags */
191208
const char *zFileTreeName
192209
){
193210
Blob fname;
194211
Blob content;
195212
int isLink;
@@ -196,11 +213,11 @@
196213
file_tree_name(zFileTreeName, &fname, 1);
197214
historical_version_of_file(zFrom, blob_str(&fname), &content, &isLink, 0, 0);
198215
if( !isLink != !file_wd_islink(zFrom) ){
199216
diff_printf("cannot compute difference between symlink and regular file\n");
200217
}else{
201
- diff_file(&content, zFileTreeName, zFileTreeName, zDiffCmd, ignoreEolWs);
218
+ diff_file(&content, zFileTreeName, zFileTreeName, zDiffCmd, diffFlags);
202219
}
203220
blob_reset(&content);
204221
blob_reset(&fname);
205222
}
206223
@@ -215,14 +232,12 @@
215232
int diffFlags /* Flags controlling diff output */
216233
){
217234
int vid;
218235
Blob sql;
219236
Stmt q;
220
- int ignoreEolWs; /* Ignore end-of-line whitespace */
221237
int asNewFile; /* Treat non-existant files as empty files */
222238
223
- ignoreEolWs = (diffFlags & DIFF_NOEOLWS)!=0;
224239
asNewFile = (diffFlags & DIFF_NEWFILE)!=0;
225240
vid = db_lget_int("checkout", 0);
226241
vfile_check_signature(vid, 1, 0);
227242
blob_zero(&sql);
228243
db_begin_transaction();
@@ -289,22 +304,22 @@
289304
if( !asNewFile ){ showDiff = 0; }
290305
}
291306
if( showDiff ){
292307
Blob content;
293308
if( !isLink != !file_wd_islink(zFullName) ){
294
- diff_print_index(zPathname);
295
- diff_printf("--- %s\n+++ %s\n", zPathname, zPathname);
309
+ diff_print_index(zPathname, diffFlags);
310
+ diff_print_filenames(zPathname, zPathname, diffFlags);
296311
diff_printf("cannot compute difference between symlink and regular file\n");
297312
continue;
298313
}
299314
if( srcid>0 ){
300315
content_get(srcid, &content);
301316
}else{
302317
blob_zero(&content);
303318
}
304
- diff_print_index(zPathname);
305
- diff_file(&content, zFullName, zPathname, zDiffCmd, ignoreEolWs);
319
+ diff_print_index(zPathname, diffFlags);
320
+ diff_file(&content, zFullName, zPathname, zDiffCmd, diffFlags);
306321
blob_reset(&content);
307322
}
308323
free(zToFree);
309324
}
310325
db_finalize(&q);
@@ -317,11 +332,11 @@
317332
*/
318333
static void diff_one_two_versions(
319334
const char *zFrom,
320335
const char *zTo,
321336
const char *zDiffCmd,
322
- int ignoreEolWs,
337
+ int diffFlags,
323338
const char *zFileTreeName
324339
){
325340
char *zName;
326341
Blob fname;
327342
Blob v1, v2;
@@ -329,14 +344,14 @@
329344
file_tree_name(zFileTreeName, &fname, 1);
330345
zName = blob_str(&fname);
331346
historical_version_of_file(zFrom, zName, &v1, &isLink1, 0, 0);
332347
historical_version_of_file(zTo, zName, &v2, &isLink2, 0, 0);
333348
if( isLink1 != isLink2 ){
334
- diff_printf("--- %s\n+++ %s\n", zName, zName);
349
+ diff_print_filenames(zName, zName, diffFlags);
335350
diff_printf("cannot compute difference between symlink and regular file\n");
336351
}else{
337
- diff_file_mem(&v1, &v2, zName, zDiffCmd, ignoreEolWs);
352
+ diff_file_mem(&v1, &v2, zName, zDiffCmd, diffFlags);
338353
}
339354
blob_reset(&v1);
340355
blob_reset(&v2);
341356
blob_reset(&fname);
342357
}
@@ -347,16 +362,16 @@
347362
*/
348363
static void diff_manifest_entry(
349364
struct ManifestFile *pFrom,
350365
struct ManifestFile *pTo,
351366
const char *zDiffCmd,
352
- int ignoreEolWs
367
+ int diffFlags
353368
){
354369
Blob f1, f2;
355370
int rid;
356371
const char *zName = pFrom ? pFrom->zName : pTo->zName;
357
- diff_print_index(zName);
372
+ diff_print_index(zName, diffFlags);
358373
if( pFrom ){
359374
rid = uuid_to_rid(pFrom->zUuid, 0);
360375
content_get(rid, &f1);
361376
}else{
362377
blob_zero(&f1);
@@ -365,11 +380,11 @@
365380
rid = uuid_to_rid(pTo->zUuid, 0);
366381
content_get(rid, &f2);
367382
}else{
368383
blob_zero(&f2);
369384
}
370
- diff_file_mem(&f1, &f2, zName, zDiffCmd, ignoreEolWs);
385
+ diff_file_mem(&f1, &f2, zName, zDiffCmd, diffFlags);
371386
blob_reset(&f1);
372387
blob_reset(&f2);
373388
}
374389
375390
/*
@@ -381,11 +396,10 @@
381396
const char *zDiffCmd,
382397
int diffFlags
383398
){
384399
Manifest *pFrom, *pTo;
385400
ManifestFile *pFromFile, *pToFile;
386
- int ignoreEolWs = (diffFlags & DIFF_NOEOLWS)!=0 ? 1 : 0;
387401
int asNewFlag = (diffFlags & DIFF_NEWFILE)!=0 ? 1 : 0;
388402
389403
pFrom = manifest_get_by_name(zFrom, 0);
390404
manifest_file_rewind(pFrom);
391405
pFromFile = manifest_file_next(pFrom,0);
@@ -403,26 +417,26 @@
403417
cmp = fossil_strcmp(pFromFile->zName, pToFile->zName);
404418
}
405419
if( cmp<0 ){
406420
diff_printf("DELETED %s\n", pFromFile->zName);
407421
if( asNewFlag ){
408
- diff_manifest_entry(pFromFile, 0, zDiffCmd, ignoreEolWs);
422
+ diff_manifest_entry(pFromFile, 0, zDiffCmd, diffFlags);
409423
}
410424
pFromFile = manifest_file_next(pFrom,0);
411425
}else if( cmp>0 ){
412426
diff_printf("ADDED %s\n", pToFile->zName);
413427
if( asNewFlag ){
414
- diff_manifest_entry(0, pToFile, zDiffCmd, ignoreEolWs);
428
+ diff_manifest_entry(0, pToFile, zDiffCmd, diffFlags);
415429
}
416430
pToFile = manifest_file_next(pTo,0);
417431
}else if( fossil_strcmp(pFromFile->zUuid, pToFile->zUuid)==0 ){
418432
/* No changes */
419433
pFromFile = manifest_file_next(pFrom,0);
420434
pToFile = manifest_file_next(pTo,0);
421435
}else{
422436
/* diff_printf("CHANGED %s\n", pFromFile->zName); */
423
- diff_manifest_entry(pFromFile, pToFile, zDiffCmd, ignoreEolWs);
437
+ diff_manifest_entry(pFromFile, pToFile, zDiffCmd, diffFlags);
424438
pFromFile = manifest_file_next(pFrom,0);
425439
pToFile = manifest_file_next(pTo,0);
426440
}
427441
}
428442
manifest_destroy(pFrom);
@@ -456,14 +470,17 @@
456470
**
457471
** The "-N" or "--new-file" option causes the complete text of added or
458472
** deleted files to be displayed.
459473
**
460474
** Options:
475
+** --context|-c N Use N lines of context
461476
** --from|-r VERSION select VERSION as source for the diff
462477
** --new-file|-N output complete text of added or deleted files
463478
** -i use internal diff logic
464479
** --to VERSION select VERSION as target for the diff
480
+** --side-by-side|-y side-by-side diff
481
+** --width|-W N Width of lines in side-by-side diff
465482
*/
466483
void diff_cmd(void){
467484
int isGDiff; /* True for gdiff. False for normal diff */
468485
int isInternDiff; /* True for internal diff */
469486
int hasNFlag; /* True if -N or --new-file flag is used */
@@ -475,23 +492,23 @@
475492
476493
isGDiff = g.argv[1][0]=='g';
477494
isInternDiff = find_option("internal","i",0)!=0;
478495
zFrom = find_option("from", "r", 1);
479496
zTo = find_option("to", 0, 1);
497
+ diffFlags = diff_options();
480498
hasNFlag = find_option("new-file","N",0)!=0;
481
-
482
-
483499
if( hasNFlag ) diffFlags |= DIFF_NEWFILE;
500
+
484501
if( zTo==0 ){
485502
db_must_be_within_tree();
486503
verify_all_options();
487504
if( !isInternDiff ){
488505
zDiffCmd = db_get(isGDiff ? "gdiff-command" : "diff-command", 0);
489506
}
490507
if( g.argc>=3 ){
491508
for(f=2; f<g.argc; ++f){
492
- diff_one_against_disk(zFrom, zDiffCmd, 0, g.argv[f]);
509
+ diff_one_against_disk(zFrom, zDiffCmd, diffFlags, g.argv[f]);
493510
}
494511
}else{
495512
diff_all_against_disk(zFrom, zDiffCmd, diffFlags);
496513
}
497514
}else if( zFrom==0 ){
@@ -502,11 +519,11 @@
502519
if( !isInternDiff ){
503520
zDiffCmd = db_get(isGDiff ? "gdiff-command" : "diff-command", 0);
504521
}
505522
if( g.argc>=3 ){
506523
for(f=2; f<g.argc; ++f){
507
- diff_one_two_versions(zFrom, zTo, zDiffCmd, 0, g.argv[f]);
524
+ diff_one_two_versions(zFrom, zTo, zDiffCmd, diffFlags, g.argv[f]);
508525
}
509526
}else{
510527
diff_all_two_versions(zFrom, zTo, zDiffCmd, diffFlags);
511528
}
512529
}
513530
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -19,16 +19,10 @@
19 */
20 #include "config.h"
21 #include "diffcmd.h"
22 #include <assert.h>
23
24 /*
25 ** Diff option flags
26 */
27 #define DIFF_NEWFILE 0x01 /* Treat non-existing fails as empty files */
28 #define DIFF_NOEOLWS 0x02 /* Ignore whitespace at the end of lines */
29
30 /*
31 ** Output the results of a diff. Output goes to stdout for command-line
32 ** or to the CGI/HTTP result buffer for web pages.
33 */
34 static void diff_printf(const char *zFormat, ...){
@@ -41,15 +35,38 @@
41 }
42 va_end(ap);
43 }
44
45 /*
46 ** Print the "Index:" message that patch wants to see at the top of a diff.
 
 
 
 
 
 
 
 
 
 
 
47 */
48 void diff_print_index(const char *zFile){
49 diff_printf("Index: %s\n======================================="
50 "============================\n", zFile);
 
 
 
 
 
 
 
 
 
 
 
 
51 }
52
53 /*
54 ** Show the difference between two files, one in memory and one on disk.
55 **
@@ -62,11 +79,11 @@
62 void diff_file(
63 Blob *pFile1, /* In memory content to compare from */
64 const char *zFile2, /* On disk content to compare to */
65 const char *zName, /* Display name of the file */
66 const char *zDiffCmd, /* Command for comparison */
67 int ignoreEolWs /* Ignore whitespace at end of line */
68 ){
69 if( zDiffCmd==0 ){
70 Blob out; /* Diff output text */
71 Blob file2; /* Content of zFile2 */
72 const char *zName2; /* Name of zFile2 for display */
@@ -84,13 +101,13 @@
84 zName2 = zName;
85 }
86
87 /* Compute and output the differences */
88 blob_zero(&out);
89 text_diff(pFile1, &file2, &out, 5, ignoreEolWs);
90 if( blob_size(&out) ){
91 diff_printf("--- %s\n+++ %s\n", zName, zName2);
92 diff_printf("%s\n", blob_str(&out));
93 }
94
95 /* Release memory resources */
96 blob_reset(&file2);
@@ -138,18 +155,18 @@
138 void diff_file_mem(
139 Blob *pFile1, /* In memory content to compare from */
140 Blob *pFile2, /* In memory content to compare to */
141 const char *zName, /* Display name of the file */
142 const char *zDiffCmd, /* Command for comparison */
143 int ignoreEolWs /* Ignore whitespace at end of lines */
144 ){
145 if( zDiffCmd==0 ){
146 Blob out; /* Diff output text */
147
148 blob_zero(&out);
149 text_diff(pFile1, pFile2, &out, 5, ignoreEolWs);
150 diff_printf("--- %s\n+++ %s\n", zName, zName);
151 diff_printf("%s\n", blob_str(&out));
152
153 /* Release memory resources */
154 blob_reset(&out);
155 }else{
@@ -185,11 +202,11 @@
185 ** against the same file on disk.
186 */
187 static void diff_one_against_disk(
188 const char *zFrom, /* Name of file */
189 const char *zDiffCmd, /* Use this "diff" command */
190 int ignoreEolWs, /* Ignore whitespace changes at end of lines */
191 const char *zFileTreeName
192 ){
193 Blob fname;
194 Blob content;
195 int isLink;
@@ -196,11 +213,11 @@
196 file_tree_name(zFileTreeName, &fname, 1);
197 historical_version_of_file(zFrom, blob_str(&fname), &content, &isLink, 0, 0);
198 if( !isLink != !file_wd_islink(zFrom) ){
199 diff_printf("cannot compute difference between symlink and regular file\n");
200 }else{
201 diff_file(&content, zFileTreeName, zFileTreeName, zDiffCmd, ignoreEolWs);
202 }
203 blob_reset(&content);
204 blob_reset(&fname);
205 }
206
@@ -215,14 +232,12 @@
215 int diffFlags /* Flags controlling diff output */
216 ){
217 int vid;
218 Blob sql;
219 Stmt q;
220 int ignoreEolWs; /* Ignore end-of-line whitespace */
221 int asNewFile; /* Treat non-existant files as empty files */
222
223 ignoreEolWs = (diffFlags & DIFF_NOEOLWS)!=0;
224 asNewFile = (diffFlags & DIFF_NEWFILE)!=0;
225 vid = db_lget_int("checkout", 0);
226 vfile_check_signature(vid, 1, 0);
227 blob_zero(&sql);
228 db_begin_transaction();
@@ -289,22 +304,22 @@
289 if( !asNewFile ){ showDiff = 0; }
290 }
291 if( showDiff ){
292 Blob content;
293 if( !isLink != !file_wd_islink(zFullName) ){
294 diff_print_index(zPathname);
295 diff_printf("--- %s\n+++ %s\n", zPathname, zPathname);
296 diff_printf("cannot compute difference between symlink and regular file\n");
297 continue;
298 }
299 if( srcid>0 ){
300 content_get(srcid, &content);
301 }else{
302 blob_zero(&content);
303 }
304 diff_print_index(zPathname);
305 diff_file(&content, zFullName, zPathname, zDiffCmd, ignoreEolWs);
306 blob_reset(&content);
307 }
308 free(zToFree);
309 }
310 db_finalize(&q);
@@ -317,11 +332,11 @@
317 */
318 static void diff_one_two_versions(
319 const char *zFrom,
320 const char *zTo,
321 const char *zDiffCmd,
322 int ignoreEolWs,
323 const char *zFileTreeName
324 ){
325 char *zName;
326 Blob fname;
327 Blob v1, v2;
@@ -329,14 +344,14 @@
329 file_tree_name(zFileTreeName, &fname, 1);
330 zName = blob_str(&fname);
331 historical_version_of_file(zFrom, zName, &v1, &isLink1, 0, 0);
332 historical_version_of_file(zTo, zName, &v2, &isLink2, 0, 0);
333 if( isLink1 != isLink2 ){
334 diff_printf("--- %s\n+++ %s\n", zName, zName);
335 diff_printf("cannot compute difference between symlink and regular file\n");
336 }else{
337 diff_file_mem(&v1, &v2, zName, zDiffCmd, ignoreEolWs);
338 }
339 blob_reset(&v1);
340 blob_reset(&v2);
341 blob_reset(&fname);
342 }
@@ -347,16 +362,16 @@
347 */
348 static void diff_manifest_entry(
349 struct ManifestFile *pFrom,
350 struct ManifestFile *pTo,
351 const char *zDiffCmd,
352 int ignoreEolWs
353 ){
354 Blob f1, f2;
355 int rid;
356 const char *zName = pFrom ? pFrom->zName : pTo->zName;
357 diff_print_index(zName);
358 if( pFrom ){
359 rid = uuid_to_rid(pFrom->zUuid, 0);
360 content_get(rid, &f1);
361 }else{
362 blob_zero(&f1);
@@ -365,11 +380,11 @@
365 rid = uuid_to_rid(pTo->zUuid, 0);
366 content_get(rid, &f2);
367 }else{
368 blob_zero(&f2);
369 }
370 diff_file_mem(&f1, &f2, zName, zDiffCmd, ignoreEolWs);
371 blob_reset(&f1);
372 blob_reset(&f2);
373 }
374
375 /*
@@ -381,11 +396,10 @@
381 const char *zDiffCmd,
382 int diffFlags
383 ){
384 Manifest *pFrom, *pTo;
385 ManifestFile *pFromFile, *pToFile;
386 int ignoreEolWs = (diffFlags & DIFF_NOEOLWS)!=0 ? 1 : 0;
387 int asNewFlag = (diffFlags & DIFF_NEWFILE)!=0 ? 1 : 0;
388
389 pFrom = manifest_get_by_name(zFrom, 0);
390 manifest_file_rewind(pFrom);
391 pFromFile = manifest_file_next(pFrom,0);
@@ -403,26 +417,26 @@
403 cmp = fossil_strcmp(pFromFile->zName, pToFile->zName);
404 }
405 if( cmp<0 ){
406 diff_printf("DELETED %s\n", pFromFile->zName);
407 if( asNewFlag ){
408 diff_manifest_entry(pFromFile, 0, zDiffCmd, ignoreEolWs);
409 }
410 pFromFile = manifest_file_next(pFrom,0);
411 }else if( cmp>0 ){
412 diff_printf("ADDED %s\n", pToFile->zName);
413 if( asNewFlag ){
414 diff_manifest_entry(0, pToFile, zDiffCmd, ignoreEolWs);
415 }
416 pToFile = manifest_file_next(pTo,0);
417 }else if( fossil_strcmp(pFromFile->zUuid, pToFile->zUuid)==0 ){
418 /* No changes */
419 pFromFile = manifest_file_next(pFrom,0);
420 pToFile = manifest_file_next(pTo,0);
421 }else{
422 /* diff_printf("CHANGED %s\n", pFromFile->zName); */
423 diff_manifest_entry(pFromFile, pToFile, zDiffCmd, ignoreEolWs);
424 pFromFile = manifest_file_next(pFrom,0);
425 pToFile = manifest_file_next(pTo,0);
426 }
427 }
428 manifest_destroy(pFrom);
@@ -456,14 +470,17 @@
456 **
457 ** The "-N" or "--new-file" option causes the complete text of added or
458 ** deleted files to be displayed.
459 **
460 ** Options:
 
461 ** --from|-r VERSION select VERSION as source for the diff
462 ** --new-file|-N output complete text of added or deleted files
463 ** -i use internal diff logic
464 ** --to VERSION select VERSION as target for the diff
 
 
465 */
466 void diff_cmd(void){
467 int isGDiff; /* True for gdiff. False for normal diff */
468 int isInternDiff; /* True for internal diff */
469 int hasNFlag; /* True if -N or --new-file flag is used */
@@ -475,23 +492,23 @@
475
476 isGDiff = g.argv[1][0]=='g';
477 isInternDiff = find_option("internal","i",0)!=0;
478 zFrom = find_option("from", "r", 1);
479 zTo = find_option("to", 0, 1);
 
480 hasNFlag = find_option("new-file","N",0)!=0;
481
482
483 if( hasNFlag ) diffFlags |= DIFF_NEWFILE;
 
484 if( zTo==0 ){
485 db_must_be_within_tree();
486 verify_all_options();
487 if( !isInternDiff ){
488 zDiffCmd = db_get(isGDiff ? "gdiff-command" : "diff-command", 0);
489 }
490 if( g.argc>=3 ){
491 for(f=2; f<g.argc; ++f){
492 diff_one_against_disk(zFrom, zDiffCmd, 0, g.argv[f]);
493 }
494 }else{
495 diff_all_against_disk(zFrom, zDiffCmd, diffFlags);
496 }
497 }else if( zFrom==0 ){
@@ -502,11 +519,11 @@
502 if( !isInternDiff ){
503 zDiffCmd = db_get(isGDiff ? "gdiff-command" : "diff-command", 0);
504 }
505 if( g.argc>=3 ){
506 for(f=2; f<g.argc; ++f){
507 diff_one_two_versions(zFrom, zTo, zDiffCmd, 0, g.argv[f]);
508 }
509 }else{
510 diff_all_two_versions(zFrom, zTo, zDiffCmd, diffFlags);
511 }
512 }
513
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -19,16 +19,10 @@
19 */
20 #include "config.h"
21 #include "diffcmd.h"
22 #include <assert.h>
23
 
 
 
 
 
 
24 /*
25 ** Output the results of a diff. Output goes to stdout for command-line
26 ** or to the CGI/HTTP result buffer for web pages.
27 */
28 static void diff_printf(const char *zFormat, ...){
@@ -41,15 +35,38 @@
35 }
36 va_end(ap);
37 }
38
39 /*
40 ** Print the "Index:" message that patches wants to see at the top of a diff.
41 */
42 void diff_print_index(const char *zFile, int diffFlags){
43 if( (diffFlags & DIFF_SIDEBYSIDE)==0 ){
44 char *z = mprintf("Index: %s\n%.66c\n", zFile, '=');
45 diff_printf("%s", z);
46 fossil_free(z);
47 }
48 }
49
50 /*
51 ** Print the +++/--- filename lines for a diff operation.
52 */
53 void diff_print_filenames(const char *zLeft, const char *zRight, int diffFlags){
54 char *z = 0;
55 if( diffFlags & DIFF_SIDEBYSIDE ){
56 int w = diff_width(diffFlags);
57 int n1 = strlen(zLeft);
58 int x;
59 if( n1>w*2 ) n1 = w*2;
60 x = w*2+17 - (n1+2);
61 z = mprintf("%.*c %.*s %.*c\n",
62 x/2, '=', n1, zLeft, (x+1)/2, '=');
63 }else{
64 z = mprintf("--- %s\n+++ %s\n", zLeft, zRight);
65 }
66 diff_printf("%s", z);
67 fossil_free(z);
68 }
69
70 /*
71 ** Show the difference between two files, one in memory and one on disk.
72 **
@@ -62,11 +79,11 @@
79 void diff_file(
80 Blob *pFile1, /* In memory content to compare from */
81 const char *zFile2, /* On disk content to compare to */
82 const char *zName, /* Display name of the file */
83 const char *zDiffCmd, /* Command for comparison */
84 int diffFlags /* Flags to control the diff */
85 ){
86 if( zDiffCmd==0 ){
87 Blob out; /* Diff output text */
88 Blob file2; /* Content of zFile2 */
89 const char *zName2; /* Name of zFile2 for display */
@@ -84,13 +101,13 @@
101 zName2 = zName;
102 }
103
104 /* Compute and output the differences */
105 blob_zero(&out);
106 text_diff(pFile1, &file2, &out, diffFlags);
107 if( blob_size(&out) ){
108 diff_print_filenames(zName, zName2, diffFlags);
109 diff_printf("%s\n", blob_str(&out));
110 }
111
112 /* Release memory resources */
113 blob_reset(&file2);
@@ -138,18 +155,18 @@
155 void diff_file_mem(
156 Blob *pFile1, /* In memory content to compare from */
157 Blob *pFile2, /* In memory content to compare to */
158 const char *zName, /* Display name of the file */
159 const char *zDiffCmd, /* Command for comparison */
160 int diffFlags /* Diff flags */
161 ){
162 if( zDiffCmd==0 ){
163 Blob out; /* Diff output text */
164
165 blob_zero(&out);
166 text_diff(pFile1, pFile2, &out, diffFlags);
167 diff_print_filenames(zName, zName, diffFlags);
168 diff_printf("%s\n", blob_str(&out));
169
170 /* Release memory resources */
171 blob_reset(&out);
172 }else{
@@ -185,11 +202,11 @@
202 ** against the same file on disk.
203 */
204 static void diff_one_against_disk(
205 const char *zFrom, /* Name of file */
206 const char *zDiffCmd, /* Use this "diff" command */
207 int diffFlags, /* Diff control flags */
208 const char *zFileTreeName
209 ){
210 Blob fname;
211 Blob content;
212 int isLink;
@@ -196,11 +213,11 @@
213 file_tree_name(zFileTreeName, &fname, 1);
214 historical_version_of_file(zFrom, blob_str(&fname), &content, &isLink, 0, 0);
215 if( !isLink != !file_wd_islink(zFrom) ){
216 diff_printf("cannot compute difference between symlink and regular file\n");
217 }else{
218 diff_file(&content, zFileTreeName, zFileTreeName, zDiffCmd, diffFlags);
219 }
220 blob_reset(&content);
221 blob_reset(&fname);
222 }
223
@@ -215,14 +232,12 @@
232 int diffFlags /* Flags controlling diff output */
233 ){
234 int vid;
235 Blob sql;
236 Stmt q;
 
237 int asNewFile; /* Treat non-existant files as empty files */
238
 
239 asNewFile = (diffFlags & DIFF_NEWFILE)!=0;
240 vid = db_lget_int("checkout", 0);
241 vfile_check_signature(vid, 1, 0);
242 blob_zero(&sql);
243 db_begin_transaction();
@@ -289,22 +304,22 @@
304 if( !asNewFile ){ showDiff = 0; }
305 }
306 if( showDiff ){
307 Blob content;
308 if( !isLink != !file_wd_islink(zFullName) ){
309 diff_print_index(zPathname, diffFlags);
310 diff_print_filenames(zPathname, zPathname, diffFlags);
311 diff_printf("cannot compute difference between symlink and regular file\n");
312 continue;
313 }
314 if( srcid>0 ){
315 content_get(srcid, &content);
316 }else{
317 blob_zero(&content);
318 }
319 diff_print_index(zPathname, diffFlags);
320 diff_file(&content, zFullName, zPathname, zDiffCmd, diffFlags);
321 blob_reset(&content);
322 }
323 free(zToFree);
324 }
325 db_finalize(&q);
@@ -317,11 +332,11 @@
332 */
333 static void diff_one_two_versions(
334 const char *zFrom,
335 const char *zTo,
336 const char *zDiffCmd,
337 int diffFlags,
338 const char *zFileTreeName
339 ){
340 char *zName;
341 Blob fname;
342 Blob v1, v2;
@@ -329,14 +344,14 @@
344 file_tree_name(zFileTreeName, &fname, 1);
345 zName = blob_str(&fname);
346 historical_version_of_file(zFrom, zName, &v1, &isLink1, 0, 0);
347 historical_version_of_file(zTo, zName, &v2, &isLink2, 0, 0);
348 if( isLink1 != isLink2 ){
349 diff_print_filenames(zName, zName, diffFlags);
350 diff_printf("cannot compute difference between symlink and regular file\n");
351 }else{
352 diff_file_mem(&v1, &v2, zName, zDiffCmd, diffFlags);
353 }
354 blob_reset(&v1);
355 blob_reset(&v2);
356 blob_reset(&fname);
357 }
@@ -347,16 +362,16 @@
362 */
363 static void diff_manifest_entry(
364 struct ManifestFile *pFrom,
365 struct ManifestFile *pTo,
366 const char *zDiffCmd,
367 int diffFlags
368 ){
369 Blob f1, f2;
370 int rid;
371 const char *zName = pFrom ? pFrom->zName : pTo->zName;
372 diff_print_index(zName, diffFlags);
373 if( pFrom ){
374 rid = uuid_to_rid(pFrom->zUuid, 0);
375 content_get(rid, &f1);
376 }else{
377 blob_zero(&f1);
@@ -365,11 +380,11 @@
380 rid = uuid_to_rid(pTo->zUuid, 0);
381 content_get(rid, &f2);
382 }else{
383 blob_zero(&f2);
384 }
385 diff_file_mem(&f1, &f2, zName, zDiffCmd, diffFlags);
386 blob_reset(&f1);
387 blob_reset(&f2);
388 }
389
390 /*
@@ -381,11 +396,10 @@
396 const char *zDiffCmd,
397 int diffFlags
398 ){
399 Manifest *pFrom, *pTo;
400 ManifestFile *pFromFile, *pToFile;
 
401 int asNewFlag = (diffFlags & DIFF_NEWFILE)!=0 ? 1 : 0;
402
403 pFrom = manifest_get_by_name(zFrom, 0);
404 manifest_file_rewind(pFrom);
405 pFromFile = manifest_file_next(pFrom,0);
@@ -403,26 +417,26 @@
417 cmp = fossil_strcmp(pFromFile->zName, pToFile->zName);
418 }
419 if( cmp<0 ){
420 diff_printf("DELETED %s\n", pFromFile->zName);
421 if( asNewFlag ){
422 diff_manifest_entry(pFromFile, 0, zDiffCmd, diffFlags);
423 }
424 pFromFile = manifest_file_next(pFrom,0);
425 }else if( cmp>0 ){
426 diff_printf("ADDED %s\n", pToFile->zName);
427 if( asNewFlag ){
428 diff_manifest_entry(0, pToFile, zDiffCmd, diffFlags);
429 }
430 pToFile = manifest_file_next(pTo,0);
431 }else if( fossil_strcmp(pFromFile->zUuid, pToFile->zUuid)==0 ){
432 /* No changes */
433 pFromFile = manifest_file_next(pFrom,0);
434 pToFile = manifest_file_next(pTo,0);
435 }else{
436 /* diff_printf("CHANGED %s\n", pFromFile->zName); */
437 diff_manifest_entry(pFromFile, pToFile, zDiffCmd, diffFlags);
438 pFromFile = manifest_file_next(pFrom,0);
439 pToFile = manifest_file_next(pTo,0);
440 }
441 }
442 manifest_destroy(pFrom);
@@ -456,14 +470,17 @@
470 **
471 ** The "-N" or "--new-file" option causes the complete text of added or
472 ** deleted files to be displayed.
473 **
474 ** Options:
475 ** --context|-c N Use N lines of context
476 ** --from|-r VERSION select VERSION as source for the diff
477 ** --new-file|-N output complete text of added or deleted files
478 ** -i use internal diff logic
479 ** --to VERSION select VERSION as target for the diff
480 ** --side-by-side|-y side-by-side diff
481 ** --width|-W N Width of lines in side-by-side diff
482 */
483 void diff_cmd(void){
484 int isGDiff; /* True for gdiff. False for normal diff */
485 int isInternDiff; /* True for internal diff */
486 int hasNFlag; /* True if -N or --new-file flag is used */
@@ -475,23 +492,23 @@
492
493 isGDiff = g.argv[1][0]=='g';
494 isInternDiff = find_option("internal","i",0)!=0;
495 zFrom = find_option("from", "r", 1);
496 zTo = find_option("to", 0, 1);
497 diffFlags = diff_options();
498 hasNFlag = find_option("new-file","N",0)!=0;
 
 
499 if( hasNFlag ) diffFlags |= DIFF_NEWFILE;
500
501 if( zTo==0 ){
502 db_must_be_within_tree();
503 verify_all_options();
504 if( !isInternDiff ){
505 zDiffCmd = db_get(isGDiff ? "gdiff-command" : "diff-command", 0);
506 }
507 if( g.argc>=3 ){
508 for(f=2; f<g.argc; ++f){
509 diff_one_against_disk(zFrom, zDiffCmd, diffFlags, g.argv[f]);
510 }
511 }else{
512 diff_all_against_disk(zFrom, zDiffCmd, diffFlags);
513 }
514 }else if( zFrom==0 ){
@@ -502,11 +519,11 @@
519 if( !isInternDiff ){
520 zDiffCmd = db_get(isGDiff ? "gdiff-command" : "diff-command", 0);
521 }
522 if( g.argc>=3 ){
523 for(f=2; f<g.argc; ++f){
524 diff_one_two_versions(zFrom, zTo, zDiffCmd, diffFlags, g.argv[f]);
525 }
526 }else{
527 diff_all_two_versions(zFrom, zTo, zDiffCmd, diffFlags);
528 }
529 }
530
+1 -1
--- src/finfo.c
+++ src/finfo.c
@@ -287,11 +287,11 @@
287287
char zShortCkin[20];
288288
if( zBr==0 ) zBr = "trunk";
289289
if( uBg ){
290290
zBgClr = hash_color(zUser);
291291
}else if( brBg || zBgClr==0 || zBgClr[0]==0 ){
292
- zBgClr = strcmp(zBr,"trunk")==0 ? "white" : hash_color(zBr);
292
+ zBgClr = strcmp(zBr,"trunk")==0 ? "" : hash_color(zBr);
293293
}
294294
gidx = graph_add_row(pGraph, frid, fpid>0 ? 1 : 0, &fpid, zBr, zBgClr, 0);
295295
if( memcmp(zDate, zPrevDate, 10) ){
296296
sqlite3_snprintf(sizeof(zPrevDate), zPrevDate, "%.10s", zDate);
297297
@ <tr><td>
298298
--- src/finfo.c
+++ src/finfo.c
@@ -287,11 +287,11 @@
287 char zShortCkin[20];
288 if( zBr==0 ) zBr = "trunk";
289 if( uBg ){
290 zBgClr = hash_color(zUser);
291 }else if( brBg || zBgClr==0 || zBgClr[0]==0 ){
292 zBgClr = strcmp(zBr,"trunk")==0 ? "white" : hash_color(zBr);
293 }
294 gidx = graph_add_row(pGraph, frid, fpid>0 ? 1 : 0, &fpid, zBr, zBgClr, 0);
295 if( memcmp(zDate, zPrevDate, 10) ){
296 sqlite3_snprintf(sizeof(zPrevDate), zPrevDate, "%.10s", zDate);
297 @ <tr><td>
298
--- src/finfo.c
+++ src/finfo.c
@@ -287,11 +287,11 @@
287 char zShortCkin[20];
288 if( zBr==0 ) zBr = "trunk";
289 if( uBg ){
290 zBgClr = hash_color(zUser);
291 }else if( brBg || zBgClr==0 || zBgClr[0]==0 ){
292 zBgClr = strcmp(zBr,"trunk")==0 ? "" : hash_color(zBr);
293 }
294 gidx = graph_add_row(pGraph, frid, fpid>0 ? 1 : 0, &fpid, zBr, zBgClr, 0);
295 if( memcmp(zDate, zPrevDate, 10) ){
296 sqlite3_snprintf(sizeof(zPrevDate), zPrevDate, "%.10s", zDate);
297 @ <tr><td>
298
+2 -2
--- src/info.c
+++ src/info.c
@@ -270,11 +270,11 @@
270270
content_get(toid, &to);
271271
}else{
272272
blob_zero(&to);
273273
}
274274
blob_zero(&out);
275
- text_diff(&from, &to, &out, 5, 1);
275
+ text_diff(&from, &to, &out, DIFF_IGNORE_EOLWS | 5);
276276
@ %h(blob_str(&out))
277277
blob_reset(&from);
278278
blob_reset(&to);
279279
blob_reset(&out);
280280
}
@@ -1091,11 +1091,11 @@
10911091
pOut = &diff;
10921092
}
10931093
if( !sideBySide || isPatch ){
10941094
content_get(v1, &c1);
10951095
content_get(v2, &c2);
1096
- text_diff(&c1, &c2, pOut, 4, 1);
1096
+ text_diff(&c1, &c2, pOut, 4 | 0);
10971097
blob_reset(&c1);
10981098
blob_reset(&c2);
10991099
}
11001100
if( !isPatch ){
11011101
style_header("Diff");
11021102
--- src/info.c
+++ src/info.c
@@ -270,11 +270,11 @@
270 content_get(toid, &to);
271 }else{
272 blob_zero(&to);
273 }
274 blob_zero(&out);
275 text_diff(&from, &to, &out, 5, 1);
276 @ %h(blob_str(&out))
277 blob_reset(&from);
278 blob_reset(&to);
279 blob_reset(&out);
280 }
@@ -1091,11 +1091,11 @@
1091 pOut = &diff;
1092 }
1093 if( !sideBySide || isPatch ){
1094 content_get(v1, &c1);
1095 content_get(v2, &c2);
1096 text_diff(&c1, &c2, pOut, 4, 1);
1097 blob_reset(&c1);
1098 blob_reset(&c2);
1099 }
1100 if( !isPatch ){
1101 style_header("Diff");
1102
--- src/info.c
+++ src/info.c
@@ -270,11 +270,11 @@
270 content_get(toid, &to);
271 }else{
272 blob_zero(&to);
273 }
274 blob_zero(&out);
275 text_diff(&from, &to, &out, DIFF_IGNORE_EOLWS | 5);
276 @ %h(blob_str(&out))
277 blob_reset(&from);
278 blob_reset(&to);
279 blob_reset(&out);
280 }
@@ -1091,11 +1091,11 @@
1091 pOut = &diff;
1092 }
1093 if( !sideBySide || isPatch ){
1094 content_get(v1, &c1);
1095 content_get(v2, &c2);
1096 text_diff(&c1, &c2, pOut, 4 | 0);
1097 blob_reset(&c1);
1098 blob_reset(&c2);
1099 }
1100 if( !isPatch ){
1101 style_header("Diff");
1102
+32 -28
--- src/login.c
+++ src/login.c
@@ -347,10 +347,37 @@
347347
** downstream problems here. We could alternately use "" here.
348348
*/
349349
;
350350
}
351351
}
352
+
353
+/*
354
+** SQL function for constant time comparison of two values.
355
+** Sets result to 0 if two values are equal.
356
+*/
357
+static void constant_time_cmp_function(
358
+ sqlite3_context *context,
359
+ int argc,
360
+ sqlite3_value **argv
361
+){
362
+ const unsigned char *buf1, *buf2;
363
+ int len, i;
364
+ unsigned char rc = 0;
365
+
366
+ assert( argc==2 );
367
+ len = sqlite3_value_bytes(argv[0]);
368
+ if( len==0 || len!=sqlite3_value_bytes(argv[1]) ){
369
+ rc = 1;
370
+ }else{
371
+ buf1 = sqlite3_value_text(argv[0]);
372
+ buf2 = sqlite3_value_text(argv[1]);
373
+ for( i=0; i<len; i++ ){
374
+ rc = rc | (buf1[i] ^ buf2[i]);
375
+ }
376
+ }
377
+ sqlite3_result_int(context, rc);
378
+}
352379
353380
/*
354381
** WEBPAGE: login
355382
** WEBPAGE: logout
356383
** WEBPAGE: my
@@ -371,18 +398,22 @@
371398
int uid; /* User id loged in user */
372399
char *zSha1Pw;
373400
const char *zIpAddr; /* IP address of requestor */
374401
375402
login_check_credentials();
403
+ sqlite3_create_function(g.db, "constant_time_cmp", 2, SQLITE_UTF8, 0,
404
+ constant_time_cmp_function, 0, 0);
376405
zUsername = P("u");
377406
zPasswd = P("p");
378407
anonFlag = P("anon")!=0;
379408
if( P("out")!=0 ){
380409
login_clear_login_data();
381410
redirect_to_g();
382411
}
383
- if( g.perm.Password && zPasswd && (zNew1 = P("n1"))!=0 && (zNew2 = P("n2"))!=0 ){
412
+ if( g.perm.Password && zPasswd
413
+ && (zNew1 = P("n1"))!=0 && (zNew2 = P("n2"))!=0
414
+ ){
384415
/* The user requests a password change */
385416
zSha1Pw = sha1_shared_secret(zPasswd, g.zLogin, 0);
386417
if( db_int(1, "SELECT 0 FROM user"
387418
" WHERE uid=%d"
388419
" AND (constant_time_cmp(pw,%Q)=0"
@@ -561,37 +592,10 @@
561592
@ </form>
562593
}
563594
style_footer();
564595
}
565596
566
-/*
567
-** SQL function for constant time comparison of two values.
568
-** Sets result to 0 if two values are equal.
569
-*/
570
-static void constant_time_cmp_function(
571
- sqlite3_context *context,
572
- int argc,
573
- sqlite3_value **argv
574
-){
575
- const unsigned char *buf1, *buf2;
576
- int len, i;
577
- unsigned char rc = 0;
578
-
579
- assert( argc==2 );
580
- len = sqlite3_value_bytes(argv[0]);
581
- if( len==0 || len!=sqlite3_value_bytes(argv[1]) ){
582
- rc = 1;
583
- }else{
584
- buf1 = sqlite3_value_text(argv[0]);
585
- buf2 = sqlite3_value_text(argv[1]);
586
- for( i=0; i<len; i++ ){
587
- rc = rc | (buf1[i] ^ buf2[i]);
588
- }
589
- }
590
- sqlite3_result_int(context, rc);
591
-}
592
-
593597
/*
594598
** Attempt to find login credentials for user zLogin on a peer repository
595599
** with project code zCode. Transfer those credentials to the local
596600
** repository.
597601
**
598602
--- src/login.c
+++ src/login.c
@@ -347,10 +347,37 @@
347 ** downstream problems here. We could alternately use "" here.
348 */
349 ;
350 }
351 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
352
353 /*
354 ** WEBPAGE: login
355 ** WEBPAGE: logout
356 ** WEBPAGE: my
@@ -371,18 +398,22 @@
371 int uid; /* User id loged in user */
372 char *zSha1Pw;
373 const char *zIpAddr; /* IP address of requestor */
374
375 login_check_credentials();
 
 
376 zUsername = P("u");
377 zPasswd = P("p");
378 anonFlag = P("anon")!=0;
379 if( P("out")!=0 ){
380 login_clear_login_data();
381 redirect_to_g();
382 }
383 if( g.perm.Password && zPasswd && (zNew1 = P("n1"))!=0 && (zNew2 = P("n2"))!=0 ){
 
 
384 /* The user requests a password change */
385 zSha1Pw = sha1_shared_secret(zPasswd, g.zLogin, 0);
386 if( db_int(1, "SELECT 0 FROM user"
387 " WHERE uid=%d"
388 " AND (constant_time_cmp(pw,%Q)=0"
@@ -561,37 +592,10 @@
561 @ </form>
562 }
563 style_footer();
564 }
565
566 /*
567 ** SQL function for constant time comparison of two values.
568 ** Sets result to 0 if two values are equal.
569 */
570 static void constant_time_cmp_function(
571 sqlite3_context *context,
572 int argc,
573 sqlite3_value **argv
574 ){
575 const unsigned char *buf1, *buf2;
576 int len, i;
577 unsigned char rc = 0;
578
579 assert( argc==2 );
580 len = sqlite3_value_bytes(argv[0]);
581 if( len==0 || len!=sqlite3_value_bytes(argv[1]) ){
582 rc = 1;
583 }else{
584 buf1 = sqlite3_value_text(argv[0]);
585 buf2 = sqlite3_value_text(argv[1]);
586 for( i=0; i<len; i++ ){
587 rc = rc | (buf1[i] ^ buf2[i]);
588 }
589 }
590 sqlite3_result_int(context, rc);
591 }
592
593 /*
594 ** Attempt to find login credentials for user zLogin on a peer repository
595 ** with project code zCode. Transfer those credentials to the local
596 ** repository.
597 **
598
--- src/login.c
+++ src/login.c
@@ -347,10 +347,37 @@
347 ** downstream problems here. We could alternately use "" here.
348 */
349 ;
350 }
351 }
352
353 /*
354 ** SQL function for constant time comparison of two values.
355 ** Sets result to 0 if two values are equal.
356 */
357 static void constant_time_cmp_function(
358 sqlite3_context *context,
359 int argc,
360 sqlite3_value **argv
361 ){
362 const unsigned char *buf1, *buf2;
363 int len, i;
364 unsigned char rc = 0;
365
366 assert( argc==2 );
367 len = sqlite3_value_bytes(argv[0]);
368 if( len==0 || len!=sqlite3_value_bytes(argv[1]) ){
369 rc = 1;
370 }else{
371 buf1 = sqlite3_value_text(argv[0]);
372 buf2 = sqlite3_value_text(argv[1]);
373 for( i=0; i<len; i++ ){
374 rc = rc | (buf1[i] ^ buf2[i]);
375 }
376 }
377 sqlite3_result_int(context, rc);
378 }
379
380 /*
381 ** WEBPAGE: login
382 ** WEBPAGE: logout
383 ** WEBPAGE: my
@@ -371,18 +398,22 @@
398 int uid; /* User id loged in user */
399 char *zSha1Pw;
400 const char *zIpAddr; /* IP address of requestor */
401
402 login_check_credentials();
403 sqlite3_create_function(g.db, "constant_time_cmp", 2, SQLITE_UTF8, 0,
404 constant_time_cmp_function, 0, 0);
405 zUsername = P("u");
406 zPasswd = P("p");
407 anonFlag = P("anon")!=0;
408 if( P("out")!=0 ){
409 login_clear_login_data();
410 redirect_to_g();
411 }
412 if( g.perm.Password && zPasswd
413 && (zNew1 = P("n1"))!=0 && (zNew2 = P("n2"))!=0
414 ){
415 /* The user requests a password change */
416 zSha1Pw = sha1_shared_secret(zPasswd, g.zLogin, 0);
417 if( db_int(1, "SELECT 0 FROM user"
418 " WHERE uid=%d"
419 " AND (constant_time_cmp(pw,%Q)=0"
@@ -561,37 +592,10 @@
592 @ </form>
593 }
594 style_footer();
595 }
596
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
597 /*
598 ** Attempt to find login credentials for user zLogin on a peer repository
599 ** with project code zCode. Transfer those credentials to the local
600 ** repository.
601 **
602
+32 -28
--- src/login.c
+++ src/login.c
@@ -347,10 +347,37 @@
347347
** downstream problems here. We could alternately use "" here.
348348
*/
349349
;
350350
}
351351
}
352
+
353
+/*
354
+** SQL function for constant time comparison of two values.
355
+** Sets result to 0 if two values are equal.
356
+*/
357
+static void constant_time_cmp_function(
358
+ sqlite3_context *context,
359
+ int argc,
360
+ sqlite3_value **argv
361
+){
362
+ const unsigned char *buf1, *buf2;
363
+ int len, i;
364
+ unsigned char rc = 0;
365
+
366
+ assert( argc==2 );
367
+ len = sqlite3_value_bytes(argv[0]);
368
+ if( len==0 || len!=sqlite3_value_bytes(argv[1]) ){
369
+ rc = 1;
370
+ }else{
371
+ buf1 = sqlite3_value_text(argv[0]);
372
+ buf2 = sqlite3_value_text(argv[1]);
373
+ for( i=0; i<len; i++ ){
374
+ rc = rc | (buf1[i] ^ buf2[i]);
375
+ }
376
+ }
377
+ sqlite3_result_int(context, rc);
378
+}
352379
353380
/*
354381
** WEBPAGE: login
355382
** WEBPAGE: logout
356383
** WEBPAGE: my
@@ -371,18 +398,22 @@
371398
int uid; /* User id loged in user */
372399
char *zSha1Pw;
373400
const char *zIpAddr; /* IP address of requestor */
374401
375402
login_check_credentials();
403
+ sqlite3_create_function(g.db, "constant_time_cmp", 2, SQLITE_UTF8, 0,
404
+ constant_time_cmp_function, 0, 0);
376405
zUsername = P("u");
377406
zPasswd = P("p");
378407
anonFlag = P("anon")!=0;
379408
if( P("out")!=0 ){
380409
login_clear_login_data();
381410
redirect_to_g();
382411
}
383
- if( g.perm.Password && zPasswd && (zNew1 = P("n1"))!=0 && (zNew2 = P("n2"))!=0 ){
412
+ if( g.perm.Password && zPasswd
413
+ && (zNew1 = P("n1"))!=0 && (zNew2 = P("n2"))!=0
414
+ ){
384415
/* The user requests a password change */
385416
zSha1Pw = sha1_shared_secret(zPasswd, g.zLogin, 0);
386417
if( db_int(1, "SELECT 0 FROM user"
387418
" WHERE uid=%d"
388419
" AND (constant_time_cmp(pw,%Q)=0"
@@ -561,37 +592,10 @@
561592
@ </form>
562593
}
563594
style_footer();
564595
}
565596
566
-/*
567
-** SQL function for constant time comparison of two values.
568
-** Sets result to 0 if two values are equal.
569
-*/
570
-static void constant_time_cmp_function(
571
- sqlite3_context *context,
572
- int argc,
573
- sqlite3_value **argv
574
-){
575
- const unsigned char *buf1, *buf2;
576
- int len, i;
577
- unsigned char rc = 0;
578
-
579
- assert( argc==2 );
580
- len = sqlite3_value_bytes(argv[0]);
581
- if( len==0 || len!=sqlite3_value_bytes(argv[1]) ){
582
- rc = 1;
583
- }else{
584
- buf1 = sqlite3_value_text(argv[0]);
585
- buf2 = sqlite3_value_text(argv[1]);
586
- for( i=0; i<len; i++ ){
587
- rc = rc | (buf1[i] ^ buf2[i]);
588
- }
589
- }
590
- sqlite3_result_int(context, rc);
591
-}
592
-
593597
/*
594598
** Attempt to find login credentials for user zLogin on a peer repository
595599
** with project code zCode. Transfer those credentials to the local
596600
** repository.
597601
**
598602
--- src/login.c
+++ src/login.c
@@ -347,10 +347,37 @@
347 ** downstream problems here. We could alternately use "" here.
348 */
349 ;
350 }
351 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
352
353 /*
354 ** WEBPAGE: login
355 ** WEBPAGE: logout
356 ** WEBPAGE: my
@@ -371,18 +398,22 @@
371 int uid; /* User id loged in user */
372 char *zSha1Pw;
373 const char *zIpAddr; /* IP address of requestor */
374
375 login_check_credentials();
 
 
376 zUsername = P("u");
377 zPasswd = P("p");
378 anonFlag = P("anon")!=0;
379 if( P("out")!=0 ){
380 login_clear_login_data();
381 redirect_to_g();
382 }
383 if( g.perm.Password && zPasswd && (zNew1 = P("n1"))!=0 && (zNew2 = P("n2"))!=0 ){
 
 
384 /* The user requests a password change */
385 zSha1Pw = sha1_shared_secret(zPasswd, g.zLogin, 0);
386 if( db_int(1, "SELECT 0 FROM user"
387 " WHERE uid=%d"
388 " AND (constant_time_cmp(pw,%Q)=0"
@@ -561,37 +592,10 @@
561 @ </form>
562 }
563 style_footer();
564 }
565
566 /*
567 ** SQL function for constant time comparison of two values.
568 ** Sets result to 0 if two values are equal.
569 */
570 static void constant_time_cmp_function(
571 sqlite3_context *context,
572 int argc,
573 sqlite3_value **argv
574 ){
575 const unsigned char *buf1, *buf2;
576 int len, i;
577 unsigned char rc = 0;
578
579 assert( argc==2 );
580 len = sqlite3_value_bytes(argv[0]);
581 if( len==0 || len!=sqlite3_value_bytes(argv[1]) ){
582 rc = 1;
583 }else{
584 buf1 = sqlite3_value_text(argv[0]);
585 buf2 = sqlite3_value_text(argv[1]);
586 for( i=0; i<len; i++ ){
587 rc = rc | (buf1[i] ^ buf2[i]);
588 }
589 }
590 sqlite3_result_int(context, rc);
591 }
592
593 /*
594 ** Attempt to find login credentials for user zLogin on a peer repository
595 ** with project code zCode. Transfer those credentials to the local
596 ** repository.
597 **
598
--- src/login.c
+++ src/login.c
@@ -347,10 +347,37 @@
347 ** downstream problems here. We could alternately use "" here.
348 */
349 ;
350 }
351 }
352
353 /*
354 ** SQL function for constant time comparison of two values.
355 ** Sets result to 0 if two values are equal.
356 */
357 static void constant_time_cmp_function(
358 sqlite3_context *context,
359 int argc,
360 sqlite3_value **argv
361 ){
362 const unsigned char *buf1, *buf2;
363 int len, i;
364 unsigned char rc = 0;
365
366 assert( argc==2 );
367 len = sqlite3_value_bytes(argv[0]);
368 if( len==0 || len!=sqlite3_value_bytes(argv[1]) ){
369 rc = 1;
370 }else{
371 buf1 = sqlite3_value_text(argv[0]);
372 buf2 = sqlite3_value_text(argv[1]);
373 for( i=0; i<len; i++ ){
374 rc = rc | (buf1[i] ^ buf2[i]);
375 }
376 }
377 sqlite3_result_int(context, rc);
378 }
379
380 /*
381 ** WEBPAGE: login
382 ** WEBPAGE: logout
383 ** WEBPAGE: my
@@ -371,18 +398,22 @@
398 int uid; /* User id loged in user */
399 char *zSha1Pw;
400 const char *zIpAddr; /* IP address of requestor */
401
402 login_check_credentials();
403 sqlite3_create_function(g.db, "constant_time_cmp", 2, SQLITE_UTF8, 0,
404 constant_time_cmp_function, 0, 0);
405 zUsername = P("u");
406 zPasswd = P("p");
407 anonFlag = P("anon")!=0;
408 if( P("out")!=0 ){
409 login_clear_login_data();
410 redirect_to_g();
411 }
412 if( g.perm.Password && zPasswd
413 && (zNew1 = P("n1"))!=0 && (zNew2 = P("n2"))!=0
414 ){
415 /* The user requests a password change */
416 zSha1Pw = sha1_shared_secret(zPasswd, g.zLogin, 0);
417 if( db_int(1, "SELECT 0 FROM user"
418 " WHERE uid=%d"
419 " AND (constant_time_cmp(pw,%Q)=0"
@@ -561,37 +592,10 @@
592 @ </form>
593 }
594 style_footer();
595 }
596
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
597 /*
598 ** Attempt to find login credentials for user zLogin on a peer repository
599 ** with project code zCode. Transfer those credentials to the local
600 ** repository.
601 **
602
+2 -2
--- src/main.mk
+++ src/main.mk
@@ -320,12 +320,12 @@
320320
$(BCC) -o $(OBJDIR)/mkversion $(SRCDIR)/mkversion.c
321321
322322
# WARNING. DANGER. Running the testsuite modifies the repository the
323323
# build is done from, i.e. the checkout belongs to. Do not sync/push
324324
# the repository after running the tests.
325
-test: $(APPNAME)
326
- $(TCLSH) test/tester.tcl $(APPNAME)
325
+test: $(OBJDIR) $(APPNAME)
326
+ $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME)
327327
328328
$(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion
329329
$(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h
330330
331331
# The USE_SYSTEM_SQLITE variable may be undefined, set to 0, or set
332332
--- src/main.mk
+++ src/main.mk
@@ -320,12 +320,12 @@
320 $(BCC) -o $(OBJDIR)/mkversion $(SRCDIR)/mkversion.c
321
322 # WARNING. DANGER. Running the testsuite modifies the repository the
323 # build is done from, i.e. the checkout belongs to. Do not sync/push
324 # the repository after running the tests.
325 test: $(APPNAME)
326 $(TCLSH) test/tester.tcl $(APPNAME)
327
328 $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion
329 $(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h
330
331 # The USE_SYSTEM_SQLITE variable may be undefined, set to 0, or set
332
--- src/main.mk
+++ src/main.mk
@@ -320,12 +320,12 @@
320 $(BCC) -o $(OBJDIR)/mkversion $(SRCDIR)/mkversion.c
321
322 # WARNING. DANGER. Running the testsuite modifies the repository the
323 # build is done from, i.e. the checkout belongs to. Do not sync/push
324 # the repository after running the tests.
325 test: $(OBJDIR) $(APPNAME)
326 $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME)
327
328 $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion
329 $(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h
330
331 # The USE_SYSTEM_SQLITE variable may be undefined, set to 0, or set
332
+2 -2
--- src/main.mk
+++ src/main.mk
@@ -320,12 +320,12 @@
320320
$(BCC) -o $(OBJDIR)/mkversion $(SRCDIR)/mkversion.c
321321
322322
# WARNING. DANGER. Running the testsuite modifies the repository the
323323
# build is done from, i.e. the checkout belongs to. Do not sync/push
324324
# the repository after running the tests.
325
-test: $(APPNAME)
326
- $(TCLSH) test/tester.tcl $(APPNAME)
325
+test: $(OBJDIR) $(APPNAME)
326
+ $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME)
327327
328328
$(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion
329329
$(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h
330330
331331
# The USE_SYSTEM_SQLITE variable may be undefined, set to 0, or set
332332
--- src/main.mk
+++ src/main.mk
@@ -320,12 +320,12 @@
320 $(BCC) -o $(OBJDIR)/mkversion $(SRCDIR)/mkversion.c
321
322 # WARNING. DANGER. Running the testsuite modifies the repository the
323 # build is done from, i.e. the checkout belongs to. Do not sync/push
324 # the repository after running the tests.
325 test: $(APPNAME)
326 $(TCLSH) test/tester.tcl $(APPNAME)
327
328 $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion
329 $(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h
330
331 # The USE_SYSTEM_SQLITE variable may be undefined, set to 0, or set
332
--- src/main.mk
+++ src/main.mk
@@ -320,12 +320,12 @@
320 $(BCC) -o $(OBJDIR)/mkversion $(SRCDIR)/mkversion.c
321
322 # WARNING. DANGER. Running the testsuite modifies the repository the
323 # build is done from, i.e. the checkout belongs to. Do not sync/push
324 # the repository after running the tests.
325 test: $(OBJDIR) $(APPNAME)
326 $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME)
327
328 $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion
329 $(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h
330
331 # The USE_SYSTEM_SQLITE variable may be undefined, set to 0, or set
332
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -193,12 +193,12 @@
193193
$(BCC) -o $(OBJDIR)/mkversion $(SRCDIR)/mkversion.c
194194
195195
# WARNING. DANGER. Running the testsuite modifies the repository the
196196
# build is done from, i.e. the checkout belongs to. Do not sync/push
197197
# the repository after running the tests.
198
-test: $(APPNAME)
199
- $(TCLSH) test/tester.tcl $(APPNAME)
198
+test: $(OBJDIR) $(APPNAME)
199
+ $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME)
200200
201201
$(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion
202202
$(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid \
203203
$(SRCDIR)/../manifest \
204204
$(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h
205205
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -193,12 +193,12 @@
193 $(BCC) -o $(OBJDIR)/mkversion $(SRCDIR)/mkversion.c
194
195 # WARNING. DANGER. Running the testsuite modifies the repository the
196 # build is done from, i.e. the checkout belongs to. Do not sync/push
197 # the repository after running the tests.
198 test: $(APPNAME)
199 $(TCLSH) test/tester.tcl $(APPNAME)
200
201 $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion
202 $(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid \
203 $(SRCDIR)/../manifest \
204 $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h
205
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -193,12 +193,12 @@
193 $(BCC) -o $(OBJDIR)/mkversion $(SRCDIR)/mkversion.c
194
195 # WARNING. DANGER. Running the testsuite modifies the repository the
196 # build is done from, i.e. the checkout belongs to. Do not sync/push
197 # the repository after running the tests.
198 test: $(OBJDIR) $(APPNAME)
199 $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME)
200
201 $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion
202 $(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid \
203 $(SRCDIR)/../manifest \
204 $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h
205
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -193,12 +193,12 @@
193193
$(BCC) -o $(OBJDIR)/mkversion $(SRCDIR)/mkversion.c
194194
195195
# WARNING. DANGER. Running the testsuite modifies the repository the
196196
# build is done from, i.e. the checkout belongs to. Do not sync/push
197197
# the repository after running the tests.
198
-test: $(APPNAME)
199
- $(TCLSH) test/tester.tcl $(APPNAME)
198
+test: $(OBJDIR) $(APPNAME)
199
+ $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME)
200200
201201
$(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion
202202
$(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid \
203203
$(SRCDIR)/../manifest \
204204
$(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h
205205
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -193,12 +193,12 @@
193 $(BCC) -o $(OBJDIR)/mkversion $(SRCDIR)/mkversion.c
194
195 # WARNING. DANGER. Running the testsuite modifies the repository the
196 # build is done from, i.e. the checkout belongs to. Do not sync/push
197 # the repository after running the tests.
198 test: $(APPNAME)
199 $(TCLSH) test/tester.tcl $(APPNAME)
200
201 $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion
202 $(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid \
203 $(SRCDIR)/../manifest \
204 $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h
205
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -193,12 +193,12 @@
193 $(BCC) -o $(OBJDIR)/mkversion $(SRCDIR)/mkversion.c
194
195 # WARNING. DANGER. Running the testsuite modifies the repository the
196 # build is done from, i.e. the checkout belongs to. Do not sync/push
197 # the repository after running the tests.
198 test: $(OBJDIR) $(APPNAME)
199 $(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME)
200
201 $(OBJDIR)/VERSION.h: $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION $(OBJDIR)/mkversion
202 $(OBJDIR)/mkversion $(SRCDIR)/../manifest.uuid \
203 $(SRCDIR)/../manifest \
204 $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h
205
+2 -2
--- src/merge3.c
+++ src/merge3.c
@@ -171,12 +171,12 @@
171171
** is the number of lines of text to copy directly from the pivot,
172172
** the second integer is the number of lines of text to omit from the
173173
** pivot, and the third integer is the number of lines of text that are
174174
** inserted. The edit array ends with a triple of 0,0,0.
175175
*/
176
- aC1 = text_diff(pPivot, pV1, 0, 0, 0);
177
- aC2 = text_diff(pPivot, pV2, 0, 0, 0);
176
+ aC1 = text_diff(pPivot, pV1, 0, 0);
177
+ aC2 = text_diff(pPivot, pV2, 0, 0);
178178
if( aC1==0 || aC2==0 ){
179179
free(aC1);
180180
free(aC2);
181181
return -1;
182182
}
183183
--- src/merge3.c
+++ src/merge3.c
@@ -171,12 +171,12 @@
171 ** is the number of lines of text to copy directly from the pivot,
172 ** the second integer is the number of lines of text to omit from the
173 ** pivot, and the third integer is the number of lines of text that are
174 ** inserted. The edit array ends with a triple of 0,0,0.
175 */
176 aC1 = text_diff(pPivot, pV1, 0, 0, 0);
177 aC2 = text_diff(pPivot, pV2, 0, 0, 0);
178 if( aC1==0 || aC2==0 ){
179 free(aC1);
180 free(aC2);
181 return -1;
182 }
183
--- src/merge3.c
+++ src/merge3.c
@@ -171,12 +171,12 @@
171 ** is the number of lines of text to copy directly from the pivot,
172 ** the second integer is the number of lines of text to omit from the
173 ** pivot, and the third integer is the number of lines of text that are
174 ** inserted. The edit array ends with a triple of 0,0,0.
175 */
176 aC1 = text_diff(pPivot, pV1, 0, 0);
177 aC2 = text_diff(pPivot, pV2, 0, 0);
178 if( aC1==0 || aC2==0 ){
179 free(aC1);
180 free(aC2);
181 return -1;
182 }
183
+1 -1
--- src/printf.c
+++ src/printf.c
@@ -545,11 +545,11 @@
545545
buf[0] = '%';
546546
bufpt = buf;
547547
length = 1;
548548
break;
549549
case etCHARX:
550
- c = buf[0] = (xtype==etCHARX ? va_arg(ap,int) : *++fmt);
550
+ c = buf[0] = va_arg(ap,int);
551551
if( precision>=0 ){
552552
for(idx=1; idx<precision; idx++) buf[idx] = c;
553553
length = precision;
554554
}else{
555555
length =1;
556556
--- src/printf.c
+++ src/printf.c
@@ -545,11 +545,11 @@
545 buf[0] = '%';
546 bufpt = buf;
547 length = 1;
548 break;
549 case etCHARX:
550 c = buf[0] = (xtype==etCHARX ? va_arg(ap,int) : *++fmt);
551 if( precision>=0 ){
552 for(idx=1; idx<precision; idx++) buf[idx] = c;
553 length = precision;
554 }else{
555 length =1;
556
--- src/printf.c
+++ src/printf.c
@@ -545,11 +545,11 @@
545 buf[0] = '%';
546 bufpt = buf;
547 length = 1;
548 break;
549 case etCHARX:
550 c = buf[0] = va_arg(ap,int);
551 if( precision>=0 ){
552 for(idx=1; idx<precision; idx++) buf[idx] = c;
553 length = precision;
554 }else{
555 length =1;
556
+1 -1
--- src/report.c
+++ src/report.c
@@ -1116,11 +1116,11 @@
11161116
if( rn ){
11171117
db_prepare(&q,
11181118
"SELECT sqlcode FROM reportfmt WHERE rn=%d", rn);
11191119
}else{
11201120
db_prepare(&q,
1121
- "SELECT sqlcode FROM reportfmt WHERE title='%s'", zRep);
1121
+ "SELECT sqlcode FROM reportfmt WHERE title=%Q", zRep);
11221122
}
11231123
if( db_step(&q)!=SQLITE_ROW ){
11241124
db_finalize(&q);
11251125
rpt_list_reports();
11261126
fossil_fatal("unknown report format(%s)!",zRep);
11271127
--- src/report.c
+++ src/report.c
@@ -1116,11 +1116,11 @@
1116 if( rn ){
1117 db_prepare(&q,
1118 "SELECT sqlcode FROM reportfmt WHERE rn=%d", rn);
1119 }else{
1120 db_prepare(&q,
1121 "SELECT sqlcode FROM reportfmt WHERE title='%s'", zRep);
1122 }
1123 if( db_step(&q)!=SQLITE_ROW ){
1124 db_finalize(&q);
1125 rpt_list_reports();
1126 fossil_fatal("unknown report format(%s)!",zRep);
1127
--- src/report.c
+++ src/report.c
@@ -1116,11 +1116,11 @@
1116 if( rn ){
1117 db_prepare(&q,
1118 "SELECT sqlcode FROM reportfmt WHERE rn=%d", rn);
1119 }else{
1120 db_prepare(&q,
1121 "SELECT sqlcode FROM reportfmt WHERE title=%Q", zRep);
1122 }
1123 if( db_step(&q)!=SQLITE_ROW ){
1124 db_finalize(&q);
1125 rpt_list_reports();
1126 fossil_fatal("unknown report format(%s)!",zRep);
1127
+1 -1
--- src/report.c
+++ src/report.c
@@ -1116,11 +1116,11 @@
11161116
if( rn ){
11171117
db_prepare(&q,
11181118
"SELECT sqlcode FROM reportfmt WHERE rn=%d", rn);
11191119
}else{
11201120
db_prepare(&q,
1121
- "SELECT sqlcode FROM reportfmt WHERE title='%s'", zRep);
1121
+ "SELECT sqlcode FROM reportfmt WHERE title=%Q", zRep);
11221122
}
11231123
if( db_step(&q)!=SQLITE_ROW ){
11241124
db_finalize(&q);
11251125
rpt_list_reports();
11261126
fossil_fatal("unknown report format(%s)!",zRep);
11271127
--- src/report.c
+++ src/report.c
@@ -1116,11 +1116,11 @@
1116 if( rn ){
1117 db_prepare(&q,
1118 "SELECT sqlcode FROM reportfmt WHERE rn=%d", rn);
1119 }else{
1120 db_prepare(&q,
1121 "SELECT sqlcode FROM reportfmt WHERE title='%s'", zRep);
1122 }
1123 if( db_step(&q)!=SQLITE_ROW ){
1124 db_finalize(&q);
1125 rpt_list_reports();
1126 fossil_fatal("unknown report format(%s)!",zRep);
1127
--- src/report.c
+++ src/report.c
@@ -1116,11 +1116,11 @@
1116 if( rn ){
1117 db_prepare(&q,
1118 "SELECT sqlcode FROM reportfmt WHERE rn=%d", rn);
1119 }else{
1120 db_prepare(&q,
1121 "SELECT sqlcode FROM reportfmt WHERE title=%Q", zRep);
1122 }
1123 if( db_step(&q)!=SQLITE_ROW ){
1124 db_finalize(&q);
1125 rpt_list_reports();
1126 fossil_fatal("unknown report format(%s)!",zRep);
1127
+573 -170
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -656,11 +656,11 @@
656656
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
657657
** [sqlite_version()] and [sqlite_source_id()].
658658
*/
659659
#define SQLITE_VERSION "3.7.9"
660660
#define SQLITE_VERSION_NUMBER 3007009
661
-#define SQLITE_SOURCE_ID "2011-10-15 00:16:30 39408702a989f907261c298bf0947f3e68bd10fe"
661
+#define SQLITE_SOURCE_ID "2011-10-20 00:55:54 4344483f7d7f64dffadde0053e6c745948db9486"
662662
663663
/*
664664
** CAPI3REF: Run-Time Library Version Numbers
665665
** KEYWORDS: sqlite3_version, sqlite3_sourceid
666666
**
@@ -1951,12 +1951,12 @@
19511951
** memory pointer is not NULL and either [SQLITE_ENABLE_MEMSYS3] or
19521952
** [SQLITE_ENABLE_MEMSYS5] are defined, then the alternative memory
19531953
** allocator is engaged to handle all of SQLites memory allocation needs.
19541954
** The first pointer (the memory pointer) must be aligned to an 8-byte
19551955
** boundary or subsequent behavior of SQLite will be undefined.
1956
-** The minimum allocation size is capped at 2^12. Reasonable values
1957
-** for the minimum allocation size are 2^5 through 2^8.</dd>
1956
+** The minimum allocation size is capped at 2**12. Reasonable values
1957
+** for the minimum allocation size are 2**5 through 2**8.</dd>
19581958
**
19591959
** [[SQLITE_CONFIG_MUTEX]] <dt>SQLITE_CONFIG_MUTEX</dt>
19601960
** <dd> ^(This option takes a single argument which is a pointer to an
19611961
** instance of the [sqlite3_mutex_methods] structure. The argument specifies
19621962
** alternative low-level mutex routines to be used in place
@@ -20969,11 +20969,11 @@
2096920969
}else if( *z=='+' ){
2097020970
z+=incr;
2097120971
}
2097220972
/* copy digits to exponent */
2097320973
while( z<zEnd && sqlite3Isdigit(*z) ){
20974
- e = e*10 + (*z - '0');
20974
+ e = e<10000 ? (e*10 + (*z - '0')) : 10000;
2097520975
z+=incr;
2097620976
eValid = 1;
2097720977
}
2097820978
}
2097920979
@@ -21020,10 +21020,16 @@
2102021020
result /= 1.0e+308;
2102121021
}else{
2102221022
result = s * scale;
2102321023
result *= 1.0e+308;
2102421024
}
21025
+ }else if( e>=342 ){
21026
+ if( esign<0 ){
21027
+ result = 0.0*s;
21028
+ }else{
21029
+ result = 1e308*1e308*s; /* Infinity */
21030
+ }
2102521031
}else{
2102621032
/* 1.0e+22 is the largest power of 10 than can be
2102721033
** represented exactly. */
2102821034
while( e%22 ) { scale *= 1.0e+1; e -= 1; }
2102921035
while( e>0 ) { scale *= 1.0e+22; e -= 22; }
@@ -68962,11 +68968,11 @@
6896268968
6896368969
/* Do not allow a transition to journal_mode=WAL for a database
6896468970
** in temporary storage or if the VFS does not support shared memory
6896568971
*/
6896668972
if( u.ch.eNew==PAGER_JOURNALMODE_WAL
68967
- && (u.ch.zFilename[0]==0 /* Temp file */
68973
+ && (sqlite3Strlen30(u.ch.zFilename)==0 /* Temp file */
6896868974
|| !sqlite3PagerWalSupported(u.ch.pPager)) /* No shared-memory support */
6896968975
){
6897068976
u.ch.eNew = u.ch.eOld;
6897168977
}
6897268978
@@ -69397,14 +69403,19 @@
6939769403
u.co.pName = &aMem[pOp->p1];
6939869404
assert( u.co.pVtab->pModule->xRename );
6939969405
assert( memIsValid(u.co.pName) );
6940069406
REGISTER_TRACE(pOp->p1, u.co.pName);
6940169407
assert( u.co.pName->flags & MEM_Str );
69402
- rc = u.co.pVtab->pModule->xRename(u.co.pVtab, u.co.pName->z);
69403
- importVtabErrMsg(p, u.co.pVtab);
69404
- p->expired = 0;
69405
-
69408
+ testcase( u.co.pName->enc==SQLITE_UTF8 );
69409
+ testcase( u.co.pName->enc==SQLITE_UTF16BE );
69410
+ testcase( u.co.pName->enc==SQLITE_UTF16LE );
69411
+ rc = sqlite3VdbeChangeEncoding(u.co.pName, SQLITE_UTF8);
69412
+ if( rc==SQLITE_OK ){
69413
+ rc = u.co.pVtab->pModule->xRename(u.co.pVtab, u.co.pName->z);
69414
+ importVtabErrMsg(p, u.co.pVtab);
69415
+ p->expired = 0;
69416
+ }
6940669417
break;
6940769418
}
6940869419
#endif
6940969420
6941069421
#ifndef SQLITE_OMIT_VIRTUALTABLE
@@ -71758,10 +71769,28 @@
7175871769
ExprSetProperty(pExpr, EP_Static);
7175971770
sqlite3ExprDelete(db, pExpr);
7176071771
memcpy(pExpr, pDup, sizeof(*pExpr));
7176171772
sqlite3DbFree(db, pDup);
7176271773
}
71774
+
71775
+
71776
+/*
71777
+** Return TRUE if the name zCol occurs anywhere in the USING clause.
71778
+**
71779
+** Return FALSE if the USING clause is NULL or if it does not contain
71780
+** zCol.
71781
+*/
71782
+static int nameInUsingClause(IdList *pUsing, const char *zCol){
71783
+ if( pUsing ){
71784
+ int k;
71785
+ for(k=0; k<pUsing->nId; k++){
71786
+ if( sqlite3StrICmp(pUsing->a[k].zName, zCol)==0 ) return 1;
71787
+ }
71788
+ }
71789
+ return 0;
71790
+}
71791
+
7176371792
7176471793
/*
7176571794
** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up
7176671795
** that name in the set of source tables in pSrcList and make the pExpr
7176771796
** expression node refer back to that source column. The following changes
@@ -71850,38 +71879,25 @@
7185071879
pSchema = pTab->pSchema;
7185171880
pMatch = pItem;
7185271881
}
7185371882
for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){
7185471883
if( sqlite3StrICmp(pCol->zName, zCol)==0 ){
71855
- IdList *pUsing;
71884
+ /* If there has been exactly one prior match and this match
71885
+ ** is for the right-hand table of a NATURAL JOIN or is in a
71886
+ ** USING clause, then skip this match.
71887
+ */
71888
+ if( cnt==1 ){
71889
+ if( pItem->jointype & JT_NATURAL ) continue;
71890
+ if( nameInUsingClause(pItem->pUsing, zCol) ) continue;
71891
+ }
7185671892
cnt++;
7185771893
pExpr->iTable = pItem->iCursor;
7185871894
pExpr->pTab = pTab;
7185971895
pMatch = pItem;
7186071896
pSchema = pTab->pSchema;
7186171897
/* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
7186271898
pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j;
71863
- if( i<pSrcList->nSrc-1 ){
71864
- if( pItem[1].jointype & JT_NATURAL ){
71865
- /* If this match occurred in the left table of a natural join,
71866
- ** then skip the right table to avoid a duplicate match */
71867
- pItem++;
71868
- i++;
71869
- }else if( (pUsing = pItem[1].pUsing)!=0 ){
71870
- /* If this match occurs on a column that is in the USING clause
71871
- ** of a join, skip the search of the right table of the join
71872
- ** to avoid a duplicate match there. */
71873
- int k;
71874
- for(k=0; k<pUsing->nId; k++){
71875
- if( sqlite3StrICmp(pUsing->a[k].zName, zCol)==0 ){
71876
- pItem++;
71877
- i++;
71878
- break;
71879
- }
71880
- }
71881
- }
71882
- }
7188371899
break;
7188471900
}
7188571901
}
7188671902
}
7188771903
}
@@ -102501,10 +102517,11 @@
102501102517
tempWC.pParse = pWC->pParse;
102502102518
tempWC.pMaskSet = pWC->pMaskSet;
102503102519
tempWC.pOuter = pWC;
102504102520
tempWC.op = TK_AND;
102505102521
tempWC.a = pOrTerm;
102522
+ tempWC.wctrlFlags = 0;
102506102523
tempWC.nTerm = 1;
102507102524
bestIndex(pParse, &tempWC, pSrc, notReady, notValid, 0, &sTermCost);
102508102525
}else{
102509102526
continue;
102510102527
}
@@ -114528,10 +114545,11 @@
114528114545
const char *zDb; /* logical database name */
114529114546
const char *zName; /* virtual table name */
114530114547
int nColumn; /* number of named columns in virtual table */
114531114548
char **azColumn; /* column names. malloced */
114532114549
sqlite3_tokenizer *pTokenizer; /* tokenizer for inserts and queries */
114550
+ char *zContentTbl; /* content=xxx option, or NULL */
114533114551
114534114552
/* Precompiled statements used by the implementation. Each of these
114535114553
** statements is run and reset within a single virtual table API call.
114536114554
*/
114537114555
sqlite3_stmt *aStmt[27];
@@ -114568,11 +114586,11 @@
114568114586
} *aIndex;
114569114587
int nMaxPendingData; /* Max pending data before flush to disk */
114570114588
int nPendingData; /* Current bytes of pending data */
114571114589
sqlite_int64 iPrevDocid; /* Docid of most recently inserted document */
114572114590
114573
-#if defined(SQLITE_DEBUG)
114591
+#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
114574114592
/* State variables used for validating that the transaction control
114575114593
** methods of the virtual table are called at appropriate times. These
114576114594
** values do not contribution to the FTS computation; they are used for
114577114595
** verifying the SQLite core.
114578114596
*/
@@ -114653,10 +114671,11 @@
114653114671
*/
114654114672
struct Fts3PhraseToken {
114655114673
char *z; /* Text of the token */
114656114674
int n; /* Number of bytes in buffer z */
114657114675
int isPrefix; /* True if token ends with a "*" character */
114676
+ int bFirst; /* True if token must appear at position 0 */
114658114677
114659114678
/* Variables above this point are populated when the expression is
114660114679
** parsed (by code in fts3_expr.c). Below this point the variables are
114661114680
** used when evaluating the expression. */
114662114681
Fts3DeferredToken *pDeferred; /* Deferred token object for this token */
@@ -114771,10 +114790,11 @@
114771114790
#define FTS3_SEGMENT_REQUIRE_POS 0x00000001
114772114791
#define FTS3_SEGMENT_IGNORE_EMPTY 0x00000002
114773114792
#define FTS3_SEGMENT_COLUMN_FILTER 0x00000004
114774114793
#define FTS3_SEGMENT_PREFIX 0x00000008
114775114794
#define FTS3_SEGMENT_SCAN 0x00000010
114795
+#define FTS3_SEGMENT_FIRST 0x00000020
114776114796
114777114797
/* Type passed as 4th argument to SegmentReaderIterate() */
114778114798
struct Fts3SegFilter {
114779114799
const char *zTerm;
114780114800
int nTerm;
@@ -114810,12 +114830,12 @@
114810114830
SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *, sqlite_int64 *);
114811114831
SQLITE_PRIVATE int sqlite3Fts3GetVarint32(const char *, int *);
114812114832
SQLITE_PRIVATE int sqlite3Fts3VarintLen(sqlite3_uint64);
114813114833
SQLITE_PRIVATE void sqlite3Fts3Dequote(char *);
114814114834
SQLITE_PRIVATE void sqlite3Fts3DoclistPrev(int,char*,int,char**,sqlite3_int64*,int*,u8*);
114815
-
114816114835
SQLITE_PRIVATE int sqlite3Fts3EvalPhraseStats(Fts3Cursor *, Fts3Expr *, u32 *);
114836
+SQLITE_PRIVATE int sqlite3Fts3FirstFilter(sqlite3_int64, char *, int, char *);
114817114837
114818114838
/* fts3_tokenizer.c */
114819114839
SQLITE_PRIVATE const char *sqlite3Fts3NextToken(const char *, int *);
114820114840
SQLITE_PRIVATE int sqlite3Fts3InitHashTable(sqlite3 *, Fts3Hash *, const char *);
114821114841
SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(Fts3Hash *pHash, const char *,
@@ -114830,11 +114850,11 @@
114830114850
);
114831114851
SQLITE_PRIVATE void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *, const char *);
114832114852
114833114853
/* fts3_expr.c */
114834114854
SQLITE_PRIVATE int sqlite3Fts3ExprParse(sqlite3_tokenizer *,
114835
- char **, int, int, const char *, int, Fts3Expr **
114855
+ char **, int, int, int, const char *, int, Fts3Expr **
114836114856
);
114837114857
SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *);
114838114858
#ifdef SQLITE_TEST
114839114859
SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3 *db);
114840114860
SQLITE_PRIVATE int sqlite3Fts3InitTerm(sqlite3 *db);
@@ -115031,10 +115051,11 @@
115031115051
sqlite3_finalize(p->aStmt[i]);
115032115052
}
115033115053
sqlite3_free(p->zSegmentsTbl);
115034115054
sqlite3_free(p->zReadExprlist);
115035115055
sqlite3_free(p->zWriteExprlist);
115056
+ sqlite3_free(p->zContentTbl);
115036115057
115037115058
/* Invoke the tokenizer destructor to free the tokenizer. */
115038115059
p->pTokenizer->pModule->xDestroy(p->pTokenizer);
115039115060
115040115061
sqlite3_free(p);
@@ -115070,20 +115091,23 @@
115070115091
115071115092
/*
115072115093
** The xDestroy() virtual table method.
115073115094
*/
115074115095
static int fts3DestroyMethod(sqlite3_vtab *pVtab){
115075
- int rc = SQLITE_OK; /* Return code */
115076115096
Fts3Table *p = (Fts3Table *)pVtab;
115077
- sqlite3 *db = p->db;
115097
+ int rc = SQLITE_OK; /* Return code */
115098
+ const char *zDb = p->zDb; /* Name of database (e.g. "main", "temp") */
115099
+ sqlite3 *db = p->db; /* Database handle */
115078115100
115079115101
/* Drop the shadow tables */
115080
- fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_content'", p->zDb, p->zName);
115081
- fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segments'", p->zDb,p->zName);
115082
- fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segdir'", p->zDb, p->zName);
115083
- fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_docsize'", p->zDb, p->zName);
115084
- fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_stat'", p->zDb, p->zName);
115102
+ if( p->zContentTbl==0 ){
115103
+ fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_content'", zDb, p->zName);
115104
+ }
115105
+ fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segments'", zDb,p->zName);
115106
+ fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segdir'", zDb, p->zName);
115107
+ fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_docsize'", zDb, p->zName);
115108
+ fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_stat'", zDb, p->zName);
115085115109
115086115110
/* If everything has worked, invoke fts3DisconnectMethod() to free the
115087115111
** memory associated with the Fts3Table structure and return SQLITE_OK.
115088115112
** Otherwise, return an SQLite error code.
115089115113
*/
@@ -115141,27 +115165,31 @@
115141115165
** %_stat tables required by FTS4.
115142115166
*/
115143115167
static int fts3CreateTables(Fts3Table *p){
115144115168
int rc = SQLITE_OK; /* Return code */
115145115169
int i; /* Iterator variable */
115146
- char *zContentCols; /* Columns of %_content table */
115147115170
sqlite3 *db = p->db; /* The database connection */
115148115171
115149
- /* Create a list of user columns for the content table */
115150
- zContentCols = sqlite3_mprintf("docid INTEGER PRIMARY KEY");
115151
- for(i=0; zContentCols && i<p->nColumn; i++){
115152
- char *z = p->azColumn[i];
115153
- zContentCols = sqlite3_mprintf("%z, 'c%d%q'", zContentCols, i, z);
115154
- }
115155
- if( zContentCols==0 ) rc = SQLITE_NOMEM;
115156
-
115157
- /* Create the content table */
115158
- fts3DbExec(&rc, db,
115159
- "CREATE TABLE %Q.'%q_content'(%s)",
115160
- p->zDb, p->zName, zContentCols
115161
- );
115162
- sqlite3_free(zContentCols);
115172
+ if( p->zContentTbl==0 ){
115173
+ char *zContentCols; /* Columns of %_content table */
115174
+
115175
+ /* Create a list of user columns for the content table */
115176
+ zContentCols = sqlite3_mprintf("docid INTEGER PRIMARY KEY");
115177
+ for(i=0; zContentCols && i<p->nColumn; i++){
115178
+ char *z = p->azColumn[i];
115179
+ zContentCols = sqlite3_mprintf("%z, 'c%d%q'", zContentCols, i, z);
115180
+ }
115181
+ if( zContentCols==0 ) rc = SQLITE_NOMEM;
115182
+
115183
+ /* Create the content table */
115184
+ fts3DbExec(&rc, db,
115185
+ "CREATE TABLE %Q.'%q_content'(%s)",
115186
+ p->zDb, p->zName, zContentCols
115187
+ );
115188
+ sqlite3_free(zContentCols);
115189
+ }
115190
+
115163115191
/* Create other tables */
115164115192
fts3DbExec(&rc, db,
115165115193
"CREATE TABLE %Q.'%q_segments'(blockid INTEGER PRIMARY KEY, block BLOB);",
115166115194
p->zDb, p->zName
115167115195
);
@@ -115308,12 +115336,12 @@
115308115336
}
115309115337
return zRet;
115310115338
}
115311115339
115312115340
/*
115313
-** Return a list of comma separated SQL expressions that could be used
115314
-** in a SELECT statement such as the following:
115341
+** Return a list of comma separated SQL expressions and a FROM clause that
115342
+** could be used in a SELECT statement such as the following:
115315115343
**
115316115344
** SELECT <list of expressions> FROM %_content AS x ...
115317115345
**
115318115346
** to return the docid, followed by each column of text data in order
115319115347
** from left to write. If parameter zFunc is not NULL, then instead of
@@ -115320,11 +115348,11 @@
115320115348
** being returned directly each column of text data is passed to an SQL
115321115349
** function named zFunc first. For example, if zFunc is "unzip" and the
115322115350
** table has the three user-defined columns "a", "b", and "c", the following
115323115351
** string is returned:
115324115352
**
115325
-** "docid, unzip(x.'a'), unzip(x.'b'), unzip(x.'c')"
115353
+** "docid, unzip(x.'a'), unzip(x.'b'), unzip(x.'c') FROM %_content AS x"
115326115354
**
115327115355
** The pointer returned points to a buffer allocated by sqlite3_malloc(). It
115328115356
** is the responsibility of the caller to eventually free it.
115329115357
**
115330115358
** If *pRc is not SQLITE_OK when this function is called, it is a no-op (and
@@ -115336,20 +115364,32 @@
115336115364
char *zRet = 0;
115337115365
char *zFree = 0;
115338115366
char *zFunction;
115339115367
int i;
115340115368
115341
- if( !zFunc ){
115342
- zFunction = "";
115369
+ if( p->zContentTbl==0 ){
115370
+ if( !zFunc ){
115371
+ zFunction = "";
115372
+ }else{
115373
+ zFree = zFunction = fts3QuoteId(zFunc);
115374
+ }
115375
+ fts3Appendf(pRc, &zRet, "docid");
115376
+ for(i=0; i<p->nColumn; i++){
115377
+ fts3Appendf(pRc, &zRet, ",%s(x.'c%d%q')", zFunction, i, p->azColumn[i]);
115378
+ }
115379
+ sqlite3_free(zFree);
115343115380
}else{
115344
- zFree = zFunction = fts3QuoteId(zFunc);
115381
+ fts3Appendf(pRc, &zRet, "rowid");
115382
+ for(i=0; i<p->nColumn; i++){
115383
+ fts3Appendf(pRc, &zRet, ", x.'%q'", p->azColumn[i]);
115384
+ }
115345115385
}
115346
- fts3Appendf(pRc, &zRet, "docid");
115347
- for(i=0; i<p->nColumn; i++){
115348
- fts3Appendf(pRc, &zRet, ",%s(x.'c%d%q')", zFunction, i, p->azColumn[i]);
115349
- }
115350
- sqlite3_free(zFree);
115386
+ fts3Appendf(pRc, &zRet, "FROM '%q'.'%q%s' AS x",
115387
+ p->zDb,
115388
+ (p->zContentTbl ? p->zContentTbl : p->zName),
115389
+ (p->zContentTbl ? "" : "_content")
115390
+ );
115351115391
return zRet;
115352115392
}
115353115393
115354115394
/*
115355115395
** Return a list of N comma separated question marks, where N is the number
@@ -115468,10 +115508,95 @@
115468115508
}
115469115509
}
115470115510
115471115511
return SQLITE_OK;
115472115512
}
115513
+
115514
+/*
115515
+** This function is called when initializing an FTS4 table that uses the
115516
+** content=xxx option. It determines the number of and names of the columns
115517
+** of the new FTS4 table.
115518
+**
115519
+** The third argument passed to this function is the value passed to the
115520
+** config=xxx option (i.e. "xxx"). This function queries the database for
115521
+** a table of that name. If found, the output variables are populated
115522
+** as follows:
115523
+**
115524
+** *pnCol: Set to the number of columns table xxx has,
115525
+**
115526
+** *pnStr: Set to the total amount of space required to store a copy
115527
+** of each columns name, including the nul-terminator.
115528
+**
115529
+** *pazCol: Set to point to an array of *pnCol strings. Each string is
115530
+** the name of the corresponding column in table xxx. The array
115531
+** and its contents are allocated using a single allocation. It
115532
+** is the responsibility of the caller to free this allocation
115533
+** by eventually passing the *pazCol value to sqlite3_free().
115534
+**
115535
+** If the table cannot be found, an error code is returned and the output
115536
+** variables are undefined. Or, if an OOM is encountered, SQLITE_NOMEM is
115537
+** returned (and the output variables are undefined).
115538
+*/
115539
+static int fts3ContentColumns(
115540
+ sqlite3 *db, /* Database handle */
115541
+ const char *zDb, /* Name of db (i.e. "main", "temp" etc.) */
115542
+ const char *zTbl, /* Name of content table */
115543
+ const char ***pazCol, /* OUT: Malloc'd array of column names */
115544
+ int *pnCol, /* OUT: Size of array *pazCol */
115545
+ int *pnStr /* OUT: Bytes of string content */
115546
+){
115547
+ int rc = SQLITE_OK; /* Return code */
115548
+ char *zSql; /* "SELECT *" statement on zTbl */
115549
+ sqlite3_stmt *pStmt = 0; /* Compiled version of zSql */
115550
+
115551
+ zSql = sqlite3_mprintf("SELECT * FROM %Q.%Q", zDb, zTbl);
115552
+ if( !zSql ){
115553
+ rc = SQLITE_NOMEM;
115554
+ }else{
115555
+ rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
115556
+ }
115557
+ sqlite3_free(zSql);
115558
+
115559
+ if( rc==SQLITE_OK ){
115560
+ const char **azCol; /* Output array */
115561
+ int nStr = 0; /* Size of all column names (incl. 0x00) */
115562
+ int nCol; /* Number of table columns */
115563
+ int i; /* Used to iterate through columns */
115564
+
115565
+ /* Loop through the returned columns. Set nStr to the number of bytes of
115566
+ ** space required to store a copy of each column name, including the
115567
+ ** nul-terminator byte. */
115568
+ nCol = sqlite3_column_count(pStmt);
115569
+ for(i=0; i<nCol; i++){
115570
+ const char *zCol = sqlite3_column_name(pStmt, i);
115571
+ nStr += strlen(zCol) + 1;
115572
+ }
115573
+
115574
+ /* Allocate and populate the array to return. */
115575
+ azCol = (const char **)sqlite3_malloc(sizeof(char *) * nCol + nStr);
115576
+ if( azCol==0 ){
115577
+ rc = SQLITE_NOMEM;
115578
+ }else{
115579
+ char *p = (char *)&azCol[nCol];
115580
+ for(i=0; i<nCol; i++){
115581
+ const char *zCol = sqlite3_column_name(pStmt, i);
115582
+ int n = strlen(zCol)+1;
115583
+ memcpy(p, zCol, n);
115584
+ azCol[i] = p;
115585
+ p += n;
115586
+ }
115587
+ }
115588
+ sqlite3_finalize(pStmt);
115589
+
115590
+ /* Set the output variables. */
115591
+ *pnCol = nCol;
115592
+ *pnStr = nStr;
115593
+ *pazCol = azCol;
115594
+ }
115595
+
115596
+ return rc;
115597
+}
115473115598
115474115599
/*
115475115600
** This function is the implementation of both the xConnect and xCreate
115476115601
** methods of the FTS3 virtual table.
115477115602
**
@@ -115513,10 +115638,11 @@
115513115638
int bNoDocsize = 0; /* True to omit %_docsize table */
115514115639
int bDescIdx = 0; /* True to store descending indexes */
115515115640
char *zPrefix = 0; /* Prefix parameter value (or NULL) */
115516115641
char *zCompress = 0; /* compress=? parameter (or NULL) */
115517115642
char *zUncompress = 0; /* uncompress=? parameter (or NULL) */
115643
+ char *zContent = 0; /* content=? parameter (or NULL) */
115518115644
115519115645
assert( strlen(argv[0])==4 );
115520115646
assert( (sqlite3_strnicmp(argv[0], "fts4", 4)==0 && isFts4)
115521115647
|| (sqlite3_strnicmp(argv[0], "fts3", 4)==0 && !isFts4)
115522115648
);
@@ -115556,17 +115682,17 @@
115556115682
/* Check if it is an FTS4 special argument. */
115557115683
else if( isFts4 && fts3IsSpecialColumn(z, &nKey, &zVal) ){
115558115684
struct Fts4Option {
115559115685
const char *zOpt;
115560115686
int nOpt;
115561
- char **pzVar;
115562115687
} aFts4Opt[] = {
115563
- { "matchinfo", 9, 0 }, /* 0 -> MATCHINFO */
115564
- { "prefix", 6, 0 }, /* 1 -> PREFIX */
115565
- { "compress", 8, 0 }, /* 2 -> COMPRESS */
115566
- { "uncompress", 10, 0 }, /* 3 -> UNCOMPRESS */
115567
- { "order", 5, 0 } /* 4 -> ORDER */
115688
+ { "matchinfo", 9 }, /* 0 -> MATCHINFO */
115689
+ { "prefix", 6 }, /* 1 -> PREFIX */
115690
+ { "compress", 8 }, /* 2 -> COMPRESS */
115691
+ { "uncompress", 10 }, /* 3 -> UNCOMPRESS */
115692
+ { "order", 5 }, /* 4 -> ORDER */
115693
+ { "content", 7 } /* 5 -> CONTENT */
115568115694
};
115569115695
115570115696
int iOpt;
115571115697
if( !zVal ){
115572115698
rc = SQLITE_NOMEM;
@@ -115608,17 +115734,24 @@
115608115734
zVal = 0;
115609115735
break;
115610115736
115611115737
case 4: /* ORDER */
115612115738
if( (strlen(zVal)!=3 || sqlite3_strnicmp(zVal, "asc", 3))
115613
- && (strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "desc", 3))
115739
+ && (strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "desc", 4))
115614115740
){
115615115741
*pzErr = sqlite3_mprintf("unrecognized order: %s", zVal);
115616115742
rc = SQLITE_ERROR;
115617115743
}
115618115744
bDescIdx = (zVal[0]=='d' || zVal[0]=='D');
115619115745
break;
115746
+
115747
+ default: /* CONTENT */
115748
+ assert( iOpt==5 );
115749
+ sqlite3_free(zUncompress);
115750
+ zContent = zVal;
115751
+ zVal = 0;
115752
+ break;
115620115753
}
115621115754
}
115622115755
sqlite3_free(zVal);
115623115756
}
115624115757
}
@@ -115627,10 +115760,30 @@
115627115760
else {
115628115761
nString += (int)(strlen(z) + 1);
115629115762
aCol[nCol++] = z;
115630115763
}
115631115764
}
115765
+
115766
+ /* If a content=xxx option was specified, the following:
115767
+ **
115768
+ ** 1. Ignore any compress= and uncompress= options.
115769
+ **
115770
+ ** 2. If no column names were specified as part of the CREATE VIRTUAL
115771
+ ** TABLE statement, use all columns from the content table.
115772
+ */
115773
+ if( rc==SQLITE_OK && zContent ){
115774
+ sqlite3_free(zCompress);
115775
+ sqlite3_free(zUncompress);
115776
+ zCompress = 0;
115777
+ zUncompress = 0;
115778
+ if( nCol==0 ){
115779
+ sqlite3_free((void*)aCol);
115780
+ aCol = 0;
115781
+ rc = fts3ContentColumns(db, argv[1], zContent, &aCol, &nCol, &nString);
115782
+ }
115783
+ assert( rc!=SQLITE_OK || nCol>0 );
115784
+ }
115632115785
if( rc!=SQLITE_OK ) goto fts3_init_out;
115633115786
115634115787
if( nCol==0 ){
115635115788
assert( nString==0 );
115636115789
aCol[0] = "content";
@@ -115671,10 +115824,12 @@
115671115824
p->pTokenizer = pTokenizer;
115672115825
p->nMaxPendingData = FTS3_MAX_PENDING_DATA;
115673115826
p->bHasDocsize = (isFts4 && bNoDocsize==0);
115674115827
p->bHasStat = isFts4;
115675115828
p->bDescIdx = bDescIdx;
115829
+ p->zContentTbl = zContent;
115830
+ zContent = 0;
115676115831
TESTONLY( p->inTransaction = -1 );
115677115832
TESTONLY( p->mxSavepoint = -1 );
115678115833
115679115834
p->aIndex = (struct Fts3Index *)&p->azColumn[nCol];
115680115835
memcpy(p->aIndex, aIndex, sizeof(struct Fts3Index) * nIndex);
@@ -115732,10 +115887,11 @@
115732115887
fts3_init_out:
115733115888
sqlite3_free(zPrefix);
115734115889
sqlite3_free(aIndex);
115735115890
sqlite3_free(zCompress);
115736115891
sqlite3_free(zUncompress);
115892
+ sqlite3_free(zContent);
115737115893
sqlite3_free((void *)aCol);
115738115894
if( rc!=SQLITE_OK ){
115739115895
if( p ){
115740115896
fts3DisconnectMethod((sqlite3_vtab *)p);
115741115897
}else if( pTokenizer ){
@@ -115882,40 +116038,69 @@
115882116038
sqlite3_free(pCsr->aMatchinfo);
115883116039
assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 );
115884116040
sqlite3_free(pCsr);
115885116041
return SQLITE_OK;
115886116042
}
116043
+
116044
+/*
116045
+** If pCsr->pStmt has not been prepared (i.e. if pCsr->pStmt==0), then
116046
+** compose and prepare an SQL statement of the form:
116047
+**
116048
+** "SELECT <columns> FROM %_content WHERE rowid = ?"
116049
+**
116050
+** (or the equivalent for a content=xxx table) and set pCsr->pStmt to
116051
+** it. If an error occurs, return an SQLite error code.
116052
+**
116053
+** Otherwise, set *ppStmt to point to pCsr->pStmt and return SQLITE_OK.
116054
+*/
116055
+static int fts3CursorSeekStmt(Fts3Cursor *pCsr, sqlite3_stmt **ppStmt){
116056
+ int rc = SQLITE_OK;
116057
+ if( pCsr->pStmt==0 ){
116058
+ Fts3Table *p = (Fts3Table *)pCsr->base.pVtab;
116059
+ char *zSql;
116060
+ zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist);
116061
+ if( !zSql ) return SQLITE_NOMEM;
116062
+ rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0);
116063
+ sqlite3_free(zSql);
116064
+ }
116065
+ *ppStmt = pCsr->pStmt;
116066
+ return rc;
116067
+}
115887116068
115888116069
/*
115889116070
** Position the pCsr->pStmt statement so that it is on the row
115890116071
** of the %_content table that contains the last match. Return
115891116072
** SQLITE_OK on success.
115892116073
*/
115893116074
static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){
116075
+ int rc = SQLITE_OK;
115894116076
if( pCsr->isRequireSeek ){
115895
- sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iPrevId);
115896
- pCsr->isRequireSeek = 0;
115897
- if( SQLITE_ROW==sqlite3_step(pCsr->pStmt) ){
115898
- return SQLITE_OK;
115899
- }else{
115900
- int rc = sqlite3_reset(pCsr->pStmt);
115901
- if( rc==SQLITE_OK ){
115902
- /* If no row was found and no error has occured, then the %_content
115903
- ** table is missing a row that is present in the full-text index.
115904
- ** The data structures are corrupt.
115905
- */
115906
- rc = FTS_CORRUPT_VTAB;
115907
- }
115908
- pCsr->isEof = 1;
115909
- if( pContext ){
115910
- sqlite3_result_error_code(pContext, rc);
115911
- }
115912
- return rc;
115913
- }
115914
- }else{
115915
- return SQLITE_OK;
115916
- }
116077
+ sqlite3_stmt *pStmt = 0;
116078
+
116079
+ rc = fts3CursorSeekStmt(pCsr, &pStmt);
116080
+ if( rc==SQLITE_OK ){
116081
+ sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iPrevId);
116082
+ pCsr->isRequireSeek = 0;
116083
+ if( SQLITE_ROW==sqlite3_step(pCsr->pStmt) ){
116084
+ return SQLITE_OK;
116085
+ }else{
116086
+ rc = sqlite3_reset(pCsr->pStmt);
116087
+ if( rc==SQLITE_OK && ((Fts3Table *)pCsr->base.pVtab)->zContentTbl==0 ){
116088
+ /* If no row was found and no error has occured, then the %_content
116089
+ ** table is missing a row that is present in the full-text index.
116090
+ ** The data structures are corrupt. */
116091
+ rc = FTS_CORRUPT_VTAB;
116092
+ pCsr->isEof = 1;
116093
+ }
116094
+ }
116095
+ }
116096
+ }
116097
+
116098
+ if( rc!=SQLITE_OK && pContext ){
116099
+ sqlite3_result_error_code(pContext, rc);
116100
+ }
116101
+ return rc;
115917116102
}
115918116103
115919116104
/*
115920116105
** This function is used to process a single interior node when searching
115921116106
** a b-tree for a term or term prefix. The node data is passed to this
@@ -116351,20 +116536,20 @@
116351116536
int isSaveLeft, /* Save the left position */
116352116537
int isExact, /* If *pp1 is exactly nTokens before *pp2 */
116353116538
char **pp1, /* IN/OUT: Left input list */
116354116539
char **pp2 /* IN/OUT: Right input list */
116355116540
){
116356
- char *p = (pp ? *pp : 0);
116541
+ char *p = *pp;
116357116542
char *p1 = *pp1;
116358116543
char *p2 = *pp2;
116359116544
int iCol1 = 0;
116360116545
int iCol2 = 0;
116361116546
116362116547
/* Never set both isSaveLeft and isExact for the same invocation. */
116363116548
assert( isSaveLeft==0 || isExact==0 );
116364116549
116365
- assert( *p1!=0 && *p2!=0 );
116550
+ assert( p!=0 && *p1!=0 && *p2!=0 );
116366116551
if( *p1==POS_COLUMN ){
116367116552
p1++;
116368116553
p1 += sqlite3Fts3GetVarint32(p1, &iCol1);
116369116554
}
116370116555
if( *p2==POS_COLUMN ){
@@ -116377,11 +116562,11 @@
116377116562
char *pSave = p;
116378116563
sqlite3_int64 iPrev = 0;
116379116564
sqlite3_int64 iPos1 = 0;
116380116565
sqlite3_int64 iPos2 = 0;
116381116566
116382
- if( pp && iCol1 ){
116567
+ if( iCol1 ){
116383116568
*p++ = POS_COLUMN;
116384116569
p += sqlite3Fts3PutVarint(p, iCol1);
116385116570
}
116386116571
116387116572
assert( *p1!=POS_END && *p1!=POS_COLUMN );
@@ -116392,20 +116577,14 @@
116392116577
while( 1 ){
116393116578
if( iPos2==iPos1+nToken
116394116579
|| (isExact==0 && iPos2>iPos1 && iPos2<=iPos1+nToken)
116395116580
){
116396116581
sqlite3_int64 iSave;
116397
- if( !pp ){
116398
- fts3PoslistCopy(0, &p2);
116399
- fts3PoslistCopy(0, &p1);
116400
- *pp1 = p1;
116401
- *pp2 = p2;
116402
- return 1;
116403
- }
116404116582
iSave = isSaveLeft ? iPos1 : iPos2;
116405116583
fts3PutDeltaVarint(&p, &iPrev, iSave+2); iPrev -= 2;
116406116584
pSave = 0;
116585
+ assert( p );
116407116586
}
116408116587
if( (!isSaveLeft && iPos2<=(iPos1+nToken)) || iPos2<=iPos1 ){
116409116588
if( (*p2&0xFE)==0 ) break;
116410116589
fts3GetDeltaVarint(&p2, &iPos2); iPos2 -= 2;
116411116590
}else{
@@ -116450,11 +116629,11 @@
116450116629
116451116630
fts3PoslistCopy(0, &p2);
116452116631
fts3PoslistCopy(0, &p1);
116453116632
*pp1 = p1;
116454116633
*pp2 = p2;
116455
- if( !pp || *pp==p ){
116634
+ if( *pp==p ){
116456116635
return 0;
116457116636
}
116458116637
*p++ = 0x00;
116459116638
*pp = p;
116460116639
return 1;
@@ -116752,10 +116931,60 @@
116752116931
}
116753116932
}
116754116933
116755116934
*pnRight = p - aOut;
116756116935
}
116936
+
116937
+/*
116938
+** Argument pList points to a position list nList bytes in size. This
116939
+** function checks to see if the position list contains any entries for
116940
+** a token in position 0 (of any column). If so, it writes argument iDelta
116941
+** to the output buffer pOut, followed by a position list consisting only
116942
+** of the entries from pList at position 0, and terminated by an 0x00 byte.
116943
+** The value returned is the number of bytes written to pOut (if any).
116944
+*/
116945
+SQLITE_PRIVATE int sqlite3Fts3FirstFilter(
116946
+ sqlite3_int64 iDelta, /* Varint that may be written to pOut */
116947
+ char *pList, /* Position list (no 0x00 term) */
116948
+ int nList, /* Size of pList in bytes */
116949
+ char *pOut /* Write output here */
116950
+){
116951
+ int nOut = 0;
116952
+ int bWritten = 0; /* True once iDelta has been written */
116953
+ char *p = pList;
116954
+ char *pEnd = &pList[nList];
116955
+
116956
+ if( *p!=0x01 ){
116957
+ if( *p==0x02 ){
116958
+ nOut += sqlite3Fts3PutVarint(&pOut[nOut], iDelta);
116959
+ pOut[nOut++] = 0x02;
116960
+ bWritten = 1;
116961
+ }
116962
+ fts3ColumnlistCopy(0, &p);
116963
+ }
116964
+
116965
+ while( p<pEnd && *p==0x01 ){
116966
+ sqlite3_int64 iCol;
116967
+ p++;
116968
+ p += sqlite3Fts3GetVarint(p, &iCol);
116969
+ if( *p==0x02 ){
116970
+ if( bWritten==0 ){
116971
+ nOut += sqlite3Fts3PutVarint(&pOut[nOut], iDelta);
116972
+ bWritten = 1;
116973
+ }
116974
+ pOut[nOut++] = 0x01;
116975
+ nOut += sqlite3Fts3PutVarint(&pOut[nOut], iCol);
116976
+ pOut[nOut++] = 0x02;
116977
+ }
116978
+ fts3ColumnlistCopy(0, &p);
116979
+ }
116980
+ if( bWritten ){
116981
+ pOut[nOut++] = 0x00;
116982
+ }
116983
+
116984
+ return nOut;
116985
+}
116757116986
116758116987
116759116988
/*
116760116989
** Merge all doclists in the TermSelect.aaOutput[] array into a single
116761116990
** doclist stored in TermSelect.aaOutput[0]. If successful, delete all
@@ -117109,10 +117338,11 @@
117109117338
pSegcsr = pTok->pSegcsr;
117110117339
memset(&tsc, 0, sizeof(TermSelect));
117111117340
117112117341
filter.flags = FTS3_SEGMENT_IGNORE_EMPTY | FTS3_SEGMENT_REQUIRE_POS
117113117342
| (pTok->isPrefix ? FTS3_SEGMENT_PREFIX : 0)
117343
+ | (pTok->bFirst ? FTS3_SEGMENT_FIRST : 0)
117114117344
| (iColumn<p->nColumn ? FTS3_SEGMENT_COLUMN_FILTER : 0);
117115117345
filter.iCol = iColumn;
117116117346
filter.zTerm = pTok->z;
117117117347
filter.nTerm = pTok->n;
117118117348
@@ -117249,12 +117479,12 @@
117249117479
117250117480
if( zQuery==0 && sqlite3_value_type(apVal[0])!=SQLITE_NULL ){
117251117481
return SQLITE_NOMEM;
117252117482
}
117253117483
117254
- rc = sqlite3Fts3ExprParse(p->pTokenizer, p->azColumn, p->nColumn,
117255
- iCol, zQuery, -1, &pCsr->pExpr
117484
+ rc = sqlite3Fts3ExprParse(p->pTokenizer, p->azColumn, p->bHasStat,
117485
+ p->nColumn, iCol, zQuery, -1, &pCsr->pExpr
117256117486
);
117257117487
if( rc!=SQLITE_OK ){
117258117488
if( rc==SQLITE_ERROR ){
117259117489
static const char *zErr = "malformed MATCH expression: [%s]";
117260117490
p->base.zErrMsg = sqlite3_mprintf(zErr, zQuery);
@@ -117277,26 +117507,27 @@
117277117507
** statement loops through all rows of the %_content table. For a
117278117508
** full-text query or docid lookup, the statement retrieves a single
117279117509
** row by docid.
117280117510
*/
117281117511
if( idxNum==FTS3_FULLSCAN_SEARCH ){
117282
- const char *zSort = (pCsr->bDesc ? "DESC" : "ASC");
117283
- const char *zTmpl = "SELECT %s FROM %Q.'%q_content' AS x ORDER BY docid %s";
117284
- zSql = sqlite3_mprintf(zTmpl, p->zReadExprlist, p->zDb, p->zName, zSort);
117285
- }else{
117286
- const char *zTmpl = "SELECT %s FROM %Q.'%q_content' AS x WHERE docid = ?";
117287
- zSql = sqlite3_mprintf(zTmpl, p->zReadExprlist, p->zDb, p->zName);
117288
- }
117289
- if( !zSql ) return SQLITE_NOMEM;
117290
- rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0);
117291
- sqlite3_free(zSql);
117292
- if( rc!=SQLITE_OK ) return rc;
117293
-
117294
- if( idxNum==FTS3_DOCID_SEARCH ){
117295
- rc = sqlite3_bind_value(pCsr->pStmt, 1, apVal[0]);
117296
- if( rc!=SQLITE_OK ) return rc;
117297
- }
117512
+ zSql = sqlite3_mprintf(
117513
+ "SELECT %s ORDER BY rowid %s",
117514
+ p->zReadExprlist, (pCsr->bDesc ? "DESC" : "ASC")
117515
+ );
117516
+ if( zSql ){
117517
+ rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0);
117518
+ sqlite3_free(zSql);
117519
+ }else{
117520
+ rc = SQLITE_NOMEM;
117521
+ }
117522
+ }else if( idxNum==FTS3_DOCID_SEARCH ){
117523
+ rc = fts3CursorSeekStmt(pCsr, &pCsr->pStmt);
117524
+ if( rc==SQLITE_OK ){
117525
+ rc = sqlite3_bind_value(pCsr->pStmt, 1, apVal[0]);
117526
+ }
117527
+ }
117528
+ if( rc!=SQLITE_OK ) return rc;
117298117529
117299117530
return fts3NextMethod(pCursor);
117300117531
}
117301117532
117302117533
/*
@@ -117345,11 +117576,11 @@
117345117576
** Return a blob which is a pointer to the cursor.
117346117577
*/
117347117578
sqlite3_result_blob(pContext, &pCsr, sizeof(pCsr), SQLITE_TRANSIENT);
117348117579
}else{
117349117580
rc = fts3CursorSeek(0, pCsr);
117350
- if( rc==SQLITE_OK ){
117581
+ if( rc==SQLITE_OK && sqlite3_data_count(pCsr->pStmt)>(iCol+1) ){
117351117582
sqlite3_result_value(pContext, sqlite3_column_value(pCsr->pStmt, iCol+1));
117352117583
}
117353117584
}
117354117585
117355117586
assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 );
@@ -117638,19 +117869,26 @@
117638117869
){
117639117870
Fts3Table *p = (Fts3Table *)pVtab;
117640117871
sqlite3 *db = p->db; /* Database connection */
117641117872
int rc; /* Return Code */
117642117873
117874
+ /* As it happens, the pending terms table is always empty here. This is
117875
+ ** because an "ALTER TABLE RENAME TABLE" statement inside a transaction
117876
+ ** always opens a savepoint transaction. And the xSavepoint() method
117877
+ ** flushes the pending terms table. But leave the (no-op) call to
117878
+ ** PendingTermsFlush() in in case that changes.
117879
+ */
117880
+ assert( p->nPendingData==0 );
117643117881
rc = sqlite3Fts3PendingTermsFlush(p);
117644
- if( rc!=SQLITE_OK ){
117645
- return rc;
117882
+
117883
+ if( p->zContentTbl==0 ){
117884
+ fts3DbExec(&rc, db,
117885
+ "ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';",
117886
+ p->zDb, p->zName, zName
117887
+ );
117646117888
}
117647117889
117648
- fts3DbExec(&rc, db,
117649
- "ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';",
117650
- p->zDb, p->zName, zName
117651
- );
117652117890
if( p->bHasDocsize ){
117653117891
fts3DbExec(&rc, db,
117654117892
"ALTER TABLE %Q.'%q_docsize' RENAME TO '%q_docsize';",
117655117893
p->zDb, p->zName, zName
117656117894
);
@@ -118005,25 +118243,24 @@
118005118243
**
118006118244
** SQLITE_OK is returned if no error occurs, otherwise an SQLite error code.
118007118245
*/
118008118246
static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
118009118247
int iToken; /* Used to iterate through phrase tokens */
118010
- int rc = SQLITE_OK; /* Return code */
118011118248
char *aPoslist = 0; /* Position list for deferred tokens */
118012118249
int nPoslist = 0; /* Number of bytes in aPoslist */
118013118250
int iPrev = -1; /* Token number of previous deferred token */
118014118251
118015118252
assert( pPhrase->doclist.bFreeList==0 );
118016118253
118017
- for(iToken=0; rc==SQLITE_OK && iToken<pPhrase->nToken; iToken++){
118254
+ for(iToken=0; iToken<pPhrase->nToken; iToken++){
118018118255
Fts3PhraseToken *pToken = &pPhrase->aToken[iToken];
118019118256
Fts3DeferredToken *pDeferred = pToken->pDeferred;
118020118257
118021118258
if( pDeferred ){
118022118259
char *pList;
118023118260
int nList;
118024
- rc = sqlite3Fts3DeferredTokenList(pDeferred, &pList, &nList);
118261
+ int rc = sqlite3Fts3DeferredTokenList(pDeferred, &pList, &nList);
118025118262
if( rc!=SQLITE_OK ) return rc;
118026118263
118027118264
if( pList==0 ){
118028118265
sqlite3_free(aPoslist);
118029118266
pPhrase->doclist.pList = 0;
@@ -118120,10 +118357,11 @@
118120118357
if( pCsr->bDesc==pTab->bDescIdx
118121118358
&& bOptOk==1
118122118359
&& p->nToken==1
118123118360
&& pFirst->pSegcsr
118124118361
&& pFirst->pSegcsr->bLookup
118362
+ && pFirst->bFirst==0
118125118363
){
118126118364
/* Use the incremental approach. */
118127118365
int iCol = (p->iColumn >= pTab->nColumn ? -1 : p->iColumn);
118128118366
rc = sqlite3Fts3MsrIncrStart(
118129118367
pTab, pFirst->pSegcsr, iCol, pFirst->z, pFirst->n);
@@ -118349,11 +118587,11 @@
118349118587
Fts3Expr *pExpr, /* Expression to consider */
118350118588
Fts3TokenAndCost **ppTC, /* Write new entries to *(*ppTC)++ */
118351118589
Fts3Expr ***ppOr, /* Write new OR root to *(*ppOr)++ */
118352118590
int *pRc /* IN/OUT: Error code */
118353118591
){
118354
- if( *pRc==SQLITE_OK && pExpr ){
118592
+ if( *pRc==SQLITE_OK ){
118355118593
if( pExpr->eType==FTSQUERY_PHRASE ){
118356118594
Fts3Phrase *pPhrase = pExpr->pPhrase;
118357118595
int i;
118358118596
for(i=0; *pRc==SQLITE_OK && i<pPhrase->nToken; i++){
118359118597
Fts3TokenAndCost *pTC = (*ppTC)++;
@@ -118363,10 +118601,15 @@
118363118601
pTC->pToken = &pPhrase->aToken[i];
118364118602
pTC->iCol = pPhrase->iColumn;
118365118603
*pRc = sqlite3Fts3MsrOvfl(pCsr, pTC->pToken->pSegcsr, &pTC->nOvfl);
118366118604
}
118367118605
}else if( pExpr->eType!=FTSQUERY_NOT ){
118606
+ assert( pExpr->eType==FTSQUERY_OR
118607
+ || pExpr->eType==FTSQUERY_AND
118608
+ || pExpr->eType==FTSQUERY_NEAR
118609
+ );
118610
+ assert( pExpr->pLeft && pExpr->pRight );
118368118611
if( pExpr->eType==FTSQUERY_OR ){
118369118612
pRoot = pExpr->pLeft;
118370118613
**ppOr = pRoot;
118371118614
(*ppOr)++;
118372118615
}
@@ -118466,10 +118709,19 @@
118466118709
int nOvfl = 0; /* Total overflow pages used by doclists */
118467118710
int nToken = 0; /* Total number of tokens in cluster */
118468118711
118469118712
int nMinEst = 0; /* The minimum count for any phrase so far. */
118470118713
int nLoad4 = 1; /* (Phrases that will be loaded)^4. */
118714
+
118715
+ /* Tokens are never deferred for FTS tables created using the content=xxx
118716
+ ** option. The reason being that it is not guaranteed that the content
118717
+ ** table actually contains the same data as the index. To prevent this from
118718
+ ** causing any problems, the deferred token optimization is completely
118719
+ ** disabled for content=xxx tables. */
118720
+ if( pTab->zContentTbl ){
118721
+ return SQLITE_OK;
118722
+ }
118471118723
118472118724
/* Count the tokens in this AND/NEAR cluster. If none of the doclists
118473118725
** associated with the tokens spill onto overflow pages, or if there is
118474118726
** only 1 token, exit early. No tokens to defer in this case. */
118475118727
for(ii=0; ii<nTC; ii++){
@@ -118529,11 +118781,15 @@
118529118781
Fts3PhraseToken *pToken = pTC->pToken;
118530118782
rc = sqlite3Fts3DeferToken(pCsr, pToken, pTC->iCol);
118531118783
fts3SegReaderCursorFree(pToken->pSegcsr);
118532118784
pToken->pSegcsr = 0;
118533118785
}else{
118534
- nLoad4 = nLoad4*4;
118786
+ /* Set nLoad4 to the value of (4^nOther) for the next iteration of the
118787
+ ** for-loop. Except, limit the value to 2^24 to prevent it from
118788
+ ** overflowing the 32-bit integer it is stored in. */
118789
+ if( ii<12 ) nLoad4 = nLoad4*4;
118790
+
118535118791
if( ii==0 || pTC->pPhrase->nToken>1 ){
118536118792
/* Either this is the cheapest token in the entire query, or it is
118537118793
** part of a multi-token phrase. Either way, the entire doclist will
118538118794
** (eventually) be loaded into memory. It may as well be now. */
118539118795
Fts3PhraseToken *pToken = pTC->pToken;
@@ -119990,10 +120246,11 @@
119990120246
*/
119991120247
typedef struct ParseContext ParseContext;
119992120248
struct ParseContext {
119993120249
sqlite3_tokenizer *pTokenizer; /* Tokenizer module */
119994120250
const char **azCol; /* Array of column names for fts3 table */
120251
+ int bFts4; /* True to allow FTS4-only syntax */
119995120252
int nCol; /* Number of entries in azCol[] */
119996120253
int iDefaultCol; /* Default column to query */
119997120254
int isNot; /* True if getNextNode() sees a unary - */
119998120255
sqlite3_context *pCtx; /* Write error message here */
119999120256
int nNest; /* Number of nested brackets */
@@ -120077,13 +120334,25 @@
120077120334
120078120335
if( iEnd<n && z[iEnd]=='*' ){
120079120336
pRet->pPhrase->aToken[0].isPrefix = 1;
120080120337
iEnd++;
120081120338
}
120082
- if( !sqlite3_fts3_enable_parentheses && iStart>0 && z[iStart-1]=='-' ){
120083
- pParse->isNot = 1;
120339
+
120340
+ while( 1 ){
120341
+ if( !sqlite3_fts3_enable_parentheses
120342
+ && iStart>0 && z[iStart-1]=='-'
120343
+ ){
120344
+ pParse->isNot = 1;
120345
+ iStart--;
120346
+ }else if( pParse->bFts4 && iStart>0 && z[iStart-1]=='^' ){
120347
+ pRet->pPhrase->aToken[0].bFirst = 1;
120348
+ iStart--;
120349
+ }else{
120350
+ break;
120351
+ }
120084120352
}
120353
+
120085120354
}
120086120355
nConsumed = iEnd;
120087120356
}
120088120357
120089120358
pModule->xClose(pCursor);
@@ -120178,10 +120447,11 @@
120178120447
memcpy(&zTemp[nTemp], zByte, nByte);
120179120448
nTemp += nByte;
120180120449
120181120450
pToken->n = nByte;
120182120451
pToken->isPrefix = (iEnd<nInput && zInput[iEnd]=='*');
120452
+ pToken->bFirst = (iBegin>0 && zInput[iBegin-1]=='^');
120183120453
nToken = ii+1;
120184120454
}
120185120455
}
120186120456
120187120457
pModule->xClose(pCursor);
@@ -120629,10 +120899,11 @@
120629120899
** match any table column.
120630120900
*/
120631120901
SQLITE_PRIVATE int sqlite3Fts3ExprParse(
120632120902
sqlite3_tokenizer *pTokenizer, /* Tokenizer module */
120633120903
char **azCol, /* Array of column names for fts3 table */
120904
+ int bFts4, /* True to allow FTS4-only syntax */
120634120905
int nCol, /* Number of entries in azCol[] */
120635120906
int iDefaultCol, /* Default column to query */
120636120907
const char *z, int n, /* Text of MATCH query */
120637120908
Fts3Expr **ppExpr /* OUT: Parsed query structure */
120638120909
){
@@ -120642,10 +120913,11 @@
120642120913
sParse.pTokenizer = pTokenizer;
120643120914
sParse.azCol = (const char **)azCol;
120644120915
sParse.nCol = nCol;
120645120916
sParse.iDefaultCol = iDefaultCol;
120646120917
sParse.nNest = 0;
120918
+ sParse.bFts4 = bFts4;
120647120919
if( z==0 ){
120648120920
*ppExpr = 0;
120649120921
return SQLITE_OK;
120650120922
}
120651120923
if( n<0 ){
@@ -120831,11 +121103,11 @@
120831121103
for(ii=0; ii<nCol; ii++){
120832121104
azCol[ii] = (char *)sqlite3_value_text(argv[ii+2]);
120833121105
}
120834121106
120835121107
rc = sqlite3Fts3ExprParse(
120836
- pTokenizer, azCol, nCol, nCol, zExpr, nExpr, &pExpr
121108
+ pTokenizer, azCol, 0, nCol, nCol, zExpr, nExpr, &pExpr
120837121109
);
120838121110
if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){
120839121111
sqlite3_result_error(context, "Error parsing expression", -1);
120840121112
}else if( rc==SQLITE_NOMEM || !(zBuf = exprToString(pExpr, 0)) ){
120841121113
sqlite3_result_error_nomem(context);
@@ -122878,11 +123150,11 @@
122878123150
/* 2 */ "DELETE FROM %Q.'%q_content'",
122879123151
/* 3 */ "DELETE FROM %Q.'%q_segments'",
122880123152
/* 4 */ "DELETE FROM %Q.'%q_segdir'",
122881123153
/* 5 */ "DELETE FROM %Q.'%q_docsize'",
122882123154
/* 6 */ "DELETE FROM %Q.'%q_stat'",
122883
-/* 7 */ "SELECT %s FROM %Q.'%q_content' AS x WHERE rowid=?",
123155
+/* 7 */ "SELECT %s WHERE rowid=?",
122884123156
/* 8 */ "SELECT (SELECT max(idx) FROM %Q.'%q_segdir' WHERE level = ?) + 1",
122885123157
/* 9 */ "INSERT INTO %Q.'%q_segments'(blockid, block) VALUES(?, ?)",
122886123158
/* 10 */ "SELECT coalesce((SELECT max(blockid) FROM %Q.'%q_segments') + 1, 1)",
122887123159
/* 11 */ "INSERT INTO %Q.'%q_segdir' VALUES(?,?,?,?,?,?)",
122888123160
@@ -122920,11 +123192,11 @@
122920123192
if( !pStmt ){
122921123193
char *zSql;
122922123194
if( eStmt==SQL_CONTENT_INSERT ){
122923123195
zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName, p->zWriteExprlist);
122924123196
}else if( eStmt==SQL_SELECT_CONTENT_BY_ROWID ){
122925
- zSql = sqlite3_mprintf(azSql[eStmt], p->zReadExprlist, p->zDb, p->zName);
123197
+ zSql = sqlite3_mprintf(azSql[eStmt], p->zReadExprlist);
122926123198
}else{
122927123199
zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName);
122928123200
}
122929123201
if( !zSql ){
122930123202
rc = SQLITE_NOMEM;
@@ -123031,21 +123303,28 @@
123031123303
** We try to avoid this because if FTS3 returns any error when committing
123032123304
** a transaction, the whole transaction will be rolled back. And this is
123033123305
** not what users expect when they get SQLITE_LOCKED_SHAREDCACHE. It can
123034123306
** still happen if the user reads data directly from the %_segments or
123035123307
** %_segdir tables instead of going through FTS3 though.
123308
+**
123309
+** This reasoning does not apply to a content=xxx table.
123036123310
*/
123037123311
SQLITE_PRIVATE int sqlite3Fts3ReadLock(Fts3Table *p){
123038123312
int rc; /* Return code */
123039123313
sqlite3_stmt *pStmt; /* Statement used to obtain lock */
123040123314
123041
- rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pStmt, 0);
123042
- if( rc==SQLITE_OK ){
123043
- sqlite3_bind_null(pStmt, 1);
123044
- sqlite3_step(pStmt);
123045
- rc = sqlite3_reset(pStmt);
123315
+ if( p->zContentTbl==0 ){
123316
+ rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pStmt, 0);
123317
+ if( rc==SQLITE_OK ){
123318
+ sqlite3_bind_null(pStmt, 1);
123319
+ sqlite3_step(pStmt);
123320
+ rc = sqlite3_reset(pStmt);
123321
+ }
123322
+ }else{
123323
+ rc = SQLITE_OK;
123046123324
}
123325
+
123047123326
return rc;
123048123327
}
123049123328
123050123329
/*
123051123330
** Set *ppStmt to a statement handle that may be used to iterate through
@@ -123401,10 +123680,22 @@
123401123680
sqlite3_value **apVal, /* Array of values to insert */
123402123681
sqlite3_int64 *piDocid /* OUT: Docid for row just inserted */
123403123682
){
123404123683
int rc; /* Return code */
123405123684
sqlite3_stmt *pContentInsert; /* INSERT INTO %_content VALUES(...) */
123685
+
123686
+ if( p->zContentTbl ){
123687
+ sqlite3_value *pRowid = apVal[p->nColumn+3];
123688
+ if( sqlite3_value_type(pRowid)==SQLITE_NULL ){
123689
+ pRowid = apVal[1];
123690
+ }
123691
+ if( sqlite3_value_type(pRowid)!=SQLITE_INTEGER ){
123692
+ return SQLITE_CONSTRAINT;
123693
+ }
123694
+ *piDocid = sqlite3_value_int64(pRowid);
123695
+ return SQLITE_OK;
123696
+ }
123406123697
123407123698
/* Locate the statement handle used to insert data into the %_content
123408123699
** table. The SQL for this statement is:
123409123700
**
123410123701
** INSERT INTO %_content VALUES(?, ?, ?, ...)
@@ -123452,18 +123743,20 @@
123452123743
123453123744
/*
123454123745
** Remove all data from the FTS3 table. Clear the hash table containing
123455123746
** pending terms.
123456123747
*/
123457
-static int fts3DeleteAll(Fts3Table *p){
123748
+static int fts3DeleteAll(Fts3Table *p, int bContent){
123458123749
int rc = SQLITE_OK; /* Return code */
123459123750
123460123751
/* Discard the contents of the pending-terms hash table. */
123461123752
sqlite3Fts3PendingTermsClear(p);
123462123753
123463
- /* Delete everything from the %_content, %_segments and %_segdir tables. */
123464
- fts3SqlExec(&rc, p, SQL_DELETE_ALL_CONTENT, 0);
123754
+ /* Delete everything from the shadow tables. Except, leave %_content as
123755
+ ** is if bContent is false. */
123756
+ assert( p->zContentTbl==0 || bContent==0 );
123757
+ if( bContent ) fts3SqlExec(&rc, p, SQL_DELETE_ALL_CONTENT, 0);
123465123758
fts3SqlExec(&rc, p, SQL_DELETE_ALL_SEGMENTS, 0);
123466123759
fts3SqlExec(&rc, p, SQL_DELETE_ALL_SEGDIR, 0);
123467123760
if( p->bHasDocsize ){
123468123761
fts3SqlExec(&rc, p, SQL_DELETE_ALL_DOCSIZE, 0);
123469123762
}
@@ -124747,16 +125040,22 @@
124747125040
** error occurs, an SQLite error code is returned.
124748125041
*/
124749125042
static int fts3IsEmpty(Fts3Table *p, sqlite3_value *pRowid, int *pisEmpty){
124750125043
sqlite3_stmt *pStmt;
124751125044
int rc;
124752
- rc = fts3SqlStmt(p, SQL_IS_EMPTY, &pStmt, &pRowid);
124753
- if( rc==SQLITE_OK ){
124754
- if( SQLITE_ROW==sqlite3_step(pStmt) ){
124755
- *pisEmpty = sqlite3_column_int(pStmt, 0);
125045
+ if( p->zContentTbl ){
125046
+ /* If using the content=xxx option, assume the table is never empty */
125047
+ *pisEmpty = 0;
125048
+ rc = SQLITE_OK;
125049
+ }else{
125050
+ rc = fts3SqlStmt(p, SQL_IS_EMPTY, &pStmt, &pRowid);
125051
+ if( rc==SQLITE_OK ){
125052
+ if( SQLITE_ROW==sqlite3_step(pStmt) ){
125053
+ *pisEmpty = sqlite3_column_int(pStmt, 0);
125054
+ }
125055
+ rc = sqlite3_reset(pStmt);
124756125056
}
124757
- rc = sqlite3_reset(pStmt);
124758125057
}
124759125058
return rc;
124760125059
}
124761125060
124762125061
/*
@@ -125104,10 +125403,11 @@
125104125403
int isIgnoreEmpty = (pCsr->pFilter->flags & FTS3_SEGMENT_IGNORE_EMPTY);
125105125404
int isRequirePos = (pCsr->pFilter->flags & FTS3_SEGMENT_REQUIRE_POS);
125106125405
int isColFilter = (pCsr->pFilter->flags & FTS3_SEGMENT_COLUMN_FILTER);
125107125406
int isPrefix = (pCsr->pFilter->flags & FTS3_SEGMENT_PREFIX);
125108125407
int isScan = (pCsr->pFilter->flags & FTS3_SEGMENT_SCAN);
125408
+ int isFirst = (pCsr->pFilter->flags & FTS3_SEGMENT_FIRST);
125109125409
125110125410
Fts3SegReader **apSegment = pCsr->apSegment;
125111125411
int nSegment = pCsr->nSegment;
125112125412
Fts3SegFilter *pFilter = pCsr->pFilter;
125113125413
int (*xCmp)(Fts3SegReader *, Fts3SegReader *) = (
@@ -125163,10 +125463,11 @@
125163125463
}
125164125464
125165125465
assert( isIgnoreEmpty || (isRequirePos && !isColFilter) );
125166125466
if( nMerge==1
125167125467
&& !isIgnoreEmpty
125468
+ && !isFirst
125168125469
&& (p->bDescIdx==0 || fts3SegReaderIsPending(apSegment[0])==0)
125169125470
){
125170125471
pCsr->nDoclist = apSegment[0]->nDoclist;
125171125472
if( fts3SegReaderIsPending(apSegment[0]) ){
125172125473
rc = fts3MsrBufferData(pCsr, apSegment[0]->aDoclist, pCsr->nDoclist);
@@ -125228,16 +125529,28 @@
125228125529
if( !aNew ){
125229125530
return SQLITE_NOMEM;
125230125531
}
125231125532
pCsr->aBuffer = aNew;
125232125533
}
125233
- nDoclist += sqlite3Fts3PutVarint(&pCsr->aBuffer[nDoclist], iDelta);
125234
- iPrev = iDocid;
125235
- if( isRequirePos ){
125236
- memcpy(&pCsr->aBuffer[nDoclist], pList, nList);
125237
- nDoclist += nList;
125238
- pCsr->aBuffer[nDoclist++] = '\0';
125534
+
125535
+ if( isFirst ){
125536
+ char *a = &pCsr->aBuffer[nDoclist];
125537
+ int nWrite;
125538
+
125539
+ nWrite = sqlite3Fts3FirstFilter(iDelta, pList, nList, a);
125540
+ if( nWrite ){
125541
+ iPrev = iDocid;
125542
+ nDoclist += nWrite;
125543
+ }
125544
+ }else{
125545
+ nDoclist += sqlite3Fts3PutVarint(&pCsr->aBuffer[nDoclist], iDelta);
125546
+ iPrev = iDocid;
125547
+ if( isRequirePos ){
125548
+ memcpy(&pCsr->aBuffer[nDoclist], pList, nList);
125549
+ nDoclist += nList;
125550
+ pCsr->aBuffer[nDoclist++] = '\0';
125551
+ }
125239125552
}
125240125553
}
125241125554
125242125555
fts3SegReaderSort(apSegment, nMerge, j, xCmp);
125243125556
}
@@ -125409,13 +125722,13 @@
125409125722
** Insert the sizes (in tokens) for each column of the document
125410125723
** with docid equal to p->iPrevDocid. The sizes are encoded as
125411125724
** a blob of varints.
125412125725
*/
125413125726
static void fts3InsertDocsize(
125414
- int *pRC, /* Result code */
125415
- Fts3Table *p, /* Table into which to insert */
125416
- u32 *aSz /* Sizes of each column */
125727
+ int *pRC, /* Result code */
125728
+ Fts3Table *p, /* Table into which to insert */
125729
+ u32 *aSz /* Sizes of each column, in tokens */
125417125730
){
125418125731
char *pBlob; /* The BLOB encoding of the document size */
125419125732
int nBlob; /* Number of bytes in the BLOB */
125420125733
sqlite3_stmt *pStmt; /* Statement used to insert the encoding */
125421125734
int rc; /* Result code from subfunctions */
@@ -125532,10 +125845,90 @@
125532125845
sqlite3Fts3SegmentsClose(p);
125533125846
sqlite3Fts3PendingTermsClear(p);
125534125847
125535125848
return (rc==SQLITE_OK && bReturnDone && bSeenDone) ? SQLITE_DONE : rc;
125536125849
}
125850
+
125851
+/*
125852
+** This function is called when the user executes the following statement:
125853
+**
125854
+** INSERT INTO <tbl>(<tbl>) VALUES('rebuild');
125855
+**
125856
+** The entire FTS index is discarded and rebuilt. If the table is one
125857
+** created using the content=xxx option, then the new index is based on
125858
+** the current contents of the xxx table. Otherwise, it is rebuilt based
125859
+** on the contents of the %_content table.
125860
+*/
125861
+static int fts3DoRebuild(Fts3Table *p){
125862
+ int rc; /* Return Code */
125863
+
125864
+ rc = fts3DeleteAll(p, 0);
125865
+ if( rc==SQLITE_OK ){
125866
+ u32 *aSz = 0;
125867
+ u32 *aSzIns = 0;
125868
+ u32 *aSzDel = 0;
125869
+ sqlite3_stmt *pStmt = 0;
125870
+ int nEntry = 0;
125871
+
125872
+ /* Compose and prepare an SQL statement to loop through the content table */
125873
+ char *zSql = sqlite3_mprintf("SELECT %s" , p->zReadExprlist);
125874
+ if( !zSql ){
125875
+ rc = SQLITE_NOMEM;
125876
+ }else{
125877
+ rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
125878
+ sqlite3_free(zSql);
125879
+ }
125880
+
125881
+ if( rc==SQLITE_OK ){
125882
+ int nByte = sizeof(u32) * (p->nColumn+1)*3;
125883
+ aSz = (u32 *)sqlite3_malloc(nByte);
125884
+ if( aSz==0 ){
125885
+ rc = SQLITE_NOMEM;
125886
+ }else{
125887
+ memset(aSz, 0, nByte);
125888
+ aSzIns = &aSz[p->nColumn+1];
125889
+ aSzDel = &aSzIns[p->nColumn+1];
125890
+ }
125891
+ }
125892
+
125893
+ while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
125894
+ int iCol;
125895
+ rc = fts3PendingTermsDocid(p, sqlite3_column_int64(pStmt, 0));
125896
+ aSz[p->nColumn] = 0;
125897
+ for(iCol=0; rc==SQLITE_OK && iCol<p->nColumn; iCol++){
125898
+ const char *z = (const char *) sqlite3_column_text(pStmt, iCol+1);
125899
+ rc = fts3PendingTermsAdd(p, z, iCol, &aSz[iCol]);
125900
+ aSz[p->nColumn] += sqlite3_column_bytes(pStmt, iCol+1);
125901
+ }
125902
+ if( p->bHasDocsize ){
125903
+ fts3InsertDocsize(&rc, p, aSz);
125904
+ }
125905
+ if( rc!=SQLITE_OK ){
125906
+ sqlite3_finalize(pStmt);
125907
+ pStmt = 0;
125908
+ }else{
125909
+ nEntry++;
125910
+ for(iCol=0; iCol<=p->nColumn; iCol++){
125911
+ aSzIns[iCol] += aSz[iCol];
125912
+ }
125913
+ }
125914
+ }
125915
+ if( p->bHasStat ){
125916
+ fts3UpdateDocTotals(&rc, p, aSzIns, aSzDel, nEntry);
125917
+ }
125918
+ sqlite3_free(aSz);
125919
+
125920
+ if( pStmt ){
125921
+ int rc2 = sqlite3_finalize(pStmt);
125922
+ if( rc==SQLITE_OK ){
125923
+ rc = rc2;
125924
+ }
125925
+ }
125926
+ }
125927
+
125928
+ return rc;
125929
+}
125537125930
125538125931
/*
125539125932
** Handle a 'special' INSERT of the form:
125540125933
**
125541125934
** "INSERT INTO tbl(tbl) VALUES(<expr>)"
@@ -125550,10 +125943,12 @@
125550125943
125551125944
if( !zVal ){
125552125945
return SQLITE_NOMEM;
125553125946
}else if( nVal==8 && 0==sqlite3_strnicmp(zVal, "optimize", 8) ){
125554125947
rc = fts3DoOptimize(p, 0);
125948
+ }else if( nVal==7 && 0==sqlite3_strnicmp(zVal, "rebuild", 7) ){
125949
+ rc = fts3DoRebuild(p);
125555125950
#ifdef SQLITE_TEST
125556125951
}else if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){
125557125952
p->nNodeSize = atoi(&zVal[9]);
125558125953
rc = SQLITE_OK;
125559125954
}else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 9) ){
@@ -125630,10 +126025,11 @@
125630126025
pTC->pTokenizer = pT;
125631126026
rc = pModule->xNext(pTC, &zToken, &nToken, &iDum1, &iDum2, &iPos);
125632126027
for(pDef=pCsr->pDeferred; pDef && rc==SQLITE_OK; pDef=pDef->pNext){
125633126028
Fts3PhraseToken *pPT = pDef->pToken;
125634126029
if( (pDef->iCol>=p->nColumn || pDef->iCol==i)
126030
+ && (pPT->bFirst==0 || iPos==0)
125635126031
&& (pPT->n==nToken || (pPT->isPrefix && pPT->n<nToken))
125636126032
&& (0==memcmp(zToken, pPT->z, pPT->n))
125637126033
){
125638126034
fts3PendingListAppend(&pDef->pList, iDocid, i, iPos, &rc);
125639126035
}
@@ -125721,18 +126117,22 @@
125721126117
if( rc==SQLITE_OK ){
125722126118
if( isEmpty ){
125723126119
/* Deleting this row means the whole table is empty. In this case
125724126120
** delete the contents of all three tables and throw away any
125725126121
** data in the pendingTerms hash table. */
125726
- rc = fts3DeleteAll(p);
126122
+ rc = fts3DeleteAll(p, 1);
125727126123
*pnDoc = *pnDoc - 1;
125728126124
}else{
125729126125
sqlite3_int64 iRemove = sqlite3_value_int64(pRowid);
125730126126
rc = fts3PendingTermsDocid(p, iRemove);
125731126127
fts3DeleteTerms(&rc, p, pRowid, aSzDel);
125732
- fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, &pRowid);
125733
- if( sqlite3_changes(p->db) ) *pnDoc = *pnDoc - 1;
126128
+ if( p->zContentTbl==0 ){
126129
+ fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, &pRowid);
126130
+ if( sqlite3_changes(p->db) ) *pnDoc = *pnDoc - 1;
126131
+ }else{
126132
+ *pnDoc = *pnDoc - 1;
126133
+ }
125734126134
if( p->bHasDocsize ){
125735126135
fts3SqlExec(&rc, p, SQL_DELETE_DOCSIZE, &pRowid);
125736126136
}
125737126137
}
125738126138
}
@@ -125788,11 +126188,11 @@
125788126188
** should be deleted from the database before inserting the new row. Or,
125789126189
** if the on-conflict mode is other than REPLACE, then this method must
125790126190
** detect the conflict and return SQLITE_CONSTRAINT before beginning to
125791126191
** modify the database file.
125792126192
*/
125793
- if( nArg>1 ){
126193
+ if( nArg>1 && p->zContentTbl==0 ){
125794126194
/* Find the value object that holds the new rowid value. */
125795126195
sqlite3_value *pNewRowid = apVal[3+p->nColumn];
125796126196
if( sqlite3_value_type(pNewRowid)==SQLITE_NULL ){
125797126197
pNewRowid = apVal[1];
125798126198
}
@@ -125839,11 +126239,13 @@
125839126239
125840126240
/* If this is an INSERT or UPDATE operation, insert the new record. */
125841126241
if( nArg>1 && rc==SQLITE_OK ){
125842126242
if( bInsertDone==0 ){
125843126243
rc = fts3InsertData(p, apVal, pRowid);
125844
- if( rc==SQLITE_CONSTRAINT ) rc = FTS_CORRUPT_VTAB;
126244
+ if( rc==SQLITE_CONSTRAINT && p->zContentTbl==0 ){
126245
+ rc = FTS_CORRUPT_VTAB;
126246
+ }
125845126247
}
125846126248
if( rc==SQLITE_OK && (!isRemove || *pRowid!=p->iPrevDocid ) ){
125847126249
rc = fts3PendingTermsDocid(p, *pRowid);
125848126250
}
125849126251
if( rc==SQLITE_OK ){
@@ -126259,10 +126661,11 @@
126259126661
pCsr = sqlite3Fts3EvalPhrasePoslist(p->pCsr, pExpr, p->iCol);
126260126662
if( pCsr ){
126261126663
int iFirst = 0;
126262126664
pPhrase->pList = pCsr;
126263126665
fts3GetDeltaPosition(&pCsr, &iFirst);
126666
+ assert( iFirst>=0 );
126264126667
pPhrase->pHead = pCsr;
126265126668
pPhrase->pTail = pCsr;
126266126669
pPhrase->iHead = iFirst;
126267126670
pPhrase->iTail = iFirst;
126268126671
}else{
@@ -127300,11 +127703,11 @@
127300127703
}
127301127704
}
127302127705
127303127706
if( !pTerm ){
127304127707
/* All offsets for this column have been gathered. */
127305
- break;
127708
+ rc = SQLITE_DONE;
127306127709
}else{
127307127710
assert( iCurrent<=iMinPos );
127308127711
if( 0==(0xFE&*pTerm->pList) ){
127309127712
pTerm->pList = 0;
127310127713
}else{
@@ -127317,11 +127720,11 @@
127317127720
char aBuffer[64];
127318127721
sqlite3_snprintf(sizeof(aBuffer), aBuffer,
127319127722
"%d %d %d %d ", iCol, pTerm-sCtx.aTerm, iStart, iEnd-iStart
127320127723
);
127321127724
rc = fts3StringAppend(&res, aBuffer, -1);
127322
- }else if( rc==SQLITE_DONE ){
127725
+ }else if( rc==SQLITE_DONE && pTab->zContentTbl==0 ){
127323127726
rc = FTS_CORRUPT_VTAB;
127324127727
}
127325127728
}
127326127729
}
127327127730
if( rc==SQLITE_DONE ){
127328127731
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -656,11 +656,11 @@
656 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
657 ** [sqlite_version()] and [sqlite_source_id()].
658 */
659 #define SQLITE_VERSION "3.7.9"
660 #define SQLITE_VERSION_NUMBER 3007009
661 #define SQLITE_SOURCE_ID "2011-10-15 00:16:30 39408702a989f907261c298bf0947f3e68bd10fe"
662
663 /*
664 ** CAPI3REF: Run-Time Library Version Numbers
665 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
666 **
@@ -1951,12 +1951,12 @@
1951 ** memory pointer is not NULL and either [SQLITE_ENABLE_MEMSYS3] or
1952 ** [SQLITE_ENABLE_MEMSYS5] are defined, then the alternative memory
1953 ** allocator is engaged to handle all of SQLites memory allocation needs.
1954 ** The first pointer (the memory pointer) must be aligned to an 8-byte
1955 ** boundary or subsequent behavior of SQLite will be undefined.
1956 ** The minimum allocation size is capped at 2^12. Reasonable values
1957 ** for the minimum allocation size are 2^5 through 2^8.</dd>
1958 **
1959 ** [[SQLITE_CONFIG_MUTEX]] <dt>SQLITE_CONFIG_MUTEX</dt>
1960 ** <dd> ^(This option takes a single argument which is a pointer to an
1961 ** instance of the [sqlite3_mutex_methods] structure. The argument specifies
1962 ** alternative low-level mutex routines to be used in place
@@ -20969,11 +20969,11 @@
20969 }else if( *z=='+' ){
20970 z+=incr;
20971 }
20972 /* copy digits to exponent */
20973 while( z<zEnd && sqlite3Isdigit(*z) ){
20974 e = e*10 + (*z - '0');
20975 z+=incr;
20976 eValid = 1;
20977 }
20978 }
20979
@@ -21020,10 +21020,16 @@
21020 result /= 1.0e+308;
21021 }else{
21022 result = s * scale;
21023 result *= 1.0e+308;
21024 }
 
 
 
 
 
 
21025 }else{
21026 /* 1.0e+22 is the largest power of 10 than can be
21027 ** represented exactly. */
21028 while( e%22 ) { scale *= 1.0e+1; e -= 1; }
21029 while( e>0 ) { scale *= 1.0e+22; e -= 22; }
@@ -68962,11 +68968,11 @@
68962
68963 /* Do not allow a transition to journal_mode=WAL for a database
68964 ** in temporary storage or if the VFS does not support shared memory
68965 */
68966 if( u.ch.eNew==PAGER_JOURNALMODE_WAL
68967 && (u.ch.zFilename[0]==0 /* Temp file */
68968 || !sqlite3PagerWalSupported(u.ch.pPager)) /* No shared-memory support */
68969 ){
68970 u.ch.eNew = u.ch.eOld;
68971 }
68972
@@ -69397,14 +69403,19 @@
69397 u.co.pName = &aMem[pOp->p1];
69398 assert( u.co.pVtab->pModule->xRename );
69399 assert( memIsValid(u.co.pName) );
69400 REGISTER_TRACE(pOp->p1, u.co.pName);
69401 assert( u.co.pName->flags & MEM_Str );
69402 rc = u.co.pVtab->pModule->xRename(u.co.pVtab, u.co.pName->z);
69403 importVtabErrMsg(p, u.co.pVtab);
69404 p->expired = 0;
69405
 
 
 
 
 
69406 break;
69407 }
69408 #endif
69409
69410 #ifndef SQLITE_OMIT_VIRTUALTABLE
@@ -71758,10 +71769,28 @@
71758 ExprSetProperty(pExpr, EP_Static);
71759 sqlite3ExprDelete(db, pExpr);
71760 memcpy(pExpr, pDup, sizeof(*pExpr));
71761 sqlite3DbFree(db, pDup);
71762 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71763
71764 /*
71765 ** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up
71766 ** that name in the set of source tables in pSrcList and make the pExpr
71767 ** expression node refer back to that source column. The following changes
@@ -71850,38 +71879,25 @@
71850 pSchema = pTab->pSchema;
71851 pMatch = pItem;
71852 }
71853 for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){
71854 if( sqlite3StrICmp(pCol->zName, zCol)==0 ){
71855 IdList *pUsing;
 
 
 
 
 
 
 
71856 cnt++;
71857 pExpr->iTable = pItem->iCursor;
71858 pExpr->pTab = pTab;
71859 pMatch = pItem;
71860 pSchema = pTab->pSchema;
71861 /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
71862 pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j;
71863 if( i<pSrcList->nSrc-1 ){
71864 if( pItem[1].jointype & JT_NATURAL ){
71865 /* If this match occurred in the left table of a natural join,
71866 ** then skip the right table to avoid a duplicate match */
71867 pItem++;
71868 i++;
71869 }else if( (pUsing = pItem[1].pUsing)!=0 ){
71870 /* If this match occurs on a column that is in the USING clause
71871 ** of a join, skip the search of the right table of the join
71872 ** to avoid a duplicate match there. */
71873 int k;
71874 for(k=0; k<pUsing->nId; k++){
71875 if( sqlite3StrICmp(pUsing->a[k].zName, zCol)==0 ){
71876 pItem++;
71877 i++;
71878 break;
71879 }
71880 }
71881 }
71882 }
71883 break;
71884 }
71885 }
71886 }
71887 }
@@ -102501,10 +102517,11 @@
102501 tempWC.pParse = pWC->pParse;
102502 tempWC.pMaskSet = pWC->pMaskSet;
102503 tempWC.pOuter = pWC;
102504 tempWC.op = TK_AND;
102505 tempWC.a = pOrTerm;
 
102506 tempWC.nTerm = 1;
102507 bestIndex(pParse, &tempWC, pSrc, notReady, notValid, 0, &sTermCost);
102508 }else{
102509 continue;
102510 }
@@ -114528,10 +114545,11 @@
114528 const char *zDb; /* logical database name */
114529 const char *zName; /* virtual table name */
114530 int nColumn; /* number of named columns in virtual table */
114531 char **azColumn; /* column names. malloced */
114532 sqlite3_tokenizer *pTokenizer; /* tokenizer for inserts and queries */
 
114533
114534 /* Precompiled statements used by the implementation. Each of these
114535 ** statements is run and reset within a single virtual table API call.
114536 */
114537 sqlite3_stmt *aStmt[27];
@@ -114568,11 +114586,11 @@
114568 } *aIndex;
114569 int nMaxPendingData; /* Max pending data before flush to disk */
114570 int nPendingData; /* Current bytes of pending data */
114571 sqlite_int64 iPrevDocid; /* Docid of most recently inserted document */
114572
114573 #if defined(SQLITE_DEBUG)
114574 /* State variables used for validating that the transaction control
114575 ** methods of the virtual table are called at appropriate times. These
114576 ** values do not contribution to the FTS computation; they are used for
114577 ** verifying the SQLite core.
114578 */
@@ -114653,10 +114671,11 @@
114653 */
114654 struct Fts3PhraseToken {
114655 char *z; /* Text of the token */
114656 int n; /* Number of bytes in buffer z */
114657 int isPrefix; /* True if token ends with a "*" character */
 
114658
114659 /* Variables above this point are populated when the expression is
114660 ** parsed (by code in fts3_expr.c). Below this point the variables are
114661 ** used when evaluating the expression. */
114662 Fts3DeferredToken *pDeferred; /* Deferred token object for this token */
@@ -114771,10 +114790,11 @@
114771 #define FTS3_SEGMENT_REQUIRE_POS 0x00000001
114772 #define FTS3_SEGMENT_IGNORE_EMPTY 0x00000002
114773 #define FTS3_SEGMENT_COLUMN_FILTER 0x00000004
114774 #define FTS3_SEGMENT_PREFIX 0x00000008
114775 #define FTS3_SEGMENT_SCAN 0x00000010
 
114776
114777 /* Type passed as 4th argument to SegmentReaderIterate() */
114778 struct Fts3SegFilter {
114779 const char *zTerm;
114780 int nTerm;
@@ -114810,12 +114830,12 @@
114810 SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *, sqlite_int64 *);
114811 SQLITE_PRIVATE int sqlite3Fts3GetVarint32(const char *, int *);
114812 SQLITE_PRIVATE int sqlite3Fts3VarintLen(sqlite3_uint64);
114813 SQLITE_PRIVATE void sqlite3Fts3Dequote(char *);
114814 SQLITE_PRIVATE void sqlite3Fts3DoclistPrev(int,char*,int,char**,sqlite3_int64*,int*,u8*);
114815
114816 SQLITE_PRIVATE int sqlite3Fts3EvalPhraseStats(Fts3Cursor *, Fts3Expr *, u32 *);
 
114817
114818 /* fts3_tokenizer.c */
114819 SQLITE_PRIVATE const char *sqlite3Fts3NextToken(const char *, int *);
114820 SQLITE_PRIVATE int sqlite3Fts3InitHashTable(sqlite3 *, Fts3Hash *, const char *);
114821 SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(Fts3Hash *pHash, const char *,
@@ -114830,11 +114850,11 @@
114830 );
114831 SQLITE_PRIVATE void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *, const char *);
114832
114833 /* fts3_expr.c */
114834 SQLITE_PRIVATE int sqlite3Fts3ExprParse(sqlite3_tokenizer *,
114835 char **, int, int, const char *, int, Fts3Expr **
114836 );
114837 SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *);
114838 #ifdef SQLITE_TEST
114839 SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3 *db);
114840 SQLITE_PRIVATE int sqlite3Fts3InitTerm(sqlite3 *db);
@@ -115031,10 +115051,11 @@
115031 sqlite3_finalize(p->aStmt[i]);
115032 }
115033 sqlite3_free(p->zSegmentsTbl);
115034 sqlite3_free(p->zReadExprlist);
115035 sqlite3_free(p->zWriteExprlist);
 
115036
115037 /* Invoke the tokenizer destructor to free the tokenizer. */
115038 p->pTokenizer->pModule->xDestroy(p->pTokenizer);
115039
115040 sqlite3_free(p);
@@ -115070,20 +115091,23 @@
115070
115071 /*
115072 ** The xDestroy() virtual table method.
115073 */
115074 static int fts3DestroyMethod(sqlite3_vtab *pVtab){
115075 int rc = SQLITE_OK; /* Return code */
115076 Fts3Table *p = (Fts3Table *)pVtab;
115077 sqlite3 *db = p->db;
 
 
115078
115079 /* Drop the shadow tables */
115080 fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_content'", p->zDb, p->zName);
115081 fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segments'", p->zDb,p->zName);
115082 fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segdir'", p->zDb, p->zName);
115083 fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_docsize'", p->zDb, p->zName);
115084 fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_stat'", p->zDb, p->zName);
 
 
115085
115086 /* If everything has worked, invoke fts3DisconnectMethod() to free the
115087 ** memory associated with the Fts3Table structure and return SQLITE_OK.
115088 ** Otherwise, return an SQLite error code.
115089 */
@@ -115141,27 +115165,31 @@
115141 ** %_stat tables required by FTS4.
115142 */
115143 static int fts3CreateTables(Fts3Table *p){
115144 int rc = SQLITE_OK; /* Return code */
115145 int i; /* Iterator variable */
115146 char *zContentCols; /* Columns of %_content table */
115147 sqlite3 *db = p->db; /* The database connection */
115148
115149 /* Create a list of user columns for the content table */
115150 zContentCols = sqlite3_mprintf("docid INTEGER PRIMARY KEY");
115151 for(i=0; zContentCols && i<p->nColumn; i++){
115152 char *z = p->azColumn[i];
115153 zContentCols = sqlite3_mprintf("%z, 'c%d%q'", zContentCols, i, z);
115154 }
115155 if( zContentCols==0 ) rc = SQLITE_NOMEM;
115156
115157 /* Create the content table */
115158 fts3DbExec(&rc, db,
115159 "CREATE TABLE %Q.'%q_content'(%s)",
115160 p->zDb, p->zName, zContentCols
115161 );
115162 sqlite3_free(zContentCols);
 
 
 
 
 
115163 /* Create other tables */
115164 fts3DbExec(&rc, db,
115165 "CREATE TABLE %Q.'%q_segments'(blockid INTEGER PRIMARY KEY, block BLOB);",
115166 p->zDb, p->zName
115167 );
@@ -115308,12 +115336,12 @@
115308 }
115309 return zRet;
115310 }
115311
115312 /*
115313 ** Return a list of comma separated SQL expressions that could be used
115314 ** in a SELECT statement such as the following:
115315 **
115316 ** SELECT <list of expressions> FROM %_content AS x ...
115317 **
115318 ** to return the docid, followed by each column of text data in order
115319 ** from left to write. If parameter zFunc is not NULL, then instead of
@@ -115320,11 +115348,11 @@
115320 ** being returned directly each column of text data is passed to an SQL
115321 ** function named zFunc first. For example, if zFunc is "unzip" and the
115322 ** table has the three user-defined columns "a", "b", and "c", the following
115323 ** string is returned:
115324 **
115325 ** "docid, unzip(x.'a'), unzip(x.'b'), unzip(x.'c')"
115326 **
115327 ** The pointer returned points to a buffer allocated by sqlite3_malloc(). It
115328 ** is the responsibility of the caller to eventually free it.
115329 **
115330 ** If *pRc is not SQLITE_OK when this function is called, it is a no-op (and
@@ -115336,20 +115364,32 @@
115336 char *zRet = 0;
115337 char *zFree = 0;
115338 char *zFunction;
115339 int i;
115340
115341 if( !zFunc ){
115342 zFunction = "";
 
 
 
 
 
 
 
 
 
115343 }else{
115344 zFree = zFunction = fts3QuoteId(zFunc);
 
 
 
115345 }
115346 fts3Appendf(pRc, &zRet, "docid");
115347 for(i=0; i<p->nColumn; i++){
115348 fts3Appendf(pRc, &zRet, ",%s(x.'c%d%q')", zFunction, i, p->azColumn[i]);
115349 }
115350 sqlite3_free(zFree);
115351 return zRet;
115352 }
115353
115354 /*
115355 ** Return a list of N comma separated question marks, where N is the number
@@ -115468,10 +115508,95 @@
115468 }
115469 }
115470
115471 return SQLITE_OK;
115472 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115473
115474 /*
115475 ** This function is the implementation of both the xConnect and xCreate
115476 ** methods of the FTS3 virtual table.
115477 **
@@ -115513,10 +115638,11 @@
115513 int bNoDocsize = 0; /* True to omit %_docsize table */
115514 int bDescIdx = 0; /* True to store descending indexes */
115515 char *zPrefix = 0; /* Prefix parameter value (or NULL) */
115516 char *zCompress = 0; /* compress=? parameter (or NULL) */
115517 char *zUncompress = 0; /* uncompress=? parameter (or NULL) */
 
115518
115519 assert( strlen(argv[0])==4 );
115520 assert( (sqlite3_strnicmp(argv[0], "fts4", 4)==0 && isFts4)
115521 || (sqlite3_strnicmp(argv[0], "fts3", 4)==0 && !isFts4)
115522 );
@@ -115556,17 +115682,17 @@
115556 /* Check if it is an FTS4 special argument. */
115557 else if( isFts4 && fts3IsSpecialColumn(z, &nKey, &zVal) ){
115558 struct Fts4Option {
115559 const char *zOpt;
115560 int nOpt;
115561 char **pzVar;
115562 } aFts4Opt[] = {
115563 { "matchinfo", 9, 0 }, /* 0 -> MATCHINFO */
115564 { "prefix", 6, 0 }, /* 1 -> PREFIX */
115565 { "compress", 8, 0 }, /* 2 -> COMPRESS */
115566 { "uncompress", 10, 0 }, /* 3 -> UNCOMPRESS */
115567 { "order", 5, 0 } /* 4 -> ORDER */
 
115568 };
115569
115570 int iOpt;
115571 if( !zVal ){
115572 rc = SQLITE_NOMEM;
@@ -115608,17 +115734,24 @@
115608 zVal = 0;
115609 break;
115610
115611 case 4: /* ORDER */
115612 if( (strlen(zVal)!=3 || sqlite3_strnicmp(zVal, "asc", 3))
115613 && (strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "desc", 3))
115614 ){
115615 *pzErr = sqlite3_mprintf("unrecognized order: %s", zVal);
115616 rc = SQLITE_ERROR;
115617 }
115618 bDescIdx = (zVal[0]=='d' || zVal[0]=='D');
115619 break;
 
 
 
 
 
 
 
115620 }
115621 }
115622 sqlite3_free(zVal);
115623 }
115624 }
@@ -115627,10 +115760,30 @@
115627 else {
115628 nString += (int)(strlen(z) + 1);
115629 aCol[nCol++] = z;
115630 }
115631 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115632 if( rc!=SQLITE_OK ) goto fts3_init_out;
115633
115634 if( nCol==0 ){
115635 assert( nString==0 );
115636 aCol[0] = "content";
@@ -115671,10 +115824,12 @@
115671 p->pTokenizer = pTokenizer;
115672 p->nMaxPendingData = FTS3_MAX_PENDING_DATA;
115673 p->bHasDocsize = (isFts4 && bNoDocsize==0);
115674 p->bHasStat = isFts4;
115675 p->bDescIdx = bDescIdx;
 
 
115676 TESTONLY( p->inTransaction = -1 );
115677 TESTONLY( p->mxSavepoint = -1 );
115678
115679 p->aIndex = (struct Fts3Index *)&p->azColumn[nCol];
115680 memcpy(p->aIndex, aIndex, sizeof(struct Fts3Index) * nIndex);
@@ -115732,10 +115887,11 @@
115732 fts3_init_out:
115733 sqlite3_free(zPrefix);
115734 sqlite3_free(aIndex);
115735 sqlite3_free(zCompress);
115736 sqlite3_free(zUncompress);
 
115737 sqlite3_free((void *)aCol);
115738 if( rc!=SQLITE_OK ){
115739 if( p ){
115740 fts3DisconnectMethod((sqlite3_vtab *)p);
115741 }else if( pTokenizer ){
@@ -115882,40 +116038,69 @@
115882 sqlite3_free(pCsr->aMatchinfo);
115883 assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 );
115884 sqlite3_free(pCsr);
115885 return SQLITE_OK;
115886 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115887
115888 /*
115889 ** Position the pCsr->pStmt statement so that it is on the row
115890 ** of the %_content table that contains the last match. Return
115891 ** SQLITE_OK on success.
115892 */
115893 static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){
 
115894 if( pCsr->isRequireSeek ){
115895 sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iPrevId);
115896 pCsr->isRequireSeek = 0;
115897 if( SQLITE_ROW==sqlite3_step(pCsr->pStmt) ){
115898 return SQLITE_OK;
115899 }else{
115900 int rc = sqlite3_reset(pCsr->pStmt);
115901 if( rc==SQLITE_OK ){
115902 /* If no row was found and no error has occured, then the %_content
115903 ** table is missing a row that is present in the full-text index.
115904 ** The data structures are corrupt.
115905 */
115906 rc = FTS_CORRUPT_VTAB;
115907 }
115908 pCsr->isEof = 1;
115909 if( pContext ){
115910 sqlite3_result_error_code(pContext, rc);
115911 }
115912 return rc;
115913 }
115914 }else{
115915 return SQLITE_OK;
115916 }
 
 
 
115917 }
115918
115919 /*
115920 ** This function is used to process a single interior node when searching
115921 ** a b-tree for a term or term prefix. The node data is passed to this
@@ -116351,20 +116536,20 @@
116351 int isSaveLeft, /* Save the left position */
116352 int isExact, /* If *pp1 is exactly nTokens before *pp2 */
116353 char **pp1, /* IN/OUT: Left input list */
116354 char **pp2 /* IN/OUT: Right input list */
116355 ){
116356 char *p = (pp ? *pp : 0);
116357 char *p1 = *pp1;
116358 char *p2 = *pp2;
116359 int iCol1 = 0;
116360 int iCol2 = 0;
116361
116362 /* Never set both isSaveLeft and isExact for the same invocation. */
116363 assert( isSaveLeft==0 || isExact==0 );
116364
116365 assert( *p1!=0 && *p2!=0 );
116366 if( *p1==POS_COLUMN ){
116367 p1++;
116368 p1 += sqlite3Fts3GetVarint32(p1, &iCol1);
116369 }
116370 if( *p2==POS_COLUMN ){
@@ -116377,11 +116562,11 @@
116377 char *pSave = p;
116378 sqlite3_int64 iPrev = 0;
116379 sqlite3_int64 iPos1 = 0;
116380 sqlite3_int64 iPos2 = 0;
116381
116382 if( pp && iCol1 ){
116383 *p++ = POS_COLUMN;
116384 p += sqlite3Fts3PutVarint(p, iCol1);
116385 }
116386
116387 assert( *p1!=POS_END && *p1!=POS_COLUMN );
@@ -116392,20 +116577,14 @@
116392 while( 1 ){
116393 if( iPos2==iPos1+nToken
116394 || (isExact==0 && iPos2>iPos1 && iPos2<=iPos1+nToken)
116395 ){
116396 sqlite3_int64 iSave;
116397 if( !pp ){
116398 fts3PoslistCopy(0, &p2);
116399 fts3PoslistCopy(0, &p1);
116400 *pp1 = p1;
116401 *pp2 = p2;
116402 return 1;
116403 }
116404 iSave = isSaveLeft ? iPos1 : iPos2;
116405 fts3PutDeltaVarint(&p, &iPrev, iSave+2); iPrev -= 2;
116406 pSave = 0;
 
116407 }
116408 if( (!isSaveLeft && iPos2<=(iPos1+nToken)) || iPos2<=iPos1 ){
116409 if( (*p2&0xFE)==0 ) break;
116410 fts3GetDeltaVarint(&p2, &iPos2); iPos2 -= 2;
116411 }else{
@@ -116450,11 +116629,11 @@
116450
116451 fts3PoslistCopy(0, &p2);
116452 fts3PoslistCopy(0, &p1);
116453 *pp1 = p1;
116454 *pp2 = p2;
116455 if( !pp || *pp==p ){
116456 return 0;
116457 }
116458 *p++ = 0x00;
116459 *pp = p;
116460 return 1;
@@ -116752,10 +116931,60 @@
116752 }
116753 }
116754
116755 *pnRight = p - aOut;
116756 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116757
116758
116759 /*
116760 ** Merge all doclists in the TermSelect.aaOutput[] array into a single
116761 ** doclist stored in TermSelect.aaOutput[0]. If successful, delete all
@@ -117109,10 +117338,11 @@
117109 pSegcsr = pTok->pSegcsr;
117110 memset(&tsc, 0, sizeof(TermSelect));
117111
117112 filter.flags = FTS3_SEGMENT_IGNORE_EMPTY | FTS3_SEGMENT_REQUIRE_POS
117113 | (pTok->isPrefix ? FTS3_SEGMENT_PREFIX : 0)
 
117114 | (iColumn<p->nColumn ? FTS3_SEGMENT_COLUMN_FILTER : 0);
117115 filter.iCol = iColumn;
117116 filter.zTerm = pTok->z;
117117 filter.nTerm = pTok->n;
117118
@@ -117249,12 +117479,12 @@
117249
117250 if( zQuery==0 && sqlite3_value_type(apVal[0])!=SQLITE_NULL ){
117251 return SQLITE_NOMEM;
117252 }
117253
117254 rc = sqlite3Fts3ExprParse(p->pTokenizer, p->azColumn, p->nColumn,
117255 iCol, zQuery, -1, &pCsr->pExpr
117256 );
117257 if( rc!=SQLITE_OK ){
117258 if( rc==SQLITE_ERROR ){
117259 static const char *zErr = "malformed MATCH expression: [%s]";
117260 p->base.zErrMsg = sqlite3_mprintf(zErr, zQuery);
@@ -117277,26 +117507,27 @@
117277 ** statement loops through all rows of the %_content table. For a
117278 ** full-text query or docid lookup, the statement retrieves a single
117279 ** row by docid.
117280 */
117281 if( idxNum==FTS3_FULLSCAN_SEARCH ){
117282 const char *zSort = (pCsr->bDesc ? "DESC" : "ASC");
117283 const char *zTmpl = "SELECT %s FROM %Q.'%q_content' AS x ORDER BY docid %s";
117284 zSql = sqlite3_mprintf(zTmpl, p->zReadExprlist, p->zDb, p->zName, zSort);
117285 }else{
117286 const char *zTmpl = "SELECT %s FROM %Q.'%q_content' AS x WHERE docid = ?";
117287 zSql = sqlite3_mprintf(zTmpl, p->zReadExprlist, p->zDb, p->zName);
117288 }
117289 if( !zSql ) return SQLITE_NOMEM;
117290 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0);
117291 sqlite3_free(zSql);
117292 if( rc!=SQLITE_OK ) return rc;
117293
117294 if( idxNum==FTS3_DOCID_SEARCH ){
117295 rc = sqlite3_bind_value(pCsr->pStmt, 1, apVal[0]);
117296 if( rc!=SQLITE_OK ) return rc;
117297 }
 
117298
117299 return fts3NextMethod(pCursor);
117300 }
117301
117302 /*
@@ -117345,11 +117576,11 @@
117345 ** Return a blob which is a pointer to the cursor.
117346 */
117347 sqlite3_result_blob(pContext, &pCsr, sizeof(pCsr), SQLITE_TRANSIENT);
117348 }else{
117349 rc = fts3CursorSeek(0, pCsr);
117350 if( rc==SQLITE_OK ){
117351 sqlite3_result_value(pContext, sqlite3_column_value(pCsr->pStmt, iCol+1));
117352 }
117353 }
117354
117355 assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 );
@@ -117638,19 +117869,26 @@
117638 ){
117639 Fts3Table *p = (Fts3Table *)pVtab;
117640 sqlite3 *db = p->db; /* Database connection */
117641 int rc; /* Return Code */
117642
 
 
 
 
 
 
 
117643 rc = sqlite3Fts3PendingTermsFlush(p);
117644 if( rc!=SQLITE_OK ){
117645 return rc;
 
 
 
 
117646 }
117647
117648 fts3DbExec(&rc, db,
117649 "ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';",
117650 p->zDb, p->zName, zName
117651 );
117652 if( p->bHasDocsize ){
117653 fts3DbExec(&rc, db,
117654 "ALTER TABLE %Q.'%q_docsize' RENAME TO '%q_docsize';",
117655 p->zDb, p->zName, zName
117656 );
@@ -118005,25 +118243,24 @@
118005 **
118006 ** SQLITE_OK is returned if no error occurs, otherwise an SQLite error code.
118007 */
118008 static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
118009 int iToken; /* Used to iterate through phrase tokens */
118010 int rc = SQLITE_OK; /* Return code */
118011 char *aPoslist = 0; /* Position list for deferred tokens */
118012 int nPoslist = 0; /* Number of bytes in aPoslist */
118013 int iPrev = -1; /* Token number of previous deferred token */
118014
118015 assert( pPhrase->doclist.bFreeList==0 );
118016
118017 for(iToken=0; rc==SQLITE_OK && iToken<pPhrase->nToken; iToken++){
118018 Fts3PhraseToken *pToken = &pPhrase->aToken[iToken];
118019 Fts3DeferredToken *pDeferred = pToken->pDeferred;
118020
118021 if( pDeferred ){
118022 char *pList;
118023 int nList;
118024 rc = sqlite3Fts3DeferredTokenList(pDeferred, &pList, &nList);
118025 if( rc!=SQLITE_OK ) return rc;
118026
118027 if( pList==0 ){
118028 sqlite3_free(aPoslist);
118029 pPhrase->doclist.pList = 0;
@@ -118120,10 +118357,11 @@
118120 if( pCsr->bDesc==pTab->bDescIdx
118121 && bOptOk==1
118122 && p->nToken==1
118123 && pFirst->pSegcsr
118124 && pFirst->pSegcsr->bLookup
 
118125 ){
118126 /* Use the incremental approach. */
118127 int iCol = (p->iColumn >= pTab->nColumn ? -1 : p->iColumn);
118128 rc = sqlite3Fts3MsrIncrStart(
118129 pTab, pFirst->pSegcsr, iCol, pFirst->z, pFirst->n);
@@ -118349,11 +118587,11 @@
118349 Fts3Expr *pExpr, /* Expression to consider */
118350 Fts3TokenAndCost **ppTC, /* Write new entries to *(*ppTC)++ */
118351 Fts3Expr ***ppOr, /* Write new OR root to *(*ppOr)++ */
118352 int *pRc /* IN/OUT: Error code */
118353 ){
118354 if( *pRc==SQLITE_OK && pExpr ){
118355 if( pExpr->eType==FTSQUERY_PHRASE ){
118356 Fts3Phrase *pPhrase = pExpr->pPhrase;
118357 int i;
118358 for(i=0; *pRc==SQLITE_OK && i<pPhrase->nToken; i++){
118359 Fts3TokenAndCost *pTC = (*ppTC)++;
@@ -118363,10 +118601,15 @@
118363 pTC->pToken = &pPhrase->aToken[i];
118364 pTC->iCol = pPhrase->iColumn;
118365 *pRc = sqlite3Fts3MsrOvfl(pCsr, pTC->pToken->pSegcsr, &pTC->nOvfl);
118366 }
118367 }else if( pExpr->eType!=FTSQUERY_NOT ){
 
 
 
 
 
118368 if( pExpr->eType==FTSQUERY_OR ){
118369 pRoot = pExpr->pLeft;
118370 **ppOr = pRoot;
118371 (*ppOr)++;
118372 }
@@ -118466,10 +118709,19 @@
118466 int nOvfl = 0; /* Total overflow pages used by doclists */
118467 int nToken = 0; /* Total number of tokens in cluster */
118468
118469 int nMinEst = 0; /* The minimum count for any phrase so far. */
118470 int nLoad4 = 1; /* (Phrases that will be loaded)^4. */
 
 
 
 
 
 
 
 
 
118471
118472 /* Count the tokens in this AND/NEAR cluster. If none of the doclists
118473 ** associated with the tokens spill onto overflow pages, or if there is
118474 ** only 1 token, exit early. No tokens to defer in this case. */
118475 for(ii=0; ii<nTC; ii++){
@@ -118529,11 +118781,15 @@
118529 Fts3PhraseToken *pToken = pTC->pToken;
118530 rc = sqlite3Fts3DeferToken(pCsr, pToken, pTC->iCol);
118531 fts3SegReaderCursorFree(pToken->pSegcsr);
118532 pToken->pSegcsr = 0;
118533 }else{
118534 nLoad4 = nLoad4*4;
 
 
 
 
118535 if( ii==0 || pTC->pPhrase->nToken>1 ){
118536 /* Either this is the cheapest token in the entire query, or it is
118537 ** part of a multi-token phrase. Either way, the entire doclist will
118538 ** (eventually) be loaded into memory. It may as well be now. */
118539 Fts3PhraseToken *pToken = pTC->pToken;
@@ -119990,10 +120246,11 @@
119990 */
119991 typedef struct ParseContext ParseContext;
119992 struct ParseContext {
119993 sqlite3_tokenizer *pTokenizer; /* Tokenizer module */
119994 const char **azCol; /* Array of column names for fts3 table */
 
119995 int nCol; /* Number of entries in azCol[] */
119996 int iDefaultCol; /* Default column to query */
119997 int isNot; /* True if getNextNode() sees a unary - */
119998 sqlite3_context *pCtx; /* Write error message here */
119999 int nNest; /* Number of nested brackets */
@@ -120077,13 +120334,25 @@
120077
120078 if( iEnd<n && z[iEnd]=='*' ){
120079 pRet->pPhrase->aToken[0].isPrefix = 1;
120080 iEnd++;
120081 }
120082 if( !sqlite3_fts3_enable_parentheses && iStart>0 && z[iStart-1]=='-' ){
120083 pParse->isNot = 1;
 
 
 
 
 
 
 
 
 
 
 
120084 }
 
120085 }
120086 nConsumed = iEnd;
120087 }
120088
120089 pModule->xClose(pCursor);
@@ -120178,10 +120447,11 @@
120178 memcpy(&zTemp[nTemp], zByte, nByte);
120179 nTemp += nByte;
120180
120181 pToken->n = nByte;
120182 pToken->isPrefix = (iEnd<nInput && zInput[iEnd]=='*');
 
120183 nToken = ii+1;
120184 }
120185 }
120186
120187 pModule->xClose(pCursor);
@@ -120629,10 +120899,11 @@
120629 ** match any table column.
120630 */
120631 SQLITE_PRIVATE int sqlite3Fts3ExprParse(
120632 sqlite3_tokenizer *pTokenizer, /* Tokenizer module */
120633 char **azCol, /* Array of column names for fts3 table */
 
120634 int nCol, /* Number of entries in azCol[] */
120635 int iDefaultCol, /* Default column to query */
120636 const char *z, int n, /* Text of MATCH query */
120637 Fts3Expr **ppExpr /* OUT: Parsed query structure */
120638 ){
@@ -120642,10 +120913,11 @@
120642 sParse.pTokenizer = pTokenizer;
120643 sParse.azCol = (const char **)azCol;
120644 sParse.nCol = nCol;
120645 sParse.iDefaultCol = iDefaultCol;
120646 sParse.nNest = 0;
 
120647 if( z==0 ){
120648 *ppExpr = 0;
120649 return SQLITE_OK;
120650 }
120651 if( n<0 ){
@@ -120831,11 +121103,11 @@
120831 for(ii=0; ii<nCol; ii++){
120832 azCol[ii] = (char *)sqlite3_value_text(argv[ii+2]);
120833 }
120834
120835 rc = sqlite3Fts3ExprParse(
120836 pTokenizer, azCol, nCol, nCol, zExpr, nExpr, &pExpr
120837 );
120838 if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){
120839 sqlite3_result_error(context, "Error parsing expression", -1);
120840 }else if( rc==SQLITE_NOMEM || !(zBuf = exprToString(pExpr, 0)) ){
120841 sqlite3_result_error_nomem(context);
@@ -122878,11 +123150,11 @@
122878 /* 2 */ "DELETE FROM %Q.'%q_content'",
122879 /* 3 */ "DELETE FROM %Q.'%q_segments'",
122880 /* 4 */ "DELETE FROM %Q.'%q_segdir'",
122881 /* 5 */ "DELETE FROM %Q.'%q_docsize'",
122882 /* 6 */ "DELETE FROM %Q.'%q_stat'",
122883 /* 7 */ "SELECT %s FROM %Q.'%q_content' AS x WHERE rowid=?",
122884 /* 8 */ "SELECT (SELECT max(idx) FROM %Q.'%q_segdir' WHERE level = ?) + 1",
122885 /* 9 */ "INSERT INTO %Q.'%q_segments'(blockid, block) VALUES(?, ?)",
122886 /* 10 */ "SELECT coalesce((SELECT max(blockid) FROM %Q.'%q_segments') + 1, 1)",
122887 /* 11 */ "INSERT INTO %Q.'%q_segdir' VALUES(?,?,?,?,?,?)",
122888
@@ -122920,11 +123192,11 @@
122920 if( !pStmt ){
122921 char *zSql;
122922 if( eStmt==SQL_CONTENT_INSERT ){
122923 zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName, p->zWriteExprlist);
122924 }else if( eStmt==SQL_SELECT_CONTENT_BY_ROWID ){
122925 zSql = sqlite3_mprintf(azSql[eStmt], p->zReadExprlist, p->zDb, p->zName);
122926 }else{
122927 zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName);
122928 }
122929 if( !zSql ){
122930 rc = SQLITE_NOMEM;
@@ -123031,21 +123303,28 @@
123031 ** We try to avoid this because if FTS3 returns any error when committing
123032 ** a transaction, the whole transaction will be rolled back. And this is
123033 ** not what users expect when they get SQLITE_LOCKED_SHAREDCACHE. It can
123034 ** still happen if the user reads data directly from the %_segments or
123035 ** %_segdir tables instead of going through FTS3 though.
 
 
123036 */
123037 SQLITE_PRIVATE int sqlite3Fts3ReadLock(Fts3Table *p){
123038 int rc; /* Return code */
123039 sqlite3_stmt *pStmt; /* Statement used to obtain lock */
123040
123041 rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pStmt, 0);
123042 if( rc==SQLITE_OK ){
123043 sqlite3_bind_null(pStmt, 1);
123044 sqlite3_step(pStmt);
123045 rc = sqlite3_reset(pStmt);
 
 
 
 
123046 }
 
123047 return rc;
123048 }
123049
123050 /*
123051 ** Set *ppStmt to a statement handle that may be used to iterate through
@@ -123401,10 +123680,22 @@
123401 sqlite3_value **apVal, /* Array of values to insert */
123402 sqlite3_int64 *piDocid /* OUT: Docid for row just inserted */
123403 ){
123404 int rc; /* Return code */
123405 sqlite3_stmt *pContentInsert; /* INSERT INTO %_content VALUES(...) */
 
 
 
 
 
 
 
 
 
 
 
 
123406
123407 /* Locate the statement handle used to insert data into the %_content
123408 ** table. The SQL for this statement is:
123409 **
123410 ** INSERT INTO %_content VALUES(?, ?, ?, ...)
@@ -123452,18 +123743,20 @@
123452
123453 /*
123454 ** Remove all data from the FTS3 table. Clear the hash table containing
123455 ** pending terms.
123456 */
123457 static int fts3DeleteAll(Fts3Table *p){
123458 int rc = SQLITE_OK; /* Return code */
123459
123460 /* Discard the contents of the pending-terms hash table. */
123461 sqlite3Fts3PendingTermsClear(p);
123462
123463 /* Delete everything from the %_content, %_segments and %_segdir tables. */
123464 fts3SqlExec(&rc, p, SQL_DELETE_ALL_CONTENT, 0);
 
 
123465 fts3SqlExec(&rc, p, SQL_DELETE_ALL_SEGMENTS, 0);
123466 fts3SqlExec(&rc, p, SQL_DELETE_ALL_SEGDIR, 0);
123467 if( p->bHasDocsize ){
123468 fts3SqlExec(&rc, p, SQL_DELETE_ALL_DOCSIZE, 0);
123469 }
@@ -124747,16 +125040,22 @@
124747 ** error occurs, an SQLite error code is returned.
124748 */
124749 static int fts3IsEmpty(Fts3Table *p, sqlite3_value *pRowid, int *pisEmpty){
124750 sqlite3_stmt *pStmt;
124751 int rc;
124752 rc = fts3SqlStmt(p, SQL_IS_EMPTY, &pStmt, &pRowid);
124753 if( rc==SQLITE_OK ){
124754 if( SQLITE_ROW==sqlite3_step(pStmt) ){
124755 *pisEmpty = sqlite3_column_int(pStmt, 0);
 
 
 
 
 
 
 
124756 }
124757 rc = sqlite3_reset(pStmt);
124758 }
124759 return rc;
124760 }
124761
124762 /*
@@ -125104,10 +125403,11 @@
125104 int isIgnoreEmpty = (pCsr->pFilter->flags & FTS3_SEGMENT_IGNORE_EMPTY);
125105 int isRequirePos = (pCsr->pFilter->flags & FTS3_SEGMENT_REQUIRE_POS);
125106 int isColFilter = (pCsr->pFilter->flags & FTS3_SEGMENT_COLUMN_FILTER);
125107 int isPrefix = (pCsr->pFilter->flags & FTS3_SEGMENT_PREFIX);
125108 int isScan = (pCsr->pFilter->flags & FTS3_SEGMENT_SCAN);
 
125109
125110 Fts3SegReader **apSegment = pCsr->apSegment;
125111 int nSegment = pCsr->nSegment;
125112 Fts3SegFilter *pFilter = pCsr->pFilter;
125113 int (*xCmp)(Fts3SegReader *, Fts3SegReader *) = (
@@ -125163,10 +125463,11 @@
125163 }
125164
125165 assert( isIgnoreEmpty || (isRequirePos && !isColFilter) );
125166 if( nMerge==1
125167 && !isIgnoreEmpty
 
125168 && (p->bDescIdx==0 || fts3SegReaderIsPending(apSegment[0])==0)
125169 ){
125170 pCsr->nDoclist = apSegment[0]->nDoclist;
125171 if( fts3SegReaderIsPending(apSegment[0]) ){
125172 rc = fts3MsrBufferData(pCsr, apSegment[0]->aDoclist, pCsr->nDoclist);
@@ -125228,16 +125529,28 @@
125228 if( !aNew ){
125229 return SQLITE_NOMEM;
125230 }
125231 pCsr->aBuffer = aNew;
125232 }
125233 nDoclist += sqlite3Fts3PutVarint(&pCsr->aBuffer[nDoclist], iDelta);
125234 iPrev = iDocid;
125235 if( isRequirePos ){
125236 memcpy(&pCsr->aBuffer[nDoclist], pList, nList);
125237 nDoclist += nList;
125238 pCsr->aBuffer[nDoclist++] = '\0';
 
 
 
 
 
 
 
 
 
 
 
 
125239 }
125240 }
125241
125242 fts3SegReaderSort(apSegment, nMerge, j, xCmp);
125243 }
@@ -125409,13 +125722,13 @@
125409 ** Insert the sizes (in tokens) for each column of the document
125410 ** with docid equal to p->iPrevDocid. The sizes are encoded as
125411 ** a blob of varints.
125412 */
125413 static void fts3InsertDocsize(
125414 int *pRC, /* Result code */
125415 Fts3Table *p, /* Table into which to insert */
125416 u32 *aSz /* Sizes of each column */
125417 ){
125418 char *pBlob; /* The BLOB encoding of the document size */
125419 int nBlob; /* Number of bytes in the BLOB */
125420 sqlite3_stmt *pStmt; /* Statement used to insert the encoding */
125421 int rc; /* Result code from subfunctions */
@@ -125532,10 +125845,90 @@
125532 sqlite3Fts3SegmentsClose(p);
125533 sqlite3Fts3PendingTermsClear(p);
125534
125535 return (rc==SQLITE_OK && bReturnDone && bSeenDone) ? SQLITE_DONE : rc;
125536 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125537
125538 /*
125539 ** Handle a 'special' INSERT of the form:
125540 **
125541 ** "INSERT INTO tbl(tbl) VALUES(<expr>)"
@@ -125550,10 +125943,12 @@
125550
125551 if( !zVal ){
125552 return SQLITE_NOMEM;
125553 }else if( nVal==8 && 0==sqlite3_strnicmp(zVal, "optimize", 8) ){
125554 rc = fts3DoOptimize(p, 0);
 
 
125555 #ifdef SQLITE_TEST
125556 }else if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){
125557 p->nNodeSize = atoi(&zVal[9]);
125558 rc = SQLITE_OK;
125559 }else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 9) ){
@@ -125630,10 +126025,11 @@
125630 pTC->pTokenizer = pT;
125631 rc = pModule->xNext(pTC, &zToken, &nToken, &iDum1, &iDum2, &iPos);
125632 for(pDef=pCsr->pDeferred; pDef && rc==SQLITE_OK; pDef=pDef->pNext){
125633 Fts3PhraseToken *pPT = pDef->pToken;
125634 if( (pDef->iCol>=p->nColumn || pDef->iCol==i)
 
125635 && (pPT->n==nToken || (pPT->isPrefix && pPT->n<nToken))
125636 && (0==memcmp(zToken, pPT->z, pPT->n))
125637 ){
125638 fts3PendingListAppend(&pDef->pList, iDocid, i, iPos, &rc);
125639 }
@@ -125721,18 +126117,22 @@
125721 if( rc==SQLITE_OK ){
125722 if( isEmpty ){
125723 /* Deleting this row means the whole table is empty. In this case
125724 ** delete the contents of all three tables and throw away any
125725 ** data in the pendingTerms hash table. */
125726 rc = fts3DeleteAll(p);
125727 *pnDoc = *pnDoc - 1;
125728 }else{
125729 sqlite3_int64 iRemove = sqlite3_value_int64(pRowid);
125730 rc = fts3PendingTermsDocid(p, iRemove);
125731 fts3DeleteTerms(&rc, p, pRowid, aSzDel);
125732 fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, &pRowid);
125733 if( sqlite3_changes(p->db) ) *pnDoc = *pnDoc - 1;
 
 
 
 
125734 if( p->bHasDocsize ){
125735 fts3SqlExec(&rc, p, SQL_DELETE_DOCSIZE, &pRowid);
125736 }
125737 }
125738 }
@@ -125788,11 +126188,11 @@
125788 ** should be deleted from the database before inserting the new row. Or,
125789 ** if the on-conflict mode is other than REPLACE, then this method must
125790 ** detect the conflict and return SQLITE_CONSTRAINT before beginning to
125791 ** modify the database file.
125792 */
125793 if( nArg>1 ){
125794 /* Find the value object that holds the new rowid value. */
125795 sqlite3_value *pNewRowid = apVal[3+p->nColumn];
125796 if( sqlite3_value_type(pNewRowid)==SQLITE_NULL ){
125797 pNewRowid = apVal[1];
125798 }
@@ -125839,11 +126239,13 @@
125839
125840 /* If this is an INSERT or UPDATE operation, insert the new record. */
125841 if( nArg>1 && rc==SQLITE_OK ){
125842 if( bInsertDone==0 ){
125843 rc = fts3InsertData(p, apVal, pRowid);
125844 if( rc==SQLITE_CONSTRAINT ) rc = FTS_CORRUPT_VTAB;
 
 
125845 }
125846 if( rc==SQLITE_OK && (!isRemove || *pRowid!=p->iPrevDocid ) ){
125847 rc = fts3PendingTermsDocid(p, *pRowid);
125848 }
125849 if( rc==SQLITE_OK ){
@@ -126259,10 +126661,11 @@
126259 pCsr = sqlite3Fts3EvalPhrasePoslist(p->pCsr, pExpr, p->iCol);
126260 if( pCsr ){
126261 int iFirst = 0;
126262 pPhrase->pList = pCsr;
126263 fts3GetDeltaPosition(&pCsr, &iFirst);
 
126264 pPhrase->pHead = pCsr;
126265 pPhrase->pTail = pCsr;
126266 pPhrase->iHead = iFirst;
126267 pPhrase->iTail = iFirst;
126268 }else{
@@ -127300,11 +127703,11 @@
127300 }
127301 }
127302
127303 if( !pTerm ){
127304 /* All offsets for this column have been gathered. */
127305 break;
127306 }else{
127307 assert( iCurrent<=iMinPos );
127308 if( 0==(0xFE&*pTerm->pList) ){
127309 pTerm->pList = 0;
127310 }else{
@@ -127317,11 +127720,11 @@
127317 char aBuffer[64];
127318 sqlite3_snprintf(sizeof(aBuffer), aBuffer,
127319 "%d %d %d %d ", iCol, pTerm-sCtx.aTerm, iStart, iEnd-iStart
127320 );
127321 rc = fts3StringAppend(&res, aBuffer, -1);
127322 }else if( rc==SQLITE_DONE ){
127323 rc = FTS_CORRUPT_VTAB;
127324 }
127325 }
127326 }
127327 if( rc==SQLITE_DONE ){
127328
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -656,11 +656,11 @@
656 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
657 ** [sqlite_version()] and [sqlite_source_id()].
658 */
659 #define SQLITE_VERSION "3.7.9"
660 #define SQLITE_VERSION_NUMBER 3007009
661 #define SQLITE_SOURCE_ID "2011-10-20 00:55:54 4344483f7d7f64dffadde0053e6c745948db9486"
662
663 /*
664 ** CAPI3REF: Run-Time Library Version Numbers
665 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
666 **
@@ -1951,12 +1951,12 @@
1951 ** memory pointer is not NULL and either [SQLITE_ENABLE_MEMSYS3] or
1952 ** [SQLITE_ENABLE_MEMSYS5] are defined, then the alternative memory
1953 ** allocator is engaged to handle all of SQLites memory allocation needs.
1954 ** The first pointer (the memory pointer) must be aligned to an 8-byte
1955 ** boundary or subsequent behavior of SQLite will be undefined.
1956 ** The minimum allocation size is capped at 2**12. Reasonable values
1957 ** for the minimum allocation size are 2**5 through 2**8.</dd>
1958 **
1959 ** [[SQLITE_CONFIG_MUTEX]] <dt>SQLITE_CONFIG_MUTEX</dt>
1960 ** <dd> ^(This option takes a single argument which is a pointer to an
1961 ** instance of the [sqlite3_mutex_methods] structure. The argument specifies
1962 ** alternative low-level mutex routines to be used in place
@@ -20969,11 +20969,11 @@
20969 }else if( *z=='+' ){
20970 z+=incr;
20971 }
20972 /* copy digits to exponent */
20973 while( z<zEnd && sqlite3Isdigit(*z) ){
20974 e = e<10000 ? (e*10 + (*z - '0')) : 10000;
20975 z+=incr;
20976 eValid = 1;
20977 }
20978 }
20979
@@ -21020,10 +21020,16 @@
21020 result /= 1.0e+308;
21021 }else{
21022 result = s * scale;
21023 result *= 1.0e+308;
21024 }
21025 }else if( e>=342 ){
21026 if( esign<0 ){
21027 result = 0.0*s;
21028 }else{
21029 result = 1e308*1e308*s; /* Infinity */
21030 }
21031 }else{
21032 /* 1.0e+22 is the largest power of 10 than can be
21033 ** represented exactly. */
21034 while( e%22 ) { scale *= 1.0e+1; e -= 1; }
21035 while( e>0 ) { scale *= 1.0e+22; e -= 22; }
@@ -68962,11 +68968,11 @@
68968
68969 /* Do not allow a transition to journal_mode=WAL for a database
68970 ** in temporary storage or if the VFS does not support shared memory
68971 */
68972 if( u.ch.eNew==PAGER_JOURNALMODE_WAL
68973 && (sqlite3Strlen30(u.ch.zFilename)==0 /* Temp file */
68974 || !sqlite3PagerWalSupported(u.ch.pPager)) /* No shared-memory support */
68975 ){
68976 u.ch.eNew = u.ch.eOld;
68977 }
68978
@@ -69397,14 +69403,19 @@
69403 u.co.pName = &aMem[pOp->p1];
69404 assert( u.co.pVtab->pModule->xRename );
69405 assert( memIsValid(u.co.pName) );
69406 REGISTER_TRACE(pOp->p1, u.co.pName);
69407 assert( u.co.pName->flags & MEM_Str );
69408 testcase( u.co.pName->enc==SQLITE_UTF8 );
69409 testcase( u.co.pName->enc==SQLITE_UTF16BE );
69410 testcase( u.co.pName->enc==SQLITE_UTF16LE );
69411 rc = sqlite3VdbeChangeEncoding(u.co.pName, SQLITE_UTF8);
69412 if( rc==SQLITE_OK ){
69413 rc = u.co.pVtab->pModule->xRename(u.co.pVtab, u.co.pName->z);
69414 importVtabErrMsg(p, u.co.pVtab);
69415 p->expired = 0;
69416 }
69417 break;
69418 }
69419 #endif
69420
69421 #ifndef SQLITE_OMIT_VIRTUALTABLE
@@ -71758,10 +71769,28 @@
71769 ExprSetProperty(pExpr, EP_Static);
71770 sqlite3ExprDelete(db, pExpr);
71771 memcpy(pExpr, pDup, sizeof(*pExpr));
71772 sqlite3DbFree(db, pDup);
71773 }
71774
71775
71776 /*
71777 ** Return TRUE if the name zCol occurs anywhere in the USING clause.
71778 **
71779 ** Return FALSE if the USING clause is NULL or if it does not contain
71780 ** zCol.
71781 */
71782 static int nameInUsingClause(IdList *pUsing, const char *zCol){
71783 if( pUsing ){
71784 int k;
71785 for(k=0; k<pUsing->nId; k++){
71786 if( sqlite3StrICmp(pUsing->a[k].zName, zCol)==0 ) return 1;
71787 }
71788 }
71789 return 0;
71790 }
71791
71792
71793 /*
71794 ** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up
71795 ** that name in the set of source tables in pSrcList and make the pExpr
71796 ** expression node refer back to that source column. The following changes
@@ -71850,38 +71879,25 @@
71879 pSchema = pTab->pSchema;
71880 pMatch = pItem;
71881 }
71882 for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){
71883 if( sqlite3StrICmp(pCol->zName, zCol)==0 ){
71884 /* If there has been exactly one prior match and this match
71885 ** is for the right-hand table of a NATURAL JOIN or is in a
71886 ** USING clause, then skip this match.
71887 */
71888 if( cnt==1 ){
71889 if( pItem->jointype & JT_NATURAL ) continue;
71890 if( nameInUsingClause(pItem->pUsing, zCol) ) continue;
71891 }
71892 cnt++;
71893 pExpr->iTable = pItem->iCursor;
71894 pExpr->pTab = pTab;
71895 pMatch = pItem;
71896 pSchema = pTab->pSchema;
71897 /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
71898 pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71899 break;
71900 }
71901 }
71902 }
71903 }
@@ -102501,10 +102517,11 @@
102517 tempWC.pParse = pWC->pParse;
102518 tempWC.pMaskSet = pWC->pMaskSet;
102519 tempWC.pOuter = pWC;
102520 tempWC.op = TK_AND;
102521 tempWC.a = pOrTerm;
102522 tempWC.wctrlFlags = 0;
102523 tempWC.nTerm = 1;
102524 bestIndex(pParse, &tempWC, pSrc, notReady, notValid, 0, &sTermCost);
102525 }else{
102526 continue;
102527 }
@@ -114528,10 +114545,11 @@
114545 const char *zDb; /* logical database name */
114546 const char *zName; /* virtual table name */
114547 int nColumn; /* number of named columns in virtual table */
114548 char **azColumn; /* column names. malloced */
114549 sqlite3_tokenizer *pTokenizer; /* tokenizer for inserts and queries */
114550 char *zContentTbl; /* content=xxx option, or NULL */
114551
114552 /* Precompiled statements used by the implementation. Each of these
114553 ** statements is run and reset within a single virtual table API call.
114554 */
114555 sqlite3_stmt *aStmt[27];
@@ -114568,11 +114586,11 @@
114586 } *aIndex;
114587 int nMaxPendingData; /* Max pending data before flush to disk */
114588 int nPendingData; /* Current bytes of pending data */
114589 sqlite_int64 iPrevDocid; /* Docid of most recently inserted document */
114590
114591 #if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
114592 /* State variables used for validating that the transaction control
114593 ** methods of the virtual table are called at appropriate times. These
114594 ** values do not contribution to the FTS computation; they are used for
114595 ** verifying the SQLite core.
114596 */
@@ -114653,10 +114671,11 @@
114671 */
114672 struct Fts3PhraseToken {
114673 char *z; /* Text of the token */
114674 int n; /* Number of bytes in buffer z */
114675 int isPrefix; /* True if token ends with a "*" character */
114676 int bFirst; /* True if token must appear at position 0 */
114677
114678 /* Variables above this point are populated when the expression is
114679 ** parsed (by code in fts3_expr.c). Below this point the variables are
114680 ** used when evaluating the expression. */
114681 Fts3DeferredToken *pDeferred; /* Deferred token object for this token */
@@ -114771,10 +114790,11 @@
114790 #define FTS3_SEGMENT_REQUIRE_POS 0x00000001
114791 #define FTS3_SEGMENT_IGNORE_EMPTY 0x00000002
114792 #define FTS3_SEGMENT_COLUMN_FILTER 0x00000004
114793 #define FTS3_SEGMENT_PREFIX 0x00000008
114794 #define FTS3_SEGMENT_SCAN 0x00000010
114795 #define FTS3_SEGMENT_FIRST 0x00000020
114796
114797 /* Type passed as 4th argument to SegmentReaderIterate() */
114798 struct Fts3SegFilter {
114799 const char *zTerm;
114800 int nTerm;
@@ -114810,12 +114830,12 @@
114830 SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *, sqlite_int64 *);
114831 SQLITE_PRIVATE int sqlite3Fts3GetVarint32(const char *, int *);
114832 SQLITE_PRIVATE int sqlite3Fts3VarintLen(sqlite3_uint64);
114833 SQLITE_PRIVATE void sqlite3Fts3Dequote(char *);
114834 SQLITE_PRIVATE void sqlite3Fts3DoclistPrev(int,char*,int,char**,sqlite3_int64*,int*,u8*);
 
114835 SQLITE_PRIVATE int sqlite3Fts3EvalPhraseStats(Fts3Cursor *, Fts3Expr *, u32 *);
114836 SQLITE_PRIVATE int sqlite3Fts3FirstFilter(sqlite3_int64, char *, int, char *);
114837
114838 /* fts3_tokenizer.c */
114839 SQLITE_PRIVATE const char *sqlite3Fts3NextToken(const char *, int *);
114840 SQLITE_PRIVATE int sqlite3Fts3InitHashTable(sqlite3 *, Fts3Hash *, const char *);
114841 SQLITE_PRIVATE int sqlite3Fts3InitTokenizer(Fts3Hash *pHash, const char *,
@@ -114830,11 +114850,11 @@
114850 );
114851 SQLITE_PRIVATE void sqlite3Fts3Matchinfo(sqlite3_context *, Fts3Cursor *, const char *);
114852
114853 /* fts3_expr.c */
114854 SQLITE_PRIVATE int sqlite3Fts3ExprParse(sqlite3_tokenizer *,
114855 char **, int, int, int, const char *, int, Fts3Expr **
114856 );
114857 SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *);
114858 #ifdef SQLITE_TEST
114859 SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3 *db);
114860 SQLITE_PRIVATE int sqlite3Fts3InitTerm(sqlite3 *db);
@@ -115031,10 +115051,11 @@
115051 sqlite3_finalize(p->aStmt[i]);
115052 }
115053 sqlite3_free(p->zSegmentsTbl);
115054 sqlite3_free(p->zReadExprlist);
115055 sqlite3_free(p->zWriteExprlist);
115056 sqlite3_free(p->zContentTbl);
115057
115058 /* Invoke the tokenizer destructor to free the tokenizer. */
115059 p->pTokenizer->pModule->xDestroy(p->pTokenizer);
115060
115061 sqlite3_free(p);
@@ -115070,20 +115091,23 @@
115091
115092 /*
115093 ** The xDestroy() virtual table method.
115094 */
115095 static int fts3DestroyMethod(sqlite3_vtab *pVtab){
 
115096 Fts3Table *p = (Fts3Table *)pVtab;
115097 int rc = SQLITE_OK; /* Return code */
115098 const char *zDb = p->zDb; /* Name of database (e.g. "main", "temp") */
115099 sqlite3 *db = p->db; /* Database handle */
115100
115101 /* Drop the shadow tables */
115102 if( p->zContentTbl==0 ){
115103 fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_content'", zDb, p->zName);
115104 }
115105 fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segments'", zDb,p->zName);
115106 fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_segdir'", zDb, p->zName);
115107 fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_docsize'", zDb, p->zName);
115108 fts3DbExec(&rc, db, "DROP TABLE IF EXISTS %Q.'%q_stat'", zDb, p->zName);
115109
115110 /* If everything has worked, invoke fts3DisconnectMethod() to free the
115111 ** memory associated with the Fts3Table structure and return SQLITE_OK.
115112 ** Otherwise, return an SQLite error code.
115113 */
@@ -115141,27 +115165,31 @@
115165 ** %_stat tables required by FTS4.
115166 */
115167 static int fts3CreateTables(Fts3Table *p){
115168 int rc = SQLITE_OK; /* Return code */
115169 int i; /* Iterator variable */
 
115170 sqlite3 *db = p->db; /* The database connection */
115171
115172 if( p->zContentTbl==0 ){
115173 char *zContentCols; /* Columns of %_content table */
115174
115175 /* Create a list of user columns for the content table */
115176 zContentCols = sqlite3_mprintf("docid INTEGER PRIMARY KEY");
115177 for(i=0; zContentCols && i<p->nColumn; i++){
115178 char *z = p->azColumn[i];
115179 zContentCols = sqlite3_mprintf("%z, 'c%d%q'", zContentCols, i, z);
115180 }
115181 if( zContentCols==0 ) rc = SQLITE_NOMEM;
115182
115183 /* Create the content table */
115184 fts3DbExec(&rc, db,
115185 "CREATE TABLE %Q.'%q_content'(%s)",
115186 p->zDb, p->zName, zContentCols
115187 );
115188 sqlite3_free(zContentCols);
115189 }
115190
115191 /* Create other tables */
115192 fts3DbExec(&rc, db,
115193 "CREATE TABLE %Q.'%q_segments'(blockid INTEGER PRIMARY KEY, block BLOB);",
115194 p->zDb, p->zName
115195 );
@@ -115308,12 +115336,12 @@
115336 }
115337 return zRet;
115338 }
115339
115340 /*
115341 ** Return a list of comma separated SQL expressions and a FROM clause that
115342 ** could be used in a SELECT statement such as the following:
115343 **
115344 ** SELECT <list of expressions> FROM %_content AS x ...
115345 **
115346 ** to return the docid, followed by each column of text data in order
115347 ** from left to write. If parameter zFunc is not NULL, then instead of
@@ -115320,11 +115348,11 @@
115348 ** being returned directly each column of text data is passed to an SQL
115349 ** function named zFunc first. For example, if zFunc is "unzip" and the
115350 ** table has the three user-defined columns "a", "b", and "c", the following
115351 ** string is returned:
115352 **
115353 ** "docid, unzip(x.'a'), unzip(x.'b'), unzip(x.'c') FROM %_content AS x"
115354 **
115355 ** The pointer returned points to a buffer allocated by sqlite3_malloc(). It
115356 ** is the responsibility of the caller to eventually free it.
115357 **
115358 ** If *pRc is not SQLITE_OK when this function is called, it is a no-op (and
@@ -115336,20 +115364,32 @@
115364 char *zRet = 0;
115365 char *zFree = 0;
115366 char *zFunction;
115367 int i;
115368
115369 if( p->zContentTbl==0 ){
115370 if( !zFunc ){
115371 zFunction = "";
115372 }else{
115373 zFree = zFunction = fts3QuoteId(zFunc);
115374 }
115375 fts3Appendf(pRc, &zRet, "docid");
115376 for(i=0; i<p->nColumn; i++){
115377 fts3Appendf(pRc, &zRet, ",%s(x.'c%d%q')", zFunction, i, p->azColumn[i]);
115378 }
115379 sqlite3_free(zFree);
115380 }else{
115381 fts3Appendf(pRc, &zRet, "rowid");
115382 for(i=0; i<p->nColumn; i++){
115383 fts3Appendf(pRc, &zRet, ", x.'%q'", p->azColumn[i]);
115384 }
115385 }
115386 fts3Appendf(pRc, &zRet, "FROM '%q'.'%q%s' AS x",
115387 p->zDb,
115388 (p->zContentTbl ? p->zContentTbl : p->zName),
115389 (p->zContentTbl ? "" : "_content")
115390 );
115391 return zRet;
115392 }
115393
115394 /*
115395 ** Return a list of N comma separated question marks, where N is the number
@@ -115468,10 +115508,95 @@
115508 }
115509 }
115510
115511 return SQLITE_OK;
115512 }
115513
115514 /*
115515 ** This function is called when initializing an FTS4 table that uses the
115516 ** content=xxx option. It determines the number of and names of the columns
115517 ** of the new FTS4 table.
115518 **
115519 ** The third argument passed to this function is the value passed to the
115520 ** config=xxx option (i.e. "xxx"). This function queries the database for
115521 ** a table of that name. If found, the output variables are populated
115522 ** as follows:
115523 **
115524 ** *pnCol: Set to the number of columns table xxx has,
115525 **
115526 ** *pnStr: Set to the total amount of space required to store a copy
115527 ** of each columns name, including the nul-terminator.
115528 **
115529 ** *pazCol: Set to point to an array of *pnCol strings. Each string is
115530 ** the name of the corresponding column in table xxx. The array
115531 ** and its contents are allocated using a single allocation. It
115532 ** is the responsibility of the caller to free this allocation
115533 ** by eventually passing the *pazCol value to sqlite3_free().
115534 **
115535 ** If the table cannot be found, an error code is returned and the output
115536 ** variables are undefined. Or, if an OOM is encountered, SQLITE_NOMEM is
115537 ** returned (and the output variables are undefined).
115538 */
115539 static int fts3ContentColumns(
115540 sqlite3 *db, /* Database handle */
115541 const char *zDb, /* Name of db (i.e. "main", "temp" etc.) */
115542 const char *zTbl, /* Name of content table */
115543 const char ***pazCol, /* OUT: Malloc'd array of column names */
115544 int *pnCol, /* OUT: Size of array *pazCol */
115545 int *pnStr /* OUT: Bytes of string content */
115546 ){
115547 int rc = SQLITE_OK; /* Return code */
115548 char *zSql; /* "SELECT *" statement on zTbl */
115549 sqlite3_stmt *pStmt = 0; /* Compiled version of zSql */
115550
115551 zSql = sqlite3_mprintf("SELECT * FROM %Q.%Q", zDb, zTbl);
115552 if( !zSql ){
115553 rc = SQLITE_NOMEM;
115554 }else{
115555 rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0);
115556 }
115557 sqlite3_free(zSql);
115558
115559 if( rc==SQLITE_OK ){
115560 const char **azCol; /* Output array */
115561 int nStr = 0; /* Size of all column names (incl. 0x00) */
115562 int nCol; /* Number of table columns */
115563 int i; /* Used to iterate through columns */
115564
115565 /* Loop through the returned columns. Set nStr to the number of bytes of
115566 ** space required to store a copy of each column name, including the
115567 ** nul-terminator byte. */
115568 nCol = sqlite3_column_count(pStmt);
115569 for(i=0; i<nCol; i++){
115570 const char *zCol = sqlite3_column_name(pStmt, i);
115571 nStr += strlen(zCol) + 1;
115572 }
115573
115574 /* Allocate and populate the array to return. */
115575 azCol = (const char **)sqlite3_malloc(sizeof(char *) * nCol + nStr);
115576 if( azCol==0 ){
115577 rc = SQLITE_NOMEM;
115578 }else{
115579 char *p = (char *)&azCol[nCol];
115580 for(i=0; i<nCol; i++){
115581 const char *zCol = sqlite3_column_name(pStmt, i);
115582 int n = strlen(zCol)+1;
115583 memcpy(p, zCol, n);
115584 azCol[i] = p;
115585 p += n;
115586 }
115587 }
115588 sqlite3_finalize(pStmt);
115589
115590 /* Set the output variables. */
115591 *pnCol = nCol;
115592 *pnStr = nStr;
115593 *pazCol = azCol;
115594 }
115595
115596 return rc;
115597 }
115598
115599 /*
115600 ** This function is the implementation of both the xConnect and xCreate
115601 ** methods of the FTS3 virtual table.
115602 **
@@ -115513,10 +115638,11 @@
115638 int bNoDocsize = 0; /* True to omit %_docsize table */
115639 int bDescIdx = 0; /* True to store descending indexes */
115640 char *zPrefix = 0; /* Prefix parameter value (or NULL) */
115641 char *zCompress = 0; /* compress=? parameter (or NULL) */
115642 char *zUncompress = 0; /* uncompress=? parameter (or NULL) */
115643 char *zContent = 0; /* content=? parameter (or NULL) */
115644
115645 assert( strlen(argv[0])==4 );
115646 assert( (sqlite3_strnicmp(argv[0], "fts4", 4)==0 && isFts4)
115647 || (sqlite3_strnicmp(argv[0], "fts3", 4)==0 && !isFts4)
115648 );
@@ -115556,17 +115682,17 @@
115682 /* Check if it is an FTS4 special argument. */
115683 else if( isFts4 && fts3IsSpecialColumn(z, &nKey, &zVal) ){
115684 struct Fts4Option {
115685 const char *zOpt;
115686 int nOpt;
 
115687 } aFts4Opt[] = {
115688 { "matchinfo", 9 }, /* 0 -> MATCHINFO */
115689 { "prefix", 6 }, /* 1 -> PREFIX */
115690 { "compress", 8 }, /* 2 -> COMPRESS */
115691 { "uncompress", 10 }, /* 3 -> UNCOMPRESS */
115692 { "order", 5 }, /* 4 -> ORDER */
115693 { "content", 7 } /* 5 -> CONTENT */
115694 };
115695
115696 int iOpt;
115697 if( !zVal ){
115698 rc = SQLITE_NOMEM;
@@ -115608,17 +115734,24 @@
115734 zVal = 0;
115735 break;
115736
115737 case 4: /* ORDER */
115738 if( (strlen(zVal)!=3 || sqlite3_strnicmp(zVal, "asc", 3))
115739 && (strlen(zVal)!=4 || sqlite3_strnicmp(zVal, "desc", 4))
115740 ){
115741 *pzErr = sqlite3_mprintf("unrecognized order: %s", zVal);
115742 rc = SQLITE_ERROR;
115743 }
115744 bDescIdx = (zVal[0]=='d' || zVal[0]=='D');
115745 break;
115746
115747 default: /* CONTENT */
115748 assert( iOpt==5 );
115749 sqlite3_free(zUncompress);
115750 zContent = zVal;
115751 zVal = 0;
115752 break;
115753 }
115754 }
115755 sqlite3_free(zVal);
115756 }
115757 }
@@ -115627,10 +115760,30 @@
115760 else {
115761 nString += (int)(strlen(z) + 1);
115762 aCol[nCol++] = z;
115763 }
115764 }
115765
115766 /* If a content=xxx option was specified, the following:
115767 **
115768 ** 1. Ignore any compress= and uncompress= options.
115769 **
115770 ** 2. If no column names were specified as part of the CREATE VIRTUAL
115771 ** TABLE statement, use all columns from the content table.
115772 */
115773 if( rc==SQLITE_OK && zContent ){
115774 sqlite3_free(zCompress);
115775 sqlite3_free(zUncompress);
115776 zCompress = 0;
115777 zUncompress = 0;
115778 if( nCol==0 ){
115779 sqlite3_free((void*)aCol);
115780 aCol = 0;
115781 rc = fts3ContentColumns(db, argv[1], zContent, &aCol, &nCol, &nString);
115782 }
115783 assert( rc!=SQLITE_OK || nCol>0 );
115784 }
115785 if( rc!=SQLITE_OK ) goto fts3_init_out;
115786
115787 if( nCol==0 ){
115788 assert( nString==0 );
115789 aCol[0] = "content";
@@ -115671,10 +115824,12 @@
115824 p->pTokenizer = pTokenizer;
115825 p->nMaxPendingData = FTS3_MAX_PENDING_DATA;
115826 p->bHasDocsize = (isFts4 && bNoDocsize==0);
115827 p->bHasStat = isFts4;
115828 p->bDescIdx = bDescIdx;
115829 p->zContentTbl = zContent;
115830 zContent = 0;
115831 TESTONLY( p->inTransaction = -1 );
115832 TESTONLY( p->mxSavepoint = -1 );
115833
115834 p->aIndex = (struct Fts3Index *)&p->azColumn[nCol];
115835 memcpy(p->aIndex, aIndex, sizeof(struct Fts3Index) * nIndex);
@@ -115732,10 +115887,11 @@
115887 fts3_init_out:
115888 sqlite3_free(zPrefix);
115889 sqlite3_free(aIndex);
115890 sqlite3_free(zCompress);
115891 sqlite3_free(zUncompress);
115892 sqlite3_free(zContent);
115893 sqlite3_free((void *)aCol);
115894 if( rc!=SQLITE_OK ){
115895 if( p ){
115896 fts3DisconnectMethod((sqlite3_vtab *)p);
115897 }else if( pTokenizer ){
@@ -115882,40 +116038,69 @@
116038 sqlite3_free(pCsr->aMatchinfo);
116039 assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 );
116040 sqlite3_free(pCsr);
116041 return SQLITE_OK;
116042 }
116043
116044 /*
116045 ** If pCsr->pStmt has not been prepared (i.e. if pCsr->pStmt==0), then
116046 ** compose and prepare an SQL statement of the form:
116047 **
116048 ** "SELECT <columns> FROM %_content WHERE rowid = ?"
116049 **
116050 ** (or the equivalent for a content=xxx table) and set pCsr->pStmt to
116051 ** it. If an error occurs, return an SQLite error code.
116052 **
116053 ** Otherwise, set *ppStmt to point to pCsr->pStmt and return SQLITE_OK.
116054 */
116055 static int fts3CursorSeekStmt(Fts3Cursor *pCsr, sqlite3_stmt **ppStmt){
116056 int rc = SQLITE_OK;
116057 if( pCsr->pStmt==0 ){
116058 Fts3Table *p = (Fts3Table *)pCsr->base.pVtab;
116059 char *zSql;
116060 zSql = sqlite3_mprintf("SELECT %s WHERE rowid = ?", p->zReadExprlist);
116061 if( !zSql ) return SQLITE_NOMEM;
116062 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0);
116063 sqlite3_free(zSql);
116064 }
116065 *ppStmt = pCsr->pStmt;
116066 return rc;
116067 }
116068
116069 /*
116070 ** Position the pCsr->pStmt statement so that it is on the row
116071 ** of the %_content table that contains the last match. Return
116072 ** SQLITE_OK on success.
116073 */
116074 static int fts3CursorSeek(sqlite3_context *pContext, Fts3Cursor *pCsr){
116075 int rc = SQLITE_OK;
116076 if( pCsr->isRequireSeek ){
116077 sqlite3_stmt *pStmt = 0;
116078
116079 rc = fts3CursorSeekStmt(pCsr, &pStmt);
116080 if( rc==SQLITE_OK ){
116081 sqlite3_bind_int64(pCsr->pStmt, 1, pCsr->iPrevId);
116082 pCsr->isRequireSeek = 0;
116083 if( SQLITE_ROW==sqlite3_step(pCsr->pStmt) ){
116084 return SQLITE_OK;
116085 }else{
116086 rc = sqlite3_reset(pCsr->pStmt);
116087 if( rc==SQLITE_OK && ((Fts3Table *)pCsr->base.pVtab)->zContentTbl==0 ){
116088 /* If no row was found and no error has occured, then the %_content
116089 ** table is missing a row that is present in the full-text index.
116090 ** The data structures are corrupt. */
116091 rc = FTS_CORRUPT_VTAB;
116092 pCsr->isEof = 1;
116093 }
116094 }
116095 }
116096 }
116097
116098 if( rc!=SQLITE_OK && pContext ){
116099 sqlite3_result_error_code(pContext, rc);
116100 }
116101 return rc;
116102 }
116103
116104 /*
116105 ** This function is used to process a single interior node when searching
116106 ** a b-tree for a term or term prefix. The node data is passed to this
@@ -116351,20 +116536,20 @@
116536 int isSaveLeft, /* Save the left position */
116537 int isExact, /* If *pp1 is exactly nTokens before *pp2 */
116538 char **pp1, /* IN/OUT: Left input list */
116539 char **pp2 /* IN/OUT: Right input list */
116540 ){
116541 char *p = *pp;
116542 char *p1 = *pp1;
116543 char *p2 = *pp2;
116544 int iCol1 = 0;
116545 int iCol2 = 0;
116546
116547 /* Never set both isSaveLeft and isExact for the same invocation. */
116548 assert( isSaveLeft==0 || isExact==0 );
116549
116550 assert( p!=0 && *p1!=0 && *p2!=0 );
116551 if( *p1==POS_COLUMN ){
116552 p1++;
116553 p1 += sqlite3Fts3GetVarint32(p1, &iCol1);
116554 }
116555 if( *p2==POS_COLUMN ){
@@ -116377,11 +116562,11 @@
116562 char *pSave = p;
116563 sqlite3_int64 iPrev = 0;
116564 sqlite3_int64 iPos1 = 0;
116565 sqlite3_int64 iPos2 = 0;
116566
116567 if( iCol1 ){
116568 *p++ = POS_COLUMN;
116569 p += sqlite3Fts3PutVarint(p, iCol1);
116570 }
116571
116572 assert( *p1!=POS_END && *p1!=POS_COLUMN );
@@ -116392,20 +116577,14 @@
116577 while( 1 ){
116578 if( iPos2==iPos1+nToken
116579 || (isExact==0 && iPos2>iPos1 && iPos2<=iPos1+nToken)
116580 ){
116581 sqlite3_int64 iSave;
 
 
 
 
 
 
 
116582 iSave = isSaveLeft ? iPos1 : iPos2;
116583 fts3PutDeltaVarint(&p, &iPrev, iSave+2); iPrev -= 2;
116584 pSave = 0;
116585 assert( p );
116586 }
116587 if( (!isSaveLeft && iPos2<=(iPos1+nToken)) || iPos2<=iPos1 ){
116588 if( (*p2&0xFE)==0 ) break;
116589 fts3GetDeltaVarint(&p2, &iPos2); iPos2 -= 2;
116590 }else{
@@ -116450,11 +116629,11 @@
116629
116630 fts3PoslistCopy(0, &p2);
116631 fts3PoslistCopy(0, &p1);
116632 *pp1 = p1;
116633 *pp2 = p2;
116634 if( *pp==p ){
116635 return 0;
116636 }
116637 *p++ = 0x00;
116638 *pp = p;
116639 return 1;
@@ -116752,10 +116931,60 @@
116931 }
116932 }
116933
116934 *pnRight = p - aOut;
116935 }
116936
116937 /*
116938 ** Argument pList points to a position list nList bytes in size. This
116939 ** function checks to see if the position list contains any entries for
116940 ** a token in position 0 (of any column). If so, it writes argument iDelta
116941 ** to the output buffer pOut, followed by a position list consisting only
116942 ** of the entries from pList at position 0, and terminated by an 0x00 byte.
116943 ** The value returned is the number of bytes written to pOut (if any).
116944 */
116945 SQLITE_PRIVATE int sqlite3Fts3FirstFilter(
116946 sqlite3_int64 iDelta, /* Varint that may be written to pOut */
116947 char *pList, /* Position list (no 0x00 term) */
116948 int nList, /* Size of pList in bytes */
116949 char *pOut /* Write output here */
116950 ){
116951 int nOut = 0;
116952 int bWritten = 0; /* True once iDelta has been written */
116953 char *p = pList;
116954 char *pEnd = &pList[nList];
116955
116956 if( *p!=0x01 ){
116957 if( *p==0x02 ){
116958 nOut += sqlite3Fts3PutVarint(&pOut[nOut], iDelta);
116959 pOut[nOut++] = 0x02;
116960 bWritten = 1;
116961 }
116962 fts3ColumnlistCopy(0, &p);
116963 }
116964
116965 while( p<pEnd && *p==0x01 ){
116966 sqlite3_int64 iCol;
116967 p++;
116968 p += sqlite3Fts3GetVarint(p, &iCol);
116969 if( *p==0x02 ){
116970 if( bWritten==0 ){
116971 nOut += sqlite3Fts3PutVarint(&pOut[nOut], iDelta);
116972 bWritten = 1;
116973 }
116974 pOut[nOut++] = 0x01;
116975 nOut += sqlite3Fts3PutVarint(&pOut[nOut], iCol);
116976 pOut[nOut++] = 0x02;
116977 }
116978 fts3ColumnlistCopy(0, &p);
116979 }
116980 if( bWritten ){
116981 pOut[nOut++] = 0x00;
116982 }
116983
116984 return nOut;
116985 }
116986
116987
116988 /*
116989 ** Merge all doclists in the TermSelect.aaOutput[] array into a single
116990 ** doclist stored in TermSelect.aaOutput[0]. If successful, delete all
@@ -117109,10 +117338,11 @@
117338 pSegcsr = pTok->pSegcsr;
117339 memset(&tsc, 0, sizeof(TermSelect));
117340
117341 filter.flags = FTS3_SEGMENT_IGNORE_EMPTY | FTS3_SEGMENT_REQUIRE_POS
117342 | (pTok->isPrefix ? FTS3_SEGMENT_PREFIX : 0)
117343 | (pTok->bFirst ? FTS3_SEGMENT_FIRST : 0)
117344 | (iColumn<p->nColumn ? FTS3_SEGMENT_COLUMN_FILTER : 0);
117345 filter.iCol = iColumn;
117346 filter.zTerm = pTok->z;
117347 filter.nTerm = pTok->n;
117348
@@ -117249,12 +117479,12 @@
117479
117480 if( zQuery==0 && sqlite3_value_type(apVal[0])!=SQLITE_NULL ){
117481 return SQLITE_NOMEM;
117482 }
117483
117484 rc = sqlite3Fts3ExprParse(p->pTokenizer, p->azColumn, p->bHasStat,
117485 p->nColumn, iCol, zQuery, -1, &pCsr->pExpr
117486 );
117487 if( rc!=SQLITE_OK ){
117488 if( rc==SQLITE_ERROR ){
117489 static const char *zErr = "malformed MATCH expression: [%s]";
117490 p->base.zErrMsg = sqlite3_mprintf(zErr, zQuery);
@@ -117277,26 +117507,27 @@
117507 ** statement loops through all rows of the %_content table. For a
117508 ** full-text query or docid lookup, the statement retrieves a single
117509 ** row by docid.
117510 */
117511 if( idxNum==FTS3_FULLSCAN_SEARCH ){
117512 zSql = sqlite3_mprintf(
117513 "SELECT %s ORDER BY rowid %s",
117514 p->zReadExprlist, (pCsr->bDesc ? "DESC" : "ASC")
117515 );
117516 if( zSql ){
117517 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0);
117518 sqlite3_free(zSql);
117519 }else{
117520 rc = SQLITE_NOMEM;
117521 }
117522 }else if( idxNum==FTS3_DOCID_SEARCH ){
117523 rc = fts3CursorSeekStmt(pCsr, &pCsr->pStmt);
117524 if( rc==SQLITE_OK ){
117525 rc = sqlite3_bind_value(pCsr->pStmt, 1, apVal[0]);
117526 }
117527 }
117528 if( rc!=SQLITE_OK ) return rc;
117529
117530 return fts3NextMethod(pCursor);
117531 }
117532
117533 /*
@@ -117345,11 +117576,11 @@
117576 ** Return a blob which is a pointer to the cursor.
117577 */
117578 sqlite3_result_blob(pContext, &pCsr, sizeof(pCsr), SQLITE_TRANSIENT);
117579 }else{
117580 rc = fts3CursorSeek(0, pCsr);
117581 if( rc==SQLITE_OK && sqlite3_data_count(pCsr->pStmt)>(iCol+1) ){
117582 sqlite3_result_value(pContext, sqlite3_column_value(pCsr->pStmt, iCol+1));
117583 }
117584 }
117585
117586 assert( ((Fts3Table *)pCsr->base.pVtab)->pSegments==0 );
@@ -117638,19 +117869,26 @@
117869 ){
117870 Fts3Table *p = (Fts3Table *)pVtab;
117871 sqlite3 *db = p->db; /* Database connection */
117872 int rc; /* Return Code */
117873
117874 /* As it happens, the pending terms table is always empty here. This is
117875 ** because an "ALTER TABLE RENAME TABLE" statement inside a transaction
117876 ** always opens a savepoint transaction. And the xSavepoint() method
117877 ** flushes the pending terms table. But leave the (no-op) call to
117878 ** PendingTermsFlush() in in case that changes.
117879 */
117880 assert( p->nPendingData==0 );
117881 rc = sqlite3Fts3PendingTermsFlush(p);
117882
117883 if( p->zContentTbl==0 ){
117884 fts3DbExec(&rc, db,
117885 "ALTER TABLE %Q.'%q_content' RENAME TO '%q_content';",
117886 p->zDb, p->zName, zName
117887 );
117888 }
117889
 
 
 
 
117890 if( p->bHasDocsize ){
117891 fts3DbExec(&rc, db,
117892 "ALTER TABLE %Q.'%q_docsize' RENAME TO '%q_docsize';",
117893 p->zDb, p->zName, zName
117894 );
@@ -118005,25 +118243,24 @@
118243 **
118244 ** SQLITE_OK is returned if no error occurs, otherwise an SQLite error code.
118245 */
118246 static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){
118247 int iToken; /* Used to iterate through phrase tokens */
 
118248 char *aPoslist = 0; /* Position list for deferred tokens */
118249 int nPoslist = 0; /* Number of bytes in aPoslist */
118250 int iPrev = -1; /* Token number of previous deferred token */
118251
118252 assert( pPhrase->doclist.bFreeList==0 );
118253
118254 for(iToken=0; iToken<pPhrase->nToken; iToken++){
118255 Fts3PhraseToken *pToken = &pPhrase->aToken[iToken];
118256 Fts3DeferredToken *pDeferred = pToken->pDeferred;
118257
118258 if( pDeferred ){
118259 char *pList;
118260 int nList;
118261 int rc = sqlite3Fts3DeferredTokenList(pDeferred, &pList, &nList);
118262 if( rc!=SQLITE_OK ) return rc;
118263
118264 if( pList==0 ){
118265 sqlite3_free(aPoslist);
118266 pPhrase->doclist.pList = 0;
@@ -118120,10 +118357,11 @@
118357 if( pCsr->bDesc==pTab->bDescIdx
118358 && bOptOk==1
118359 && p->nToken==1
118360 && pFirst->pSegcsr
118361 && pFirst->pSegcsr->bLookup
118362 && pFirst->bFirst==0
118363 ){
118364 /* Use the incremental approach. */
118365 int iCol = (p->iColumn >= pTab->nColumn ? -1 : p->iColumn);
118366 rc = sqlite3Fts3MsrIncrStart(
118367 pTab, pFirst->pSegcsr, iCol, pFirst->z, pFirst->n);
@@ -118349,11 +118587,11 @@
118587 Fts3Expr *pExpr, /* Expression to consider */
118588 Fts3TokenAndCost **ppTC, /* Write new entries to *(*ppTC)++ */
118589 Fts3Expr ***ppOr, /* Write new OR root to *(*ppOr)++ */
118590 int *pRc /* IN/OUT: Error code */
118591 ){
118592 if( *pRc==SQLITE_OK ){
118593 if( pExpr->eType==FTSQUERY_PHRASE ){
118594 Fts3Phrase *pPhrase = pExpr->pPhrase;
118595 int i;
118596 for(i=0; *pRc==SQLITE_OK && i<pPhrase->nToken; i++){
118597 Fts3TokenAndCost *pTC = (*ppTC)++;
@@ -118363,10 +118601,15 @@
118601 pTC->pToken = &pPhrase->aToken[i];
118602 pTC->iCol = pPhrase->iColumn;
118603 *pRc = sqlite3Fts3MsrOvfl(pCsr, pTC->pToken->pSegcsr, &pTC->nOvfl);
118604 }
118605 }else if( pExpr->eType!=FTSQUERY_NOT ){
118606 assert( pExpr->eType==FTSQUERY_OR
118607 || pExpr->eType==FTSQUERY_AND
118608 || pExpr->eType==FTSQUERY_NEAR
118609 );
118610 assert( pExpr->pLeft && pExpr->pRight );
118611 if( pExpr->eType==FTSQUERY_OR ){
118612 pRoot = pExpr->pLeft;
118613 **ppOr = pRoot;
118614 (*ppOr)++;
118615 }
@@ -118466,10 +118709,19 @@
118709 int nOvfl = 0; /* Total overflow pages used by doclists */
118710 int nToken = 0; /* Total number of tokens in cluster */
118711
118712 int nMinEst = 0; /* The minimum count for any phrase so far. */
118713 int nLoad4 = 1; /* (Phrases that will be loaded)^4. */
118714
118715 /* Tokens are never deferred for FTS tables created using the content=xxx
118716 ** option. The reason being that it is not guaranteed that the content
118717 ** table actually contains the same data as the index. To prevent this from
118718 ** causing any problems, the deferred token optimization is completely
118719 ** disabled for content=xxx tables. */
118720 if( pTab->zContentTbl ){
118721 return SQLITE_OK;
118722 }
118723
118724 /* Count the tokens in this AND/NEAR cluster. If none of the doclists
118725 ** associated with the tokens spill onto overflow pages, or if there is
118726 ** only 1 token, exit early. No tokens to defer in this case. */
118727 for(ii=0; ii<nTC; ii++){
@@ -118529,11 +118781,15 @@
118781 Fts3PhraseToken *pToken = pTC->pToken;
118782 rc = sqlite3Fts3DeferToken(pCsr, pToken, pTC->iCol);
118783 fts3SegReaderCursorFree(pToken->pSegcsr);
118784 pToken->pSegcsr = 0;
118785 }else{
118786 /* Set nLoad4 to the value of (4^nOther) for the next iteration of the
118787 ** for-loop. Except, limit the value to 2^24 to prevent it from
118788 ** overflowing the 32-bit integer it is stored in. */
118789 if( ii<12 ) nLoad4 = nLoad4*4;
118790
118791 if( ii==0 || pTC->pPhrase->nToken>1 ){
118792 /* Either this is the cheapest token in the entire query, or it is
118793 ** part of a multi-token phrase. Either way, the entire doclist will
118794 ** (eventually) be loaded into memory. It may as well be now. */
118795 Fts3PhraseToken *pToken = pTC->pToken;
@@ -119990,10 +120246,11 @@
120246 */
120247 typedef struct ParseContext ParseContext;
120248 struct ParseContext {
120249 sqlite3_tokenizer *pTokenizer; /* Tokenizer module */
120250 const char **azCol; /* Array of column names for fts3 table */
120251 int bFts4; /* True to allow FTS4-only syntax */
120252 int nCol; /* Number of entries in azCol[] */
120253 int iDefaultCol; /* Default column to query */
120254 int isNot; /* True if getNextNode() sees a unary - */
120255 sqlite3_context *pCtx; /* Write error message here */
120256 int nNest; /* Number of nested brackets */
@@ -120077,13 +120334,25 @@
120334
120335 if( iEnd<n && z[iEnd]=='*' ){
120336 pRet->pPhrase->aToken[0].isPrefix = 1;
120337 iEnd++;
120338 }
120339
120340 while( 1 ){
120341 if( !sqlite3_fts3_enable_parentheses
120342 && iStart>0 && z[iStart-1]=='-'
120343 ){
120344 pParse->isNot = 1;
120345 iStart--;
120346 }else if( pParse->bFts4 && iStart>0 && z[iStart-1]=='^' ){
120347 pRet->pPhrase->aToken[0].bFirst = 1;
120348 iStart--;
120349 }else{
120350 break;
120351 }
120352 }
120353
120354 }
120355 nConsumed = iEnd;
120356 }
120357
120358 pModule->xClose(pCursor);
@@ -120178,10 +120447,11 @@
120447 memcpy(&zTemp[nTemp], zByte, nByte);
120448 nTemp += nByte;
120449
120450 pToken->n = nByte;
120451 pToken->isPrefix = (iEnd<nInput && zInput[iEnd]=='*');
120452 pToken->bFirst = (iBegin>0 && zInput[iBegin-1]=='^');
120453 nToken = ii+1;
120454 }
120455 }
120456
120457 pModule->xClose(pCursor);
@@ -120629,10 +120899,11 @@
120899 ** match any table column.
120900 */
120901 SQLITE_PRIVATE int sqlite3Fts3ExprParse(
120902 sqlite3_tokenizer *pTokenizer, /* Tokenizer module */
120903 char **azCol, /* Array of column names for fts3 table */
120904 int bFts4, /* True to allow FTS4-only syntax */
120905 int nCol, /* Number of entries in azCol[] */
120906 int iDefaultCol, /* Default column to query */
120907 const char *z, int n, /* Text of MATCH query */
120908 Fts3Expr **ppExpr /* OUT: Parsed query structure */
120909 ){
@@ -120642,10 +120913,11 @@
120913 sParse.pTokenizer = pTokenizer;
120914 sParse.azCol = (const char **)azCol;
120915 sParse.nCol = nCol;
120916 sParse.iDefaultCol = iDefaultCol;
120917 sParse.nNest = 0;
120918 sParse.bFts4 = bFts4;
120919 if( z==0 ){
120920 *ppExpr = 0;
120921 return SQLITE_OK;
120922 }
120923 if( n<0 ){
@@ -120831,11 +121103,11 @@
121103 for(ii=0; ii<nCol; ii++){
121104 azCol[ii] = (char *)sqlite3_value_text(argv[ii+2]);
121105 }
121106
121107 rc = sqlite3Fts3ExprParse(
121108 pTokenizer, azCol, 0, nCol, nCol, zExpr, nExpr, &pExpr
121109 );
121110 if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){
121111 sqlite3_result_error(context, "Error parsing expression", -1);
121112 }else if( rc==SQLITE_NOMEM || !(zBuf = exprToString(pExpr, 0)) ){
121113 sqlite3_result_error_nomem(context);
@@ -122878,11 +123150,11 @@
123150 /* 2 */ "DELETE FROM %Q.'%q_content'",
123151 /* 3 */ "DELETE FROM %Q.'%q_segments'",
123152 /* 4 */ "DELETE FROM %Q.'%q_segdir'",
123153 /* 5 */ "DELETE FROM %Q.'%q_docsize'",
123154 /* 6 */ "DELETE FROM %Q.'%q_stat'",
123155 /* 7 */ "SELECT %s WHERE rowid=?",
123156 /* 8 */ "SELECT (SELECT max(idx) FROM %Q.'%q_segdir' WHERE level = ?) + 1",
123157 /* 9 */ "INSERT INTO %Q.'%q_segments'(blockid, block) VALUES(?, ?)",
123158 /* 10 */ "SELECT coalesce((SELECT max(blockid) FROM %Q.'%q_segments') + 1, 1)",
123159 /* 11 */ "INSERT INTO %Q.'%q_segdir' VALUES(?,?,?,?,?,?)",
123160
@@ -122920,11 +123192,11 @@
123192 if( !pStmt ){
123193 char *zSql;
123194 if( eStmt==SQL_CONTENT_INSERT ){
123195 zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName, p->zWriteExprlist);
123196 }else if( eStmt==SQL_SELECT_CONTENT_BY_ROWID ){
123197 zSql = sqlite3_mprintf(azSql[eStmt], p->zReadExprlist);
123198 }else{
123199 zSql = sqlite3_mprintf(azSql[eStmt], p->zDb, p->zName);
123200 }
123201 if( !zSql ){
123202 rc = SQLITE_NOMEM;
@@ -123031,21 +123303,28 @@
123303 ** We try to avoid this because if FTS3 returns any error when committing
123304 ** a transaction, the whole transaction will be rolled back. And this is
123305 ** not what users expect when they get SQLITE_LOCKED_SHAREDCACHE. It can
123306 ** still happen if the user reads data directly from the %_segments or
123307 ** %_segdir tables instead of going through FTS3 though.
123308 **
123309 ** This reasoning does not apply to a content=xxx table.
123310 */
123311 SQLITE_PRIVATE int sqlite3Fts3ReadLock(Fts3Table *p){
123312 int rc; /* Return code */
123313 sqlite3_stmt *pStmt; /* Statement used to obtain lock */
123314
123315 if( p->zContentTbl==0 ){
123316 rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pStmt, 0);
123317 if( rc==SQLITE_OK ){
123318 sqlite3_bind_null(pStmt, 1);
123319 sqlite3_step(pStmt);
123320 rc = sqlite3_reset(pStmt);
123321 }
123322 }else{
123323 rc = SQLITE_OK;
123324 }
123325
123326 return rc;
123327 }
123328
123329 /*
123330 ** Set *ppStmt to a statement handle that may be used to iterate through
@@ -123401,10 +123680,22 @@
123680 sqlite3_value **apVal, /* Array of values to insert */
123681 sqlite3_int64 *piDocid /* OUT: Docid for row just inserted */
123682 ){
123683 int rc; /* Return code */
123684 sqlite3_stmt *pContentInsert; /* INSERT INTO %_content VALUES(...) */
123685
123686 if( p->zContentTbl ){
123687 sqlite3_value *pRowid = apVal[p->nColumn+3];
123688 if( sqlite3_value_type(pRowid)==SQLITE_NULL ){
123689 pRowid = apVal[1];
123690 }
123691 if( sqlite3_value_type(pRowid)!=SQLITE_INTEGER ){
123692 return SQLITE_CONSTRAINT;
123693 }
123694 *piDocid = sqlite3_value_int64(pRowid);
123695 return SQLITE_OK;
123696 }
123697
123698 /* Locate the statement handle used to insert data into the %_content
123699 ** table. The SQL for this statement is:
123700 **
123701 ** INSERT INTO %_content VALUES(?, ?, ?, ...)
@@ -123452,18 +123743,20 @@
123743
123744 /*
123745 ** Remove all data from the FTS3 table. Clear the hash table containing
123746 ** pending terms.
123747 */
123748 static int fts3DeleteAll(Fts3Table *p, int bContent){
123749 int rc = SQLITE_OK; /* Return code */
123750
123751 /* Discard the contents of the pending-terms hash table. */
123752 sqlite3Fts3PendingTermsClear(p);
123753
123754 /* Delete everything from the shadow tables. Except, leave %_content as
123755 ** is if bContent is false. */
123756 assert( p->zContentTbl==0 || bContent==0 );
123757 if( bContent ) fts3SqlExec(&rc, p, SQL_DELETE_ALL_CONTENT, 0);
123758 fts3SqlExec(&rc, p, SQL_DELETE_ALL_SEGMENTS, 0);
123759 fts3SqlExec(&rc, p, SQL_DELETE_ALL_SEGDIR, 0);
123760 if( p->bHasDocsize ){
123761 fts3SqlExec(&rc, p, SQL_DELETE_ALL_DOCSIZE, 0);
123762 }
@@ -124747,16 +125040,22 @@
125040 ** error occurs, an SQLite error code is returned.
125041 */
125042 static int fts3IsEmpty(Fts3Table *p, sqlite3_value *pRowid, int *pisEmpty){
125043 sqlite3_stmt *pStmt;
125044 int rc;
125045 if( p->zContentTbl ){
125046 /* If using the content=xxx option, assume the table is never empty */
125047 *pisEmpty = 0;
125048 rc = SQLITE_OK;
125049 }else{
125050 rc = fts3SqlStmt(p, SQL_IS_EMPTY, &pStmt, &pRowid);
125051 if( rc==SQLITE_OK ){
125052 if( SQLITE_ROW==sqlite3_step(pStmt) ){
125053 *pisEmpty = sqlite3_column_int(pStmt, 0);
125054 }
125055 rc = sqlite3_reset(pStmt);
125056 }
 
125057 }
125058 return rc;
125059 }
125060
125061 /*
@@ -125104,10 +125403,11 @@
125403 int isIgnoreEmpty = (pCsr->pFilter->flags & FTS3_SEGMENT_IGNORE_EMPTY);
125404 int isRequirePos = (pCsr->pFilter->flags & FTS3_SEGMENT_REQUIRE_POS);
125405 int isColFilter = (pCsr->pFilter->flags & FTS3_SEGMENT_COLUMN_FILTER);
125406 int isPrefix = (pCsr->pFilter->flags & FTS3_SEGMENT_PREFIX);
125407 int isScan = (pCsr->pFilter->flags & FTS3_SEGMENT_SCAN);
125408 int isFirst = (pCsr->pFilter->flags & FTS3_SEGMENT_FIRST);
125409
125410 Fts3SegReader **apSegment = pCsr->apSegment;
125411 int nSegment = pCsr->nSegment;
125412 Fts3SegFilter *pFilter = pCsr->pFilter;
125413 int (*xCmp)(Fts3SegReader *, Fts3SegReader *) = (
@@ -125163,10 +125463,11 @@
125463 }
125464
125465 assert( isIgnoreEmpty || (isRequirePos && !isColFilter) );
125466 if( nMerge==1
125467 && !isIgnoreEmpty
125468 && !isFirst
125469 && (p->bDescIdx==0 || fts3SegReaderIsPending(apSegment[0])==0)
125470 ){
125471 pCsr->nDoclist = apSegment[0]->nDoclist;
125472 if( fts3SegReaderIsPending(apSegment[0]) ){
125473 rc = fts3MsrBufferData(pCsr, apSegment[0]->aDoclist, pCsr->nDoclist);
@@ -125228,16 +125529,28 @@
125529 if( !aNew ){
125530 return SQLITE_NOMEM;
125531 }
125532 pCsr->aBuffer = aNew;
125533 }
125534
125535 if( isFirst ){
125536 char *a = &pCsr->aBuffer[nDoclist];
125537 int nWrite;
125538
125539 nWrite = sqlite3Fts3FirstFilter(iDelta, pList, nList, a);
125540 if( nWrite ){
125541 iPrev = iDocid;
125542 nDoclist += nWrite;
125543 }
125544 }else{
125545 nDoclist += sqlite3Fts3PutVarint(&pCsr->aBuffer[nDoclist], iDelta);
125546 iPrev = iDocid;
125547 if( isRequirePos ){
125548 memcpy(&pCsr->aBuffer[nDoclist], pList, nList);
125549 nDoclist += nList;
125550 pCsr->aBuffer[nDoclist++] = '\0';
125551 }
125552 }
125553 }
125554
125555 fts3SegReaderSort(apSegment, nMerge, j, xCmp);
125556 }
@@ -125409,13 +125722,13 @@
125722 ** Insert the sizes (in tokens) for each column of the document
125723 ** with docid equal to p->iPrevDocid. The sizes are encoded as
125724 ** a blob of varints.
125725 */
125726 static void fts3InsertDocsize(
125727 int *pRC, /* Result code */
125728 Fts3Table *p, /* Table into which to insert */
125729 u32 *aSz /* Sizes of each column, in tokens */
125730 ){
125731 char *pBlob; /* The BLOB encoding of the document size */
125732 int nBlob; /* Number of bytes in the BLOB */
125733 sqlite3_stmt *pStmt; /* Statement used to insert the encoding */
125734 int rc; /* Result code from subfunctions */
@@ -125532,10 +125845,90 @@
125845 sqlite3Fts3SegmentsClose(p);
125846 sqlite3Fts3PendingTermsClear(p);
125847
125848 return (rc==SQLITE_OK && bReturnDone && bSeenDone) ? SQLITE_DONE : rc;
125849 }
125850
125851 /*
125852 ** This function is called when the user executes the following statement:
125853 **
125854 ** INSERT INTO <tbl>(<tbl>) VALUES('rebuild');
125855 **
125856 ** The entire FTS index is discarded and rebuilt. If the table is one
125857 ** created using the content=xxx option, then the new index is based on
125858 ** the current contents of the xxx table. Otherwise, it is rebuilt based
125859 ** on the contents of the %_content table.
125860 */
125861 static int fts3DoRebuild(Fts3Table *p){
125862 int rc; /* Return Code */
125863
125864 rc = fts3DeleteAll(p, 0);
125865 if( rc==SQLITE_OK ){
125866 u32 *aSz = 0;
125867 u32 *aSzIns = 0;
125868 u32 *aSzDel = 0;
125869 sqlite3_stmt *pStmt = 0;
125870 int nEntry = 0;
125871
125872 /* Compose and prepare an SQL statement to loop through the content table */
125873 char *zSql = sqlite3_mprintf("SELECT %s" , p->zReadExprlist);
125874 if( !zSql ){
125875 rc = SQLITE_NOMEM;
125876 }else{
125877 rc = sqlite3_prepare_v2(p->db, zSql, -1, &pStmt, 0);
125878 sqlite3_free(zSql);
125879 }
125880
125881 if( rc==SQLITE_OK ){
125882 int nByte = sizeof(u32) * (p->nColumn+1)*3;
125883 aSz = (u32 *)sqlite3_malloc(nByte);
125884 if( aSz==0 ){
125885 rc = SQLITE_NOMEM;
125886 }else{
125887 memset(aSz, 0, nByte);
125888 aSzIns = &aSz[p->nColumn+1];
125889 aSzDel = &aSzIns[p->nColumn+1];
125890 }
125891 }
125892
125893 while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
125894 int iCol;
125895 rc = fts3PendingTermsDocid(p, sqlite3_column_int64(pStmt, 0));
125896 aSz[p->nColumn] = 0;
125897 for(iCol=0; rc==SQLITE_OK && iCol<p->nColumn; iCol++){
125898 const char *z = (const char *) sqlite3_column_text(pStmt, iCol+1);
125899 rc = fts3PendingTermsAdd(p, z, iCol, &aSz[iCol]);
125900 aSz[p->nColumn] += sqlite3_column_bytes(pStmt, iCol+1);
125901 }
125902 if( p->bHasDocsize ){
125903 fts3InsertDocsize(&rc, p, aSz);
125904 }
125905 if( rc!=SQLITE_OK ){
125906 sqlite3_finalize(pStmt);
125907 pStmt = 0;
125908 }else{
125909 nEntry++;
125910 for(iCol=0; iCol<=p->nColumn; iCol++){
125911 aSzIns[iCol] += aSz[iCol];
125912 }
125913 }
125914 }
125915 if( p->bHasStat ){
125916 fts3UpdateDocTotals(&rc, p, aSzIns, aSzDel, nEntry);
125917 }
125918 sqlite3_free(aSz);
125919
125920 if( pStmt ){
125921 int rc2 = sqlite3_finalize(pStmt);
125922 if( rc==SQLITE_OK ){
125923 rc = rc2;
125924 }
125925 }
125926 }
125927
125928 return rc;
125929 }
125930
125931 /*
125932 ** Handle a 'special' INSERT of the form:
125933 **
125934 ** "INSERT INTO tbl(tbl) VALUES(<expr>)"
@@ -125550,10 +125943,12 @@
125943
125944 if( !zVal ){
125945 return SQLITE_NOMEM;
125946 }else if( nVal==8 && 0==sqlite3_strnicmp(zVal, "optimize", 8) ){
125947 rc = fts3DoOptimize(p, 0);
125948 }else if( nVal==7 && 0==sqlite3_strnicmp(zVal, "rebuild", 7) ){
125949 rc = fts3DoRebuild(p);
125950 #ifdef SQLITE_TEST
125951 }else if( nVal>9 && 0==sqlite3_strnicmp(zVal, "nodesize=", 9) ){
125952 p->nNodeSize = atoi(&zVal[9]);
125953 rc = SQLITE_OK;
125954 }else if( nVal>11 && 0==sqlite3_strnicmp(zVal, "maxpending=", 9) ){
@@ -125630,10 +126025,11 @@
126025 pTC->pTokenizer = pT;
126026 rc = pModule->xNext(pTC, &zToken, &nToken, &iDum1, &iDum2, &iPos);
126027 for(pDef=pCsr->pDeferred; pDef && rc==SQLITE_OK; pDef=pDef->pNext){
126028 Fts3PhraseToken *pPT = pDef->pToken;
126029 if( (pDef->iCol>=p->nColumn || pDef->iCol==i)
126030 && (pPT->bFirst==0 || iPos==0)
126031 && (pPT->n==nToken || (pPT->isPrefix && pPT->n<nToken))
126032 && (0==memcmp(zToken, pPT->z, pPT->n))
126033 ){
126034 fts3PendingListAppend(&pDef->pList, iDocid, i, iPos, &rc);
126035 }
@@ -125721,18 +126117,22 @@
126117 if( rc==SQLITE_OK ){
126118 if( isEmpty ){
126119 /* Deleting this row means the whole table is empty. In this case
126120 ** delete the contents of all three tables and throw away any
126121 ** data in the pendingTerms hash table. */
126122 rc = fts3DeleteAll(p, 1);
126123 *pnDoc = *pnDoc - 1;
126124 }else{
126125 sqlite3_int64 iRemove = sqlite3_value_int64(pRowid);
126126 rc = fts3PendingTermsDocid(p, iRemove);
126127 fts3DeleteTerms(&rc, p, pRowid, aSzDel);
126128 if( p->zContentTbl==0 ){
126129 fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, &pRowid);
126130 if( sqlite3_changes(p->db) ) *pnDoc = *pnDoc - 1;
126131 }else{
126132 *pnDoc = *pnDoc - 1;
126133 }
126134 if( p->bHasDocsize ){
126135 fts3SqlExec(&rc, p, SQL_DELETE_DOCSIZE, &pRowid);
126136 }
126137 }
126138 }
@@ -125788,11 +126188,11 @@
126188 ** should be deleted from the database before inserting the new row. Or,
126189 ** if the on-conflict mode is other than REPLACE, then this method must
126190 ** detect the conflict and return SQLITE_CONSTRAINT before beginning to
126191 ** modify the database file.
126192 */
126193 if( nArg>1 && p->zContentTbl==0 ){
126194 /* Find the value object that holds the new rowid value. */
126195 sqlite3_value *pNewRowid = apVal[3+p->nColumn];
126196 if( sqlite3_value_type(pNewRowid)==SQLITE_NULL ){
126197 pNewRowid = apVal[1];
126198 }
@@ -125839,11 +126239,13 @@
126239
126240 /* If this is an INSERT or UPDATE operation, insert the new record. */
126241 if( nArg>1 && rc==SQLITE_OK ){
126242 if( bInsertDone==0 ){
126243 rc = fts3InsertData(p, apVal, pRowid);
126244 if( rc==SQLITE_CONSTRAINT && p->zContentTbl==0 ){
126245 rc = FTS_CORRUPT_VTAB;
126246 }
126247 }
126248 if( rc==SQLITE_OK && (!isRemove || *pRowid!=p->iPrevDocid ) ){
126249 rc = fts3PendingTermsDocid(p, *pRowid);
126250 }
126251 if( rc==SQLITE_OK ){
@@ -126259,10 +126661,11 @@
126661 pCsr = sqlite3Fts3EvalPhrasePoslist(p->pCsr, pExpr, p->iCol);
126662 if( pCsr ){
126663 int iFirst = 0;
126664 pPhrase->pList = pCsr;
126665 fts3GetDeltaPosition(&pCsr, &iFirst);
126666 assert( iFirst>=0 );
126667 pPhrase->pHead = pCsr;
126668 pPhrase->pTail = pCsr;
126669 pPhrase->iHead = iFirst;
126670 pPhrase->iTail = iFirst;
126671 }else{
@@ -127300,11 +127703,11 @@
127703 }
127704 }
127705
127706 if( !pTerm ){
127707 /* All offsets for this column have been gathered. */
127708 rc = SQLITE_DONE;
127709 }else{
127710 assert( iCurrent<=iMinPos );
127711 if( 0==(0xFE&*pTerm->pList) ){
127712 pTerm->pList = 0;
127713 }else{
@@ -127317,11 +127720,11 @@
127720 char aBuffer[64];
127721 sqlite3_snprintf(sizeof(aBuffer), aBuffer,
127722 "%d %d %d %d ", iCol, pTerm-sCtx.aTerm, iStart, iEnd-iStart
127723 );
127724 rc = fts3StringAppend(&res, aBuffer, -1);
127725 }else if( rc==SQLITE_DONE && pTab->zContentTbl==0 ){
127726 rc = FTS_CORRUPT_VTAB;
127727 }
127728 }
127729 }
127730 if( rc==SQLITE_DONE ){
127731
+3 -3
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -107,11 +107,11 @@
107107
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
108108
** [sqlite_version()] and [sqlite_source_id()].
109109
*/
110110
#define SQLITE_VERSION "3.7.9"
111111
#define SQLITE_VERSION_NUMBER 3007009
112
-#define SQLITE_SOURCE_ID "2011-10-15 00:16:30 39408702a989f907261c298bf0947f3e68bd10fe"
112
+#define SQLITE_SOURCE_ID "2011-10-20 00:55:54 4344483f7d7f64dffadde0053e6c745948db9486"
113113
114114
/*
115115
** CAPI3REF: Run-Time Library Version Numbers
116116
** KEYWORDS: sqlite3_version, sqlite3_sourceid
117117
**
@@ -1402,12 +1402,12 @@
14021402
** memory pointer is not NULL and either [SQLITE_ENABLE_MEMSYS3] or
14031403
** [SQLITE_ENABLE_MEMSYS5] are defined, then the alternative memory
14041404
** allocator is engaged to handle all of SQLites memory allocation needs.
14051405
** The first pointer (the memory pointer) must be aligned to an 8-byte
14061406
** boundary or subsequent behavior of SQLite will be undefined.
1407
-** The minimum allocation size is capped at 2^12. Reasonable values
1408
-** for the minimum allocation size are 2^5 through 2^8.</dd>
1407
+** The minimum allocation size is capped at 2**12. Reasonable values
1408
+** for the minimum allocation size are 2**5 through 2**8.</dd>
14091409
**
14101410
** [[SQLITE_CONFIG_MUTEX]] <dt>SQLITE_CONFIG_MUTEX</dt>
14111411
** <dd> ^(This option takes a single argument which is a pointer to an
14121412
** instance of the [sqlite3_mutex_methods] structure. The argument specifies
14131413
** alternative low-level mutex routines to be used in place
14141414
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -107,11 +107,11 @@
107 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
108 ** [sqlite_version()] and [sqlite_source_id()].
109 */
110 #define SQLITE_VERSION "3.7.9"
111 #define SQLITE_VERSION_NUMBER 3007009
112 #define SQLITE_SOURCE_ID "2011-10-15 00:16:30 39408702a989f907261c298bf0947f3e68bd10fe"
113
114 /*
115 ** CAPI3REF: Run-Time Library Version Numbers
116 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
117 **
@@ -1402,12 +1402,12 @@
1402 ** memory pointer is not NULL and either [SQLITE_ENABLE_MEMSYS3] or
1403 ** [SQLITE_ENABLE_MEMSYS5] are defined, then the alternative memory
1404 ** allocator is engaged to handle all of SQLites memory allocation needs.
1405 ** The first pointer (the memory pointer) must be aligned to an 8-byte
1406 ** boundary or subsequent behavior of SQLite will be undefined.
1407 ** The minimum allocation size is capped at 2^12. Reasonable values
1408 ** for the minimum allocation size are 2^5 through 2^8.</dd>
1409 **
1410 ** [[SQLITE_CONFIG_MUTEX]] <dt>SQLITE_CONFIG_MUTEX</dt>
1411 ** <dd> ^(This option takes a single argument which is a pointer to an
1412 ** instance of the [sqlite3_mutex_methods] structure. The argument specifies
1413 ** alternative low-level mutex routines to be used in place
1414
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -107,11 +107,11 @@
107 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
108 ** [sqlite_version()] and [sqlite_source_id()].
109 */
110 #define SQLITE_VERSION "3.7.9"
111 #define SQLITE_VERSION_NUMBER 3007009
112 #define SQLITE_SOURCE_ID "2011-10-20 00:55:54 4344483f7d7f64dffadde0053e6c745948db9486"
113
114 /*
115 ** CAPI3REF: Run-Time Library Version Numbers
116 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
117 **
@@ -1402,12 +1402,12 @@
1402 ** memory pointer is not NULL and either [SQLITE_ENABLE_MEMSYS3] or
1403 ** [SQLITE_ENABLE_MEMSYS5] are defined, then the alternative memory
1404 ** allocator is engaged to handle all of SQLites memory allocation needs.
1405 ** The first pointer (the memory pointer) must be aligned to an 8-byte
1406 ** boundary or subsequent behavior of SQLite will be undefined.
1407 ** The minimum allocation size is capped at 2**12. Reasonable values
1408 ** for the minimum allocation size are 2**5 through 2**8.</dd>
1409 **
1410 ** [[SQLITE_CONFIG_MUTEX]] <dt>SQLITE_CONFIG_MUTEX</dt>
1411 ** <dd> ^(This option takes a single argument which is a pointer to an
1412 ** instance of the [sqlite3_mutex_methods] structure. The argument specifies
1413 ** alternative low-level mutex routines to be used in place
1414
+12 -10
--- src/stash.c
+++ src/stash.c
@@ -266,11 +266,11 @@
266266
}
267267
268268
/*
269269
** Show the diffs associate with a single stash.
270270
*/
271
-static void stash_diff(int stashid, const char *zDiffCmd){
271
+static void stash_diff(int stashid, const char *zDiffCmd, int diffFlags){
272272
Stmt q;
273273
Blob empty;
274274
blob_zero(&empty);
275275
db_prepare(&q,
276276
"SELECT rid, isRemoved, isExec, isLink, origname, newname, delta"
@@ -286,21 +286,21 @@
286286
char *zOPath = mprintf("%s%s", g.zLocalRoot, zOrig);
287287
Blob delta;
288288
if( rid==0 ){
289289
db_ephemeral_blob(&q, 6, &delta);
290290
fossil_print("ADDED %s\n", zNew);
291
- diff_print_index(zNew);
292
- diff_file_mem(&empty, &delta, zNew, zDiffCmd, 0);
291
+ diff_print_index(zNew, diffFlags);
292
+ diff_file_mem(&empty, &delta, zNew, zDiffCmd, diffFlags);
293293
}else if( isRemoved ){
294294
fossil_print("DELETE %s\n", zOrig);
295295
if( file_wd_islink(zOPath) ){
296296
blob_read_link(&delta, zOPath);
297297
}else{
298298
blob_read_from_file(&delta, zOPath);
299299
}
300
- diff_print_index(zNew);
301
- diff_file_mem(&delta, &empty, zOrig, zDiffCmd, 0);
300
+ diff_print_index(zNew, diffFlags);
301
+ diff_file_mem(&delta, &empty, zOrig, zDiffCmd, diffFlags);
302302
}else{
303303
Blob a, b, disk;
304304
int isOrigLink = file_wd_islink(zOPath);
305305
db_ephemeral_blob(&q, 6, &delta);
306306
if( isOrigLink ){
@@ -308,17 +308,17 @@
308308
}else{
309309
blob_read_from_file(&disk, zOPath);
310310
}
311311
fossil_print("CHANGED %s\n", zNew);
312312
if( !isOrigLink != !isLink ){
313
- diff_print_index(zNew);
314
- printf("--- %s\n+++ %s\n", zOrig, zNew);
313
+ diff_print_index(zNew, diffFlags);
314
+ diff_print_filenames(zOrig, zNew, diffFlags);
315315
printf("cannot compute difference between symlink and regular file\n");
316316
}else{
317317
content_get(rid, &a);
318318
blob_delta_apply(&a, &delta, &b);
319
- diff_file_mem(&disk, &b, zNew, zDiffCmd, 0);
319
+ diff_file_mem(&disk, &b, zNew, zDiffCmd, diffFlags);
320320
blob_reset(&a);
321321
blob_reset(&b);
322322
}
323323
blob_reset(&disk);
324324
}
@@ -526,20 +526,22 @@
526526
stashid);
527527
undo_finish();
528528
}else
529529
if( memcmp(zCmd, "diff", nCmd)==0 ){
530530
const char *zDiffCmd = db_get("diff-command", 0);
531
+ int diffFlags = diff_options();
531532
if( g.argc>4 ) usage("diff STASHID");
532533
stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0);
533
- stash_diff(stashid, zDiffCmd);
534
+ stash_diff(stashid, zDiffCmd, diffFlags);
534535
}else
535536
if( memcmp(zCmd, "gdiff", nCmd)==0 ){
536537
const char *zDiffCmd = db_get("gdiff-command", 0);
538
+ int diffFlags = diff_options();
537539
if( g.argc>4 ) usage("diff STASHID");
538540
stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0);
539
- stash_diff(stashid, zDiffCmd);
541
+ stash_diff(stashid, zDiffCmd, diffFlags);
540542
}else
541543
{
542544
usage("SUBCOMMAND ARGS...");
543545
}
544546
db_end_transaction(0);
545547
}
546548
--- src/stash.c
+++ src/stash.c
@@ -266,11 +266,11 @@
266 }
267
268 /*
269 ** Show the diffs associate with a single stash.
270 */
271 static void stash_diff(int stashid, const char *zDiffCmd){
272 Stmt q;
273 Blob empty;
274 blob_zero(&empty);
275 db_prepare(&q,
276 "SELECT rid, isRemoved, isExec, isLink, origname, newname, delta"
@@ -286,21 +286,21 @@
286 char *zOPath = mprintf("%s%s", g.zLocalRoot, zOrig);
287 Blob delta;
288 if( rid==0 ){
289 db_ephemeral_blob(&q, 6, &delta);
290 fossil_print("ADDED %s\n", zNew);
291 diff_print_index(zNew);
292 diff_file_mem(&empty, &delta, zNew, zDiffCmd, 0);
293 }else if( isRemoved ){
294 fossil_print("DELETE %s\n", zOrig);
295 if( file_wd_islink(zOPath) ){
296 blob_read_link(&delta, zOPath);
297 }else{
298 blob_read_from_file(&delta, zOPath);
299 }
300 diff_print_index(zNew);
301 diff_file_mem(&delta, &empty, zOrig, zDiffCmd, 0);
302 }else{
303 Blob a, b, disk;
304 int isOrigLink = file_wd_islink(zOPath);
305 db_ephemeral_blob(&q, 6, &delta);
306 if( isOrigLink ){
@@ -308,17 +308,17 @@
308 }else{
309 blob_read_from_file(&disk, zOPath);
310 }
311 fossil_print("CHANGED %s\n", zNew);
312 if( !isOrigLink != !isLink ){
313 diff_print_index(zNew);
314 printf("--- %s\n+++ %s\n", zOrig, zNew);
315 printf("cannot compute difference between symlink and regular file\n");
316 }else{
317 content_get(rid, &a);
318 blob_delta_apply(&a, &delta, &b);
319 diff_file_mem(&disk, &b, zNew, zDiffCmd, 0);
320 blob_reset(&a);
321 blob_reset(&b);
322 }
323 blob_reset(&disk);
324 }
@@ -526,20 +526,22 @@
526 stashid);
527 undo_finish();
528 }else
529 if( memcmp(zCmd, "diff", nCmd)==0 ){
530 const char *zDiffCmd = db_get("diff-command", 0);
 
531 if( g.argc>4 ) usage("diff STASHID");
532 stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0);
533 stash_diff(stashid, zDiffCmd);
534 }else
535 if( memcmp(zCmd, "gdiff", nCmd)==0 ){
536 const char *zDiffCmd = db_get("gdiff-command", 0);
 
537 if( g.argc>4 ) usage("diff STASHID");
538 stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0);
539 stash_diff(stashid, zDiffCmd);
540 }else
541 {
542 usage("SUBCOMMAND ARGS...");
543 }
544 db_end_transaction(0);
545 }
546
--- src/stash.c
+++ src/stash.c
@@ -266,11 +266,11 @@
266 }
267
268 /*
269 ** Show the diffs associate with a single stash.
270 */
271 static void stash_diff(int stashid, const char *zDiffCmd, int diffFlags){
272 Stmt q;
273 Blob empty;
274 blob_zero(&empty);
275 db_prepare(&q,
276 "SELECT rid, isRemoved, isExec, isLink, origname, newname, delta"
@@ -286,21 +286,21 @@
286 char *zOPath = mprintf("%s%s", g.zLocalRoot, zOrig);
287 Blob delta;
288 if( rid==0 ){
289 db_ephemeral_blob(&q, 6, &delta);
290 fossil_print("ADDED %s\n", zNew);
291 diff_print_index(zNew, diffFlags);
292 diff_file_mem(&empty, &delta, zNew, zDiffCmd, diffFlags);
293 }else if( isRemoved ){
294 fossil_print("DELETE %s\n", zOrig);
295 if( file_wd_islink(zOPath) ){
296 blob_read_link(&delta, zOPath);
297 }else{
298 blob_read_from_file(&delta, zOPath);
299 }
300 diff_print_index(zNew, diffFlags);
301 diff_file_mem(&delta, &empty, zOrig, zDiffCmd, diffFlags);
302 }else{
303 Blob a, b, disk;
304 int isOrigLink = file_wd_islink(zOPath);
305 db_ephemeral_blob(&q, 6, &delta);
306 if( isOrigLink ){
@@ -308,17 +308,17 @@
308 }else{
309 blob_read_from_file(&disk, zOPath);
310 }
311 fossil_print("CHANGED %s\n", zNew);
312 if( !isOrigLink != !isLink ){
313 diff_print_index(zNew, diffFlags);
314 diff_print_filenames(zOrig, zNew, diffFlags);
315 printf("cannot compute difference between symlink and regular file\n");
316 }else{
317 content_get(rid, &a);
318 blob_delta_apply(&a, &delta, &b);
319 diff_file_mem(&disk, &b, zNew, zDiffCmd, diffFlags);
320 blob_reset(&a);
321 blob_reset(&b);
322 }
323 blob_reset(&disk);
324 }
@@ -526,20 +526,22 @@
526 stashid);
527 undo_finish();
528 }else
529 if( memcmp(zCmd, "diff", nCmd)==0 ){
530 const char *zDiffCmd = db_get("diff-command", 0);
531 int diffFlags = diff_options();
532 if( g.argc>4 ) usage("diff STASHID");
533 stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0);
534 stash_diff(stashid, zDiffCmd, diffFlags);
535 }else
536 if( memcmp(zCmd, "gdiff", nCmd)==0 ){
537 const char *zDiffCmd = db_get("gdiff-command", 0);
538 int diffFlags = diff_options();
539 if( g.argc>4 ) usage("diff STASHID");
540 stashid = stash_get_id(g.argc==4 ? g.argv[3] : 0);
541 stash_diff(stashid, zDiffCmd, diffFlags);
542 }else
543 {
544 usage("SUBCOMMAND ARGS...");
545 }
546 db_end_transaction(0);
547 }
548
+1 -1
--- src/wiki.c
+++ src/wiki.c
@@ -621,11 +621,11 @@
621621
blob_zero(&w2);
622622
if( rid2 && (pW2 = manifest_get(rid2, CFTYPE_WIKI))!=0 ){
623623
blob_init(&w2, pW2->zWiki, -1);
624624
}
625625
blob_zero(&d);
626
- text_diff(&w2, &w1, &d, 5, 1);
626
+ text_diff(&w2, &w1, &d, 5 | DIFF_IGNORE_EOLWS);
627627
@ <pre>
628628
@ %h(blob_str(&d))
629629
@ </pre>
630630
manifest_destroy(pW1);
631631
manifest_destroy(pW2);
632632
--- src/wiki.c
+++ src/wiki.c
@@ -621,11 +621,11 @@
621 blob_zero(&w2);
622 if( rid2 && (pW2 = manifest_get(rid2, CFTYPE_WIKI))!=0 ){
623 blob_init(&w2, pW2->zWiki, -1);
624 }
625 blob_zero(&d);
626 text_diff(&w2, &w1, &d, 5, 1);
627 @ <pre>
628 @ %h(blob_str(&d))
629 @ </pre>
630 manifest_destroy(pW1);
631 manifest_destroy(pW2);
632
--- src/wiki.c
+++ src/wiki.c
@@ -621,11 +621,11 @@
621 blob_zero(&w2);
622 if( rid2 && (pW2 = manifest_get(rid2, CFTYPE_WIKI))!=0 ){
623 blob_init(&w2, pW2->zWiki, -1);
624 }
625 blob_zero(&d);
626 text_diff(&w2, &w1, &d, 5 | DIFF_IGNORE_EOLWS);
627 @ <pre>
628 @ %h(blob_str(&d))
629 @ </pre>
630 manifest_destroy(pW1);
631 manifest_destroy(pW2);
632
+1 -1
--- src/wiki.c
+++ src/wiki.c
@@ -621,11 +621,11 @@
621621
blob_zero(&w2);
622622
if( rid2 && (pW2 = manifest_get(rid2, CFTYPE_WIKI))!=0 ){
623623
blob_init(&w2, pW2->zWiki, -1);
624624
}
625625
blob_zero(&d);
626
- text_diff(&w2, &w1, &d, 5, 1);
626
+ text_diff(&w2, &w1, &d, 5 | DIFF_IGNORE_EOLWS);
627627
@ <pre>
628628
@ %h(blob_str(&d))
629629
@ </pre>
630630
manifest_destroy(pW1);
631631
manifest_destroy(pW2);
632632
--- src/wiki.c
+++ src/wiki.c
@@ -621,11 +621,11 @@
621 blob_zero(&w2);
622 if( rid2 && (pW2 = manifest_get(rid2, CFTYPE_WIKI))!=0 ){
623 blob_init(&w2, pW2->zWiki, -1);
624 }
625 blob_zero(&d);
626 text_diff(&w2, &w1, &d, 5, 1);
627 @ <pre>
628 @ %h(blob_str(&d))
629 @ </pre>
630 manifest_destroy(pW1);
631 manifest_destroy(pW2);
632
--- src/wiki.c
+++ src/wiki.c
@@ -621,11 +621,11 @@
621 blob_zero(&w2);
622 if( rid2 && (pW2 = manifest_get(rid2, CFTYPE_WIKI))!=0 ){
623 blob_init(&w2, pW2->zWiki, -1);
624 }
625 blob_zero(&d);
626 text_diff(&w2, &w1, &d, 5 | DIFF_IGNORE_EOLWS);
627 @ <pre>
628 @ %h(blob_str(&d))
629 @ </pre>
630 manifest_destroy(pW1);
631 manifest_destroy(pW2);
632
--- test/merge5.test
+++ test/merge5.test
@@ -38,14 +38,18 @@
3838
}
3939
}
4040
4141
catch {exec $::fossilexe info} res
4242
puts res=$res
43
-if {![regexp {not within an open checkout} $res]} {
43
+if {![regexp {use --repository} $res]} {
4444
puts stderr "Cannot run this test within an open checkout"
4545
return
4646
}
47
+#
48
+# Fossil will write data on $HOME, running 'fossil open' here.
49
+# We need not to clutter the $HOME of the test caller.
50
+set env(HOME) [pwd]
4751
4852
# Construct a test repository
4953
#
5054
exec sqlite3 m5.fossil <$testdir/${testfile}_repo.sql
5155
fossil rebuild m5.fossil
5256
--- test/merge5.test
+++ test/merge5.test
@@ -38,14 +38,18 @@
38 }
39 }
40
41 catch {exec $::fossilexe info} res
42 puts res=$res
43 if {![regexp {not within an open checkout} $res]} {
44 puts stderr "Cannot run this test within an open checkout"
45 return
46 }
 
 
 
 
47
48 # Construct a test repository
49 #
50 exec sqlite3 m5.fossil <$testdir/${testfile}_repo.sql
51 fossil rebuild m5.fossil
52
--- test/merge5.test
+++ test/merge5.test
@@ -38,14 +38,18 @@
38 }
39 }
40
41 catch {exec $::fossilexe info} res
42 puts res=$res
43 if {![regexp {use --repository} $res]} {
44 puts stderr "Cannot run this test within an open checkout"
45 return
46 }
47 #
48 # Fossil will write data on $HOME, running 'fossil open' here.
49 # We need not to clutter the $HOME of the test caller.
50 set env(HOME) [pwd]
51
52 # Construct a test repository
53 #
54 exec sqlite3 m5.fossil <$testdir/${testfile}_repo.sql
55 fossil rebuild m5.fossil
56
--- test/merge_renames.test
+++ test/merge_renames.test
@@ -7,10 +7,16 @@
77
puts res=$res
88
if {![regexp {use --repository} $res]} {
99
puts stderr "Cannot run this test within an open checkout"
1010
return
1111
}
12
+
13
+
14
+# Fossil will write data on $HOME, running 'fossil new' here.
15
+# We need not to clutter the $HOME of the test caller.
16
+set env(HOME) [pwd]
17
+
1218
1319
######################################
1420
# Test 1 #
1521
# Reported: Ticket [554f44ee74e3d] #
1622
######################################
1723
--- test/merge_renames.test
+++ test/merge_renames.test
@@ -7,10 +7,16 @@
7 puts res=$res
8 if {![regexp {use --repository} $res]} {
9 puts stderr "Cannot run this test within an open checkout"
10 return
11 }
 
 
 
 
 
 
12
13 ######################################
14 # Test 1 #
15 # Reported: Ticket [554f44ee74e3d] #
16 ######################################
17
--- test/merge_renames.test
+++ test/merge_renames.test
@@ -7,10 +7,16 @@
7 puts res=$res
8 if {![regexp {use --repository} $res]} {
9 puts stderr "Cannot run this test within an open checkout"
10 return
11 }
12
13
14 # Fossil will write data on $HOME, running 'fossil new' here.
15 # We need not to clutter the $HOME of the test caller.
16 set env(HOME) [pwd]
17
18
19 ######################################
20 # Test 1 #
21 # Reported: Ticket [554f44ee74e3d] #
22 ######################################
23
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,7 +1,44 @@
11
<title>Change Log</title>
22
3
+<h2>Changes For Version 1.20 (2011-10-21)</h2>
4
+ * Added side-by-side diffs in HTML interface. [0bde74ea1e]
5
+ * Added support for symlinks. (Controlled by "allow-symlinks" setting,
6
+ off by default). [e4f1c1fe95]
7
+ * Fixed CLI annotate to show the proper file version in case there
8
+ are multiple equal versions in history. [e161670939]
9
+ * Timeline now shows tag changes (requires rebuild).[87540ed6e6]
10
+ * Fixed annotate to show "more relevant" versions of lines in
11
+ some cases. [e161670939]
12
+ * New command: ticket history. [98a855c508]
13
+ * Disabled SSLv2 in HTTPS client.[ea1d369d23]
14
+ * Fixed constant prompting regarding previously-saved SSL
15
+ certificates. [636804745b]
16
+ * Other SSL improvements.
17
+ * Added -R REPOFILE support to several more CLI commands. [e080560378]
18
+ * Generated tarballs now have constant timestamps, so they are
19
+ always identical for any given checkin. [e080560378]
20
+ * A number of minor HTML-related tweaks and fixes.
21
+ * Added --args FILENAME global CLI argument to import arbitrary
22
+ CLI arguments from a file (e.g. long file lists). [e080560378]
23
+ * Fixed significant memory leak in annotation of files with long
24
+ histories.[9929bab702]
25
+ * Added warnings when a merge operation overwrites local copies
26
+ (UNDO is available, but previously this condition normally went
27
+ silently unnoticed). [39f979b08c]
28
+ * Improved performance when adding many files. [a369dc7721]
29
+ * Improve merges which contain many file renames. [0b93b0f958]
30
+ * Added protection against timing attacks. [d4a341b49d]
31
+ * Firefox now remembers filled fields when returning to forms. [3fac77d7b0]
32
+ * Added the --stats option to the rebuild command. [f25e5e53c4]
33
+ * RSS feed now passes validation. [ce354d0a9f]
34
+ * Show overridden user when entering commit comment. [ce354d0a9f]
35
+ * Made rebuilding from web interface silent. [ce354d0a9f]
36
+ * Now works on MSVC with repos >2GB. [6092935ff2]
37
+ * A number of code cleanups to resolve warnings from various compilers.
38
+ * Update the built-in SQLite to version 3.7.9 beta.
39
+
340
<h2>Changes For Version 1.19 (2011-09-02)</h2>
441
542
* Added a ./configure script based on autosetup.
643
* Added the "[/help/winsrv | fossil winsrv]" command
744
for creating a Fossil service on windows systems.
845
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,7 +1,44 @@
1 <title>Change Log</title>
2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3 <h2>Changes For Version 1.19 (2011-09-02)</h2>
4
5 * Added a ./configure script based on autosetup.
6 * Added the "[/help/winsrv | fossil winsrv]" command
7 for creating a Fossil service on windows systems.
8
--- www/changes.wiki
+++ www/changes.wiki
@@ -1,7 +1,44 @@
1 <title>Change Log</title>
2
3 <h2>Changes For Version 1.20 (2011-10-21)</h2>
4 * Added side-by-side diffs in HTML interface. [0bde74ea1e]
5 * Added support for symlinks. (Controlled by "allow-symlinks" setting,
6 off by default). [e4f1c1fe95]
7 * Fixed CLI annotate to show the proper file version in case there
8 are multiple equal versions in history. [e161670939]
9 * Timeline now shows tag changes (requires rebuild).[87540ed6e6]
10 * Fixed annotate to show "more relevant" versions of lines in
11 some cases. [e161670939]
12 * New command: ticket history. [98a855c508]
13 * Disabled SSLv2 in HTTPS client.[ea1d369d23]
14 * Fixed constant prompting regarding previously-saved SSL
15 certificates. [636804745b]
16 * Other SSL improvements.
17 * Added -R REPOFILE support to several more CLI commands. [e080560378]
18 * Generated tarballs now have constant timestamps, so they are
19 always identical for any given checkin. [e080560378]
20 * A number of minor HTML-related tweaks and fixes.
21 * Added --args FILENAME global CLI argument to import arbitrary
22 CLI arguments from a file (e.g. long file lists). [e080560378]
23 * Fixed significant memory leak in annotation of files with long
24 histories.[9929bab702]
25 * Added warnings when a merge operation overwrites local copies
26 (UNDO is available, but previously this condition normally went
27 silently unnoticed). [39f979b08c]
28 * Improved performance when adding many files. [a369dc7721]
29 * Improve merges which contain many file renames. [0b93b0f958]
30 * Added protection against timing attacks. [d4a341b49d]
31 * Firefox now remembers filled fields when returning to forms. [3fac77d7b0]
32 * Added the --stats option to the rebuild command. [f25e5e53c4]
33 * RSS feed now passes validation. [ce354d0a9f]
34 * Show overridden user when entering commit comment. [ce354d0a9f]
35 * Made rebuilding from web interface silent. [ce354d0a9f]
36 * Now works on MSVC with repos >2GB. [6092935ff2]
37 * A number of code cleanups to resolve warnings from various compilers.
38 * Update the built-in SQLite to version 3.7.9 beta.
39
40 <h2>Changes For Version 1.19 (2011-09-02)</h2>
41
42 * Added a ./configure script based on autosetup.
43 * Added the "[/help/winsrv | fossil winsrv]" command
44 for creating a Fossil service on windows systems.
45

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button