Fossil

Check-in [def52067]
Login

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

Overview
Comment:merged from trunk
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | wolfgangFormat2CSS_2
Files: files | file ages | folders
SHA1:def52067be777e33e62be11c6b998828a729eaf4
User & Date: wolfgang 2010-10-05 09:43:46
Context
2010-10-06
09:54
merge from trunk check-in: 454658c0 user: wolfgang tags: wolfgangFormat2CSS_2
2010-10-05
09:43
merged from trunk check-in: def52067 user: wolfgang tags: wolfgangFormat2CSS_2
03:55
Update to the latest SQLite 3.7.3 beta. check-in: 12a79e5b user: drh tags: trunk, release
2010-10-04
11:48
merged from trunk check-in: fafcb6c7 user: Ratte tags: wolfgangFormat2CSS_2
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/blob.c.

70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#define blob_is_reset(x)
#endif

/*
** We find that the built-in isspace() function does not work for
** some international character sets.  So here is a substitute.
*/
static int blob_isspace(char c){
  return c==' ' || (c<='\r' && c>='\t');
}

/*
** COMMAND: test-isspace
*/
void isspace_cmd(void){







|







70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#define blob_is_reset(x)
#endif

/*
** We find that the built-in isspace() function does not work for
** some international character sets.  So here is a substitute.
*/
int blob_isspace(char c){
  return c==' ' || (c<='\r' && c>='\t');
}

/*
** COMMAND: test-isspace
*/
void isspace_cmd(void){

Changes to src/content.c.

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

39

40
41
42
43
44
45
46

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












































61
62
63
64
65
66
67
68
69
70
71

72

73
74
75
76
77
78
79
..
93
94
95
96
97
98
99


100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118

119
120
121
122
123
124
125
126
127
128
...
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179

180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
...
318
319
320
321
322
323
324


325
326
327

328
329
330
331
332
333
334
335







336
337
338
339
340




341


342

343


344
345
346
347
348
349

350
351
352
353
354
355
356
**
** Procedures store and retrieve records from the repository
*/
#include "config.h"
#include "content.h"
#include <assert.h>

/*
** Macros for debugging
*/
#if 0
# define CONTENT_TRACE(X)  printf X;
#else
# define CONTENT_TRACE(X)
#endif

/*
** The artifact retrival cache
*/
#define MX_CACHE_CNT  50    /* Maximum number of positive cache entries */
#define EXPELL_INTERVAL 5   /* How often to expell from a full cache */
static struct {

  int n;               /* Current number of positive cache entries */

  int nextAge;         /* Age counter for implementing LRU */
  int skipCnt;         /* Used to limit entries expelled from cache */
  struct {             /* One instance of this for each cache entry */
    int rid;                  /* Artifact id */
    int age;                  /* Age.  Newer is larger */
    Blob content;             /* Content of the artifact */
  } a[MX_CACHE_CNT];   /* The positive cache */


  /*
  ** The missing artifact cache.
  **
  ** Artifacts whose record ID are in missingCache cannot be retrieved
  ** either because they are phantoms or because they are a delta that
  ** depends on a phantom.  Artifacts whose content we are certain is
................................................................................
  ** available are in availableCache.  If an artifact is in neither cache
  ** then its current availablity is unknown.
  */
  Bag missing;         /* Cache of artifacts that are incomplete */
  Bag available;       /* Cache of artifacts that are complete */
} contentCache;














































/*
** Clear the content cache.
*/
void content_clear_cache(void){
  int i;
  for(i=0; i<contentCache.n; i++){
    blob_reset(&contentCache.a[i].content);
  }
  bag_clear(&contentCache.missing);
  bag_clear(&contentCache.available);

  contentCache.n = 0;

}

/*
** Return the srcid associated with rid.  Or return 0 if rid is 
** original content and not a delta.
*/
static int findSrcid(int rid){
................................................................................
/*
** Check to see if content is available for artifact "rid".  Return
** true if it is.  Return false if rid is a phantom or depends on
** a phantom.
*/
int content_is_available(int rid){
  int srcid;


  if( bag_find(&contentCache.missing, rid) ){
    return 0;
  }
  if( bag_find(&contentCache.available, rid) ){
    return 1;
  }
  if( db_int(-1, "SELECT size FROM blob WHERE rid=%d", rid)<0 ){
    bag_insert(&contentCache.missing, rid);
    return 0;
  }
  srcid = findSrcid(rid);
  if( srcid==0 ){
    bag_insert(&contentCache.available, rid);
    return 1;
  }
  if( content_is_available(srcid) ){
    bag_insert(&contentCache.available, rid);
    return 1;
  }else{

    bag_insert(&contentCache.missing, rid);
    return 0;
  }
}

/*
** Mark artifact rid as being available now.  Update the cache to
** show that everything that was formerly unavailable because rid
** was missing is now available.
*/
................................................................................
    blob_uncompress(pBlob, pBlob);
    rc = 1;
  }
  db_reset(&q);
  return rc;
}


/*
** Extract the content for ID rid and put it into the
** uninitialized blob.  Return 1 on success.  If the record
** is a phantom, zero pBlob and return 0.
*/
int content_get(int rid, Blob *pBlob){
  Blob src;
  int srcid;
  int rc = 0;
  int i;
  static Bag inProcess;


  assert( g.repositoryOpen );
  blob_zero(pBlob);
  if( rid==0 ) return 0;

  /* Early out if we know the content is not available */
  if( bag_find(&contentCache.missing, rid) ){
    CONTENT_TRACE(("%*smiss from cache: %d\n",
                    bag_count(&inProcess), "", rid))
    return 0;
  }

  /* Look for the artifact in the cache first */
  for(i=0; i<contentCache.n; i++){
    if( contentCache.a[i].rid==rid ){
      *pBlob = contentCache.a[i].content;
      blob_zero(&contentCache.a[i].content);
      contentCache.n--;
      if( i<contentCache.n ){
        contentCache.a[i] = contentCache.a[contentCache.n];
      }
      CONTENT_TRACE(("%*scache: %d\n", 
                    bag_count(&inProcess), "", rid))
      return 1;
    }
  }

  /* See if we need to apply a delta to find this artifact */
  srcid = findSrcid(rid);
  CONTENT_TRACE(("%*ssearching for %d.  Need %d.\n",
                 bag_count(&inProcess), "", rid, srcid))


  if( srcid ){
    /* Yes, a delta is required */
    if( bag_find(&inProcess, srcid) ){
      db_multi_exec(
        "UPDATE blob SET content=NULL, size=-1 WHERE rid=%d;"
        "DELETE FROM delta WHERE rid=%d;"
        "INSERT OR IGNORE INTO phantom VALUES(%d);",
        srcid, srcid, srcid
      );
      blob_zero(pBlob);
      return 0;
    }
    bag_insert(&inProcess, srcid);

    if( content_get(srcid, &src) ){
      Blob delta;
      if( content_of_blob(rid, &delta) ){
        blob_init(pBlob,0,0);
        blob_delta_apply(&src, &delta, pBlob);
        blob_reset(&delta);
        rc = 1;
      }

      /* Save the srcid artifact in the cache */
      if( contentCache.n<MX_CACHE_CNT ){
        i = contentCache.n++;
      }else if( ((contentCache.skipCnt++)%EXPELL_INTERVAL)!=0 ){
        i = -1;
      }else{
        int j, best;
        best = contentCache.nextAge+1;
        i = -1;
        for(j=0; j<contentCache.n; j++){
          if( contentCache.a[j].age<best ){
            i = j;
            best = contentCache.a[j].age;
          }
        }
        CONTENT_TRACE(("%*sexpell %d from cache\n",
                       bag_count(&inProcess), "", contentCache.a[i].rid))
        blob_reset(&contentCache.a[i].content);
      }
      if( i>=0 ){
        contentCache.a[i].content = src;
        contentCache.a[i].age = contentCache.nextAge++;
        contentCache.a[i].rid = srcid;
        CONTENT_TRACE(("%*sadd %d to cache\n",
                       bag_count(&inProcess), "", srcid))
      }else{
        blob_reset(&src);
      }
    }
    bag_remove(&inProcess, srcid);
  }else{
    /* No delta required.  Read content directly from the database */
    if( content_of_blob(rid, pBlob) ){
      rc = 1;
    }
  }
  if( rc==0 ){
    bag_insert(&contentCache.missing, rid);
  }else{
    bag_insert(&contentCache.available, rid);
  }
  return rc;
................................................................................
  blob_write_to_file(&content, zFile);
}

/*
** When a record is converted from a phantom to a real record,
** if that record has other records that are derived by delta,
** then call manifest_crosslink() on those other records.


*/
void after_dephantomize(int rid, int linkFlag){
  Stmt q;

  int prevTid = 0;

  /* The prevTid variable is used to delay invoking this routine
  ** recursively, if possible, until after the query has finalized,
  ** in order to avoid having an excessive number of prepared statements.
  ** This is most effective in the common case where the query returns 
  ** just one row.
  */







  db_prepare(&q, "SELECT rid FROM delta WHERE srcid=%d", rid);
  while( db_step(&q)==SQLITE_ROW ){
    int tid = db_column_int(&q, 0);
    if( prevTid ) after_dephantomize(prevTid, 1);
    prevTid = tid;




  }


  db_finalize(&q);

  if( prevTid ) after_dephantomize(prevTid, 1);


  if( linkFlag ){
    Blob content;
    content_get(rid, &content);
    manifest_crosslink(rid, &content);
    blob_reset(&content);
  }

}

/*
** Write content into the database.  Return the record ID.  If the
** content is already in the database, just return the record ID.
**
** If srcId is specified, then pBlob is delta content from







<
<
<
<
<
<
<
<
<



<
<

>
|
>


|



|
>







 







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











>

>







 







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







 







<






<
<
|

<
>







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







 







>
>



>
|

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

>







17
18
19
20
21
22
23









24
25
26


27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
..
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
...
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154


155

156
157
158

159
160
161
162
163
164
165
...
198
199
200
201
202
203
204

205
206
207
208
209
210


211
212

213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278


























279
280
281
282
283
284
285
...
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340



341
342

343
344
345
346
347
348
349
350
351
352


353
354
355
356
357
358
359
360
361
362
363
364
365




366
367
368
369
370
371
372
373
374
**
** Procedures store and retrieve records from the repository
*/
#include "config.h"
#include "content.h"
#include <assert.h>










/*
** The artifact retrival cache
*/


static struct {
  i64 szTotal;         /* Total size of all entries in the cache */
  int n;               /* Current number of eache entries */
  int nAlloc;          /* Number of slots allocated in a[] */
  int nextAge;         /* Age counter for implementing LRU */
  int skipCnt;         /* Used to limit entries expelled from cache */
  struct cacheLine {   /* One instance of this for each cache entry */
    int rid;                  /* Artifact id */
    int age;                  /* Age.  Newer is larger */
    Blob content;             /* Content of the artifact */
  } *a;                /* The positive cache */
  Bag inCache;         /* Set of artifacts currently in cache */

  /*
  ** The missing artifact cache.
  **
  ** Artifacts whose record ID are in missingCache cannot be retrieved
  ** either because they are phantoms or because they are a delta that
  ** depends on a phantom.  Artifacts whose content we are certain is
................................................................................
  ** available are in availableCache.  If an artifact is in neither cache
  ** then its current availablity is unknown.
  */
  Bag missing;         /* Cache of artifacts that are incomplete */
  Bag available;       /* Cache of artifacts that are complete */
} contentCache;

/*
** Remove the oldest element from the content cache
*/
static void content_cache_expire_oldest(void){
  int i;
  int mnAge = contentCache.nextAge;
  int mn = -1;
  for(i=0; i<contentCache.n; i++){
    if( contentCache.a[i].age<mnAge ){
      mnAge = contentCache.a[i].age;
      mn = i;
    }
  }
  if( mn>=0 ){
    bag_remove(&contentCache.inCache, contentCache.a[mn].rid);
    contentCache.szTotal -= blob_size(&contentCache.a[mn].content);
    blob_reset(&contentCache.a[mn].content);
    contentCache.n--;
    contentCache.a[mn] = contentCache.a[contentCache.n];
  }
}

/*
** Add an entry to the content cache
*/
void content_cache_insert(int rid, Blob *pBlob){
  struct cacheLine *p;
  if( contentCache.n>500 || contentCache.szTotal>50000000 ){
    content_cache_expire_oldest();
  }
  if( contentCache.n>=contentCache.nAlloc ){
    contentCache.nAlloc = contentCache.nAlloc*2 + 10;
    contentCache.a = realloc(contentCache.a,
                             contentCache.nAlloc*sizeof(contentCache.a[0]));
    if( contentCache.a==0 ) fossil_panic("out of memory");
  }
  p = &contentCache.a[contentCache.n++];
  p->rid = rid;
  p->age = contentCache.nextAge++;
  contentCache.szTotal += blob_size(pBlob);
  p->content = *pBlob;
  blob_zero(pBlob);
  bag_insert(&contentCache.inCache, rid);
}

/*
** Clear the content cache.
*/
void content_clear_cache(void){
  int i;
  for(i=0; i<contentCache.n; i++){
    blob_reset(&contentCache.a[i].content);
  }
  bag_clear(&contentCache.missing);
  bag_clear(&contentCache.available);
  bag_clear(&contentCache.inCache);
  contentCache.n = 0;
  contentCache.szTotal = 0;
}

/*
** Return the srcid associated with rid.  Or return 0 if rid is 
** original content and not a delta.
*/
static int findSrcid(int rid){
................................................................................
/*
** Check to see if content is available for artifact "rid".  Return
** true if it is.  Return false if rid is a phantom or depends on
** a phantom.
*/
int content_is_available(int rid){
  int srcid;
  int depth = 0;  /* Limit to recursion depth */
  while( depth++ < 10000000 ){  
    if( bag_find(&contentCache.missing, rid) ){
      return 0;
    }
    if( bag_find(&contentCache.available, rid) ){
      return 1;
    }
    if( db_int(-1, "SELECT size FROM blob WHERE rid=%d", rid)<0 ){
      bag_insert(&contentCache.missing, rid);
      return 0;
    }
    srcid = findSrcid(rid);
    if( srcid==0 ){
      bag_insert(&contentCache.available, rid);
      return 1;
    }


    rid = srcid;

  }
  fossil_panic("delta-loop in repository");
  return 0;

}

/*
** Mark artifact rid as being available now.  Update the cache to
** show that everything that was formerly unavailable because rid
** was missing is now available.
*/
................................................................................
    blob_uncompress(pBlob, pBlob);
    rc = 1;
  }
  db_reset(&q);
  return rc;
}


/*
** Extract the content for ID rid and put it into the
** uninitialized blob.  Return 1 on success.  If the record
** is a phantom, zero pBlob and return 0.
*/
int content_get(int rid, Blob *pBlob){


  int rc;
  int i;

  int nextRid;

  assert( g.repositoryOpen );
  blob_zero(pBlob);
  if( rid==0 ) return 0;

  /* Early out if we know the content is not available */
  if( bag_find(&contentCache.missing, rid) ){
    return 0;
  }

  /* Look for the artifact in the cache first */
  if( bag_find(&contentCache.inCache, rid) ){
    for(i=0; i<contentCache.n; i++){
      if( contentCache.a[i].rid==rid ){
        blob_copy(pBlob, &contentCache.a[i].content);
        contentCache.a[i].age = contentCache.nextAge++;
        return 1;
      }
    }
  }

  nextRid = findSrcid(rid);
  if( nextRid==0 ){
    rc = content_of_blob(rid, pBlob);
  }else{
    int n = 1;
    int nAlloc = 10;
    int *a = 0;
    int mx;
    Blob delta, next;

    a = malloc( sizeof(a[0])*nAlloc );
    if( a==0 ) fossil_panic("out of memory");
    a[0] = rid;
    a[1] = nextRid;
    n = 1;
    while( !bag_find(&contentCache.inCache, nextRid)
        && (nextRid = findSrcid(nextRid))>0 ){
      n++;
      if( n>=nAlloc ){
        nAlloc = nAlloc*2 + 10;
        a = realloc(a, nAlloc*sizeof(a[0]));
        if( a==0 ) fossil_panic("out of memory");
      }
      a[n] = nextRid;
    }
    mx = n;
    rc = content_get(a[n], pBlob);
    n--;
    while( rc && n>=0 ){
      rc = content_of_blob(a[n], &delta);
      if( rc ){
        blob_delta_apply(pBlob, &delta, &next);
        blob_reset(&delta);
        if( (mx-n)%8==0 ){
          content_cache_insert(a[n+1], pBlob);
        }else{
          blob_reset(pBlob);
        }
        *pBlob = next;
      }
      n--;
    }
    free(a);
    if( !rc ) blob_reset(pBlob);


























  }
  if( rc==0 ){
    bag_insert(&contentCache.missing, rid);
  }else{
    bag_insert(&contentCache.available, rid);
  }
  return rc;
................................................................................
  blob_write_to_file(&content, zFile);
}

/*
** When a record is converted from a phantom to a real record,
** if that record has other records that are derived by delta,
** then call manifest_crosslink() on those other records.
**
** Tail recursion is used to minimize stack depth.
*/
void after_dephantomize(int rid, int linkFlag){
  Stmt q;
  int nChildAlloc = 0;
  int *aChild = 0;




  while( rid ){
    int nChildUsed = 0;

    int i;
    if( linkFlag ){
      Blob content;
      content_get(rid, &content);
      manifest_crosslink(rid, &content);
      blob_reset(&content);
    }
    db_prepare(&q, "SELECT rid FROM delta WHERE srcid=%d", rid);
    while( db_step(&q)==SQLITE_ROW ){
      int child = db_column_int(&q, 0);


      if( nChildUsed>=nChildAlloc ){
        nChildAlloc = nChildAlloc*2 + 10;
        aChild = realloc(aChild, nChildAlloc*sizeof(aChild));
        if( aChild==0 ) fossil_panic("out of memory");
      }
      aChild[nChildUsed++] = child;
    }
    db_finalize(&q);
    for(i=1; i<nChildUsed; i++){
      after_dephantomize(aChild[i], 1);
    }
    rid = nChildUsed>0 ? aChild[0] : 0;
    linkFlag = 1;




  }
  free(aChild);
}

/*
** Write content into the database.  Return the record ID.  If the
** content is already in the database, just return the record ID.
**
** If srcId is specified, then pBlob is delta content from

Added src/event.c.



















































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
/*
** Copyright (c) 2010 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the Simplified BSD License (also
** known as the "2-Clause License" or "FreeBSD License".)

** This program is distributed in the hope that it will be useful,
** but without any warranty; without even the implied warranty of
** merchantability or fitness for a particular purpose.
**
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*******************************************************************************
**
** This file contains code to do formatting of event messages:
**
**     Milestones
**     Blog posts
**     New articles
**     Process checkpoints
**     Announcements
*/
#include <assert.h>
#include <ctype.h>
#include "config.h"
#include "event.h"

/*
** Output a hyperlink to an event given its tagid.
*/
void hyperlink_to_event_tagid(int tagid){
  char *zEventId;
  char zShort[12];

  zEventId = db_text(0, "SELECT substr(tagname, 7) FROM tag WHERE tagid=%d",
                     tagid);
  sqlite3_snprintf(sizeof(zShort), zShort, "%.10s", zEventId);
  if( g.okHistory ){
    @ [<a href="%s(g.zTop)/event?name=%s(zEventId)">%s(zShort)</a>]
  }else{
    @ [%s(zShort)]
  }
  free(zEventId);
}

/*
** WEBPAGE: event
** URL: /event?name=EVENTID&detail=BOOLEAN&aid=ARTIFACTID
**
** Display an existing event identified by EVENTID
*/
void event_page(void){
  int rid = 0;             /* rid of the event artifact */
  char *zUuid;             /* UUID corresponding to rid */
  const char *zEventId;    /* Event identifier */
  char *zETime;            /* Time of the event */
  char *zATime;            /* Time the artifact was created */
  int specRid;             /* rid specified by aid= parameter */
  int prevRid, nextRid;    /* Previous or next edits of this event */
  Manifest m;              /* Parsed event artifact */
  Blob content;            /* Original event artifact content */
  Blob fullbody;           /* Complete content of the event body */
  Blob title;              /* Title extracted from the event body */
  Blob tail;               /* Event body that comes after the title */
  Stmt q1;                 /* Query to search for the event */
  int showDetail;          /* True to show details */


  /* wiki-read privilege is needed in order to read events.
  */
  login_check_credentials();
  if( !g.okRdWiki ){
    login_needed();
    return;
  }

  zEventId = P("name");
  if( zEventId==0 ){ fossil_redirect_home(); return; }
  zUuid = (char*)P("aid");
  specRid = zUuid ? uuid_to_rid(zUuid, 0) : 0;
  rid = nextRid = prevRid = 0;
  db_prepare(&q1,
     "SELECT rid FROM tagxref"
     " WHERE tagid=(SELECT tagid FROM tag WHERE tagname='event-%q')"
     " ORDER BY mtime DESC",
     zEventId
  );
  while( db_step(&q1)==SQLITE_ROW ){
    nextRid = rid;
    rid = db_column_int(&q1, 0);
    if( specRid==0 || specRid==rid ){
      if( db_step(&q1)==SQLITE_ROW ){
        prevRid = db_column_int(&q1, 0);
      }
      break;
    }
  }
  db_finalize(&q1);
  if( rid==0 || (specRid!=0 && specRid!=rid) ){
    style_header("No Such Event");
    @ Cannot locate specified event
    style_footer();
    return;
  }
  zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
  showDetail = atoi(PD("detail","0"));

  /* Extract the event content.
  */
  memset(&m, 0, sizeof(m));
  blob_zero(&m.content);
  content_get(rid, &content);
  manifest_parse(&m, &content);
  if( m.type!=CFTYPE_EVENT ){
    fossil_panic("Object #%d is not an event", rid);
  }
  blob_init(&fullbody, m.zWiki, -1);
  if( wiki_find_title(&fullbody, &title, &tail) ){
    style_header(blob_str(&title));
  }else{
    style_header("Event %S", zEventId);
    tail = fullbody;
  }
  if( g.okWrWiki && g.okWrite && nextRid==0 ){
    style_submenu_element("Edit", "Edit", "%s/eventedit?name=%s",
                          g.zTop, zEventId);
  }
  zETime = db_text(0, "SELECT datetime(%.17g)", m.rEventDate);
  style_submenu_element("Context", "Context", "%s/timeline?c=%T",
                        g.zTop, zETime);
  if( g.okHistory ){
    if( showDetail ){
      style_submenu_element("Plain", "Plain", "%s/event?name=%s&amp;aid=%s",
                            g.zTop, zEventId, zUuid);
      if( nextRid ){
        char *zNext;
        zNext = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nextRid);
        style_submenu_element("Next", "Next",
                              "%s/event?name=%s&amp;aid=%s&amp;detail=1",
                              g.zTop, zEventId, zNext);
        free(zNext);
      }
      if( prevRid ){
        char *zPrev;
        zPrev = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", prevRid);
        style_submenu_element("Prev", "Prev",
                              "%s/event?name=%s&amp;aid=%s&amp;detail=1",
                              g.zTop, zEventId, zPrev);
        free(zPrev);
      }
    }else{
      style_submenu_element("Detail", "Detail",
                            "%s/event?name=%s&amp;aid=%s&amp;detail=1",
                            g.zTop, zEventId, zUuid);
    }
  }

  if( showDetail && g.okHistory ){
    int i;
    const char *zClr = 0;
    Blob comment;

    zATime = db_text(0, "SELECT datetime(%.17g)", m.rDate);
    @ <p>Event [<a href="%s(g.zTop)/artifact/%s(zUuid)">%S(zUuid)</a>] at
    @ [<a href="%s(g.zTop)/timeline?c=%T(zETime)">%s(zETime)</a>]
    @ entered by user <b>%h(m.zUser)</b> on
    @ [<a href="%s(g.zTop)/timeline?c=%T(zATime)">%s(zATime)</a>]:</p>
    @ <blockquote>
    for(i=0; i<m.nTag; i++){
      if( strcmp(m.aTag[i].zName,"+bgcolor")==0 ){
        zClr = m.aTag[i].zValue;
      }
    }
    if( zClr && zClr[0]==0 ) zClr = 0;
    if( zClr ){
      @ <div style="background-color: %h(zClr);">
    }else{
      @ <div>
    }
    blob_init(&comment, m.zComment, -1);
    wiki_convert(&comment, 0, WIKI_INLINE);
    blob_reset(&comment);
    @ </div>
    @ </blockquote><hr />
  }  

  wiki_convert(&tail, 0, 0);
  style_footer();
  manifest_clear(&m);
}

/*
** WEBPAGE: eventedit
** URL: /eventedit?name=EVENTID
**
** Edit an event.  If name is omitted, create a new event.
*/
void eventedit_page(void){
  char *zTag;
  int rid = 0;
  Blob event;
  const char *zEventId;
  char *zHtmlPageName;
  int n;
  const char *z;
  char *zBody = (char*)P("w");
  char *zETime = (char*)P("t");
  const char *zComment = P("c");
  const char *zTags = P("g");
  const char *zClr;

  if( zBody ){
    zBody = mprintf("%s", zBody);
  }
  login_check_credentials();
  zEventId = P("name");
  if( zEventId==0 ){
    zEventId = db_text(0, "SELECT lower(hex(randomblob(20)))");
  }else{
    int nEventId = strlen(zEventId);
    if( nEventId!=40 || !validate16(zEventId, 40) ){
      fossil_redirect_home();
      return;
    }
  }
  zTag = mprintf("event-%s", zEventId);
  rid = db_int(0, 
    "SELECT rid FROM tagxref"
    " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)"
    " ORDER BY mtime DESC", zTag
  );
  free(zTag);

  /* Need both check-in and wiki-write or wiki-create privileges in order
  ** to edit/create an event.
  */
  if( !g.okWrite || (rid && !g.okWrWiki) || (!rid && !g.okNewWiki) ){
    login_needed();
    return;
  }

  /* Figure out the color */
  if( rid ){
    zClr = db_text("", "SELECT bgcolor  FROM event WHERE objid=%d", rid);
  }else{
    zClr = "";
  }
  zClr = PD("clr",zClr);
  if( strcmp(zClr,"##")==0 ) zClr = PD("cclr","");


  /* If editing an existing event, extract the key fields to use as
  ** a starting point for the edit.
  */
  if( rid && (zBody==0 || zETime==0 || zComment==0 || zTags==0) ){
    Manifest m;
    Blob content;
    memset(&m, 0, sizeof(m));
    blob_zero(&m.content);
    content_get(rid, &content);
    manifest_parse(&m, &content);
    if( m.type==CFTYPE_EVENT ){
      if( zBody==0 ) zBody = m.zWiki;
      if( zETime==0 ){
        zETime = db_text(0, "SELECT datetime(%.17g)", m.rEventDate);
      }
      if( zComment==0 ) zComment = m.zComment;
    }
    if( zTags==0 ){
      zTags = db_text(0,
        "SELECT group_concat(substr(tagname,5),', ')"
        "  FROM tagxref, tag"
        " WHERE tagxref.rid=%d"
        "   AND tagxref.tagid=tag.tagid"
        "   AND tag.tagname GLOB 'sym-*'",
        rid
      );
    }
  }
  zETime = db_text(0, "SELECT coalesce(datetime(%Q),datetime('now'))", zETime);
  if( P("submit")!=0 && (zBody!=0 && zComment!=0) ){
    char *zDate;
    Blob cksum;
    int nrid;
    blob_zero(&event);
    db_begin_transaction();
    login_verify_csrf_secret();
    blob_appendf(&event, "C %F\n", zComment);
    zDate = db_text(0, "SELECT datetime('now')");
    zDate[10] = 'T';
    blob_appendf(&event, "D %s\n", zDate);
    free(zDate);
    zETime[10] = 'T';
    blob_appendf(&event, "E %s %s\n", zETime, zEventId);
    zETime[10] = ' ';
    if( rid ){
      char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
      blob_appendf(&event, "P %s\n", zUuid);
      free(zUuid);
    }
    if( zClr && zClr[0] ){
      blob_appendf(&event, "T +bgcolor * %F\n", zClr);
    }
    if( zTags && zTags[0] ){
      Blob tags, one;
      int i, j;
      Stmt q;
      char *zBlob;

      /* Load the tags string into a blob */
      blob_zero(&tags);
      blob_append(&tags, zTags, -1); 

      /* Collapse all sequences of whitespace and "," characters into
      ** a single space character */
      zBlob = blob_str(&tags);
      for(i=j=0; zBlob[i]; i++, j++){
        if( blob_isspace(zBlob[i]) || zBlob[i]==',' ){
          while( blob_isspace(zBlob[i+1]) ){ i++; }
          zBlob[j] = ' ';
        }else{
          zBlob[j] = zBlob[i];
        }
      }
      blob_resize(&tags, j);

      /* Parse out each tag and load it into a temporary table for sorting */
      db_multi_exec("CREATE TEMP TABLE newtags(x);");
      while( blob_token(&tags, &one) ){
        db_multi_exec("INSERT INTO newtags VALUES(%B)", &one);
      }
      blob_reset(&tags);

      /* Extract the tags in sorted order and make an entry in the
      ** artifact for each. */
      db_prepare(&q, "SELECT x FROM newtags ORDER BY x");
      while( db_step(&q)==SQLITE_ROW ){
        blob_appendf(&event, "T +sym-%F *\n", db_column_text(&q, 0));
      }
      db_finalize(&q);
    }        
    if( g.zLogin ){
      blob_appendf(&event, "U %F\n", g.zLogin);
    }
    blob_appendf(&event, "W %d\n%s\n", strlen(zBody), zBody);
    md5sum_blob(&event, &cksum);
    blob_appendf(&event, "Z %b\n", &cksum);
    blob_reset(&cksum);
    nrid = content_put(&event, 0, 0);
    db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
    manifest_crosslink(nrid, &event);
    blob_reset(&event);
    content_deltify(rid, nrid, 0);
    db_end_transaction(0);
    cgi_redirectf("event?name=%T", zEventId);
  }
  if( P("cancel")!=0 ){
    cgi_redirectf("event?name=%T", zEventId);
    return;
  }
  if( zBody==0 ){
    zBody = mprintf("<i>Event Text</i>");
  }
  zHtmlPageName = mprintf("Edit Event %S", zEventId);
  style_header(zHtmlPageName);
  if( P("preview")!=0 ){
    Blob title, tail, com;
    @ <p><b>Timeline comment preview:</b></p>
    @ <blockquote>
    @ <table border="0">
    if( zClr && zClr[0] ){
      @ <tr><td style="background-color: %h(zClr);">
    }else{
      @ <tr><td>
    }
    blob_zero(&com);
    blob_append(&com, zComment, -1);
    wiki_convert(&com, 0, WIKI_INLINE);
    @ </td></tr></table>
    @ </blockquote>
    @ <p><b>Page content preview:</b><p>
    @ <blockquote>
    blob_zero(&event);
    blob_append(&event, zBody, -1);
    if( wiki_find_title(&event, &title, &tail) ){
      @ <h2 align="center">%h(blob_str(&title))</h2>
      wiki_convert(&tail, 0, 0);
    }else{
      wiki_convert(&event, 0, 0);
    }
    @ </blockquote><hr />
    blob_reset(&event);
  }
  for(n=2, z=zBody; z[0]; z++){
    if( z[0]=='\n' ) n++;
  }
  if( n<20 ) n = 20;
  if( n>40 ) n = 40;
  @ <form method="post" action="%s(g.zBaseURL)/eventedit"><div>
  login_insert_csrf_secret();
  @ <input type="hidden" name="name" value="%h(zEventId)" />
  @ <table border="0" cellspacing="10">

  @ <tr><td align="right" valign="top"><b>Event&nbsp;Time:</b></td>
  @ <td valign="top">
  @   <input type="text" name="t" size="25" value="%h(zETime)" />
  @ </td></tr>

  @ <tr><td align="right" valign="top"><b>Timeline&nbsp;Comment:</b></td>
  @ <td valign="top">
  @ <textarea name="c" class="eventedit" cols="80" 
  @  rows="3" wrap="virtual">%h(zComment)</textarea>
  @ </td></tr>

  @ <tr><td align="right" valign="top"><b>Background&nbsp;Color:</b></td>
  @ <td valign="top">
  render_color_chooser(0, zClr, 0, "clr", "cclr");
  @ </td></tr>
  
  @ <tr><td align="right" valign="top"><b>Tags:</b></td>
  @ <td valign="top">
  @   <input type="text" name="g" size="40" value="%h(zTags)" />
  @ </td></tr>
  
  @ <tr><td align="right" valign="top"><b>Page&nbsp;Content:</b></td>
  @ <td valign="top">
  @ <textarea name="w" class="eventedit" cols="80" 
  @  rows="%d(n)" wrap="virtual">%h(zBody)</textarea>
  @ </td></tr>

  @ <tr><td colspan="2">
  @ <input type="submit" name="preview" value="Preview Your Changes" />
  @ <input type="submit" name="submit" value="Apply These Changes" />
  @ <input type="submit" name="cancel" value="Cancel" />
  @ </td></tr></table>
  @ </div></form>
  style_footer();
}

Changes to src/info.c.

777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
...
798
799
800
801
802
803
804



805
806
807

808

809
810
811
812
813
814
815
....
1258
1259
1260
1261
1262
1263
1264
















































































1265
1266
1267
1268
1269
1270
1271
....
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
....
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
....
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
    if( pDownloadName && blob_size(pDownloadName)==0 ){
      blob_appendf(pDownloadName, "%s.wiki", zPagename);
    }
  }
  db_finalize(&q);
  if( nWiki==0 ){
    db_prepare(&q,
      "SELECT datetime(mtime), user, comment, type, uuid"
      "  FROM event, blob"
      " WHERE event.objid=%d"
      "   AND blob.rid=%d",
      rid, rid
    );
    while( db_step(&q)==SQLITE_ROW ){
      const char *zDate = db_column_text(&q, 0);
................................................................................
      }
      if( zType[0]=='w' ){
        @ Wiki edit
      }else if( zType[0]=='t' ){
        @ Ticket change
      }else if( zType[0]=='c' ){
        @ Manifest of check-in



      }else{
        @ Control file referencing
      }

      hyperlink_to_uuid(zUuid);

      @ - %w(zCom) by
      hyperlink_to_user(zUser,zDate," on");
      hyperlink_to_date(zDate, ".");
      if( pDownloadName && blob_size(pDownloadName)==0 ){
        blob_appendf(pDownloadName, "%.10s.txt", zUuid);
      }
      cnt++;
................................................................................
  if( db_exists("SELECT 1 FROM plink WHERE pid=%d", rid) ){
    ci_page();
  }else
  {
    artifact_page();
  }
}

















































































/*
** WEBPAGE: ci_edit
** URL:  ci_edit?r=RID&c=NEWCOMMENT&u=NEWUSER
**
** Present a dialog for updating properties of a baseline:
**
................................................................................
  const char *zNewBrFlag;
  const char *zNewBranch;
  const char *zCloseFlag;
  int fPropagateColor;
  char *zUuid;
  Blob comment;
  Stmt q;
  static const struct SampleColors {
     const char *zCName;
     const char *zColor;
  } aColor[] = {
     { "(none)",  "" },
     { "#f2dcdc", "#f2dcdc" },
     { "#f0ffc0", "#f0ffc0" },
     { "#bde5d6", "#bde5d6" },
     { "#c0ffc0", "#c0ffc0" },
     { "#c0fff0", "#c0fff0" },
     { "#c0f0ff", "#c0f0ff" },
     { "#d0c0ff", "#d0c0ff" },
     { "#ffc0ff", "#ffc0ff" },
     { "#ffc0d0", "#ffc0d0" },
     { "#fff0c0", "#fff0c0" },
     { "#c0c0c0", "#c0c0c0" },
     { "custom",  "##"      },
  };
  int nColor = sizeof(aColor)/sizeof(aColor[0])-1;
  int stdClrFound;
  int i;
  
  login_check_credentials();
  if( !g.okWrite ){ login_needed(); return; }
  rid = name_to_rid(P("r"));
  zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
  zComment = db_text(0, "SELECT coalesce(ecomment,comment)"
                        "  FROM event WHERE objid=%d", rid);
................................................................................
  zDate = db_text(0, "SELECT datetime(mtime)"
                     "  FROM event WHERE objid=%d", rid);
  if( zDate==0 ) fossil_redirect_home();
  zNewDate = PD("dt",zDate);
  zColor = db_text("", "SELECT bgcolor"
                        "  FROM event WHERE objid=%d", rid);
  zNewColor = PD("clr",zColor);
  if( strcmp(zNewColor,aColor[nColor].zColor)==0 ){
    zNewColor = P("clrcust");
  }
  fPropagateColor = P("pclr")!=0;
  zNewTagFlag = P("newtag") ? " checked" : "";
  zNewTag = PD("tagname","");
  zNewBrFlag = P("newbr") ? " checked" : "";
  zNewBranch = PD("brname","");
................................................................................
  @ <tr><td align="right" valign="top"><b>Check-in Time:</b></td>
  @ <td valign="top">
  @   <input type="text" name="dt" size="20" value="%h(zNewDate)" />
  @ </td></tr>

  @ <tr><td align="right" valign="top"><b>Background Color:</b></td>
  @ <td valign="top">
  @ <table border="0" cellpadding="0" cellspacing="1">
  @ <tr><td colspan="6" align="left">
  if( fPropagateColor ){
    @ <input type="checkbox" name="pclr" checked="checked" />
  }else{
    @ <input type="checkbox" name="pclr" />
  }
  @ Propagate color to descendants</td></tr>
  @ <tr>
  for(i=0,stdClrFound=0; i<nColor; i++){
    if( aColor[i].zColor[0] ){
      @ <td style="background-color: %h(aColor[i].zColor);">
    }else{
      @ <td>
    }
    if( strcmp(zNewColor, aColor[i].zColor)==0 ){
      @ <input type="radio" name="clr" value="%h(aColor[i].zColor)"
      @  checked="checked" />
      stdClrFound=1;
    }else{
      @ <input type="radio" name="clr" value="%h(aColor[i].zColor)" />
    }
    @ %h(aColor[i].zCName)</td>
    if( (i%6)==5 && i+1<nColor ){
      @ </tr><tr>
    }
  }
  @ </tr><tr>
  if (stdClrFound){
    @ <td colspan="6">
    @ <input type="radio" name="clr" value="%h(aColor[nColor].zColor)" />
  }else{
    @ <td style="background-color: %h(zNewColor);" colspan="6">
    @ <input type="radio" name="clr" value="%h(aColor[nColor].zColor)"
    @  checked="checked" />
  }
  @ %h(aColor[i].zCName)&nbsp;
  @ <input type="text" name="clrcust" id="clrcust" class="checkinUserColor"
  @  value="%h(stdClrFound?"":zNewColor)" />
  @ </td>
  @ </tr>
  @ </table>
  @ </td></tr>

  @ <tr><td align="right" valign="top"><b>Tags:</b></td>
  @ <td valign="top">
  @ <input type="checkbox" name="newtag"%s(zNewTagFlag) />
  @ Add the following new tag name to this check-in:
  @ <input type="text" style="width:15;" name="tagname" value="%h(zNewTag)" />







|







 







>
>
>



>
|
>







 







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







 







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







 







|







 







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







777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
...
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
....
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
....
1373
1374
1375
1376
1377
1378
1379





















1380
1381
1382
1383
1384
1385
1386
....
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
....
1563
1564
1565
1566
1567
1568
1569
1570









































1571
1572
1573
1574
1575
1576
1577
    if( pDownloadName && blob_size(pDownloadName)==0 ){
      blob_appendf(pDownloadName, "%s.wiki", zPagename);
    }
  }
  db_finalize(&q);
  if( nWiki==0 ){
    db_prepare(&q,
      "SELECT datetime(mtime), user, comment, type, uuid, tagid"
      "  FROM event, blob"
      " WHERE event.objid=%d"
      "   AND blob.rid=%d",
      rid, rid
    );
    while( db_step(&q)==SQLITE_ROW ){
      const char *zDate = db_column_text(&q, 0);
................................................................................
      }
      if( zType[0]=='w' ){
        @ Wiki edit
      }else if( zType[0]=='t' ){
        @ Ticket change
      }else if( zType[0]=='c' ){
        @ Manifest of check-in
      }else if( zType[0]=='e' ){
        @ Instance of event
        hyperlink_to_event_tagid(db_column_int(&q, 5));
      }else{
        @ Control file referencing
      }
      if( zType[0]!='e' ){
        hyperlink_to_uuid(zUuid);
      }
      @ - %w(zCom) by
      hyperlink_to_user(zUser,zDate," on");
      hyperlink_to_date(zDate, ".");
      if( pDownloadName && blob_size(pDownloadName)==0 ){
        blob_appendf(pDownloadName, "%.10s.txt", zUuid);
      }
      cnt++;
................................................................................
  if( db_exists("SELECT 1 FROM plink WHERE pid=%d", rid) ){
    ci_page();
  }else
  {
    artifact_page();
  }
}

/*
** Generate HTML that will present the user with a selection of
** potential background colors for timeline entries.
*/
void render_color_chooser(
  int fPropagate,             /* Default value for propagation */
  const char *zDefaultColor,  /* The current default color */
  const char *zIdPropagate,   /* ID of form element checkbox.  NULL for none */
  const char *zId,            /* The ID of the form element */
  const char *zIdCustom       /* ID of text box for custom color */
){
  static const struct SampleColors {
     const char *zCName;
     const char *zColor;
  } aColor[] = {
     { "(none)",  "" },
     { "#f2dcdc", "#f2dcdc" },
     { "#f0ffc0", "#f0ffc0" },
     { "#bde5d6", "#bde5d6" },
     { "#c0ffc0", "#c0ffc0" },
     { "#c0fff0", "#c0fff0" },
     { "#c0f0ff", "#c0f0ff" },
     { "#d0c0ff", "#d0c0ff" },
     { "#ffc0ff", "#ffc0ff" },
     { "#ffc0d0", "#ffc0d0" },
     { "#fff0c0", "#fff0c0" },
     { "#c0c0c0", "#c0c0c0" },
     { "custom",  "##"      },
  };
  int nColor = sizeof(aColor)/sizeof(aColor[0])-1;
  int stdClrFound = 0;
  int i;

  @ <table border="0" cellpadding="0" cellspacing="1">
  if( zIdPropagate ){
    @ <tr><td colspan="6" align="left">
    if( fPropagate ){
      @ <input type="checkbox" name="%s(zIdPropagate)" checked="checked" />
    }else{
      @ <input type="checkbox" name="%s(zIdPropagate)" />
    }
    @ Propagate color to descendants</td></tr>
  }
  @ <tr>
  for(i=0; i<nColor; i++){
    if( aColor[i].zColor[0] ){
      @ <td style="background-color: %h(aColor[i].zColor);">
    }else{
      @ <td>
    }
    if( strcmp(zDefaultColor, aColor[i].zColor)==0 ){
      @ <input type="radio" name="%s(zId)" value="%h(aColor[i].zColor)"
      @  checked="checked" />
      stdClrFound=1;
    }else{
      @ <input type="radio" name="%s(zId)" value="%h(aColor[i].zColor)" />
    }
    @ %h(aColor[i].zCName)</td>
    if( (i%6)==5 && i+1<nColor ){
      @ </tr><tr>
    }
  }
  @ </tr><tr>
  if (stdClrFound){
    @ <td colspan="6">
    @ <input type="radio" name="%s(zId)" value="%h(aColor[nColor].zColor)" />
  }else{
    @ <td style="background-color: %h(zDefaultColor);" colspan="6">
    @ <input type="radio" name="%s(zId)" value="%h(aColor[nColor].zColor)"
    @  checked="checked" />
  }
  @ %h(aColor[i].zCName)&nbsp;
  @ <input type="text" name="%s(zIdCustom)"
  @  id="%s(zIdCustom)" class="checkinUserColor"
  @  value="%h(stdClrFound?"":zDefaultColor)" />
  @ </td>
  @ </tr>
  @ </table>
}

/*
** WEBPAGE: ci_edit
** URL:  ci_edit?r=RID&c=NEWCOMMENT&u=NEWUSER
**
** Present a dialog for updating properties of a baseline:
**
................................................................................
  const char *zNewBrFlag;
  const char *zNewBranch;
  const char *zCloseFlag;
  int fPropagateColor;
  char *zUuid;
  Blob comment;
  Stmt q;





















  
  login_check_credentials();
  if( !g.okWrite ){ login_needed(); return; }
  rid = name_to_rid(P("r"));
  zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
  zComment = db_text(0, "SELECT coalesce(ecomment,comment)"
                        "  FROM event WHERE objid=%d", rid);
................................................................................
  zDate = db_text(0, "SELECT datetime(mtime)"
                     "  FROM event WHERE objid=%d", rid);
  if( zDate==0 ) fossil_redirect_home();
  zNewDate = PD("dt",zDate);
  zColor = db_text("", "SELECT bgcolor"
                        "  FROM event WHERE objid=%d", rid);
  zNewColor = PD("clr",zColor);
  if( strcmp(zNewColor,"##")==0 ){
    zNewColor = P("clrcust");
  }
  fPropagateColor = P("pclr")!=0;
  zNewTagFlag = P("newtag") ? " checked" : "";
  zNewTag = PD("tagname","");
  zNewBrFlag = P("newbr") ? " checked" : "";
  zNewBranch = PD("brname","");
................................................................................
  @ <tr><td align="right" valign="top"><b>Check-in Time:</b></td>
  @ <td valign="top">
  @   <input type="text" name="dt" size="20" value="%h(zNewDate)" />
  @ </td></tr>

  @ <tr><td align="right" valign="top"><b>Background Color:</b></td>
  @ <td valign="top">
  render_color_chooser(fPropagateColor, zNewColor, "pclr", "clr", "clrcust");









































  @ </td></tr>

  @ <tr><td align="right" valign="top"><b>Tags:</b></td>
  @ <td valign="top">
  @ <input type="checkbox" name="newtag"%s(zNewTagFlag) />
  @ Add the following new tag name to this check-in:
  @ <input type="text" style="width:15;" name="tagname" value="%h(zNewTag)" />

Changes to src/main.mk.

33
34
35
36
37
38
39

40
41
42
43
44
45
46
...
106
107
108
109
110
111
112

113
114
115
116
117
118
119
...
179
180
181
182
183
184
185

186
187
188
189
190
191
192
...
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
...
448
449
450
451
452
453
454







455
456
457
458
459
460
461
  $(SRCDIR)/delta.c \
  $(SRCDIR)/deltacmd.c \
  $(SRCDIR)/descendants.c \
  $(SRCDIR)/diff.c \
  $(SRCDIR)/diffcmd.c \
  $(SRCDIR)/doc.c \
  $(SRCDIR)/encode.c \

  $(SRCDIR)/file.c \
  $(SRCDIR)/finfo.c \
  $(SRCDIR)/graph.c \
  $(SRCDIR)/http.c \
  $(SRCDIR)/http_socket.c \
  $(SRCDIR)/http_ssl.c \
  $(SRCDIR)/http_transport.c \
................................................................................
  delta_.c \
  deltacmd_.c \
  descendants_.c \
  diff_.c \
  diffcmd_.c \
  doc_.c \
  encode_.c \

  file_.c \
  finfo_.c \
  graph_.c \
  http_.c \
  http_socket_.c \
  http_ssl_.c \
  http_transport_.c \
................................................................................
 $(OBJDIR)/delta.o \
 $(OBJDIR)/deltacmd.o \
 $(OBJDIR)/descendants.o \
 $(OBJDIR)/diff.o \
 $(OBJDIR)/diffcmd.o \
 $(OBJDIR)/doc.o \
 $(OBJDIR)/encode.o \

 $(OBJDIR)/file.o \
 $(OBJDIR)/finfo.o \
 $(OBJDIR)/graph.o \
 $(OBJDIR)/http.o \
 $(OBJDIR)/http_socket.o \
 $(OBJDIR)/http_ssl.o \
 $(OBJDIR)/http_transport.o \
................................................................................
#
$(SRCDIR)/../manifest:	
	# noop

clean:	
	rm -f $(OBJDIR)/*.o *_.c $(APPNAME) VERSION.h
	rm -f translate makeheaders mkindex page_index.h headers
	rm -f add.h allrepo.h attach.h bag.h blob.h branch.h browse.h captcha.h cgi.h checkin.h checkout.h clearsign.h clone.h comformat.h configure.h content.h db.h delta.h deltacmd.h descendants.h diff.h diffcmd.h doc.h encode.h file.h finfo.h graph.h http.h http_socket.h http_ssl.h http_transport.h info.h login.h main.h manifest.h md5.h merge.h merge3.h name.h pivot.h popen.h pqueue.h printf.h rebuild.h report.h rss.h schema.h search.h setup.h sha1.h shun.h skins.h stat.h style.h sync.h tag.h th_main.h timeline.h tkt.h tktsetup.h undo.h update.h url.h user.h verify.h vfile.h wiki.h wikiformat.h winhttp.h xfer.h zip.h

page_index.h: $(TRANS_SRC) mkindex
	./mkindex $(TRANS_SRC) >$@
headers:	page_index.h makeheaders VERSION.h
	./makeheaders  add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h file_.c:file.h finfo_.c:finfo.h graph_.c:graph.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h VERSION.h
	touch headers
headers: Makefile
Makefile:
add_.c:	$(SRCDIR)/add.c translate
	./translate $(SRCDIR)/add.c >add_.c

$(OBJDIR)/add.o:	add_.c add.h  $(SRCDIR)/config.h
................................................................................
encode_.c:	$(SRCDIR)/encode.c translate
	./translate $(SRCDIR)/encode.c >encode_.c

$(OBJDIR)/encode.o:	encode_.c encode.h  $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/encode.o -c encode_.c

encode.h:	headers







file_.c:	$(SRCDIR)/file.c translate
	./translate $(SRCDIR)/file.c >file_.c

$(OBJDIR)/file.o:	file_.c file.h  $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/file.o -c file_.c

file.h:	headers







>







 







>







 







>







 







|




|







 







>
>
>
>
>
>
>







33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
...
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
...
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
...
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
...
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
  $(SRCDIR)/delta.c \
  $(SRCDIR)/deltacmd.c \
  $(SRCDIR)/descendants.c \
  $(SRCDIR)/diff.c \
  $(SRCDIR)/diffcmd.c \
  $(SRCDIR)/doc.c \
  $(SRCDIR)/encode.c \
  $(SRCDIR)/event.c \
  $(SRCDIR)/file.c \
  $(SRCDIR)/finfo.c \
  $(SRCDIR)/graph.c \
  $(SRCDIR)/http.c \
  $(SRCDIR)/http_socket.c \
  $(SRCDIR)/http_ssl.c \
  $(SRCDIR)/http_transport.c \
................................................................................
  delta_.c \
  deltacmd_.c \
  descendants_.c \
  diff_.c \
  diffcmd_.c \
  doc_.c \
  encode_.c \
  event_.c \
  file_.c \
  finfo_.c \
  graph_.c \
  http_.c \
  http_socket_.c \
  http_ssl_.c \
  http_transport_.c \
................................................................................
 $(OBJDIR)/delta.o \
 $(OBJDIR)/deltacmd.o \
 $(OBJDIR)/descendants.o \
 $(OBJDIR)/diff.o \
 $(OBJDIR)/diffcmd.o \
 $(OBJDIR)/doc.o \
 $(OBJDIR)/encode.o \
 $(OBJDIR)/event.o \
 $(OBJDIR)/file.o \
 $(OBJDIR)/finfo.o \
 $(OBJDIR)/graph.o \
 $(OBJDIR)/http.o \
 $(OBJDIR)/http_socket.o \
 $(OBJDIR)/http_ssl.o \
 $(OBJDIR)/http_transport.o \
................................................................................
#
$(SRCDIR)/../manifest:	
	# noop

clean:	
	rm -f $(OBJDIR)/*.o *_.c $(APPNAME) VERSION.h
	rm -f translate makeheaders mkindex page_index.h headers
	rm -f add.h allrepo.h attach.h bag.h blob.h branch.h browse.h captcha.h cgi.h checkin.h checkout.h clearsign.h clone.h comformat.h configure.h content.h db.h delta.h deltacmd.h descendants.h diff.h diffcmd.h doc.h encode.h event.h file.h finfo.h graph.h http.h http_socket.h http_ssl.h http_transport.h info.h login.h main.h manifest.h md5.h merge.h merge3.h name.h pivot.h popen.h pqueue.h printf.h rebuild.h report.h rss.h schema.h search.h setup.h sha1.h shun.h skins.h stat.h style.h sync.h tag.h th_main.h timeline.h tkt.h tktsetup.h undo.h update.h url.h user.h verify.h vfile.h wiki.h wikiformat.h winhttp.h xfer.h zip.h

page_index.h: $(TRANS_SRC) mkindex
	./mkindex $(TRANS_SRC) >$@
headers:	page_index.h makeheaders VERSION.h
	./makeheaders  add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h file_.c:file.h finfo_.c:finfo.h graph_.c:graph.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h VERSION.h
	touch headers
headers: Makefile
Makefile:
add_.c:	$(SRCDIR)/add.c translate
	./translate $(SRCDIR)/add.c >add_.c

$(OBJDIR)/add.o:	add_.c add.h  $(SRCDIR)/config.h
................................................................................
encode_.c:	$(SRCDIR)/encode.c translate
	./translate $(SRCDIR)/encode.c >encode_.c

$(OBJDIR)/encode.o:	encode_.c encode.h  $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/encode.o -c encode_.c

encode.h:	headers
event_.c:	$(SRCDIR)/event.c translate
	./translate $(SRCDIR)/event.c >event_.c

$(OBJDIR)/event.o:	event_.c event.h  $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/event.o -c event_.c

event.h:	headers
file_.c:	$(SRCDIR)/file.c translate
	./translate $(SRCDIR)/file.c >file_.c

$(OBJDIR)/file.o:	file_.c file.h  $(SRCDIR)/config.h
	$(XTCC) -o $(OBJDIR)/file.o -c file_.c

file.h:	headers

Changes to src/makemake.tcl.

27
28
29
30
31
32
33

34
35
36
37
38
39
40
  delta
  deltacmd
  descendants
  diff
  diffcmd
  doc
  encode

  file
  finfo
  graph
  http
  http_socket
  http_transport
  info







>







27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
  delta
  deltacmd
  descendants
  diff
  diffcmd
  doc
  encode
  event
  file
  finfo
  graph
  http
  http_socket
  http_transport
  info

Changes to src/manifest.c.

30
31
32
33
34
35
36

37
38
39
40
41
42
43
44
45
46
47
48
49


50
51
52
53
54
55
56
...
228
229
230
231
232
233
234

























235
236
237
238
239
240
241
...
561
562
563
564
565
566
567
568
569
570
571
572

573
574
575
576
577
578
579
580
581
582
583
584
585

586
587
588
589
590
591
592

593
594
595
596
597
598
599













600
601
602
603
604
605
606
607
608
...
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
...
962
963
964
965
966
967
968


969
970
971
972
973
974
975
....
1041
1042
1043
1044
1045
1046
1047
1048



1049
1050
1051
1052
1053
1054
1055
....
1107
1108
1109
1110
1111
1112
1113













































1114
1115
1116
1117
1118
1119
1120
*/
#define CFTYPE_MANIFEST   1
#define CFTYPE_CLUSTER    2
#define CFTYPE_CONTROL    3
#define CFTYPE_WIKI       4
#define CFTYPE_TICKET     5
#define CFTYPE_ATTACHMENT 6


/*
** A parsed manifest or cluster.
*/
struct Manifest {
  Blob content;         /* The original content blob */
  int type;             /* Type of artifact.  One of CFTYPE_xxxxx */
  char *zComment;       /* Decoded comment.  The C card. */
  double rDate;         /* Date and time from D card.  0.0 if no D card. */
  char *zUser;          /* Name of the user from the U card. */
  char *zRepoCksum;     /* MD5 checksum of the baseline content.  R card. */
  char *zWiki;          /* Text of the wiki page.  W card. */
  char *zWikiTitle;     /* Name of the wiki page. L card. */


  char *zTicketUuid;    /* UUID for a ticket. K card. */
  char *zAttachName;    /* Filename of an attachment. A card. */
  char *zAttachSrc;     /* UUID of document being attached. A card. */
  char *zAttachTarget;  /* Ticket or wiki that attachment applies to.  A card */
  int nFile;            /* Number of F cards */
  int nFileAlloc;       /* Slots allocated in aFile[] */
  struct { 
................................................................................
        if( p->rDate!=0.0 ) goto manifest_syntax_error;
        if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error;
        if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error;
        zDate = blob_terminate(&a1);
        p->rDate = db_double(0.0, "SELECT julianday(%Q)", zDate);
        break;
      }


























      /*
      **     F <filename> <uuid> ?<permissions>? ?<old-name>?
      **
      ** Identifies a file in a manifest.  Multiple F lines are
      ** allowed in a manifest.  F lines are not allowed in any
      ** other control file.  The filename and old-name are fossil-encoded.
................................................................................
      }
    }
  }
  if( !seenHeader ) goto manifest_syntax_error;

  if( p->nFile>0 || p->zRepoCksum!=0 ){
    if( p->nCChild>0 ) goto manifest_syntax_error;
    if( p->rDate==0.0 ) goto manifest_syntax_error;
    if( p->nField>0 ) goto manifest_syntax_error;
    if( p->zTicketUuid ) goto manifest_syntax_error;
    if( p->zWiki ) goto manifest_syntax_error;
    if( p->zWikiTitle ) goto manifest_syntax_error;

    if( p->zTicketUuid ) goto manifest_syntax_error;
    if( p->zAttachName ) goto manifest_syntax_error;
    p->type = CFTYPE_MANIFEST;
  }else if( p->nCChild>0 ){
    if( p->rDate>0.0 ) goto manifest_syntax_error;
    if( p->zComment!=0 ) goto manifest_syntax_error;
    if( p->zUser!=0 ) goto manifest_syntax_error;
    if( p->nTag>0 ) goto manifest_syntax_error;
    if( p->nParent>0 ) goto manifest_syntax_error;
    if( p->nField>0 ) goto manifest_syntax_error;
    if( p->zTicketUuid ) goto manifest_syntax_error;
    if( p->zWiki ) goto manifest_syntax_error;
    if( p->zWikiTitle ) goto manifest_syntax_error;

    if( p->zAttachName ) goto manifest_syntax_error;
    if( !seenZ ) goto manifest_syntax_error;
    p->type = CFTYPE_CLUSTER;
  }else if( p->nField>0 ){
    if( p->rDate==0.0 ) goto manifest_syntax_error;
    if( p->zWiki ) goto manifest_syntax_error;
    if( p->zWikiTitle ) goto manifest_syntax_error;

    if( p->nCChild>0 ) goto manifest_syntax_error;
    if( p->nTag>0 ) goto manifest_syntax_error;
    if( p->zTicketUuid==0 ) goto manifest_syntax_error;
    if( p->zUser==0 ) goto manifest_syntax_error;
    if( p->zAttachName ) goto manifest_syntax_error;
    if( !seenZ ) goto manifest_syntax_error;
    p->type = CFTYPE_TICKET;













  }else if( p->zWiki!=0 ){
    if( p->rDate==0.0 ) goto manifest_syntax_error;
    if( p->nCChild>0 ) goto manifest_syntax_error;
    if( p->nTag>0 ) goto manifest_syntax_error;
    if( p->zTicketUuid!=0 ) goto manifest_syntax_error;
    if( p->zWikiTitle==0 ) goto manifest_syntax_error;
    if( p->zAttachName ) goto manifest_syntax_error;
    if( !seenZ ) goto manifest_syntax_error;
    p->type = CFTYPE_WIKI;
................................................................................
    if( p->zWikiTitle ) goto manifest_syntax_error;
    if( p->zTicketUuid ) goto manifest_syntax_error;
    if( p->zAttachName ) goto manifest_syntax_error;
    if( !seenZ ) goto manifest_syntax_error;
    p->type = CFTYPE_CONTROL;
  }else if( p->zAttachName ){
    if( p->nCChild>0 ) goto manifest_syntax_error;
    if( p->rDate==0.0 ) goto manifest_syntax_error;
    if( p->zTicketUuid ) goto manifest_syntax_error;
    if( p->zWikiTitle ) goto manifest_syntax_error;
    if( !seenZ ) goto manifest_syntax_error;
    p->type = CFTYPE_ATTACHMENT;
  }else{
    if( p->nCChild>0 ) goto manifest_syntax_error;
    if( p->rDate<=0.0 ) goto manifest_syntax_error;
    if( p->nParent>0 ) goto manifest_syntax_error;
    if( p->nField>0 ) goto manifest_syntax_error;
    if( p->zTicketUuid ) goto manifest_syntax_error;
    if( p->zWiki ) goto manifest_syntax_error;
    if( p->zWikiTitle ) goto manifest_syntax_error;
    if( p->zTicketUuid ) goto manifest_syntax_error;
    if( p->zAttachName ) goto manifest_syntax_error;
    p->type = CFTYPE_MANIFEST;
  }
  md5sum_init();
  return 1;

manifest_syntax_error:
  /*fprintf(stderr, "Manifest error on line %i\n", lineNo);fflush(stderr);*/
................................................................................
** any key:
**
**      *  Manifest
**      *  Control
**      *  Wiki Page
**      *  Ticket Change
**      *  Cluster


**
** If the input is a control artifact, then make appropriate entries
** in the auxiliary tables of the database in order to crosslink the
** artifact.
**
** If global variable g.xlinkClusterOnly is true, then ignore all 
** control artifacts other than clusters.
................................................................................
      int mid;
      mid = uuid_to_rid(m.azCChild[i], 1);
      if( mid>0 ){
        db_multi_exec("DELETE FROM unclustered WHERE rid=%d", mid);
      }
    }
  }
  if( m.type==CFTYPE_CONTROL || m.type==CFTYPE_MANIFEST ){



    for(i=0; i<m.nTag; i++){
      int tid;
      int type;
      if( m.aTag[i].zUuid ){
        tid = uuid_to_rid(m.aTag[i].zUuid, 1);
      }else{
        tid = rid;
................................................................................
      m.rDate, rid, m.zUser, zComment, 
      TAG_BGCOLOR, rid,
      TAG_BGCOLOR, rid,
      TAG_USER, rid,
      TAG_COMMENT, rid
    );
    free(zComment);













































  }
  if( m.type==CFTYPE_TICKET ){
    char *zTag;

    assert( manifest_crosslink_busy==1 );
    zTag = mprintf("tkt-%s", m.zTicketUuid);
    tag_insert(zTag, 1, 0, rid, m.rDate, rid);







>













>
>







 







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







 







|




>













>




|


>







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

|







 







|










<


<







 







>
>







 







|
>
>
>







 







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







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
...
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
...
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
...
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673

674
675

676
677
678
679
680
681
682
....
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
....
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
....
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
*/
#define CFTYPE_MANIFEST   1
#define CFTYPE_CLUSTER    2
#define CFTYPE_CONTROL    3
#define CFTYPE_WIKI       4
#define CFTYPE_TICKET     5
#define CFTYPE_ATTACHMENT 6
#define CFTYPE_EVENT      7

/*
** A parsed manifest or cluster.
*/
struct Manifest {
  Blob content;         /* The original content blob */
  int type;             /* Type of artifact.  One of CFTYPE_xxxxx */
  char *zComment;       /* Decoded comment.  The C card. */
  double rDate;         /* Date and time from D card.  0.0 if no D card. */
  char *zUser;          /* Name of the user from the U card. */
  char *zRepoCksum;     /* MD5 checksum of the baseline content.  R card. */
  char *zWiki;          /* Text of the wiki page.  W card. */
  char *zWikiTitle;     /* Name of the wiki page. L card. */
  double rEventDate;    /* Date of an event.  E card. */
  char *zEventId;       /* UUID for an event.  E card. */
  char *zTicketUuid;    /* UUID for a ticket. K card. */
  char *zAttachName;    /* Filename of an attachment. A card. */
  char *zAttachSrc;     /* UUID of document being attached. A card. */
  char *zAttachTarget;  /* Ticket or wiki that attachment applies to.  A card */
  int nFile;            /* Number of F cards */
  int nFileAlloc;       /* Slots allocated in aFile[] */
  struct { 
................................................................................
        if( p->rDate!=0.0 ) goto manifest_syntax_error;
        if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error;
        if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error;
        zDate = blob_terminate(&a1);
        p->rDate = db_double(0.0, "SELECT julianday(%Q)", zDate);
        break;
      }

      /*
      **     E <timestamp> <uuid>
      **
      ** An "event" card that contains the timestamp of the event in the 
      ** format YYYY-MM-DDtHH:MM:SS and a unique identifier for the event.
      ** The event timestamp is distinct from the D timestamp.  The D
      ** timestamp is when the artifact was created whereas the E timestamp
      ** is when the specific event is said to occur.
      */
      case 'E': {
        char *zEDate;
        md5sum_step_text(blob_buffer(&line), blob_size(&line));
        if( p->rEventDate!=0.0 ) goto manifest_syntax_error;
        if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error;
        if( blob_token(&line, &a2)==0 ) goto manifest_syntax_error;
        if( blob_token(&line, &a3)!=0 ) goto manifest_syntax_error;
        zEDate = blob_terminate(&a1);
        p->rEventDate = db_double(0.0, "SELECT julianday(%Q)", zEDate);
        if( p->rEventDate<=0.0 ) goto manifest_syntax_error;
        if( blob_size(&a2)!=UUID_SIZE ) goto manifest_syntax_error;
        p->zEventId = blob_terminate(&a2);
        if( !validate16(p->zEventId, UUID_SIZE) ) goto manifest_syntax_error;
        break;
      }

      /*
      **     F <filename> <uuid> ?<permissions>? ?<old-name>?
      **
      ** Identifies a file in a manifest.  Multiple F lines are
      ** allowed in a manifest.  F lines are not allowed in any
      ** other control file.  The filename and old-name are fossil-encoded.
................................................................................
      }
    }
  }
  if( !seenHeader ) goto manifest_syntax_error;

  if( p->nFile>0 || p->zRepoCksum!=0 ){
    if( p->nCChild>0 ) goto manifest_syntax_error;
    if( p->rDate<=0.0 ) goto manifest_syntax_error;
    if( p->nField>0 ) goto manifest_syntax_error;
    if( p->zTicketUuid ) goto manifest_syntax_error;
    if( p->zWiki ) goto manifest_syntax_error;
    if( p->zWikiTitle ) goto manifest_syntax_error;
    if( p->zEventId ) goto manifest_syntax_error;
    if( p->zTicketUuid ) goto manifest_syntax_error;
    if( p->zAttachName ) goto manifest_syntax_error;
    p->type = CFTYPE_MANIFEST;
  }else if( p->nCChild>0 ){
    if( p->rDate>0.0 ) goto manifest_syntax_error;
    if( p->zComment!=0 ) goto manifest_syntax_error;
    if( p->zUser!=0 ) goto manifest_syntax_error;
    if( p->nTag>0 ) goto manifest_syntax_error;
    if( p->nParent>0 ) goto manifest_syntax_error;
    if( p->nField>0 ) goto manifest_syntax_error;
    if( p->zTicketUuid ) goto manifest_syntax_error;
    if( p->zWiki ) goto manifest_syntax_error;
    if( p->zWikiTitle ) goto manifest_syntax_error;
    if( p->zEventId ) goto manifest_syntax_error;
    if( p->zAttachName ) goto manifest_syntax_error;
    if( !seenZ ) goto manifest_syntax_error;
    p->type = CFTYPE_CLUSTER;
  }else if( p->nField>0 ){
    if( p->rDate<=0.0 ) goto manifest_syntax_error;
    if( p->zWiki ) goto manifest_syntax_error;
    if( p->zWikiTitle ) goto manifest_syntax_error;
    if( p->zEventId ) goto manifest_syntax_error;
    if( p->nCChild>0 ) goto manifest_syntax_error;
    if( p->nTag>0 ) goto manifest_syntax_error;
    if( p->zTicketUuid==0 ) goto manifest_syntax_error;
    if( p->zUser==0 ) goto manifest_syntax_error;
    if( p->zAttachName ) goto manifest_syntax_error;
    if( !seenZ ) goto manifest_syntax_error;
    p->type = CFTYPE_TICKET;
  }else if( p->zEventId ){
    if( p->rDate<=0.0 ) goto manifest_syntax_error;
    if( p->nCChild>0 ) goto manifest_syntax_error;
    if( p->zTicketUuid!=0 ) goto manifest_syntax_error;
    if( p->zWikiTitle!=0 ) goto manifest_syntax_error;
    if( p->zWiki==0 ) goto manifest_syntax_error;
    if( p->zAttachName ) goto manifest_syntax_error;
    for(i=0; i<p->nTag; i++){
      if( p->aTag[i].zName[0]!='+' ) goto manifest_syntax_error;
      if( p->aTag[i].zUuid!=0 ) goto manifest_syntax_error;
    }
    if( !seenZ ) goto manifest_syntax_error;
    p->type = CFTYPE_EVENT;
  }else if( p->zWiki!=0 ){
    if( p->rDate<=0.0 ) goto manifest_syntax_error;
    if( p->nCChild>0 ) goto manifest_syntax_error;
    if( p->nTag>0 ) goto manifest_syntax_error;
    if( p->zTicketUuid!=0 ) goto manifest_syntax_error;
    if( p->zWikiTitle==0 ) goto manifest_syntax_error;
    if( p->zAttachName ) goto manifest_syntax_error;
    if( !seenZ ) goto manifest_syntax_error;
    p->type = CFTYPE_WIKI;
................................................................................
    if( p->zWikiTitle ) goto manifest_syntax_error;
    if( p->zTicketUuid ) goto manifest_syntax_error;
    if( p->zAttachName ) goto manifest_syntax_error;
    if( !seenZ ) goto manifest_syntax_error;
    p->type = CFTYPE_CONTROL;
  }else if( p->zAttachName ){
    if( p->nCChild>0 ) goto manifest_syntax_error;
    if( p->rDate<=0.0 ) goto manifest_syntax_error;
    if( p->zTicketUuid ) goto manifest_syntax_error;
    if( p->zWikiTitle ) goto manifest_syntax_error;
    if( !seenZ ) goto manifest_syntax_error;
    p->type = CFTYPE_ATTACHMENT;
  }else{
    if( p->nCChild>0 ) goto manifest_syntax_error;
    if( p->rDate<=0.0 ) goto manifest_syntax_error;
    if( p->nParent>0 ) goto manifest_syntax_error;
    if( p->nField>0 ) goto manifest_syntax_error;
    if( p->zTicketUuid ) goto manifest_syntax_error;

    if( p->zWikiTitle ) goto manifest_syntax_error;
    if( p->zTicketUuid ) goto manifest_syntax_error;

    p->type = CFTYPE_MANIFEST;
  }
  md5sum_init();
  return 1;

manifest_syntax_error:
  /*fprintf(stderr, "Manifest error on line %i\n", lineNo);fflush(stderr);*/
................................................................................
** any key:
**
**      *  Manifest
**      *  Control
**      *  Wiki Page
**      *  Ticket Change
**      *  Cluster
**      *  Attachment
**      *  Event
**
** If the input is a control artifact, then make appropriate entries
** in the auxiliary tables of the database in order to crosslink the
** artifact.
**
** If global variable g.xlinkClusterOnly is true, then ignore all 
** control artifacts other than clusters.
................................................................................
      int mid;
      mid = uuid_to_rid(m.azCChild[i], 1);
      if( mid>0 ){
        db_multi_exec("DELETE FROM unclustered WHERE rid=%d", mid);
      }
    }
  }
  if( m.type==CFTYPE_CONTROL
   || m.type==CFTYPE_MANIFEST
   || m.type==CFTYPE_EVENT
  ){
    for(i=0; i<m.nTag; i++){
      int tid;
      int type;
      if( m.aTag[i].zUuid ){
        tid = uuid_to_rid(m.aTag[i].zUuid, 1);
      }else{
        tid = rid;
................................................................................
      m.rDate, rid, m.zUser, zComment, 
      TAG_BGCOLOR, rid,
      TAG_BGCOLOR, rid,
      TAG_USER, rid,
      TAG_COMMENT, rid
    );
    free(zComment);
  }
  if( m.type==CFTYPE_EVENT ){
    char *zTag = mprintf("event-%s", m.zEventId);
    int tagid = tag_findid(zTag, 1);
    int prior, subsequent;
    int nWiki;
    char zLength[40];
    while( isspace(m.zWiki[0]) ) m.zWiki++;
    nWiki = strlen(m.zWiki);
    sqlite3_snprintf(sizeof(zLength), zLength, "%d", nWiki);
    tag_insert(zTag, 1, zLength, rid, m.rDate, rid);
    free(zTag);
    prior = db_int(0,
      "SELECT rid FROM tagxref"
      " WHERE tagid=%d AND mtime<%.17g"
      " ORDER BY mtime DESC",
      tagid, m.rDate
    );
    if( prior ){
      content_deltify(prior, rid, 0);
      db_multi_exec(
        "DELETE FROM event"
        " WHERE type='e'"
        "   AND tagid=%d"
        "   AND objid IN (SELECT rid FROM tagxref WHERE tagid=%d)",
        tagid, tagid
      );
    }
    subsequent = db_int(0,
      "SELECT rid FROM tagxref"
      " WHERE tagid=%d AND mtime>%.17g"
      " ORDER BY mtime",
      tagid, m.rDate
    );
    if( subsequent ){
      content_deltify(rid, subsequent, 0);
    }else{
      db_multi_exec(
        "REPLACE INTO event(type,mtime,objid,tagid,user,comment,bgcolor)"
        "VALUES('e',%.17g,%d,%d,%Q,%Q,"
        "  (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d));",
        m.rEventDate, rid, tagid, m.zUser, m.zComment, 
        TAG_BGCOLOR, rid
      );
    }
  }
  if( m.type==CFTYPE_TICKET ){
    char *zTag;

    assert( manifest_crosslink_busy==1 );
    zTag = mprintf("tkt-%s", m.zTicketUuid);
    tag_insert(zTag, 1, 0, rid, m.rDate, rid);

Changes to src/printf.c.

42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
                          NULL pointers replaced by SQL NULL.  %Q */
#define etPOINTER    15 /* The %p conversion */
#define etHTMLIZE    16 /* Make text safe for HTML */
#define etHTTPIZE    17 /* Make text safe for HTTP.  "/" encoded as %2f */
#define etURLIZE     18 /* Make text safe for HTTP.  "/" not encoded */
#define etFOSSILIZE  19 /* The fossil header encoding format. */
#define etPATH       20 /* Path type */
#define etWIKISTR    21 /* Wiki text rendered from a char* */
#define etWIKIBLOB   22 /* Wiki text rendered from a Blob* */
#define etSTRINGID   23 /* String with length limit for a UUID prefix */


/*
** An "etByte" is an 8-bit unsigned value.
*/
typedef unsigned char etByte;








|
|
|







42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
                          NULL pointers replaced by SQL NULL.  %Q */
#define etPOINTER    15 /* The %p conversion */
#define etHTMLIZE    16 /* Make text safe for HTML */
#define etHTTPIZE    17 /* Make text safe for HTTP.  "/" encoded as %2f */
#define etURLIZE     18 /* Make text safe for HTTP.  "/" not encoded */
#define etFOSSILIZE  19 /* The fossil header encoding format. */
#define etPATH       20 /* Path type */
#define etWIKISTR    21 /* Wiki text rendered from a char*: %w */
#define etWIKIBLOB   22 /* Wiki text rendered from a Blob*: %W */
#define etSTRINGID   23 /* String with length limit for a UUID prefix: %S */


/*
** An "etByte" is an 8-bit unsigned value.
*/
typedef unsigned char etByte;

Changes to src/rebuild.c.

119
120
121
122
123
124
125


126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167

168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184

185
186







187
188
189
190
191

192
193
194
195
196
197
198
static void rebuild_step(int rid, int size, Blob *pBase){
  static Stmt q1;
  Bag children;
  Blob copy;
  Blob *pUse;
  int nChild, i, cid;



  /* Fix up the "blob.size" field if needed. */
  if( size!=blob_size(pBase) ){
    db_multi_exec(
       "UPDATE blob SET size=%d WHERE rid=%d", blob_size(pBase), rid
    );
  }

  /* Find all children of artifact rid */
  db_static_prepare(&q1, "SELECT rid FROM delta WHERE srcid=:rid");
  db_bind_int(&q1, ":rid", rid);
  bag_init(&children);
  while( db_step(&q1)==SQLITE_ROW ){
    int cid = db_column_int(&q1, 0);
    if( !bag_find(&bagDone, cid) ){
      bag_insert(&children, cid);
    }
  }
  nChild = bag_count(&children);
  db_reset(&q1);

  /* Crosslink the artifact */
  if( nChild==0 ){
    pUse = pBase;
  }else{
    blob_copy(&copy, pBase);
    pUse = &copy;
  }
  if( zFNameFormat==0 ){
    /* We are doing "fossil rebuild" */
    manifest_crosslink(rid, pUse);
  }else{
    /* We are doing "fossil deconstruct" */
    char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
    char *zFile = mprintf(zFNameFormat, zUuid, zUuid+prefixLength);
    blob_write_to_file(pUse,zFile);
    free(zFile);
    free(zUuid);
  }
  blob_reset(pUse);
  rebuild_step_done(rid);

  /* Call all children recursively */

  for(cid=bag_first(&children), i=1; cid; cid=bag_next(&children, cid), i++){
    Stmt q2;
    int sz;
    if( nChild==i ){
      pUse = pBase;
    }else{
      blob_copy(&copy, pBase);
      pUse = &copy;
    }
    db_prepare(&q2, "SELECT content, size FROM blob WHERE rid=%d", cid);
    if( db_step(&q2)==SQLITE_ROW && (sz = db_column_int(&q2,1))>=0 ){
      Blob delta;
      db_ephemeral_blob(&q2, 0, &delta);
      blob_uncompress(&delta, &delta);
      blob_delta_apply(pUse, &delta, pUse);
      blob_reset(&delta);
      db_finalize(&q2);

      rebuild_step(cid, sz, pUse);
    }else{







      db_finalize(&q2);
      blob_reset(pUse);
    }
  }
  bag_clear(&children);

}

/*
** Check to see if the "sym-trunk" tag exists.  If not, create it
** and attach it to the very first check-in.
*/
static void rebuild_tag_trunk(void){







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







119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173






174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
static void rebuild_step(int rid, int size, Blob *pBase){
  static Stmt q1;
  Bag children;
  Blob copy;
  Blob *pUse;
  int nChild, i, cid;

  while( rid>0 ){

    /* Fix up the "blob.size" field if needed. */
    if( size!=blob_size(pBase) ){
      db_multi_exec(
         "UPDATE blob SET size=%d WHERE rid=%d", blob_size(pBase), rid
      );
    }
  
    /* Find all children of artifact rid */
    db_static_prepare(&q1, "SELECT rid FROM delta WHERE srcid=:rid");
    db_bind_int(&q1, ":rid", rid);
    bag_init(&children);
    while( db_step(&q1)==SQLITE_ROW ){
      int cid = db_column_int(&q1, 0);
      if( !bag_find(&bagDone, cid) ){
        bag_insert(&children, cid);
      }
    }
    nChild = bag_count(&children);
    db_reset(&q1);
  
    /* Crosslink the artifact */
    if( nChild==0 ){
      pUse = pBase;
    }else{
      blob_copy(&copy, pBase);
      pUse = &copy;
    }
    if( zFNameFormat==0 ){
      /* We are doing "fossil rebuild" */
      manifest_crosslink(rid, pUse);
    }else{
      /* We are doing "fossil deconstruct" */
      char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
      char *zFile = mprintf(zFNameFormat, zUuid, zUuid+prefixLength);
      blob_write_to_file(pUse,zFile);
      free(zFile);
      free(zUuid);
    }
    blob_reset(pUse);
    rebuild_step_done(rid);
  
    /* Call all children recursively */
    rid = 0;
    for(cid=bag_first(&children), i=1; cid; cid=bag_next(&children, cid), i++){
      Stmt q2;
      int sz;






      db_prepare(&q2, "SELECT content, size FROM blob WHERE rid=%d", cid);
      if( db_step(&q2)==SQLITE_ROW && (sz = db_column_int(&q2,1))>=0 ){
        Blob delta, next;
        db_ephemeral_blob(&q2, 0, &delta);
        blob_uncompress(&delta, &delta);
        blob_delta_apply(pBase, &delta, &next);
        blob_reset(&delta);
        db_finalize(&q2);
        if( i<nChild ){
          rebuild_step(cid, sz, &next);
        }else{
          /* Tail recursion */
          rid = cid;
          size = sz;
          blob_reset(pBase);
          *pBase = next;
        }
      }else{
        db_finalize(&q2);
        blob_reset(pBase);
      }
    }
    bag_clear(&children);
  }
}

/*
** Check to see if the "sym-trunk" tag exists.  If not, create it
** and attach it to the very first check-in.
*/
static void rebuild_tag_trunk(void){

Changes to src/sqlite3.c.

648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
.....
10568
10569
10570
10571
10572
10573
10574
10575
10576
10577
10578
10579
10580
10581
10582
.....
10888
10889
10890
10891
10892
10893
10894
10895
10896
10897
10898
10899
10900
10901
10902
10903
10904
.....
10936
10937
10938
10939
10940
10941
10942
10943
10944
10945
10946
10947
10948
10949
10950
.....
12635
12636
12637
12638
12639
12640
12641
12642
12643
12644
12645
12646
12647
12648
12649
12650
12651
12652
12653
12654
.....
12842
12843
12844
12845
12846
12847
12848
12849
12850
12851
12852
12853
12854
12855
12856
12857
12858
12859
12860
12861
12862
12863
12864
12865
12866
.....
13073
13074
13075
13076
13077
13078
13079
13080

13081
13082
13083
13084
13085
13086
13087
13088
.....
13129
13130
13131
13132
13133
13134
13135
13136
13137



13138
13139
13140
13141
13142
13143
13144
.....
17500
17501
17502
17503
17504
17505
17506
17507
17508
17509
17510
17511
17512
17513
17514
.....
20094
20095
20096
20097
20098
20099
20100
20101
20102
20103
20104

20105
20106
20107
20108
20109
20110
20111



20112


20113
20114
20115
20116
20117
20118
20119
20120
20121
20122
20123
20124
20125
20126
20127
20128
20129
20130
20131
20132
20133
20134
20135
20136
20137
20138
20139
20140
20141
20142
20143
20144
20145
20146


20147
20148
20149
20150
20151



20152
20153
20154

20155
20156
20157
20158
20159
20160
20161

20162
20163
20164




20165
20166


20167
20168
20169
20170
20171
20172
20173

20174
20175

20176
20177
20178
20179
20180
20181

20182
20183
20184

20185
20186
20187
20188
20189
20190
20191
20192
20193
20194
20195
20196
20197

20198
20199
20200
20201


20202
20203
20204
20205
20206
20207
20208
20209
20210
20211
20212

20213
20214
20215






20216
20217
20218
20219
20220
20221
20222
.....
20267
20268
20269
20270
20271
20272
20273
20274
20275
20276
20277
20278
20279
20280
20281
20282
20283
20284

20285
20286
20287
20288
20289
20290
20291
20292
20293
20294

20295

20296



20297
20298
20299
20300
20301
20302
20303
20304
20305
20306
20307
20308
20309




20310
20311
20312
20313
20314
20315



20316
20317

20318

20319
20320
20321


20322

20323
20324
20325
20326
20327
20328
20329
20330
20331

20332
20333

20334
20335
20336
20337
20338
20339
20340
20341
20342
20343
20344
20345
20346
20347
20348
20349
20350
20351
20352
20353
20354
20355
20356
20357
20358
20359
20360
20361
20362
20363
20364
20365
20366
20367
20368
20369
20370
20371
20372
20373
20374
20375
20376
20377
20378
20379
20380
20381
20382
20383
20384
20385
20386
20387
20388

20389
20390
20391
20392
20393
20394
20395
20396
20397
20398
20399
20400
20401
20402
.....
54147
54148
54149
54150
54151
54152
54153
54154
54155
54156
54157
54158
54159
54160
54161
54162
54163
54164
54165
54166
54167
.....
54183
54184
54185
54186
54187
54188
54189
54190
54191
54192
54193
54194
54195
54196
54197
.....
54256
54257
54258
54259
54260
54261
54262
54263
54264
54265
54266
54267
54268
54269
54270
54271
54272
54273
54274
54275
54276
54277



54278
54279
54280
54281
54282
54283
54284
.....
54813
54814
54815
54816
54817
54818
54819


54820
54821
54822
54823
54824
54825
54826
.....
54829
54830
54831
54832
54833
54834
54835











54836
54837
54838
54839
54840
54841
54842
54843
54844
54845
54846
54847
54848
54849
54850
54851
54852

54853
54854
54855
54856

54857

54858
54859
54860

54861
54862
54863
54864
54865
54866
54867
.....
59768
59769
59770
59771
59772
59773
59774
59775

59776
59777
59778
59779
59780
59781
59782
59783
59784
59785
59786
59787
59788
59789
59790

59791
59792
59793
59794
59795
59796
59797
59798
59799


59800
59801
59802
59803
59804
59805
59806
.....
61578
61579
61580
61581
61582
61583
61584
61585
61586
61587
61588
61589
61590
61591
61592
.....
61621
61622
61623
61624
61625
61626
61627
61628
61629
61630
61631
61632
61633
61634
61635
.....
61646
61647
61648
61649
61650
61651
61652
61653
61654
61655
61656
61657
61658
61659
61660
61661
61662
61663
.....
61665
61666
61667
61668
61669
61670
61671
61672
61673
61674
61675
61676
61677
61678
61679
.....
61779
61780
61781
61782
61783
61784
61785
61786
61787
61788
61789
61790
61791
61792
61793
61794
.....
62413
62414
62415
62416
62417
62418
62419
62420
62421
62422
62423
62424
62425
62426
62427
.....
62493
62494
62495
62496
62497
62498
62499
62500
62501
62502
62503
62504
62505
62506
62507
.....
68878
68879
68880
68881
68882
68883
68884
68885
68886
68887
68888
68889
68890
68891
68892
.....
70241
70242
70243
70244
70245
70246
70247
70248
70249
70250
70251
70252
70253
70254
70255
70256
70257
70258
70259
70260
70261
70262
70263
70264
70265
70266
70267
70268
70269
70270
70271
70272


70273
70274
70275
70276


70277
70278
70279
70280
70281
70282
70283
70284
70285
70286
.....
79412
79413
79414
79415
79416
79417
79418
79419
79420
79421
79422
79423
79424
79425
79426
.....
85470
85471
85472
85473
85474
85475
85476
85477
85478
85479
85480
85481
85482
85483
85484
.....
96378
96379
96380
96381
96382
96383
96384
96385

96386
96387
96388
96389
96390
96391
96392
96393
96394
96395
96396
96397
96398

96399
96400
96401
96402
96403
96404
96405
.....
96427
96428
96429
96430
96431
96432
96433
96434
96435
96436
96437
96438
96439
96440
96441
96442
96443
96444
96445
96446
96447
96448
96449
.....
96882
96883
96884
96885
96886
96887
96888
96889

96890
96891
96892
96893
96894
96895
96896
.....
97012
97013
97014
97015
97016
97017
97018
97019
97020
97021
97022
97023
97024
97025
97026
.....
97293
97294
97295
97296
97297
97298
97299
97300

97301
97302
97303
97304
97305
97306
97307
.....
97555
97556
97557
97558
97559
97560
97561
97562
97563
97564
97565
97566
97567
97568
97569
97570
97571
97572
97573
97574
97575
97576
97577
97578
97579
97580
97581
97582
97583
97584
97585
97586
97587
.....
97655
97656
97657
97658
97659
97660
97661
97662
97663
97664
97665
97666
97667
97668
97669
.....
97670
97671
97672
97673
97674
97675
97676
97677

97678
97679
97680
97681
97682
97683
97684
97685
97686
97687
97688
97689
97690
97691
97692
97693
97694
97695
97696
97697
97698
97699
.....
98900
98901
98902
98903
98904
98905
98906
98907






98908
98909
98910
98911
98912
98913
98914
98915
98916
98917
.....
98923
98924
98925
98926
98927
98928
98929
98930
98931
98932
98933
98934
98935
98936
98937
.....
98945
98946
98947
98948
98949
98950
98951
98952

98953
98954
98955
98956

98957
98958
98959
98960
98961
98962
98963
**
** See also: [sqlite3_libversion()],
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION        "3.7.3"
#define SQLITE_VERSION_NUMBER 3007003
#define SQLITE_SOURCE_ID      "2010-09-29 23:09:23 1ef0dc9328f47506cb2dcd142150e96cb4755216"

/*
** CAPI3REF: Run-Time Library Version Numbers
** KEYWORDS: sqlite3_version, sqlite3_sourceid
**
** These interfaces provide the same information as the [SQLITE_VERSION],
** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros
................................................................................
# define sqlite3Tolower(x)   tolower((unsigned char)(x))
#endif

/*
** Internal function prototypes
*/
SQLITE_PRIVATE int sqlite3StrICmp(const char *, const char *);
SQLITE_PRIVATE int sqlite3IsNumber(const char*, int*, u8);
SQLITE_PRIVATE int sqlite3Strlen30(const char*);
#define sqlite3StrNICmp sqlite3_strnicmp

SQLITE_PRIVATE int sqlite3MallocInit(void);
SQLITE_PRIVATE void sqlite3MallocEnd(void);
SQLITE_PRIVATE void *sqlite3Malloc(int);
SQLITE_PRIVATE void *sqlite3MallocZero(int);
................................................................................
SQLITE_PRIVATE void sqlite3Detach(Parse*, Expr*);
SQLITE_PRIVATE int sqlite3FixInit(DbFixer*, Parse*, int, const char*, const Token*);
SQLITE_PRIVATE int sqlite3FixSrcList(DbFixer*, SrcList*);
SQLITE_PRIVATE int sqlite3FixSelect(DbFixer*, Select*);
SQLITE_PRIVATE int sqlite3FixExpr(DbFixer*, Expr*);
SQLITE_PRIVATE int sqlite3FixExprList(DbFixer*, ExprList*);
SQLITE_PRIVATE int sqlite3FixTriggerStep(DbFixer*, TriggerStep*);
SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*);
SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*);
SQLITE_PRIVATE int sqlite3FitsIn64Bits(const char *, int);
SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nChar);
SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *pData, int nByte);
SQLITE_PRIVATE int sqlite3Utf8Read(const u8*, const u8**);

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


SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(Vdbe *, Index *);
SQLITE_PRIVATE void sqlite3TableAffinityStr(Vdbe *, Table *);
SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2);
SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity);
SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr);
SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*);
SQLITE_PRIVATE void sqlite3Error(sqlite3*, int, const char*,...);
SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n);
SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **);
SQLITE_PRIVATE const char *sqlite3ErrStr(int);
SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse);
SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int);
SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName);
................................................................................
    cnt++;
  }while( nextC );
end_getDigits:
  va_end(ap);
  return cnt;
}

/*
** Read text from z[] and convert into a floating point number.  Return
** the number of digits converted.
*/
#define getValue sqlite3AtoF

/*
** Parse a timezone extension on the end of a date-time.
** The extension is of the form:
**
**        (+/-)HH:MM
**
** Or the "zulu" notation:
................................................................................
** as there is a year and date.
*/
static int parseDateOrTime(
  sqlite3_context *context, 
  const char *zDate, 
  DateTime *p
){
  int isRealNum;    /* Return from sqlite3IsNumber().  Not used */
  if( parseYyyyMmDd(zDate,p)==0 ){
    return 0;
  }else if( parseHhMmSs(zDate, p)==0 ){
    return 0;
  }else if( sqlite3StrICmp(zDate,"now")==0){
    setDateTimeToCurrent(context, p);
    return 0;
  }else if( sqlite3IsNumber(zDate, &isRealNum, SQLITE_UTF8) ){
    double r;
    getValue(zDate, &r);
    p->iJD = (sqlite3_int64)(r*86400000.0 + 0.5);
    p->validJD = 1;
    return 0;
  }
  return 1;
}

................................................................................
      /*
      **    weekday N
      **
      ** Move the date to the same time on the next occurrence of
      ** weekday N where 0==Sunday, 1==Monday, and so forth.  If the
      ** date is already on the appropriate weekday, this is a no-op.
      */
      if( strncmp(z, "weekday ", 8)==0 && getValue(&z[8],&r)>0

                 && (n=(int)r)==r && n>=0 && r<7 ){
        sqlite3_int64 Z;
        computeYMD_HMS(p);
        p->validTZ = 0;
        p->validJD = 0;
        computeJD(p);
        Z = ((p->iJD + 129600000)/86400000) % 7;
        if( Z>n ) Z -= 7;
................................................................................
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9': {
      double rRounder;
      n = getValue(z, &r);
      assert( n>=1 );



      if( z[n]==':' ){
        /* A modifier of the form (+|-)HH:MM:SS.FFF adds (or subtracts) the
        ** specified number of hours, minutes, seconds, and fractional seconds
        ** to the time.  The ".FFF" may be omitted.  The ":SS.FFF" may be
        ** omitted.
        */
        const char *z2 = z;
................................................................................
  if( n<0 ) return priorLimit;
  if( n>0 ){
    sqlite3MemoryAlarm(softHeapLimitEnforcer, 0, n);
  }else{
    sqlite3MemoryAlarm(0, 0, 0);
  }
  excess = sqlite3_memory_used() - n;
  if( excess>0 ) sqlite3_release_memory(excess & 0x7fffffff);
  return priorLimit;
}
SQLITE_API void sqlite3_soft_heap_limit(int n){
  if( n<0 ) n = 0;
  sqlite3_soft_heap_limit64(n);
}

................................................................................
  a = (unsigned char *)zLeft;
  b = (unsigned char *)zRight;
  while( N-- > 0 && *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; }
  return N<0 ? 0 : UpperToLower[*a] - UpperToLower[*b];
}

/*
** Return TRUE if z is a pure numeric string.  Return FALSE and leave
** *realnum unchanged if the string contains any character which is not
** part of a number.
**

** If the string is pure numeric, set *realnum to TRUE if the string
** contains the '.' character or an "E+000" style exponentiation suffix.
** Otherwise set *realnum to FALSE.  Note that just becaue *realnum is
** false does not mean that the number can be successfully converted into
** an integer - it might be too big.
**
** An empty string is considered non-numeric.



*/


SQLITE_PRIVATE int sqlite3IsNumber(const char *z, int *realnum, u8 enc){
  int incr = (enc==SQLITE_UTF8?1:2);
  if( enc==SQLITE_UTF16BE ) z++;
  if( *z=='-' || *z=='+' ) z += incr;
  if( !sqlite3Isdigit(*z) ){
    return 0;
  }
  z += incr;
  *realnum = 0;
  while( sqlite3Isdigit(*z) ){ z += incr; }
#ifndef SQLITE_OMIT_FLOATING_POINT
  if( *z=='.' ){
    z += incr;
    if( !sqlite3Isdigit(*z) ) return 0;
    while( sqlite3Isdigit(*z) ){ z += incr; }
    *realnum = 1;
  }
  if( *z=='e' || *z=='E' ){
    z += incr;
    if( *z=='+' || *z=='-' ) z += incr;
    if( !sqlite3Isdigit(*z) ) return 0;
    while( sqlite3Isdigit(*z) ){ z += incr; }
    *realnum = 1;
  }
#endif
  return *z==0;
}

/*
** The string z[] is an ASCII representation of a real number.
** Convert this string to a double.
**
** This routine assumes that z[] really is a valid number.  If it
** is not, the result is undefined.


**
** This routine is used instead of the library atof() function because
** the library atof() might want to use "," as the decimal point instead
** of "." depending on how locale is set.  But that would cause problems
** for SQL.  So this routine always uses "." regardless of locale.



*/
SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult){
#ifndef SQLITE_OMIT_FLOATING_POINT

  const char *zBegin = z;
  /* sign * significand * (10 ^ (esign * exponent)) */
  int sign = 1;   /* sign of significand */
  i64 s = 0;      /* significand */
  int d = 0;      /* adjust exponent for shifting decimal point */
  int esign = 1;  /* sign of exponent */
  int e = 0;      /* exponent */

  double result;
  int nDigits = 0;





  /* skip leading spaces */
  while( sqlite3Isspace(*z) ) z++;


  /* get sign of significand */
  if( *z=='-' ){
    sign = -1;
    z++;
  }else if( *z=='+' ){
    z++;
  }

  /* skip leading zeroes */
  while( z[0]=='0' ) z++, nDigits++;


  /* copy max significant digits to significand */
  while( sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){
    s = s*10 + (*z - '0');
    z++, nDigits++;
  }

  /* skip non-significant significand digits
  ** (increase exponent by d to shift decimal left) */
  while( sqlite3Isdigit(*z) ) z++, nDigits++, d++;


  /* if decimal point is present */
  if( *z=='.' ){
    z++;
    /* copy digits from after decimal to significand
    ** (decrease exponent by d to shift decimal right) */
    while( sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){
      s = s*10 + (*z - '0');
      z++, nDigits++, d--;
    }
    /* skip non-significant digits */
    while( sqlite3Isdigit(*z) ) z++, nDigits++;
  }


  /* if exponent is present */
  if( *z=='e' || *z=='E' ){
    z++;


    /* get sign of exponent */
    if( *z=='-' ){
      esign = -1;
      z++;
    }else if( *z=='+' ){
      z++;
    }
    /* copy digits to exponent */
    while( sqlite3Isdigit(*z) ){
      e = e*10 + (*z - '0');
      z++;

    }
  }







  /* adjust exponent by d, and update sign */
  e = (e*esign) + d;
  if( e<0 ) {
    esign = -1;
    e *= -1;
  } else {
    esign = 1;
................................................................................
      result = (double)s;
    }
  }

  /* store the result */
  *pResult = result;

  /* return number of characters used */
  return (int)(z - zBegin);
#else
  return sqlite3Atoi64(z, pResult);
#endif /* SQLITE_OMIT_FLOATING_POINT */
}

/*
** Compare the 19-character string zNum against the text representation
** value 2^63:  9223372036854775808.  Return negative, zero, or positive
** if zNum is less than, equal to, or greater than the string.

**
** Unlike memcmp() this routine is guaranteed to return the difference
** in the values of the last digit if the only difference is in the
** last digit.  So, for example,
**
**      compare2pow63("9223372036854775800")
**
** will return -8.
*/
static int compare2pow63(const char *zNum){

  int c;

  c = memcmp(zNum,"922337203685477580",18)*10;



  if( c==0 ){
    c = zNum[18] - '8';
    testcase( c==(-1) );
    testcase( c==0 );
    testcase( c==(+1) );
  }
  return c;
}


/*
** Return TRUE if zNum is a 64-bit signed integer and write
** the value of the integer into *pNum.  If zNum is not an integer




** or is an integer that is too large to be expressed with 64 bits,
** then return false.
**
** When this routine was originally written it dealt with only
** 32-bit numbers.  At that time, it was much faster than the
** atoi() library routine in RedHat 7.2.



*/
SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum){

  i64 v = 0;

  int neg;
  int i, c;
  const char *zStart;


  while( sqlite3Isspace(*zNum) ) zNum++;

  if( *zNum=='-' ){
    neg = 1;
    zNum++;
  }else if( *zNum=='+' ){
    neg = 0;
    zNum++;
  }else{
    neg = 0;
  }

  zStart = zNum;
  while( zNum[0]=='0' ){ zNum++; } /* Skip over leading zeros. Ticket #2454 */

  for(i=0; (c=zNum[i])>='0' && c<='9'; i++){
    v = v*10 + c - '0';
  }
  *pNum = neg ? -v : v;
  testcase( i==18 );
  testcase( i==19 );
  testcase( i==20 );
  if( c!=0 || (i==0 && zStart==zNum) || i>19 ){
    /* zNum is empty or contains non-numeric text or is longer
    ** than 19 digits (thus guaranting that it is too large) */
    return 0;
  }else if( i<19 ){
    /* Less than 19 digits, so we know that it fits in 64 bits */
    return 1;
  }else{
    /* 19-digit numbers must be no larger than 9223372036854775807 if positive
    ** or 9223372036854775808 if negative.  Note that 9223372036854665808
    ** is 2^63. */
    return compare2pow63(zNum)<neg;
  }
}

/*
** The string zNum represents an unsigned integer.  The zNum string
** consists of one or more digit characters and is terminated by
** a zero character.  Any stray characters in zNum result in undefined
** behavior.
**
** If the unsigned integer that zNum represents will fit in a
** 64-bit signed integer, return TRUE.  Otherwise return FALSE.
**
** If the negFlag parameter is true, that means that zNum really represents
** a negative number.  (The leading "-" is omitted from zNum.)  This
** parameter is needed to determine a boundary case.  A string
** of "9223373036854775808" returns false if negFlag is false or true
** if negFlag is true.
**
** Leading zeros are ignored.
*/
SQLITE_PRIVATE int sqlite3FitsIn64Bits(const char *zNum, int negFlag){
  int i;
  int neg = 0;

  assert( zNum[0]>='0' && zNum[0]<='9' ); /* zNum is an unsigned number */

  if( negFlag ) neg = 1-neg;
  while( *zNum=='0' ){
    zNum++;   /* Skip leading zeros.  Ticket #2454 */
  }
  for(i=0; zNum[i]; i++){ assert( zNum[i]>='0' && zNum[i]<='9' ); }
  testcase( i==18 );
  testcase( i==19 );
  testcase( i==20 );
  if( i<19 ){
    /* Guaranteed to fit if less than 19 digits */

    return 1;
  }else if( i>19 ){
    /* Guaranteed to be too big if greater than 19 digits */
    return 0;
  }else{
    /* Compare against 2^63. */
    return compare2pow63(zNum)<neg;
  }
}

/*
** If zNum represents an integer that will fit in 32-bits, then set
** *pValue to that integer and return true.  Otherwise return false.
**
................................................................................
  flags = pMem->flags;
  if( flags & MEM_Int ){
    return pMem->u.i;
  }else if( flags & MEM_Real ){
    return doubleToInt64(pMem->r);
  }else if( flags & (MEM_Str|MEM_Blob) ){
    i64 value;
    pMem->flags |= MEM_Str;
    if( sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8)
       || sqlite3VdbeMemNulTerminate(pMem) ){
      return 0;
    }
    assert( pMem->z );
    sqlite3Atoi64(pMem->z, &value);
    return value;
  }else{
    return 0;
  }
}

/*
................................................................................
    pMem->flags |= MEM_Str;
    if( sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8)
       || sqlite3VdbeMemNulTerminate(pMem) ){
      /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
      return (double)0;
    }
    assert( pMem->z );
    sqlite3AtoF(pMem->z, &val);
    return val;
  }else{
    /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
    return (double)0;
  }
}

................................................................................
** Invalidate any prior representations.
**
** Every effort is made to force the conversion, even if the input
** is a string that does not look completely like a number.  Convert
** as much of the string as we can and ignore the rest.
*/
SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){
  int rc;
  assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 );
  assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 );
  assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );
  rc = sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8);
  if( rc ) return rc;
  rc = sqlite3VdbeMemNulTerminate(pMem);
  if( rc ) return rc;
  if( sqlite3Atoi64(pMem->z, &pMem->u.i) ){
    MemSetTypeFlag(pMem, MEM_Int);
  }else{
    pMem->r = sqlite3VdbeRealValue(pMem);
    MemSetTypeFlag(pMem, MEM_Real);
    sqlite3VdbeIntegerAffinity(pMem);
  }



  return SQLITE_OK;
}

/*
** Delete any previous value and set the value stored in *pMem to NULL.
*/
SQLITE_PRIVATE void sqlite3VdbeMemSetNull(Mem *pMem){
................................................................................
  u8 enc,                   /* Encoding to use */
  u8 affinity,              /* Affinity to use */
  sqlite3_value **ppVal     /* Write the new value here */
){
  int op;
  char *zVal = 0;
  sqlite3_value *pVal = 0;



  if( !pExpr ){
    *ppVal = 0;
    return SQLITE_OK;
  }
  op = pExpr->op;

................................................................................
  ** when SQLITE_ENABLE_STAT2 is omitted.
  */
#ifdef SQLITE_ENABLE_STAT2
  if( op==TK_REGISTER ) op = pExpr->op2;
#else
  if( NEVER(op==TK_REGISTER) ) op = pExpr->op2;
#endif












  if( op==TK_STRING || op==TK_FLOAT || op==TK_INTEGER ){
    pVal = sqlite3ValueNew(db);
    if( pVal==0 ) goto no_mem;
    if( ExprHasProperty(pExpr, EP_IntValue) ){
      sqlite3VdbeMemSetInt64(pVal, (i64)pExpr->u.iValue);
    }else{
      zVal = sqlite3DbStrDup(db, pExpr->u.zToken);
      if( zVal==0 ) goto no_mem;
      sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC);
      if( op==TK_FLOAT ) pVal->type = SQLITE_FLOAT;
    }
    if( (op==TK_INTEGER || op==TK_FLOAT ) && affinity==SQLITE_AFF_NONE ){
      sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, SQLITE_UTF8);
    }else{
      sqlite3ValueApplyAffinity(pVal, affinity, SQLITE_UTF8);
    }

    if( enc!=SQLITE_UTF8 ){
      sqlite3VdbeChangeEncoding(pVal, enc);
    }
  }else if( op==TK_UMINUS ) {

    if( SQLITE_OK==sqlite3ValueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal) ){

      pVal->u.i = -1 * pVal->u.i;
      /* (double)-1 In case of SQLITE_OMIT_FLOATING_POINT... */
      pVal->r = (double)-1 * pVal->r;

    }
  }
#ifndef SQLITE_OMIT_BLOB_LITERAL
  else if( op==TK_BLOB ){
    int nVal;
    assert( pExpr->u.zToken[0]=='x' || pExpr->u.zToken[0]=='X' );
    assert( pExpr->u.zToken[1]=='\'' );
................................................................................
** Try to convert a value into a numeric representation if we can
** do so without loss of information.  In other words, if the string
** looks like a number, convert it into a number.  If it does not
** look like a number, leave it alone.
*/
static void applyNumericAffinity(Mem *pRec){
  if( (pRec->flags & (MEM_Real|MEM_Int))==0 ){
    int realnum;

    u8 enc = pRec->enc;
    sqlite3VdbeMemNulTerminate(pRec);
    if( (pRec->flags&MEM_Str) && sqlite3IsNumber(pRec->z, &realnum, enc) ){
      i64 value;
      char *zUtf8 = pRec->z;
#ifndef SQLITE_OMIT_UTF16
      if( enc!=SQLITE_UTF8 ){
        assert( pRec->db );
        zUtf8 = sqlite3Utf16to8(pRec->db, pRec->z, pRec->n, enc);
        if( !zUtf8 ) return;
      }
#endif
      if( !realnum && sqlite3Atoi64(zUtf8, &value) ){
        pRec->u.i = value;
        MemSetTypeFlag(pRec, MEM_Int);

      }else{
        sqlite3AtoF(zUtf8, &pRec->r);
        MemSetTypeFlag(pRec, MEM_Real);
      }
#ifndef SQLITE_OMIT_UTF16
      if( enc!=SQLITE_UTF8 ){
        sqlite3DbFree(pRec->db, zUtf8);
      }
#endif


    }
  }
}

/*
** Processing is determine by the affinity parameter:
**
................................................................................
** This opcode is used when extracting information from a column that
** has REAL affinity.  Such column values may still be stored as
** integers, for space efficiency, but after extraction we want them
** to have only a real value.
*/
case OP_RealAffinity: {                  /* in1 */
  pIn1 = &aMem[pOp->p1];
  memAboutToChange(p, pIn1);
  if( pIn1->flags & MEM_Int ){
    sqlite3VdbeMemRealify(pIn1);
  }
  break;
}
#endif

................................................................................
** Strings are simply reinterpreted as blobs with no change
** to the underlying data.
**
** A NULL value is not changed by this routine.  It remains NULL.
*/
case OP_ToBlob: {                  /* same as TK_TO_BLOB, in1 */
  pIn1 = &aMem[pOp->p1];
  memAboutToChange(p, pIn1);
  if( pIn1->flags & MEM_Null ) break;
  if( (pIn1->flags & MEM_Blob)==0 ){
    applyAffinity(pIn1, SQLITE_AFF_TEXT, encoding);
    assert( pIn1->flags & MEM_Str || db->mallocFailed );
    MemSetTypeFlag(pIn1, MEM_Blob);
  }else{
    pIn1->flags &= ~(MEM_TypeMask&~MEM_Blob);
................................................................................
** equivalent of atoi() or atof() and store 0 if no such conversion 
** is possible.
**
** A NULL value is not changed by this routine.  It remains NULL.
*/
case OP_ToNumeric: {                  /* same as TK_TO_NUMERIC, in1 */
  pIn1 = &aMem[pOp->p1];
  memAboutToChange(p, pIn1);
  if( (pIn1->flags & (MEM_Null|MEM_Int|MEM_Real))==0 ){
    sqlite3VdbeMemNumerify(pIn1);
  }
  break;
}
#endif /* SQLITE_OMIT_CAST */

/* Opcode: ToInt P1 * * * *
**
** Force the value in register P1 to be an integer.  If
................................................................................
** If the value is text or blob, try to convert it to an integer using the
** equivalent of atoi() and store 0 if no such conversion is possible.
**
** A NULL value is not changed by this routine.  It remains NULL.
*/
case OP_ToInt: {                  /* same as TK_TO_INT, in1 */
  pIn1 = &aMem[pOp->p1];
  memAboutToChange(p, pIn1);
  if( (pIn1->flags & MEM_Null)==0 ){
    sqlite3VdbeMemIntegerify(pIn1);
  }
  break;
}

#if !defined(SQLITE_OMIT_CAST) && !defined(SQLITE_OMIT_FLOATING_POINT)
................................................................................
  char affinity;      /* Affinity to use for comparison */
  u16 flags1;         /* Copy of initial value of pIn1->flags */
  u16 flags3;         /* Copy of initial value of pIn3->flags */
#endif /* local variables moved into u.ai */

  pIn1 = &aMem[pOp->p1];
  pIn3 = &aMem[pOp->p3];
  memAboutToChange(p, pIn1);
  memAboutToChange(p, pIn3);
  u.ai.flags1 = pIn1->flags;
  u.ai.flags3 = pIn3->flags;
  if( (pIn1->flags | pIn3->flags)&MEM_Null ){
    /* One or both operands are NULL */
    if( pOp->p5 & SQLITE_NULLEQ ){
      /* If SQLITE_NULLEQ is set (which will only happen if the operator is
      ** OP_Eq or OP_Ne) then take the jump or not depending on whether
................................................................................
  u.an.zAffinity = pOp->p4.z;
  assert( u.an.zAffinity!=0 );
  assert( u.an.zAffinity[pOp->p2]==0 );
  pIn1 = &aMem[pOp->p1];
  while( (u.an.cAff = *(u.an.zAffinity++))!=0 ){
    assert( pIn1 <= &p->aMem[p->nMem] );
    assert( memIsValid(pIn1) );
    memAboutToChange(p, pIn1);
    ExpandBlob(pIn1);
    applyAffinity(pIn1, u.an.cAff, encoding);
    pIn1++;
  }
  break;
}

................................................................................

  /* Loop through the elements that will make up the record to figure
  ** out how much space is required for the new record.
  */
  for(u.ao.pRec=u.ao.pData0; u.ao.pRec<=u.ao.pLast; u.ao.pRec++){
    assert( memIsValid(u.ao.pRec) );
    if( u.ao.zAffinity ){
      memAboutToChange(p, u.ao.pRec);
      applyAffinity(u.ao.pRec, u.ao.zAffinity[u.ao.pRec-u.ao.pData0], encoding);
    }
    if( u.ao.pRec->flags&MEM_Zero && u.ao.pRec->n>0 ){
      sqlite3VdbeMemExpandBlob(u.ao.pRec);
    }
    u.ao.serial_type = sqlite3VdbeSerialType(u.ao.pRec, u.ao.file_format);
    u.ao.len = sqlite3VdbeSerialTypeLen(u.ao.serial_type);
................................................................................
    /* Wildcard of the form "?".  Assign the next variable number */
    assert( z[0]=='?' );
    pExpr->iColumn = (ynVar)(++pParse->nVar);
  }else if( z[0]=='?' ){
    /* Wildcard of the form "?nnn".  Convert "nnn" to an integer and
    ** use it as the variable number */
    i64 i;
    int bOk = sqlite3Atoi64(&z[1], &i);
    pExpr->iColumn = (ynVar)i;
    testcase( i==0 );
    testcase( i==1 );
    testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]-1 );
    testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] );
    if( bOk==0 || i<1 || i>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){
      sqlite3ErrorMsg(pParse, "variable number must be between ?1 and ?%d",
................................................................................
** z[n] character is guaranteed to be something that does not look
** like the continuation of the number.
*/
static void codeReal(Vdbe *v, const char *z, int negateFlag, int iMem){
  if( ALWAYS(z!=0) ){
    double value;
    char *zV;
    sqlite3AtoF(z, &value);
    assert( !sqlite3IsNaN(value) ); /* The new AtoF never returns NaN */
    if( negateFlag ) value = -value;
    zV = dup8bytes(v, (char*)&value);
    sqlite3VdbeAddOp4(v, OP_Real, 0, iMem, 0, zV, P4_REAL);
  }
}
#endif


/*
** Generate an instruction that will put the integer describe by
** text z[0..n-1] into register iMem.
**
** The z[] string will probably not be zero-terminated.  But the 
** z[n] character is guaranteed to be something that does not look
** like the continuation of the number.
*/
static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){
  Vdbe *v = pParse->pVdbe;
  if( pExpr->flags & EP_IntValue ){
    int i = pExpr->u.iValue;
    if( negFlag ) i = -i;
    sqlite3VdbeAddOp2(v, OP_Integer, i, iMem);
  }else{


    const char *z = pExpr->u.zToken;
    assert( z!=0 );
    if( sqlite3FitsIn64Bits(z, negFlag) ){
      i64 value;


      char *zV;
      sqlite3Atoi64(z, &value);
      if( negFlag ) value = -value;
      zV = dup8bytes(v, (char*)&value);
      sqlite3VdbeAddOp4(v, OP_Int64, 0, iMem, 0, zV, P4_INT64);
    }else{
#ifdef SQLITE_OMIT_FLOATING_POINT
      sqlite3ErrorMsg(pParse, "oversized integer: %s%s", negFlag ? "-" : "", z);
#else
      codeReal(v, z, negFlag, iMem);
................................................................................
    r = -(double)((sqlite_int64)((-r)+0.5));
  }else{
    zBuf = sqlite3_mprintf("%.*f",n,r);
    if( zBuf==0 ){
      sqlite3_result_error_nomem(context);
      return;
    }
    sqlite3AtoF(zBuf, &r);
    sqlite3_free(zBuf);
  }
  sqlite3_result_double(context, r);
}
#endif

/*
................................................................................
  **
  ** Get or set the size limit on rollback journal files.
  */
  if( sqlite3StrICmp(zLeft,"journal_size_limit")==0 ){
    Pager *pPager = sqlite3BtreePager(pDb->pBt);
    i64 iLimit = -2;
    if( zRight ){
      sqlite3Atoi64(zRight, &iLimit);
      if( iLimit<-1 ) iLimit = -1;
    }
    iLimit = sqlite3PagerJournalSizeLimit(pPager, iLimit);
    returnSingleInt(pParse, "journal_size_limit", iLimit);
  }else

#endif /* SQLITE_OMIT_PAGER_PRAGMAS */
................................................................................
#define TRACE_IDX_OUTPUTS(A)
#endif

/* 
** Required because bestIndex() is called by bestOrClauseIndex() 
*/
static void bestIndex(
    Parse*, WhereClause*, struct SrcList_item*, Bitmask, ExprList*, WhereCost*);


/*
** This routine attempts to find an scanning strategy that can be used 
** to optimize an 'OR' expression that is part of a WHERE clause. 
**
** The table associated with FROM clause term pSrc may be either a
** regular B-Tree table or a virtual table.
*/
static void bestOrClauseIndex(
  Parse *pParse,              /* The parsing context */
  WhereClause *pWC,           /* The WHERE clause */
  struct SrcList_item *pSrc,  /* The FROM clause term to search */
  Bitmask notReady,           /* Mask of cursors that are not available */

  ExprList *pOrderBy,         /* The ORDER BY clause */
  WhereCost *pCost            /* Lowest cost query plan */
){
#ifndef SQLITE_OMIT_OR_OPTIMIZATION
  const int iCur = pSrc->iCursor;   /* The cursor of the table to be accessed */
  const Bitmask maskSrc = getMask(pWC->pMaskSet, iCur);  /* Bitmask for pSrc */
  WhereTerm * const pWCEnd = &pWC->a[pWC->nTerm];        /* End of pWC->a[] */
................................................................................
      for(pOrTerm=pOrWC->a; pOrTerm<pOrWCEnd; pOrTerm++){
        WhereCost sTermCost;
        WHERETRACE(("... Multi-index OR testing for term %d of %d....\n", 
          (pOrTerm - pOrWC->a), (pTerm - pWC->a)
        ));
        if( pOrTerm->eOperator==WO_AND ){
          WhereClause *pAndWC = &pOrTerm->u.pAndInfo->wc;
          bestIndex(pParse, pAndWC, pSrc, notReady, 0, &sTermCost);
        }else if( pOrTerm->leftCursor==iCur ){
          WhereClause tempWC;
          tempWC.pParse = pWC->pParse;
          tempWC.pMaskSet = pWC->pMaskSet;
          tempWC.op = TK_AND;
          tempWC.a = pOrTerm;
          tempWC.nTerm = 1;
          bestIndex(pParse, &tempWC, pSrc, notReady, 0, &sTermCost);
        }else{
          continue;
        }
        rTotal += sTermCost.rCost;
        nRow += sTermCost.nRow;
        used |= sTermCost.used;
        if( rTotal>=pCost->rCost ) break;
................................................................................
** routine takes care of freeing the sqlite3_index_info structure after
** everybody has finished with it.
*/
static void bestVirtualIndex(
  Parse *pParse,                  /* The parsing context */
  WhereClause *pWC,               /* The WHERE clause */
  struct SrcList_item *pSrc,      /* The FROM clause term to search */
  Bitmask notReady,               /* Mask of cursors that are not available */

  ExprList *pOrderBy,             /* The order by clause */
  WhereCost *pCost,               /* Lowest cost query plan */
  sqlite3_index_info **ppIdxInfo  /* Index information passed to xBestIndex */
){
  Table *pTab = pSrc->pTab;
  sqlite3_index_info *pIdxInfo;
  struct sqlite3_index_constraint *pIdxCons;
................................................................................
  }
  pCost->plan.nEq = 0;
  pIdxInfo->nOrderBy = nOrderBy;

  /* Try to find a more efficient access pattern by using multiple indexes
  ** to optimize an OR expression within the WHERE clause. 
  */
  bestOrClauseIndex(pParse, pWC, pSrc, notReady, pOrderBy, pCost);
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */

/*
** Argument pIdx is a pointer to an index structure that has an array of
** SQLITE_INDEX_SAMPLES evenly spaced samples of the first indexed column
** stored in Index.aSample. The domain of values stored in said column
................................................................................
** selected plan may still take advantage of the tables built-in rowid
** index.
*/
static void bestBtreeIndex(
  Parse *pParse,              /* The parsing context */
  WhereClause *pWC,           /* The WHERE clause */
  struct SrcList_item *pSrc,  /* The FROM clause term to search */
  Bitmask notReady,           /* Mask of cursors that are not available */

  ExprList *pOrderBy,         /* The ORDER BY clause */
  WhereCost *pCost            /* Lowest cost query plan */
){
  int iCur = pSrc->iCursor;   /* The cursor of the table to be accessed */
  Index *pProbe;              /* An index we are evaluating */
  Index *pIdx;                /* Copy of pProbe, or zero for IPK index */
  int eqTermMask;             /* Current mask of valid equality operators */
................................................................................
    /* If there are additional constraints on this table that cannot
    ** be used with the current index, but which might lower the number
    ** of output rows, adjust the nRow value accordingly.  This only 
    ** matters if the current index is the least costly, so do not bother
    ** with this step if we already know this index will not be chosen.
    ** Also, never reduce the output row count below 2 using this step.
    **
    ** Do not reduce the output row count if pSrc is the only table that
    ** is notReady; if notReady is a power of two.  This will be the case
    ** when the main sqlite3WhereBegin() loop is scanning for a table with
    ** and "optimal" index, and on such a scan the output row count
    ** reduction is not valid because it does not update the "pCost->used"
    ** bitmap.  The notReady bitmap will also be a power of two when we
    ** are scanning for the last table in a 64-way join.  We are willing
    ** to bypass this optimization in that corner case.
    */
    if( nRow>2 && cost<=pCost->rCost && (notReady & (notReady-1))!=0 ){
      int k;                       /* Loop counter */
      int nSkipEq = nEq;           /* Number of == constraints to skip */
      int nSkipRange = nBound;     /* Number of < constraints to skip */
      Bitmask thisTab;             /* Bitmap for pSrc */

      thisTab = getMask(pWC->pMaskSet, iCur);
      for(pTerm=pWC->a, k=pWC->nTerm; nRow>2 && k; k--, pTerm++){
        if( pTerm->wtFlags & TERM_VIRTUAL ) continue;
        if( (pTerm->prereqAll & notReady)!=thisTab ) continue;
        if( pTerm->eOperator & (WO_EQ|WO_IN|WO_ISNULL) ){
          if( nSkipEq ){
            /* Ignore the first nEq equality matches since the index
            ** has already accounted for these */
            nSkipEq--;
          }else{
            /* Assume each additional equality match reduces the result
................................................................................
  );

  WHERETRACE(("best index is: %s\n", 
    ((pCost->plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ? "none" : 
         pCost->plan.u.pIdx ? pCost->plan.u.pIdx->zName : "ipk")
  ));
  
  bestOrClauseIndex(pParse, pWC, pSrc, notReady, pOrderBy, pCost);
  bestAutomaticIndex(pParse, pWC, pSrc, notReady, pCost);
  pCost->plan.wsFlags |= eqTermMask;
}

/*
** Find the query plan for accessing table pSrc->pTab. Write the
** best query plan and its cost into the WhereCost object supplied 
................................................................................
** as the last parameter. This function may calculate the cost of
** both real and virtual table scans.
*/
static void bestIndex(
  Parse *pParse,              /* The parsing context */
  WhereClause *pWC,           /* The WHERE clause */
  struct SrcList_item *pSrc,  /* The FROM clause term to search */
  Bitmask notReady,           /* Mask of cursors that are not available */

  ExprList *pOrderBy,         /* The ORDER BY clause */
  WhereCost *pCost            /* Lowest cost query plan */
){
#ifndef SQLITE_OMIT_VIRTUALTABLE
  if( IsVirtual(pSrc->pTab) ){
    sqlite3_index_info *p = 0;
    bestVirtualIndex(pParse, pWC, pSrc, notReady, pOrderBy, pCost, &p);
    if( p->needToFreeIdxStr ){
      sqlite3_free(p->idxStr);
    }
    sqlite3DbFree(pParse->db, p);
  }else
#endif
  {
    bestBtreeIndex(pParse, pWC, pSrc, notReady, pOrderBy, pCost);
  }
}

/*
** Disable a term in the WHERE clause.  Except, do not disable the term
** if it controls a LEFT OUTER JOIN and it did not originate in the ON
** or USING clause of that join.
................................................................................
    ** were used as the innermost nested loop.  In other words, a table
    ** is chosen such that the cost of running that table cannot be reduced
    ** by waiting for other tables to run first.  This "optimal" test works
    ** by first assuming that the FROM clause is on the inner loop and finding
    ** its query plan, then checking to see if that query plan uses any
    ** other FROM clause terms that are notReady.  If no notReady terms are
    ** used then the "optimal" query plan works.
    **






    ** The second loop iteration is only performed if no optimal scan
    ** strategies were found by the first loop. This 2nd iteration is used to
    ** search for the lowest cost scan overall.
    **
    ** Previous versions of SQLite performed only the second iteration -
    ** the next outermost loop was always that with the lowest overall
    ** cost. However, this meant that SQLite could select the wrong plan
    ** for scripts such as the following:
    **   
    **   CREATE TABLE t1(a, b); 
................................................................................
    ** Since the cost of a linear scan through table t2 is the same 
    ** as the cost of a linear scan through table t1, a simple greedy 
    ** algorithm may choose to use t2 for the outer loop, which is a much
    ** costlier approach.
    */
    nUnconstrained = 0;
    notIndexed = 0;
    for(isOptimal=(iFrom<nTabList-1); isOptimal>=0; isOptimal--){
      Bitmask mask;             /* Mask of tables not yet ready */
      for(j=iFrom, pTabItem=&pTabList->a[j]; j<nTabList; j++, pTabItem++){
        int doNotReorder;    /* True if this table should not be reordered */
        WhereCost sCost;     /* Cost information from best[Virtual]Index() */
        ExprList *pOrderBy;  /* ORDER BY clause for index to optimize */
  
        doNotReorder =  (pTabItem->jointype & (JT_LEFT|JT_CROSS))!=0;
................................................................................
        pOrderBy = ((i==0 && ppOrderBy )?*ppOrderBy:0);
        if( pTabItem->pIndex==0 ) nUnconstrained++;
  
        assert( pTabItem->pTab );
#ifndef SQLITE_OMIT_VIRTUALTABLE
        if( IsVirtual(pTabItem->pTab) ){
          sqlite3_index_info **pp = &pWInfo->a[j].pIdxInfo;
          bestVirtualIndex(pParse, pWC, pTabItem, mask, pOrderBy, &sCost, pp);

        }else 
#endif
        {
          bestBtreeIndex(pParse, pWC, pTabItem, mask, pOrderBy, &sCost);

        }
        assert( isOptimal || (sCost.used&notReady)==0 );

        /* If an INDEXED BY clause is present, then the plan must use that
        ** index if it uses any index at all */
        assert( pTabItem->pIndex==0 
                  || (sCost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0







|







 







<







 







|

<







 







|







 







<
<
<
<
<
<







 







|







|
<
<







 







|
>
|







 







|
|
>
>
>







 







|







 







|
|
<

>
|
<
<
<
<

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

<
<
>
>

<
<
<
<
>
>
>

|

>
|

|
|
|
|
|
>



>
>
>
>

|
>
>



|

|

>

<
>


|

|

>


|
>



|


|

|


|

>



|
>
>



|

|


|

|
>



>
>
>
>
>
>







 







|
|

|







>





|



|
>
|
>
|
>
>
>

|









|
|
>
>
>
>
|
|

<
<
<
>
>
>

|
>

>
|
|

>
>
|
>


|

<
|
<
<

>

<
>
|






|

|
|
|

|



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







 







|
<
<
<
<
|
|







 







|







 







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







 







>
>







 







>
>
>
>
>
>
>
>
>
>
>





|

|









>




>

>



>







 







|
>

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







 







<







 







<







 







<
<
|
<







 







<







 







<
<







 







<







 







<







 







|







 







|













|
<
<








>
>


<
<
>
>

<
|







 







|







 







|







 







|
>












|
>







 







|







|







 







|
>







 







|







 







|
>







 







|
|
|
|
|
|
|
|

|








|







 







|







 







|
>






|







|







 








>
>
>
>
>
>

|
|







 







|







 







|
>



|
>







648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
.....
10568
10569
10570
10571
10572
10573
10574

10575
10576
10577
10578
10579
10580
10581
.....
10887
10888
10889
10890
10891
10892
10893
10894
10895

10896
10897
10898
10899
10900
10901
10902
.....
10934
10935
10936
10937
10938
10939
10940
10941
10942
10943
10944
10945
10946
10947
10948
.....
12633
12634
12635
12636
12637
12638
12639






12640
12641
12642
12643
12644
12645
12646
.....
12834
12835
12836
12837
12838
12839
12840
12841
12842
12843
12844
12845
12846
12847
12848
12849


12850
12851
12852
12853
12854
12855
12856
.....
13063
13064
13065
13066
13067
13068
13069
13070
13071
13072
13073
13074
13075
13076
13077
13078
13079
.....
13120
13121
13122
13123
13124
13125
13126
13127
13128
13129
13130
13131
13132
13133
13134
13135
13136
13137
13138
.....
17494
17495
17496
17497
17498
17499
17500
17501
17502
17503
17504
17505
17506
17507
17508
.....
20088
20089
20090
20091
20092
20093
20094
20095
20096

20097
20098
20099




20100

20101
20102
20103
20104
20105
20106
20107






























20108


20109
20110
20111




20112
20113
20114
20115
20116
20117
20118
20119
20120
20121
20122
20123
20124
20125
20126
20127
20128
20129
20130
20131
20132
20133
20134
20135
20136
20137
20138
20139
20140
20141
20142
20143
20144
20145
20146

20147
20148
20149
20150
20151
20152
20153
20154
20155
20156
20157
20158
20159
20160
20161
20162
20163
20164
20165
20166
20167
20168
20169
20170
20171
20172
20173
20174
20175
20176
20177
20178
20179
20180
20181
20182
20183
20184
20185
20186
20187
20188
20189
20190
20191
20192
20193
20194
20195
20196
20197
20198
20199
20200
20201
20202
20203
20204
20205
20206
.....
20251
20252
20253
20254
20255
20256
20257
20258
20259
20260
20261
20262
20263
20264
20265
20266
20267
20268
20269
20270
20271
20272
20273
20274
20275
20276
20277
20278
20279
20280
20281
20282
20283
20284
20285
20286
20287
20288
20289
20290
20291
20292
20293
20294
20295
20296
20297
20298
20299
20300
20301
20302
20303
20304
20305
20306



20307
20308
20309
20310
20311
20312
20313
20314
20315
20316
20317
20318
20319
20320
20321
20322
20323
20324
20325

20326


20327
20328
20329

20330
20331
20332
20333
20334
20335
20336
20337
20338
20339
20340
20341
20342
20343
20344
20345
20346
20347
20348
20349




































20350
20351






20352
20353
20354
20355
20356
20357
20358
.....
54103
54104
54105
54106
54107
54108
54109
54110




54111
54112
54113
54114
54115
54116
54117
54118
54119
.....
54135
54136
54137
54138
54139
54140
54141
54142
54143
54144
54145
54146
54147
54148
54149
.....
54208
54209
54210
54211
54212
54213
54214

54215
54216
54217




54218
54219
54220
54221
54222
54223
54224
54225
54226
54227
54228
54229
54230
54231
54232
54233
54234
.....
54763
54764
54765
54766
54767
54768
54769
54770
54771
54772
54773
54774
54775
54776
54777
54778
.....
54781
54782
54783
54784
54785
54786
54787
54788
54789
54790
54791
54792
54793
54794
54795
54796
54797
54798
54799
54800
54801
54802
54803
54804
54805
54806
54807
54808
54809
54810
54811
54812
54813
54814
54815
54816
54817
54818
54819
54820
54821
54822
54823
54824
54825
54826
54827
54828
54829
54830
54831
54832
54833
54834
.....
59735
59736
59737
59738
59739
59740
59741
59742
59743
59744

59745
59746
59747








59748

59749
59750








59751
59752
59753
59754
59755
59756
59757
59758
59759
.....
61531
61532
61533
61534
61535
61536
61537

61538
61539
61540
61541
61542
61543
61544
.....
61573
61574
61575
61576
61577
61578
61579

61580
61581
61582
61583
61584
61585
61586
.....
61597
61598
61599
61600
61601
61602
61603


61604

61605
61606
61607
61608
61609
61610
61611
.....
61613
61614
61615
61616
61617
61618
61619

61620
61621
61622
61623
61624
61625
61626
.....
61726
61727
61728
61729
61730
61731
61732


61733
61734
61735
61736
61737
61738
61739
.....
62358
62359
62360
62361
62362
62363
62364

62365
62366
62367
62368
62369
62370
62371
.....
62437
62438
62439
62440
62441
62442
62443

62444
62445
62446
62447
62448
62449
62450
.....
68821
68822
68823
68824
68825
68826
68827
68828
68829
68830
68831
68832
68833
68834
68835
.....
70184
70185
70186
70187
70188
70189
70190
70191
70192
70193
70194
70195
70196
70197
70198
70199
70200
70201
70202
70203
70204
70205


70206
70207
70208
70209
70210
70211
70212
70213
70214
70215
70216
70217


70218
70219
70220

70221
70222
70223
70224
70225
70226
70227
70228
.....
79354
79355
79356
79357
79358
79359
79360
79361
79362
79363
79364
79365
79366
79367
79368
.....
85412
85413
85414
85415
85416
85417
85418
85419
85420
85421
85422
85423
85424
85425
85426
.....
96320
96321
96322
96323
96324
96325
96326
96327
96328
96329
96330
96331
96332
96333
96334
96335
96336
96337
96338
96339
96340
96341
96342
96343
96344
96345
96346
96347
96348
96349
.....
96371
96372
96373
96374
96375
96376
96377
96378
96379
96380
96381
96382
96383
96384
96385
96386
96387
96388
96389
96390
96391
96392
96393
.....
96826
96827
96828
96829
96830
96831
96832
96833
96834
96835
96836
96837
96838
96839
96840
96841
.....
96957
96958
96959
96960
96961
96962
96963
96964
96965
96966
96967
96968
96969
96970
96971
.....
97238
97239
97240
97241
97242
97243
97244
97245
97246
97247
97248
97249
97250
97251
97252
97253
.....
97501
97502
97503
97504
97505
97506
97507
97508
97509
97510
97511
97512
97513
97514
97515
97516
97517
97518
97519
97520
97521
97522
97523
97524
97525
97526
97527
97528
97529
97530
97531
97532
97533
.....
97601
97602
97603
97604
97605
97606
97607
97608
97609
97610
97611
97612
97613
97614
97615
.....
97616
97617
97618
97619
97620
97621
97622
97623
97624
97625
97626
97627
97628
97629
97630
97631
97632
97633
97634
97635
97636
97637
97638
97639
97640
97641
97642
97643
97644
97645
97646
.....
98847
98848
98849
98850
98851
98852
98853
98854
98855
98856
98857
98858
98859
98860
98861
98862
98863
98864
98865
98866
98867
98868
98869
98870
.....
98876
98877
98878
98879
98880
98881
98882
98883
98884
98885
98886
98887
98888
98889
98890
.....
98898
98899
98900
98901
98902
98903
98904
98905
98906
98907
98908
98909
98910
98911
98912
98913
98914
98915
98916
98917
98918
**
** See also: [sqlite3_libversion()],
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION        "3.7.3"
#define SQLITE_VERSION_NUMBER 3007003
#define SQLITE_SOURCE_ID      "2010-10-04 23:55:51 ece641eb8951c6314cedbdb3243f91cb199c3239"

/*
** CAPI3REF: Run-Time Library Version Numbers
** KEYWORDS: sqlite3_version, sqlite3_sourceid
**
** These interfaces provide the same information as the [SQLITE_VERSION],
** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros
................................................................................
# define sqlite3Tolower(x)   tolower((unsigned char)(x))
#endif

/*
** Internal function prototypes
*/
SQLITE_PRIVATE int sqlite3StrICmp(const char *, const char *);

SQLITE_PRIVATE int sqlite3Strlen30(const char*);
#define sqlite3StrNICmp sqlite3_strnicmp

SQLITE_PRIVATE int sqlite3MallocInit(void);
SQLITE_PRIVATE void sqlite3MallocEnd(void);
SQLITE_PRIVATE void *sqlite3Malloc(int);
SQLITE_PRIVATE void *sqlite3MallocZero(int);
................................................................................
SQLITE_PRIVATE void sqlite3Detach(Parse*, Expr*);
SQLITE_PRIVATE int sqlite3FixInit(DbFixer*, Parse*, int, const char*, const Token*);
SQLITE_PRIVATE int sqlite3FixSrcList(DbFixer*, SrcList*);
SQLITE_PRIVATE int sqlite3FixSelect(DbFixer*, Select*);
SQLITE_PRIVATE int sqlite3FixExpr(DbFixer*, Expr*);
SQLITE_PRIVATE int sqlite3FixExprList(DbFixer*, ExprList*);
SQLITE_PRIVATE int sqlite3FixTriggerStep(DbFixer*, TriggerStep*);
SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*, int, u8);
SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*);

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

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


SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(Vdbe *, Index *);
SQLITE_PRIVATE void sqlite3TableAffinityStr(Vdbe *, Table *);
SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2);
SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity);
SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr);
SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*, int, u8);
SQLITE_PRIVATE void sqlite3Error(sqlite3*, int, const char*,...);
SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n);
SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **);
SQLITE_PRIVATE const char *sqlite3ErrStr(int);
SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse);
SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int);
SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName);
................................................................................
    cnt++;
  }while( nextC );
end_getDigits:
  va_end(ap);
  return cnt;
}







/*
** Parse a timezone extension on the end of a date-time.
** The extension is of the form:
**
**        (+/-)HH:MM
**
** Or the "zulu" notation:
................................................................................
** as there is a year and date.
*/
static int parseDateOrTime(
  sqlite3_context *context, 
  const char *zDate, 
  DateTime *p
){
  double r;
  if( parseYyyyMmDd(zDate,p)==0 ){
    return 0;
  }else if( parseHhMmSs(zDate, p)==0 ){
    return 0;
  }else if( sqlite3StrICmp(zDate,"now")==0){
    setDateTimeToCurrent(context, p);
    return 0;
  }else if( sqlite3AtoF(zDate, &r, sqlite3Strlen30(zDate), SQLITE_UTF8) ){


    p->iJD = (sqlite3_int64)(r*86400000.0 + 0.5);
    p->validJD = 1;
    return 0;
  }
  return 1;
}

................................................................................
      /*
      **    weekday N
      **
      ** Move the date to the same time on the next occurrence of
      ** weekday N where 0==Sunday, 1==Monday, and so forth.  If the
      ** date is already on the appropriate weekday, this is a no-op.
      */
      if( strncmp(z, "weekday ", 8)==0
               && sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8)
               && (n=(int)r)==r && n>=0 && r<7 ){
        sqlite3_int64 Z;
        computeYMD_HMS(p);
        p->validTZ = 0;
        p->validJD = 0;
        computeJD(p);
        Z = ((p->iJD + 129600000)/86400000) % 7;
        if( Z>n ) Z -= 7;
................................................................................
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9': {
      double rRounder;
      for(n=1; z[n] && z[n]!=':' && !sqlite3Isspace(z[n]); n++){}
      if( !sqlite3AtoF(z, &r, n, SQLITE_UTF8) ){
        rc = 1;
        break;
      }
      if( z[n]==':' ){
        /* A modifier of the form (+|-)HH:MM:SS.FFF adds (or subtracts) the
        ** specified number of hours, minutes, seconds, and fractional seconds
        ** to the time.  The ".FFF" may be omitted.  The ":SS.FFF" may be
        ** omitted.
        */
        const char *z2 = z;
................................................................................
  if( n<0 ) return priorLimit;
  if( n>0 ){
    sqlite3MemoryAlarm(softHeapLimitEnforcer, 0, n);
  }else{
    sqlite3MemoryAlarm(0, 0, 0);
  }
  excess = sqlite3_memory_used() - n;
  if( excess>0 ) sqlite3_release_memory((int)(excess & 0x7fffffff));
  return priorLimit;
}
SQLITE_API void sqlite3_soft_heap_limit(int n){
  if( n<0 ) n = 0;
  sqlite3_soft_heap_limit64(n);
}

................................................................................
  a = (unsigned char *)zLeft;
  b = (unsigned char *)zRight;
  while( N-- > 0 && *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; }
  return N<0 ? 0 : UpperToLower[*a] - UpperToLower[*b];
}

/*
** The string z[] is an text representation of a real number.
** Convert this string to a double and write it into *pResult.

**
** The string z[] is length bytes in length (bytes, not characters) and
** uses the encoding enc.  The string is not necessarily zero-terminated.




**

** Return TRUE if the result is a valid real number (or integer) and FALSE
** if the string is empty or contains extraneous text.  Valid numbers
** are in one of these formats:
**
**    [+-]digits[E[+-]digits]
**    [+-]digits.[digits][E[+-]digits]
**    [+-].digits[E[+-]digits]






























**


** Leading and trailing whitespace is ignored for the purpose of determining
** validity.
**




** If some prefix of the input string is a valid number, this routine
** returns FALSE but it still converts the prefix and writes the result
** into *pResult.
*/
SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){
#ifndef SQLITE_OMIT_FLOATING_POINT
  int incr = (enc==SQLITE_UTF8?1:2);
  const char *zEnd = z + length;
  /* sign * significand * (10 ^ (esign * exponent)) */
  int sign = 1;    /* sign of significand */
  i64 s = 0;       /* significand */
  int d = 0;       /* adjust exponent for shifting decimal point */
  int esign = 1;   /* sign of exponent */
  int e = 0;       /* exponent */
  int eValid = 1;  /* True exponent is either not used or is well-formed */
  double result;
  int nDigits = 0;

  *pResult = 0.0;   /* Default return value, in case of an error */

  if( enc==SQLITE_UTF16BE ) z++;

  /* skip leading spaces */
  while( z<zEnd && sqlite3Isspace(*z) ) z+=incr;
  if( z>=zEnd ) return 0;

  /* get sign of significand */
  if( *z=='-' ){
    sign = -1;
    z+=incr;
  }else if( *z=='+' ){
    z+=incr;
  }

  /* skip leading zeroes */

  while( z<zEnd && z[0]=='0' ) z+=incr, nDigits++;

  /* copy max significant digits to significand */
  while( z<zEnd && sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){
    s = s*10 + (*z - '0');
    z+=incr, nDigits++;
  }

  /* skip non-significant significand digits
  ** (increase exponent by d to shift decimal left) */
  while( z<zEnd && sqlite3Isdigit(*z) ) z+=incr, nDigits++, d++;
  if( z>=zEnd ) goto do_atof_calc;

  /* if decimal point is present */
  if( *z=='.' ){
    z+=incr;
    /* copy digits from after decimal to significand
    ** (decrease exponent by d to shift decimal right) */
    while( z<zEnd && sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){
      s = s*10 + (*z - '0');
      z+=incr, nDigits++, d--;
    }
    /* skip non-significant digits */
    while( z<zEnd && sqlite3Isdigit(*z) ) z+=incr, nDigits++;
  }
  if( z>=zEnd ) goto do_atof_calc;

  /* if exponent is present */
  if( *z=='e' || *z=='E' ){
    z+=incr;
    eValid = 0;
    if( z>=zEnd ) goto do_atof_calc;
    /* get sign of exponent */
    if( *z=='-' ){
      esign = -1;
      z+=incr;
    }else if( *z=='+' ){
      z+=incr;
    }
    /* copy digits to exponent */
    while( z<zEnd && sqlite3Isdigit(*z) ){
      e = e*10 + (*z - '0');
      z+=incr;
      eValid = 1;
    }
  }

  /* skip trailing spaces */
  if( nDigits && eValid ){
    while( z<zEnd && sqlite3Isspace(*z) ) z+=incr;
  }

do_atof_calc:
  /* adjust exponent by d, and update sign */
  e = (e*esign) + d;
  if( e<0 ) {
    esign = -1;
    e *= -1;
  } else {
    esign = 1;
................................................................................
      result = (double)s;
    }
  }

  /* store the result */
  *pResult = result;

  /* return true if number and no extra non-whitespace chracters after */
  return z>=zEnd && nDigits>0 && eValid;
#else
  return !sqlite3Atoi64(z, pResult, length, enc);
#endif /* SQLITE_OMIT_FLOATING_POINT */
}

/*
** Compare the 19-character string zNum against the text representation
** value 2^63:  9223372036854775808.  Return negative, zero, or positive
** if zNum is less than, equal to, or greater than the string.
** Note that zNum must contain exactly 19 characters.
**
** Unlike memcmp() this routine is guaranteed to return the difference
** in the values of the last digit if the only difference is in the
** last digit.  So, for example,
**
**      compare2pow63("9223372036854775800", 1)
**
** will return -8.
*/
static int compare2pow63(const char *zNum, int incr){
  int c = 0;
  int i;
                    /* 012345678901234567 */
  const char *pow63 = "922337203685477580";
  for(i=0; c==0 && i<18; i++){
    c = (zNum[i*incr]-pow63[i])*10;
  }
  if( c==0 ){
    c = zNum[18*incr] - '8';
    testcase( c==(-1) );
    testcase( c==0 );
    testcase( c==(+1) );
  }
  return c;
}


/*
** Convert zNum to a 64-bit signed integer and write
** the value of the integer into *pNum.
** If zNum is exactly 9223372036854665808, return 2.
** This is a special case as the context will determine
** if it is too big (used as a negative).
** If zNum is not an integer or is an integer that 
** is too large to be expressed with 64 bits,
** then return 1.  Otherwise return 0.
**



** length is the number of bytes in the string (bytes, not characters).
** The string is not necessarily zero-terminated.  The encoding is
** given by enc.
*/
SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
  int incr = (enc==SQLITE_UTF8?1:2);
  i64 v = 0;
  int neg = 0; /* assume positive */
  int i;
  int c = 0;
  const char *zStart;
  const char *zEnd = zNum + length;
  if( enc==SQLITE_UTF16BE ) zNum++;
  while( zNum<zEnd && sqlite3Isspace(*zNum) ) zNum+=incr;
  if( zNum>=zEnd ) goto do_atoi_calc;
  if( *zNum=='-' ){
    neg = 1;
    zNum+=incr;
  }else if( *zNum=='+' ){

    zNum+=incr;


  }
do_atoi_calc:
  zStart = zNum;

  while( zNum<zEnd && zNum[0]=='0' ){ zNum+=incr; } /* Skip leading zeros. */
  for(i=0; &zNum[i]<zEnd && (c=zNum[i])>='0' && c<='9'; i+=incr){
    v = v*10 + c - '0';
  }
  *pNum = neg ? -v : v;
  testcase( i==18 );
  testcase( i==19 );
  testcase( i==20 );
  if( (c!=0 && &zNum[i]<zEnd) || (i==0 && zStart==zNum) || i>19*incr ){
    /* zNum is empty or contains non-numeric text or is longer
    ** than 19 digits (thus guaranteeing that it is too large) */
    return 1;
  }else if( i<19*incr ){
    /* Less than 19 digits, so we know that it fits in 64 bits */
    return 0;
  }else{
    /* 19-digit numbers must be no larger than 9223372036854775807 if positive
    ** or 9223372036854775808 if negative.  Note that 9223372036854665808
    ** is 2^63. Return 1 if to large */
    c=compare2pow63(zNum, incr);




































    if( c==0 && neg==0 ) return 2; /* too big, exactly 9223372036854665808 */
    return c<neg ? 0 : 1;






  }
}

/*
** If zNum represents an integer that will fit in 32-bits, then set
** *pValue to that integer and return true.  Otherwise return false.
**
................................................................................
  flags = pMem->flags;
  if( flags & MEM_Int ){
    return pMem->u.i;
  }else if( flags & MEM_Real ){
    return doubleToInt64(pMem->r);
  }else if( flags & (MEM_Str|MEM_Blob) ){
    i64 value;
    assert( pMem->z || pMem->n==0 );




    testcase( pMem->z==0 );
    sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc);
    return value;
  }else{
    return 0;
  }
}

/*
................................................................................
    pMem->flags |= MEM_Str;
    if( sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8)
       || sqlite3VdbeMemNulTerminate(pMem) ){
      /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
      return (double)0;
    }
    assert( pMem->z );
    sqlite3AtoF(pMem->z, &val, pMem->n, SQLITE_UTF8);
    return val;
  }else{
    /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
    return (double)0;
  }
}

................................................................................
** Invalidate any prior representations.
**
** Every effort is made to force the conversion, even if the input
** is a string that does not look completely like a number.  Convert
** as much of the string as we can and ignore the rest.
*/
SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){

  if( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 ){
    assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 );
    assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) );




    if( 0==sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc) ){
      MemSetTypeFlag(pMem, MEM_Int);
    }else{
      pMem->r = sqlite3VdbeRealValue(pMem);
      MemSetTypeFlag(pMem, MEM_Real);
      sqlite3VdbeIntegerAffinity(pMem);
    }
  }
  assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))!=0 );
  pMem->flags &= ~(MEM_Str|MEM_Blob);
  return SQLITE_OK;
}

/*
** Delete any previous value and set the value stored in *pMem to NULL.
*/
SQLITE_PRIVATE void sqlite3VdbeMemSetNull(Mem *pMem){
................................................................................
  u8 enc,                   /* Encoding to use */
  u8 affinity,              /* Affinity to use */
  sqlite3_value **ppVal     /* Write the new value here */
){
  int op;
  char *zVal = 0;
  sqlite3_value *pVal = 0;
  int negInt = 1;
  const char *zNeg = "";

  if( !pExpr ){
    *ppVal = 0;
    return SQLITE_OK;
  }
  op = pExpr->op;

................................................................................
  ** when SQLITE_ENABLE_STAT2 is omitted.
  */
#ifdef SQLITE_ENABLE_STAT2
  if( op==TK_REGISTER ) op = pExpr->op2;
#else
  if( NEVER(op==TK_REGISTER) ) op = pExpr->op2;
#endif

  /* Handle negative integers in a single step.  This is needed in the
  ** case when the value is -9223372036854775808.
  */
  if( op==TK_UMINUS
   && (pExpr->pLeft->op==TK_INTEGER || pExpr->pLeft->op==TK_FLOAT) ){
    pExpr = pExpr->pLeft;
    op = pExpr->op;
    negInt = -1;
    zNeg = "-";
  }

  if( op==TK_STRING || op==TK_FLOAT || op==TK_INTEGER ){
    pVal = sqlite3ValueNew(db);
    if( pVal==0 ) goto no_mem;
    if( ExprHasProperty(pExpr, EP_IntValue) ){
      sqlite3VdbeMemSetInt64(pVal, (i64)pExpr->u.iValue*negInt);
    }else{
      zVal = sqlite3MPrintf(db, "%s%s", zNeg, pExpr->u.zToken);
      if( zVal==0 ) goto no_mem;
      sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC);
      if( op==TK_FLOAT ) pVal->type = SQLITE_FLOAT;
    }
    if( (op==TK_INTEGER || op==TK_FLOAT ) && affinity==SQLITE_AFF_NONE ){
      sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, SQLITE_UTF8);
    }else{
      sqlite3ValueApplyAffinity(pVal, affinity, SQLITE_UTF8);
    }
    if( pVal->flags & (MEM_Int|MEM_Real) ) pVal->flags &= ~MEM_Str;
    if( enc!=SQLITE_UTF8 ){
      sqlite3VdbeChangeEncoding(pVal, enc);
    }
  }else if( op==TK_UMINUS ) {
    /* This branch happens for multiple negative signs.  Ex: -(-5) */
    if( SQLITE_OK==sqlite3ValueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal) ){
      sqlite3VdbeMemNumerify(pVal);
      pVal->u.i = -1 * pVal->u.i;
      /* (double)-1 In case of SQLITE_OMIT_FLOATING_POINT... */
      pVal->r = (double)-1 * pVal->r;
      sqlite3ValueApplyAffinity(pVal, affinity, enc);
    }
  }
#ifndef SQLITE_OMIT_BLOB_LITERAL
  else if( op==TK_BLOB ){
    int nVal;
    assert( pExpr->u.zToken[0]=='x' || pExpr->u.zToken[0]=='X' );
    assert( pExpr->u.zToken[1]=='\'' );
................................................................................
** Try to convert a value into a numeric representation if we can
** do so without loss of information.  In other words, if the string
** looks like a number, convert it into a number.  If it does not
** look like a number, leave it alone.
*/
static void applyNumericAffinity(Mem *pRec){
  if( (pRec->flags & (MEM_Real|MEM_Int))==0 ){
    double rValue;
    i64 iValue;
    u8 enc = pRec->enc;

    if( (pRec->flags&MEM_Str)==0 ) return;
    if( sqlite3AtoF(pRec->z, &rValue, pRec->n, enc)==0 ) return;
    if( 0==sqlite3Atoi64(pRec->z, &iValue, pRec->n, enc) ){








      pRec->u.i = iValue;

      pRec->flags |= MEM_Int;
    }else{








      pRec->r = rValue;
      pRec->flags |= MEM_Real;
    }
  }
}

/*
** Processing is determine by the affinity parameter:
**
................................................................................
** This opcode is used when extracting information from a column that
** has REAL affinity.  Such column values may still be stored as
** integers, for space efficiency, but after extraction we want them
** to have only a real value.
*/
case OP_RealAffinity: {                  /* in1 */
  pIn1 = &aMem[pOp->p1];

  if( pIn1->flags & MEM_Int ){
    sqlite3VdbeMemRealify(pIn1);
  }
  break;
}
#endif

................................................................................
** Strings are simply reinterpreted as blobs with no change
** to the underlying data.
**
** A NULL value is not changed by this routine.  It remains NULL.
*/
case OP_ToBlob: {                  /* same as TK_TO_BLOB, in1 */
  pIn1 = &aMem[pOp->p1];

  if( pIn1->flags & MEM_Null ) break;
  if( (pIn1->flags & MEM_Blob)==0 ){
    applyAffinity(pIn1, SQLITE_AFF_TEXT, encoding);
    assert( pIn1->flags & MEM_Str || db->mallocFailed );
    MemSetTypeFlag(pIn1, MEM_Blob);
  }else{
    pIn1->flags &= ~(MEM_TypeMask&~MEM_Blob);
................................................................................
** equivalent of atoi() or atof() and store 0 if no such conversion 
** is possible.
**
** A NULL value is not changed by this routine.  It remains NULL.
*/
case OP_ToNumeric: {                  /* same as TK_TO_NUMERIC, in1 */
  pIn1 = &aMem[pOp->p1];


  sqlite3VdbeMemNumerify(pIn1);

  break;
}
#endif /* SQLITE_OMIT_CAST */

/* Opcode: ToInt P1 * * * *
**
** Force the value in register P1 to be an integer.  If
................................................................................
** If the value is text or blob, try to convert it to an integer using the
** equivalent of atoi() and store 0 if no such conversion is possible.
**
** A NULL value is not changed by this routine.  It remains NULL.
*/
case OP_ToInt: {                  /* same as TK_TO_INT, in1 */
  pIn1 = &aMem[pOp->p1];

  if( (pIn1->flags & MEM_Null)==0 ){
    sqlite3VdbeMemIntegerify(pIn1);
  }
  break;
}

#if !defined(SQLITE_OMIT_CAST) && !defined(SQLITE_OMIT_FLOATING_POINT)
................................................................................
  char affinity;      /* Affinity to use for comparison */
  u16 flags1;         /* Copy of initial value of pIn1->flags */
  u16 flags3;         /* Copy of initial value of pIn3->flags */
#endif /* local variables moved into u.ai */

  pIn1 = &aMem[pOp->p1];
  pIn3 = &aMem[pOp->p3];


  u.ai.flags1 = pIn1->flags;
  u.ai.flags3 = pIn3->flags;
  if( (pIn1->flags | pIn3->flags)&MEM_Null ){
    /* One or both operands are NULL */
    if( pOp->p5 & SQLITE_NULLEQ ){
      /* If SQLITE_NULLEQ is set (which will only happen if the operator is
      ** OP_Eq or OP_Ne) then take the jump or not depending on whether
................................................................................
  u.an.zAffinity = pOp->p4.z;
  assert( u.an.zAffinity!=0 );
  assert( u.an.zAffinity[pOp->p2]==0 );
  pIn1 = &aMem[pOp->p1];
  while( (u.an.cAff = *(u.an.zAffinity++))!=0 ){
    assert( pIn1 <= &p->aMem[p->nMem] );
    assert( memIsValid(pIn1) );

    ExpandBlob(pIn1);
    applyAffinity(pIn1, u.an.cAff, encoding);
    pIn1++;
  }
  break;
}

................................................................................

  /* Loop through the elements that will make up the record to figure
  ** out how much space is required for the new record.
  */
  for(u.ao.pRec=u.ao.pData0; u.ao.pRec<=u.ao.pLast; u.ao.pRec++){
    assert( memIsValid(u.ao.pRec) );
    if( u.ao.zAffinity ){

      applyAffinity(u.ao.pRec, u.ao.zAffinity[u.ao.pRec-u.ao.pData0], encoding);
    }
    if( u.ao.pRec->flags&MEM_Zero && u.ao.pRec->n>0 ){
      sqlite3VdbeMemExpandBlob(u.ao.pRec);
    }
    u.ao.serial_type = sqlite3VdbeSerialType(u.ao.pRec, u.ao.file_format);
    u.ao.len = sqlite3VdbeSerialTypeLen(u.ao.serial_type);
................................................................................
    /* Wildcard of the form "?".  Assign the next variable number */
    assert( z[0]=='?' );
    pExpr->iColumn = (ynVar)(++pParse->nVar);
  }else if( z[0]=='?' ){
    /* Wildcard of the form "?nnn".  Convert "nnn" to an integer and
    ** use it as the variable number */
    i64 i;
    int bOk = 0==sqlite3Atoi64(&z[1], &i, sqlite3Strlen30(&z[1]), SQLITE_UTF8);
    pExpr->iColumn = (ynVar)i;
    testcase( i==0 );
    testcase( i==1 );
    testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]-1 );
    testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] );
    if( bOk==0 || i<1 || i>db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ){
      sqlite3ErrorMsg(pParse, "variable number must be between ?1 and ?%d",
................................................................................
** z[n] character is guaranteed to be something that does not look
** like the continuation of the number.
*/
static void codeReal(Vdbe *v, const char *z, int negateFlag, int iMem){
  if( ALWAYS(z!=0) ){
    double value;
    char *zV;
    sqlite3AtoF(z, &value, sqlite3Strlen30(z), SQLITE_UTF8);
    assert( !sqlite3IsNaN(value) ); /* The new AtoF never returns NaN */
    if( negateFlag ) value = -value;
    zV = dup8bytes(v, (char*)&value);
    sqlite3VdbeAddOp4(v, OP_Real, 0, iMem, 0, zV, P4_REAL);
  }
}
#endif


/*
** Generate an instruction that will put the integer describe by
** text z[0..n-1] into register iMem.
**
** Expr.u.zToken is always UTF8 and zero-terminated.


*/
static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){
  Vdbe *v = pParse->pVdbe;
  if( pExpr->flags & EP_IntValue ){
    int i = pExpr->u.iValue;
    if( negFlag ) i = -i;
    sqlite3VdbeAddOp2(v, OP_Integer, i, iMem);
  }else{
    int c;
    i64 value;
    const char *z = pExpr->u.zToken;
    assert( z!=0 );


    c = sqlite3Atoi64(z, &value, sqlite3Strlen30(z), SQLITE_UTF8);
    if( c==0 || (c==2 && negFlag) ){
      char *zV;

      if( negFlag ){ value = -value; }
      zV = dup8bytes(v, (char*)&value);
      sqlite3VdbeAddOp4(v, OP_Int64, 0, iMem, 0, zV, P4_INT64);
    }else{
#ifdef SQLITE_OMIT_FLOATING_POINT
      sqlite3ErrorMsg(pParse, "oversized integer: %s%s", negFlag ? "-" : "", z);
#else
      codeReal(v, z, negFlag, iMem);
................................................................................
    r = -(double)((sqlite_int64)((-r)+0.5));
  }else{
    zBuf = sqlite3_mprintf("%.*f",n,r);
    if( zBuf==0 ){
      sqlite3_result_error_nomem(context);
      return;
    }
    sqlite3AtoF(zBuf, &r, sqlite3Strlen30(zBuf), SQLITE_UTF8);
    sqlite3_free(zBuf);
  }
  sqlite3_result_double(context, r);
}
#endif

/*
................................................................................
  **
  ** Get or set the size limit on rollback journal files.
  */
  if( sqlite3StrICmp(zLeft,"journal_size_limit")==0 ){
    Pager *pPager = sqlite3BtreePager(pDb->pBt);
    i64 iLimit = -2;
    if( zRight ){
      sqlite3Atoi64(zRight, &iLimit, 1000000, SQLITE_UTF8);
      if( iLimit<-1 ) iLimit = -1;
    }
    iLimit = sqlite3PagerJournalSizeLimit(pPager, iLimit);
    returnSingleInt(pParse, "journal_size_limit", iLimit);
  }else

#endif /* SQLITE_OMIT_PAGER_PRAGMAS */
................................................................................
#define TRACE_IDX_OUTPUTS(A)
#endif

/* 
** Required because bestIndex() is called by bestOrClauseIndex() 
*/
static void bestIndex(
    Parse*, WhereClause*, struct SrcList_item*,
    Bitmask, Bitmask, ExprList*, WhereCost*);

/*
** This routine attempts to find an scanning strategy that can be used 
** to optimize an 'OR' expression that is part of a WHERE clause. 
**
** The table associated with FROM clause term pSrc may be either a
** regular B-Tree table or a virtual table.
*/
static void bestOrClauseIndex(
  Parse *pParse,              /* The parsing context */
  WhereClause *pWC,           /* The WHERE clause */
  struct SrcList_item *pSrc,  /* The FROM clause term to search */
  Bitmask notReady,           /* Mask of cursors not available for indexing */
  Bitmask notValid,           /* Cursors not available for any purpose */
  ExprList *pOrderBy,         /* The ORDER BY clause */
  WhereCost *pCost            /* Lowest cost query plan */
){
#ifndef SQLITE_OMIT_OR_OPTIMIZATION
  const int iCur = pSrc->iCursor;   /* The cursor of the table to be accessed */
  const Bitmask maskSrc = getMask(pWC->pMaskSet, iCur);  /* Bitmask for pSrc */
  WhereTerm * const pWCEnd = &pWC->a[pWC->nTerm];        /* End of pWC->a[] */
................................................................................
      for(pOrTerm=pOrWC->a; pOrTerm<pOrWCEnd; pOrTerm++){
        WhereCost sTermCost;
        WHERETRACE(("... Multi-index OR testing for term %d of %d....\n", 
          (pOrTerm - pOrWC->a), (pTerm - pWC->a)
        ));
        if( pOrTerm->eOperator==WO_AND ){
          WhereClause *pAndWC = &pOrTerm->u.pAndInfo->wc;
          bestIndex(pParse, pAndWC, pSrc, notReady, notValid, 0, &sTermCost);
        }else if( pOrTerm->leftCursor==iCur ){
          WhereClause tempWC;
          tempWC.pParse = pWC->pParse;
          tempWC.pMaskSet = pWC->pMaskSet;
          tempWC.op = TK_AND;
          tempWC.a = pOrTerm;
          tempWC.nTerm = 1;
          bestIndex(pParse, &tempWC, pSrc, notReady, notValid, 0, &sTermCost);
        }else{
          continue;
        }
        rTotal += sTermCost.rCost;
        nRow += sTermCost.nRow;
        used |= sTermCost.used;
        if( rTotal>=pCost->rCost ) break;
................................................................................
** routine takes care of freeing the sqlite3_index_info structure after
** everybody has finished with it.
*/
static void bestVirtualIndex(
  Parse *pParse,                  /* The parsing context */
  WhereClause *pWC,               /* The WHERE clause */
  struct SrcList_item *pSrc,      /* The FROM clause term to search */
  Bitmask notReady,               /* Mask of cursors not available for index */
  Bitmask notValid,               /* Cursors not valid for any purpose */
  ExprList *pOrderBy,             /* The order by clause */
  WhereCost *pCost,               /* Lowest cost query plan */
  sqlite3_index_info **ppIdxInfo  /* Index information passed to xBestIndex */
){
  Table *pTab = pSrc->pTab;
  sqlite3_index_info *pIdxInfo;
  struct sqlite3_index_constraint *pIdxCons;
................................................................................
  }
  pCost->plan.nEq = 0;
  pIdxInfo->nOrderBy = nOrderBy;

  /* Try to find a more efficient access pattern by using multiple indexes
  ** to optimize an OR expression within the WHERE clause. 
  */
  bestOrClauseIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost);
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */

/*
** Argument pIdx is a pointer to an index structure that has an array of
** SQLITE_INDEX_SAMPLES evenly spaced samples of the first indexed column
** stored in Index.aSample. The domain of values stored in said column
................................................................................
** selected plan may still take advantage of the tables built-in rowid
** index.
*/
static void bestBtreeIndex(
  Parse *pParse,              /* The parsing context */
  WhereClause *pWC,           /* The WHERE clause */
  struct SrcList_item *pSrc,  /* The FROM clause term to search */
  Bitmask notReady,           /* Mask of cursors not available for indexing */
  Bitmask notValid,           /* Cursors not available for any purpose */
  ExprList *pOrderBy,         /* The ORDER BY clause */
  WhereCost *pCost            /* Lowest cost query plan */
){
  int iCur = pSrc->iCursor;   /* The cursor of the table to be accessed */
  Index *pProbe;              /* An index we are evaluating */
  Index *pIdx;                /* Copy of pProbe, or zero for IPK index */
  int eqTermMask;             /* Current mask of valid equality operators */
................................................................................
    /* If there are additional constraints on this table that cannot
    ** be used with the current index, but which might lower the number
    ** of output rows, adjust the nRow value accordingly.  This only 
    ** matters if the current index is the least costly, so do not bother
    ** with this step if we already know this index will not be chosen.
    ** Also, never reduce the output row count below 2 using this step.
    **
    ** It is critical that the notValid mask be used here instead of
    ** the notReady mask.  When computing an "optimal" index, the notReady
    ** mask will only have one bit set - the bit for the current table.
    ** The notValid mask, on the other hand, always has all bits set for
    ** tables that are not in outer loops.  If notReady is used here instead
    ** of notValid, then a optimal index that depends on inner joins loops
    ** might be selected even when there exists an optimal index that has
    ** no such dependency.
    */
    if( nRow>2 && cost<=pCost->rCost ){
      int k;                       /* Loop counter */
      int nSkipEq = nEq;           /* Number of == constraints to skip */
      int nSkipRange = nBound;     /* Number of < constraints to skip */
      Bitmask thisTab;             /* Bitmap for pSrc */

      thisTab = getMask(pWC->pMaskSet, iCur);
      for(pTerm=pWC->a, k=pWC->nTerm; nRow>2 && k; k--, pTerm++){
        if( pTerm->wtFlags & TERM_VIRTUAL ) continue;
        if( (pTerm->prereqAll & notValid)!=thisTab ) continue;
        if( pTerm->eOperator & (WO_EQ|WO_IN|WO_ISNULL) ){
          if( nSkipEq ){
            /* Ignore the first nEq equality matches since the index
            ** has already accounted for these */
            nSkipEq--;
          }else{
            /* Assume each additional equality match reduces the result
................................................................................
  );

  WHERETRACE(("best index is: %s\n", 
    ((pCost->plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ? "none" : 
         pCost->plan.u.pIdx ? pCost->plan.u.pIdx->zName : "ipk")
  ));
  
  bestOrClauseIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost);
  bestAutomaticIndex(pParse, pWC, pSrc, notReady, pCost);
  pCost->plan.wsFlags |= eqTermMask;
}

/*
** Find the query plan for accessing table pSrc->pTab. Write the
** best query plan and its cost into the WhereCost object supplied 
................................................................................
** as the last parameter. This function may calculate the cost of
** both real and virtual table scans.
*/
static void bestIndex(
  Parse *pParse,              /* The parsing context */
  WhereClause *pWC,           /* The WHERE clause */
  struct SrcList_item *pSrc,  /* The FROM clause term to search */
  Bitmask notReady,           /* Mask of cursors not available for indexing */
  Bitmask notValid,           /* Cursors not available for any purpose */
  ExprList *pOrderBy,         /* The ORDER BY clause */
  WhereCost *pCost            /* Lowest cost query plan */
){
#ifndef SQLITE_OMIT_VIRTUALTABLE
  if( IsVirtual(pSrc->pTab) ){
    sqlite3_index_info *p = 0;
    bestVirtualIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost,&p);
    if( p->needToFreeIdxStr ){
      sqlite3_free(p->idxStr);
    }
    sqlite3DbFree(pParse->db, p);
  }else
#endif
  {
    bestBtreeIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost);
  }
}

/*
** Disable a term in the WHERE clause.  Except, do not disable the term
** if it controls a LEFT OUTER JOIN and it did not originate in the ON
** or USING clause of that join.
................................................................................
    ** were used as the innermost nested loop.  In other words, a table
    ** is chosen such that the cost of running that table cannot be reduced
    ** by waiting for other tables to run first.  This "optimal" test works
    ** by first assuming that the FROM clause is on the inner loop and finding
    ** its query plan, then checking to see if that query plan uses any
    ** other FROM clause terms that are notReady.  If no notReady terms are
    ** used then the "optimal" query plan works.
    **
    ** Note that the WhereCost.nRow parameter for an optimal scan might
    ** not be as small as it would be if the table really were the innermost
    ** join.  The nRow value can be reduced by WHERE clause constraints
    ** that do not use indices.  But this nRow reduction only happens if the
    ** table really is the innermost join.  
    **
    ** The second loop iteration is only performed if no optimal scan
    ** strategies were found by the first iteration. This second iteration
    ** is used to search for the lowest cost scan overall.
    **
    ** Previous versions of SQLite performed only the second iteration -
    ** the next outermost loop was always that with the lowest overall
    ** cost. However, this meant that SQLite could select the wrong plan
    ** for scripts such as the following:
    **   
    **   CREATE TABLE t1(a, b); 
................................................................................
    ** Since the cost of a linear scan through table t2 is the same 
    ** as the cost of a linear scan through table t1, a simple greedy 
    ** algorithm may choose to use t2 for the outer loop, which is a much
    ** costlier approach.
    */
    nUnconstrained = 0;
    notIndexed = 0;
    for(isOptimal=(iFrom<nTabList-1); isOptimal>=0 && bestJ<0; isOptimal--){
      Bitmask mask;             /* Mask of tables not yet ready */
      for(j=iFrom, pTabItem=&pTabList->a[j]; j<nTabList; j++, pTabItem++){
        int doNotReorder;    /* True if this table should not be reordered */
        WhereCost sCost;     /* Cost information from best[Virtual]Index() */
        ExprList *pOrderBy;  /* ORDER BY clause for index to optimize */
  
        doNotReorder =  (pTabItem->jointype & (JT_LEFT|JT_CROSS))!=0;
................................................................................
        pOrderBy = ((i==0 && ppOrderBy )?*ppOrderBy:0);
        if( pTabItem->pIndex==0 ) nUnconstrained++;
  
        assert( pTabItem->pTab );
#ifndef SQLITE_OMIT_VIRTUALTABLE
        if( IsVirtual(pTabItem->pTab) ){
          sqlite3_index_info **pp = &pWInfo->a[j].pIdxInfo;
          bestVirtualIndex(pParse, pWC, pTabItem, mask, notReady, pOrderBy,
                           &sCost, pp);
        }else 
#endif
        {
          bestBtreeIndex(pParse, pWC, pTabItem, mask, notReady, pOrderBy,
                         &sCost);
        }
        assert( isOptimal || (sCost.used&notReady)==0 );

        /* If an INDEXED BY clause is present, then the plan must use that
        ** index if it uses any index at all */
        assert( pTabItem->pIndex==0 
                  || (sCost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0

Changes to src/sqlite3.h.

105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
**
** See also: [sqlite3_libversion()],
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION        "3.7.3"
#define SQLITE_VERSION_NUMBER 3007003
#define SQLITE_SOURCE_ID      "2010-09-29 23:09:23 1ef0dc9328f47506cb2dcd142150e96cb4755216"

/*
** CAPI3REF: Run-Time Library Version Numbers
** KEYWORDS: sqlite3_version, sqlite3_sourceid
**
** These interfaces provide the same information as the [SQLITE_VERSION],
** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros







|







105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
**
** See also: [sqlite3_libversion()],
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION        "3.7.3"
#define SQLITE_VERSION_NUMBER 3007003
#define SQLITE_SOURCE_ID      "2010-10-04 23:55:51 ece641eb8951c6314cedbdb3243f91cb199c3239"

/*
** CAPI3REF: Run-Time Library Version Numbers
** KEYWORDS: sqlite3_version, sqlite3_sourceid
**
** These interfaces provide the same information as the [SQLITE_VERSION],
** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros

Changes to src/style.c.

197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
@       href="$baseurl/timeline.rss" />
@ <link rel="stylesheet" href="$baseurl/style.css?default" type="text/css"
@       media="screen" />
@ </head>
@ <body>
@ <div class="header">
@   <div class="logo">
@     <img src="$baseurl/logo" alt="logo">
@   </div>
@   <div class="title"><small>$<project_name></small><br />$<title></div>
@   <div class="status"><th1>
@      if {[info exists login]} {
@        puts "Logged in as $login"
@      } else {
@        puts "Not logged in"







|







197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
@       href="$baseurl/timeline.rss" />
@ <link rel="stylesheet" href="$baseurl/style.css?default" type="text/css"
@       media="screen" />
@ </head>
@ <body>
@ <div class="header">
@   <div class="logo">
@     <img src="$baseurl/logo" alt="logo" />
@   </div>
@   <div class="title"><small>$<project_name></small><br />$<title></div>
@   <div class="status"><th1>
@      if {[info exists login]} {
@        puts "Logged in as $login"
@      } else {
@        puts "Not logged in"

Changes to src/timeline.c.

163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
...
286
287
288
289
290
291
292


293
294
295
296
297
298
299
...
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
...
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
...
779
780
781
782
783
784
785

786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
...
810
811
812
813
814
815
816


817
818
819
820
821
822
823
...
924
925
926
927
928
929
930


931

932
933
934
935
936
937
938
939
940
941
942
943
**    2.  Date/Time
**    3.  Comment string
**    4.  User
**    5.  True if is a leaf
**    6.  background color
**    7.  type ("ci", "w", "t")
**    8.  list of symbolic tags.
**    9.  tagid for ticket or wiki
**   10.  Short comment to user for repeated tickets and wiki
*/
void www_print_timeline(
  Stmt *pQuery,          /* Query to implement the timeline */
  int tmFlags,           /* Flags controlling display behavior */
  void (*xExtra)(int)    /* Routine to call on each line of display */
){
................................................................................
                      " WHERE rid=%d AND tagid=%d AND tagtype>0",
                      rid, TAG_CLOSED) ){
          @ <span class="timelineLeaf">Closed-Leaf:</span>
        }else{
          @ <span class="timelineLeaf">Leaf:</span>
        }
      }


    }else if( (tmFlags & TIMELINE_ARTID)!=0 ){
      hyperlink_to_uuid(zUuid);
    }
    db_column_blob(pQuery, commentColumn, &comment);
    if( mxWikiLen>0 && blob_size(&comment)>mxWikiLen ){
      Blob truncated;
      blob_zero(&truncated);
................................................................................
**    c=TIMESTAMP    "circa" this date.
**    n=COUNT        number of events in output
**    p=RID          artifact RID and up to COUNT parents and ancestors
**    d=RID          artifact RID and up to COUNT descendants
**    t=TAGID        show only check-ins with the given tagid
**    r=TAGID        show check-ins related to tagid
**    u=USER         only if belonging to this user
**    y=TYPE         'ci', 'w', 't'
**    s=TEXT         string search (comment and brief)
**    ng             Suppress the graph if present
**
** p= and d= can appear individually or together.  If either p= or d=
** appear, then u=, y=, a=, and b= are ignored.
**
** If a= and b= appear, only a= is used.  If neither appear, the most
................................................................................
      blob_appendf(&desc, " of <a href='%s/info/%s'>[%.10s]</a>",
                   g.zBaseURL, zUuid, zUuid);
    }else{
      blob_appendf(&desc, " of check-in [%.10s]", zUuid);
    }
  }else{
    int n;
    const char *zEType = "event";
    char *zDate;
    char *zNEntry = mprintf("%d", nEntry);
    url_initialize(&url, "timeline");
    url_add_parameter(&url, "n", zNEntry);
    if( tagid>0 ){
      zType = "ci";
      blob_appendf(&sql,
        "AND (EXISTS(SELECT 1 FROM tagxref"
                    " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)", tagid);

      if( zBrName ){
        /* The next two blob_appendf() calls add SQL that causes checkins that
        ** are not part of the branch which are parents or childen of the branch
        ** to be included in the report.  This related check-ins are useful
        ** in helping to visualize what has happened on a quiescent branch 
        ** that is infrequently merged with a much more activate branch.
        */
        url_add_parameter(&url, "r", zBrName);
................................................................................
      }else{
        url_add_parameter(&url, "t", zTagName);
      }
      blob_appendf(&sql, ")");
    }
    if( (zType[0]=='w' && !g.okRdWiki)
     || (zType[0]=='t' && !g.okRdTkt)

     || (zType[0]=='c' && !g.okRead)
    ){
      zType = "all";
    }
    if( zType[0]=='a' ){
      if( !g.okRead || !g.okRdWiki || !g.okRdTkt ){
        char cSep = '(';
        blob_appendf(&sql, " AND event.type IN ");
        if( g.okRead ){
          blob_appendf(&sql, "%c'ci'", cSep);
          cSep = ',';
        }
        if( g.okRdWiki ){
          blob_appendf(&sql, "%c'w'", cSep);
          cSep = ',';
        }
        if( g.okRdTkt ){
          blob_appendf(&sql, "%c't'", cSep);
          cSep = ',';
        }
        blob_appendf(&sql, ")");
................................................................................
      url_add_parameter(&url, "y", zType);
      if( zType[0]=='c' ){
        zEType = "checkin";
      }else if( zType[0]=='w' ){
        zEType = "wiki edit";
      }else if( zType[0]=='t' ){
        zEType = "ticket change";


      }
    }
    if( zUser ){
      blob_appendf(&sql, " AND event.user=%Q", zUser);
      url_add_parameter(&url, "u", zUser);
    }
    if ( zSearch ){
................................................................................
        }
        if( zType[0]!='c' && g.okRead ){
          timeline_submenu(&url, "Checkins Only", "y", "ci", 0);
        }
        if( zType[0]!='t' && g.okRdTkt ){
          timeline_submenu(&url, "Tickets Only", "y", "t", 0);
        }


      }

      if( nEntry>20 ){
        timeline_submenu(&url, "20 Events", "n", "20", 0);
      }
      if( nEntry<200 ){
        timeline_submenu(&url, "200 Events", "n", "200", 0);
      }
    }
  }
  blob_zero(&sql);
  db_prepare(&q, "SELECT * FROM timeline ORDER BY timestamp DESC /*scan*/");
  @ <h2>%b(&desc)</h2>
  blob_reset(&desc);







|







 







>
>







 







|







 







|





|




|







 







>













|







 







>
>







 







>
>
|
>

|


|







163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
...
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
...
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
...
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
...
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
...
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
...
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
**    2.  Date/Time
**    3.  Comment string
**    4.  User
**    5.  True if is a leaf
**    6.  background color
**    7.  type ("ci", "w", "t")
**    8.  list of symbolic tags.
**    9.  tagid for ticket or wiki or event
**   10.  Short comment to user for repeated tickets and wiki
*/
void www_print_timeline(
  Stmt *pQuery,          /* Query to implement the timeline */
  int tmFlags,           /* Flags controlling display behavior */
  void (*xExtra)(int)    /* Routine to call on each line of display */
){
................................................................................
                      " WHERE rid=%d AND tagid=%d AND tagtype>0",
                      rid, TAG_CLOSED) ){
          @ <span class="timelineLeaf">Closed-Leaf:</span>
        }else{
          @ <span class="timelineLeaf">Leaf:</span>
        }
      }
    }else if( zType[0]=='e' && tagid ){
      hyperlink_to_event_tagid(tagid);
    }else if( (tmFlags & TIMELINE_ARTID)!=0 ){
      hyperlink_to_uuid(zUuid);
    }
    db_column_blob(pQuery, commentColumn, &comment);
    if( mxWikiLen>0 && blob_size(&comment)>mxWikiLen ){
      Blob truncated;
      blob_zero(&truncated);
................................................................................
**    c=TIMESTAMP    "circa" this date.
**    n=COUNT        number of events in output
**    p=RID          artifact RID and up to COUNT parents and ancestors
**    d=RID          artifact RID and up to COUNT descendants
**    t=TAGID        show only check-ins with the given tagid
**    r=TAGID        show check-ins related to tagid
**    u=USER         only if belonging to this user
**    y=TYPE         'ci', 'w', 't', 'e'
**    s=TEXT         string search (comment and brief)
**    ng             Suppress the graph if present
**
** p= and d= can appear individually or together.  If either p= or d=
** appear, then u=, y=, a=, and b= are ignored.
**
** If a= and b= appear, only a= is used.  If neither appear, the most
................................................................................
      blob_appendf(&desc, " of <a href='%s/info/%s'>[%.10s]</a>",
                   g.zBaseURL, zUuid, zUuid);
    }else{
      blob_appendf(&desc, " of check-in [%.10s]", zUuid);
    }
  }else{
    int n;
    const char *zEType = "timeline item";
    char *zDate;
    char *zNEntry = mprintf("%d", nEntry);
    url_initialize(&url, "timeline");
    url_add_parameter(&url, "n", zNEntry);
    if( tagid>0 ){
      if( zType[0]!='e' ) zType = "ci";
      blob_appendf(&sql,
        "AND (EXISTS(SELECT 1 FROM tagxref"
                    " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)", tagid);

      if( zBrName && zType[0]=='c' ){
        /* The next two blob_appendf() calls add SQL that causes checkins that
        ** are not part of the branch which are parents or childen of the branch
        ** to be included in the report.  This related check-ins are useful
        ** in helping to visualize what has happened on a quiescent branch 
        ** that is infrequently merged with a much more activate branch.
        */
        url_add_parameter(&url, "r", zBrName);
................................................................................
      }else{
        url_add_parameter(&url, "t", zTagName);
      }
      blob_appendf(&sql, ")");
    }
    if( (zType[0]=='w' && !g.okRdWiki)
     || (zType[0]=='t' && !g.okRdTkt)
     || (zType[0]=='e' && !g.okRdWiki)
     || (zType[0]=='c' && !g.okRead)
    ){
      zType = "all";
    }
    if( zType[0]=='a' ){
      if( !g.okRead || !g.okRdWiki || !g.okRdTkt ){
        char cSep = '(';
        blob_appendf(&sql, " AND event.type IN ");
        if( g.okRead ){
          blob_appendf(&sql, "%c'ci'", cSep);
          cSep = ',';
        }
        if( g.okRdWiki ){
          blob_appendf(&sql, "%c'w','e'", cSep);
          cSep = ',';
        }
        if( g.okRdTkt ){
          blob_appendf(&sql, "%c't'", cSep);
          cSep = ',';
        }
        blob_appendf(&sql, ")");
................................................................................
      url_add_parameter(&url, "y", zType);
      if( zType[0]=='c' ){
        zEType = "checkin";
      }else if( zType[0]=='w' ){
        zEType = "wiki edit";
      }else if( zType[0]=='t' ){
        zEType = "ticket change";
      }else if( zType[0]=='e' ){
        zEType = "event";
      }
    }
    if( zUser ){
      blob_appendf(&sql, " AND event.user=%Q", zUser);
      url_add_parameter(&url, "u", zUser);
    }
    if ( zSearch ){
................................................................................
        }
        if( zType[0]!='c' && g.okRead ){
          timeline_submenu(&url, "Checkins Only", "y", "ci", 0);
        }
        if( zType[0]!='t' && g.okRdTkt ){
          timeline_submenu(&url, "Tickets Only", "y", "t", 0);
        }
        if( zType[0]!='e' && g.okRdWiki ){
          timeline_submenu(&url, "Events Only", "y", "e", 0);
        }
      }
      if( nEntry>20 ){
        timeline_submenu(&url, "20 Entries", "n", "20", 0);
      }
      if( nEntry<200 ){
        timeline_submenu(&url, "200 Entries", "n", "200", 0);
      }
    }
  }
  blob_zero(&sql);
  db_prepare(&q, "SELECT * FROM timeline ORDER BY timestamp DESC /*scan*/");
  @ <h2>%b(&desc)</h2>
  blob_reset(&desc);

Changes to src/wiki.c.

104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
...
151
152
153
154
155
156
157



158
159
160
161
162
163
164
  }
  style_header("Home");
  @ <p>This is a stub home-page for the project.
  @ To fill in this page, first go to
  @ <a href="%s(g.zBaseURL)/setup_config">setup/config</a>
  @ and establish a "Project Name".  Then create a
  @ wiki page with that name.  The content of that wiki page
  @ will be displayed in place of this message.
  style_footer();
}

/*
** Return true if the given pagename is the name of the sandbox
*/
static int is_sandbox(const char *zPagename){
................................................................................
    @      pages. </li>
    @ <li> <a href="%s(g.zBaseURL)/wiki_rules">Formatting rules</a> for 
    @      wiki.</li>
    @ <li> Use the <a href="%s(g.zBaseURL)/wiki?name=Sandbox">Sandbox</a>
    @      to experiment.</li>
    if( g.okNewWiki ){
      @ <li>  Create a <a href="%s(g.zBaseURL)/wikinew">new wiki page</a>.</li>



    }
    @ <li> <a href="%s(g.zBaseURL)/wcontent">List of All Wiki Pages</a>
    @      available on this server.</li>
    @ <li> <form method="get" action="%s(g.zBaseURL)/wfind"><div>
    @     Search wiki titles: <input type="text" name="title"/>
    @  &nbsp; <input type="submit" /></div></form>
    @ </li>







|







 







>
>
>







104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
...
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
  }
  style_header("Home");
  @ <p>This is a stub home-page for the project.
  @ To fill in this page, first go to
  @ <a href="%s(g.zBaseURL)/setup_config">setup/config</a>
  @ and establish a "Project Name".  Then create a
  @ wiki page with that name.  The content of that wiki page
  @ will be displayed in place of this message.</p>
  style_footer();
}

/*
** Return true if the given pagename is the name of the sandbox
*/
static int is_sandbox(const char *zPagename){
................................................................................
    @      pages. </li>
    @ <li> <a href="%s(g.zBaseURL)/wiki_rules">Formatting rules</a> for 
    @      wiki.</li>
    @ <li> Use the <a href="%s(g.zBaseURL)/wiki?name=Sandbox">Sandbox</a>
    @      to experiment.</li>
    if( g.okNewWiki ){
      @ <li>  Create a <a href="%s(g.zBaseURL)/wikinew">new wiki page</a>.</li>
      if( g.okWrite ){
        @ <li>   Create a <a href="%s(g.zTop)/eventedit">new event</a>.</li>
      }
    }
    @ <li> <a href="%s(g.zBaseURL)/wcontent">List of All Wiki Pages</a>
    @      available on this server.</li>
    @ <li> <form method="get" action="%s(g.zBaseURL)/wfind"><div>
    @     Search wiki titles: <input type="text" name="title"/>
    @  &nbsp; <input type="submit" /></div></form>
    @ </li>

Changes to src/xfer.c.

117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135


136
137
138
139
140
141
142
  blob_zero(&hash);
  blob_extract(pXfer->pIn, n, &content);
  if( uuid_is_shunned(blob_str(&pXfer->aToken[1])) ){
    /* Ignore files that have been shunned */
    return;
  }
  if( pXfer->nToken==4 ){
    Blob src;
    srcid = rid_from_uuid(&pXfer->aToken[2], 1);
    if( content_get(srcid, &src)==0 ){
      rid = content_put(&content, blob_str(&pXfer->aToken[1]), srcid);
      pXfer->nDanglingFile++;
      db_multi_exec("DELETE FROM phantom WHERE rid=%d", rid);
      content_make_public(rid);
      return;
    }
    pXfer->nDeltaRcvd++;
    blob_delta_apply(&src, &content, &content);
    blob_reset(&src);


  }else{
    pXfer->nFileRcvd++;
  }
  sha1sum_blob(&content, &hash);
  if( !blob_eq_str(&pXfer->aToken[1], blob_str(&hash), -1) ){
    blob_appendf(&pXfer->err, "content does not match sha1 hash");
  }







|









|

>
>







117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
  blob_zero(&hash);
  blob_extract(pXfer->pIn, n, &content);
  if( uuid_is_shunned(blob_str(&pXfer->aToken[1])) ){
    /* Ignore files that have been shunned */
    return;
  }
  if( pXfer->nToken==4 ){
    Blob src, next;
    srcid = rid_from_uuid(&pXfer->aToken[2], 1);
    if( content_get(srcid, &src)==0 ){
      rid = content_put(&content, blob_str(&pXfer->aToken[1]), srcid);
      pXfer->nDanglingFile++;
      db_multi_exec("DELETE FROM phantom WHERE rid=%d", rid);
      content_make_public(rid);
      return;
    }
    pXfer->nDeltaRcvd++;
    blob_delta_apply(&src, &content, &next);
    blob_reset(&src);
    blob_reset(&content);
    content = next;
  }else{
    pXfer->nFileRcvd++;
  }
  sha1sum_blob(&content, &hash);
  if( !blob_eq_str(&pXfer->aToken[1], blob_str(&hash), -1) ){
    blob_appendf(&pXfer->err, "content does not match sha1 hash");
  }

Changes to www/branching.wiki.

153
154
155
156
157
158
159

160
161
162
163
164
165
166
concerned, there is no difference.  The distinction is in the intent.
In figure 2, the fact that check-in 2 has multiple children is an
accident that stems from concurrent development.  In figure 4, giving
check-in 2 multiple children is a deliberate act.  So, to a good
approximation, we define forking to be by accident and branching to
be by intent.  Apart from that, they are the same.


<h2>Tags And Properties</h2>

Tags and properties are used in fossil to help express the intent, and
thus to distinguish between forks and branches.  Figure 5 shows the
same scenario as figure 4 but with tags and properties added:

<center><table border=1 cellpadding=10 hspace=10 vspace=10>







>







153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
concerned, there is no difference.  The distinction is in the intent.
In figure 2, the fact that check-in 2 has multiple children is an
accident that stems from concurrent development.  In figure 4, giving
check-in 2 multiple children is a deliberate act.  So, to a good
approximation, we define forking to be by accident and branching to
be by intent.  Apart from that, they are the same.

<a name="tags"></a>
<h2>Tags And Properties</h2>

Tags and properties are used in fossil to help express the intent, and
thus to distinguish between forks and branches.  Figure 5 shows the
same scenario as figure 4 but with tags and properties added:

<center><table border=1 cellpadding=10 hspace=10 vspace=10>

Added www/event.wiki.























































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
<title>Events</title>

<h2>What Is An "Event"?</h2>

In Fossil, and "event" is a special kind of [./wikitheory.wiki | wiki page]
that is associated with a point in time rather than having a page name.
Each event causes a single entry to appear on the [/timeline | Timeline Page].
Clicking on the hyperlink of the timeline entry cause a jump to the wiki
content for the event.  The wiki content, the timeline entry text, the
time of the event, and the timeline background color can all be edited.

As with check-ins, wiki, and tickets, all events automatically synchronize
to other repositories.  Hence, events can be viewed, created, and edited
off-line.  And the complete edit history for events is maintained
for auditing purposes.

Possible uses for events include:

  *  <b>Milestones</b>.  Project milestones, such as releases or beta-test
      cycles, can be recorded as events.  The timeline entry for the event
      can be something simple like "Version 1.2.3" perhaps with a bright
      color background to draw attention to the entry and the wiki content
      can contain release notes, for example.

  *  <b>Blog Entries</b>.  Blog entries from developers describing the current
     state of a project, or rational for various design decisions, or 
     roadmaps for future development, can be entered as events.

  *  <b>Process Checkpoints</b>.  For projects that have a formal process,
     events can be used to record the completion or the initiation of
     various process steps.  For example, an event can be used to record
     the successful completion of a long-running test, perhaps with
     performance results and details of where the test was run and who
     ran it recorded in the wiki content.

  *  <b>News Articles</b>.  Significant occurrences in the lifecycle of
     a project can be recorded as news articles using events.  Perhaps the
     domain name of the canonical website for a project changes, or new
     server hardware is obtained.  Such happenings are appropriate for
     reporting as news.

  *  <b>Announcements</b>.  Changes to the composition of the development
     team or acquisition of new project sponsors can be communicated as
     announcements which can be implemented as events.

No project is required to use events.  But events can help many projects
stay better organized and provide a better historical record of the
development progress.

<h2>Viewing Events</h2>

Because events are considered a special kind of wiki, 
users must have permission to read wiki in order read events.
Enable the "j" permission under the /Setup/Users menu in order
to give specific users or user classes the ability to view wiki
and events.

Events show up on the timeline.  Click on the hyperlink beside the
event title to see the details of the event.

<h2>Creating And Editing Events</h2>

There is a hyperlink under the /Wiki menu that can be used to create
new events.  And there is a submenu hyperlink on event displays for
editing existing events.

Users must have check-in privileges (permission "i") in order to 
create or edit events.  In addition, users must have create-wiki
privilege (permission "f") to create new events and edit-wiki
privilege (permission "k") in order to edit existing events.

If the first non-whitespace text of the event wiki content is
&lt;title&gt;...&lt;/title&gt; then that markup is omitted from
the body of the wiki pages and is instead displayed as the page
title.

Changes to www/fileformat.wiki.

41
42
43
44
45
46
47

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



61
62
63
64
65
66
67
...
163
164
165
166
167
168
169
170

171
172
173
174
175
176
177
178
...
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
...
260
261
262
263
264
265
266

267
268
269
270
271
272
273
274
...
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
...
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
...
403
404
405
406
407
408
409
410






























































411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428

429
430
431
432
433
434
435
436
437

438
439
440
441
442
443
444
445

446
447
448
449
450
451
452
453
454
455











456
457
458
459

460
461
462
463
464
465
466
...
467
468
469
470
471
472
473

474
475
476
477
478
479
480
481

482
483
484
485
486
487
488
489
490
491

492
493
494
495
496

497
498
499
500
501
502
503
504
505
506
507
508
509

510
511
512
513

514
515
516
517
518
519
520
521
522
523
524
525
526

527
528
529
530
531

532
533
534
535
536
537
538
539
540
541
542
543
544

545
546
547

548
549
550
551
552
553
554
555
<ul>
<li> [#manifest | Manifests] </li>
<li> [#cluster | Clusters] </li>
<li> [#ctrl | Control Artifacts] </li>
<li> [#wikichng | Wiki Pages] </li>
<li> [#tktchng | Ticket Changes] </li>
<li> [#attachment | Attachments] </li>

</ul>

These five artifact types are described in the sequel.

In the current implementation (as of 2009-01-25) the artifacts that
make up a fossil repository are stored in in as delta- and zlib-compressed
blobs in an <a href="http://www.sqlite.org/">SQLite</a> database.  This
is an implementation detail and might change in a future release.  For
the purpose of this article "file format" means the format of the artifacts,
not how the artifacts are stored on disk.  It is the artifact format that
is intended to be enduring.  The specifics of how artifacts are stored on
disk, though stable, is not intended to live as long as the
artifact format.




<a name="manifest"></a>
<h2>1.0 The Manifest</h2>

A manifest defines a check-in or version of the project
source tree.  The manifest contains a list of artifacts for
each file in the project and the corresponding filenames, as
................................................................................
the manifest itself) in strict sorted lexicographical order, 
take the pathname of the file relative to the root of the
repository, append a single space (ASCII 0x20), the
size of the file in ASCII decimal, a single newline
character (ASCII 0x0A), and the complete text of the file.
Compute the MD5 checksum of the result.

A manifest might contain one or more T-cards used to set tags or

properties on the check-in.  The format of the T-card is the same as
described in <i>Control Artifacts</i> section below, except that the
second argument is the single characcter "<b>*</b>" instead of an
artifact ID.  The <b>*</b> in place of the artifact ID indicates that
the tag or property applies to the current artifact.  It is not
possible to encode the current artifact ID as part of an artifact,
since the act of inserting the artifact ID would change the artifact ID,
hence a <b>*</b> is used to represent "self".  T-cards are typically
................................................................................
symbolic name when the check-in is intended to start a new branch.

Each manifest has a single U-card.  The argument to the U-card is
the login of the user who created the manifest.  The login name
is encoded using the same character escapes as is used for the
check-in comment argument to the C-card.

A manifest has an option Z-card as its last line.  The argument
to the Z-card is a 32-character lowercase hexadecimal MD5 hash
of all prior lines of the manifest up to and including the newline 
character that immediately precedes the "Z".  The Z-card is just
a sanity check to prove that the manifest is well-formed and
consistent.

A sample manifest from Fossil itself can be seen
................................................................................
one or more T cards.  No other cards or other text is
allowed in a control artifact.  Control artifacts might be PGP
clearsigned.

The D card and the Z card of a control artifact are the same
as in a manifest.


The T card represents a "tag" or property that is applied to
some other artifact.  The T card has two or three values.  The
second argument is the 40 character lowercase artifact ID of the artifact
to which the tag is to be applied. The
first value is the tag name.  The first character of the tag
is either "+", "-", or "*".  A "+" means the tag should be added
to the artifact.  The "-" means the tag should be removed.
The "*" character means the tag should be added to the artifact
................................................................................
The W card is used to specify the text of the wiki page.  The
argument to the W card is an integer which is the number of bytes
of text in the wiki page.  That text follows the newline character
that terminates the W card.  The wiki text is always followed by one
extra newline.

An example wiki artifact can be seen
[/artifact/7b2f5fd0e0 | here].

<a name="tktchng"></a>
<h2>5.0 Ticket Changes</h2>

A ticket-change artifact represents a change to a trouble ticket.
The following cards are allowed on a ticket change artifact:

................................................................................
An example ticket-change artifact can be seen
[/artifact/91f1ec6af053 | here].

<a name="attachment"></a>
<h2>6.0 Attachments</h2>

An attachment artifact associates some other artifact that is the
attachment (the source artifact) with a ticket or wiki page to which
the attachment is connected (the target artifact).
The following cards are allowed on an attachment artifact:

<blockquote>
<b>A</b> <i>filename target</i> ?<i>source</i>?
<b>C</b> <i>comment</i><br>
<b>D</b> <i>time-and-date-stamp</i><br />
<b>U</b> <i>user-name</i><br />
<b>Z</b> <i>checksum</i>
</blockquote>

The A card specifies a filename for the attachment in its first argument.
The second argument to the A card is the name
of the wiki page or ticket to which the attachment is connected.  The
third argument is either missing or else it is the 40-character artifact 
ID of the attachment itself.  A missing third argument means that the
attachment should be deleted.

The C card is an optional comment describing what the attachment is about.
The C card is optional, but there can only be one.

................................................................................
was applied.

A single U card gives the name of the user to added the attachment.
If an attachment is added anonymously, then the U card may be omitted.

The Z card is the usual checksum over the rest of the attachment artifact.
































































<a name="summary"></a>
<h2>7.0 Card Summary</h2>

The following table summaries the various kinds of cards that
appear on Fossil artifacts:

<table border=1 width="100%">
<tr>
<th rowspan=2 valign=bottom>Card Format</th>
<th colspan=6>Used By</th>
</tr>
<tr>
<th>Manifest</th>
<th>Cluster</th>
<th>Control</th>
<th>Wiki</th>
<th>Ticket</th>
<th>Attachment</th>

</tr>
<tr>
<td><b>A</b> <i>filename target source</i></td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td align=center><b>X</b></td>

</tr>
<tr>
<td><b>C</b> <i>coment-text</i></td>
<td align=center><b>X</b></td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>

<td align=center><b>X</b></td>
</tr>
<tr>
<td><b>D</b> <i>date-time-stamp</i></td>
<td align=center><b>X</b></td>
<td align=center>&nbsp;</td>
<td align=center><b>X</b></td>
<td align=center><b>X</b></td>
<td align=center><b>X</b></td>
<td align=center><b>X</b></td>











</tr>
<tr>
<td><b>F</b> <i>filename uuid permissions oldname</i></td>
<td align=center><b>X</b></td>

<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
</tr>
<tr>
................................................................................
<td><b>J</b> <i>name value</i></td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center><b>X</b></td>
<td align=center>&nbsp;</td>

</tr>
<tr>
<td><b>K</b> <i>ticket-uuid</i></td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center><b>X</b></td>

<td align=center>&nbsp;</td>
</tr>
<tr>
<td><b>L</b> <i>wiki-title</i></td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center><b>X</b></td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>

</tr>
<tr>
<td><b>M</b> <i>uuid</i></td>
<td align=center>&nbsp;</td>
<td align=center><b>X</b></td>

<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
</tr>
<tr>
<td><b>P</b> <i>uuid ...</i></td>
<td align=center><b>X</b></td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center><b>X</b></td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>

</tr>
<tr>
<td><b>R</b> <i>md5sum</i></td>
<td align=center><b>X</b></td>

<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<tr>
<td><b>T</b> (<b>+</b>|<b>*</b>|<b>-</b>)<i>tagname uuid value</i></td>
<td align=center><b>X</b></td>
<td align=center>&nbsp;</td>
<td align=center><b>X</b></td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>

</tr>
<tr>
<td><b>U</b> <i>username</i></td>
<td align=center><b>X</b></td>
<td align=center>&nbsp;</td>

<td align=center><b>X</b></td>
<td align=center><b>X</b></td>
<td align=center><b>X</b></td>
<td align=center><b>X</b></td>
</tr>
<tr>
<td><b>W</b> <i>size</i></td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center><b>X</b></td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>

</tr>
<tr>
<td><b>Z</b> <i>md5sum</i></td>

<td align=center><b>X</b></td>
<td align=center><b>X</b></td>
<td align=center><b>X</b></td>
<td align=center><b>X</b></td>
<td align=center><b>X</b></td>
<td align=center><b>X</b></td>
</tr>
</table>







>


|










>
>
>







 







|
>
|







 







|







 







>
|







 







|







 







|




|
|







|







 








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

|







|








>









>


|





>










>
>
>
>
>
>
>
>
>
>
>




>







 







>








>










>





>













>




>













>





>













>



>








41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
...
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
...
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
...
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
...
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
...
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
...
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
...
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
<ul>
<li> [#manifest | Manifests] </li>
<li> [#cluster | Clusters] </li>
<li> [#ctrl | Control Artifacts] </li>
<li> [#wikichng | Wiki Pages] </li>
<li> [#tktchng | Ticket Changes] </li>
<li> [#attachment | Attachments] </li>
<li> [#event | Events] </li>
</ul>

These seven artifact types are described in the sequel.

In the current implementation (as of 2009-01-25) the artifacts that
make up a fossil repository are stored in in as delta- and zlib-compressed
blobs in an <a href="http://www.sqlite.org/">SQLite</a> database.  This
is an implementation detail and might change in a future release.  For
the purpose of this article "file format" means the format of the artifacts,
not how the artifacts are stored on disk.  It is the artifact format that
is intended to be enduring.  The specifics of how artifacts are stored on
disk, though stable, is not intended to live as long as the
artifact format.

All of the artifacts can be extracted from a Fossil repository using
the "fossil deconstruct" command.

<a name="manifest"></a>
<h2>1.0 The Manifest</h2>

A manifest defines a check-in or version of the project
source tree.  The manifest contains a list of artifacts for
each file in the project and the corresponding filenames, as
................................................................................
the manifest itself) in strict sorted lexicographical order, 
take the pathname of the file relative to the root of the
repository, append a single space (ASCII 0x20), the
size of the file in ASCII decimal, a single newline
character (ASCII 0x0A), and the complete text of the file.
Compute the MD5 checksum of the result.

A manifest might contain one or more T-cards used to set
[./branching.wiki#tags | tags or properties]
on the check-in.  The format of the T-card is the same as
described in <i>Control Artifacts</i> section below, except that the
second argument is the single characcter "<b>*</b>" instead of an
artifact ID.  The <b>*</b> in place of the artifact ID indicates that
the tag or property applies to the current artifact.  It is not
possible to encode the current artifact ID as part of an artifact,
since the act of inserting the artifact ID would change the artifact ID,
hence a <b>*</b> is used to represent "self".  T-cards are typically
................................................................................
symbolic name when the check-in is intended to start a new branch.

Each manifest has a single U-card.  The argument to the U-card is
the login of the user who created the manifest.  The login name
is encoded using the same character escapes as is used for the
check-in comment argument to the C-card.

A manifest has an optional Z-card as its last line.  The argument
to the Z-card is a 32-character lowercase hexadecimal MD5 hash
of all prior lines of the manifest up to and including the newline 
character that immediately precedes the "Z".  The Z-card is just
a sanity check to prove that the manifest is well-formed and
consistent.

A sample manifest from Fossil itself can be seen
................................................................................
one or more T cards.  No other cards or other text is
allowed in a control artifact.  Control artifacts might be PGP
clearsigned.

The D card and the Z card of a control artifact are the same
as in a manifest.

The T card represents a [./branching.wiki#tags | tag or property]
that is applied to
some other artifact.  The T card has two or three values.  The
second argument is the 40 character lowercase artifact ID of the artifact
to which the tag is to be applied. The
first value is the tag name.  The first character of the tag
is either "+", "-", or "*".  A "+" means the tag should be added
to the artifact.  The "-" means the tag should be removed.
The "*" character means the tag should be added to the artifact
................................................................................
The W card is used to specify the text of the wiki page.  The
argument to the W card is an integer which is the number of bytes
of text in the wiki page.  That text follows the newline character
that terminates the W card.  The wiki text is always followed by one
extra newline.

An example wiki artifact can be seen
[/artifact?name=7b2f5fd0e0&txt=1 | here].

<a name="tktchng"></a>
<h2>5.0 Ticket Changes</h2>

A ticket-change artifact represents a change to a trouble ticket.
The following cards are allowed on a ticket change artifact:

................................................................................
An example ticket-change artifact can be seen
[/artifact/91f1ec6af053 | here].

<a name="attachment"></a>
<h2>6.0 Attachments</h2>

An attachment artifact associates some other artifact that is the
attachment (the source artifact) with a ticket or wiki page or event to which
the attachment is connected (the target artifact).
The following cards are allowed on an attachment artifact:

<blockquote>
<b>A</b> <i>filename target</i> ?<i>source</i>?<br />
<b>C</b> <i>comment</i><br />
<b>D</b> <i>time-and-date-stamp</i><br />
<b>U</b> <i>user-name</i><br />
<b>Z</b> <i>checksum</i>
</blockquote>

The A card specifies a filename for the attachment in its first argument.
The second argument to the A card is the name
of the wiki page or ticket or event to which the attachment is connected.  The
third argument is either missing or else it is the 40-character artifact 
ID of the attachment itself.  A missing third argument means that the
attachment should be deleted.

The C card is an optional comment describing what the attachment is about.
The C card is optional, but there can only be one.

................................................................................
was applied.

A single U card gives the name of the user to added the attachment.
If an attachment is added anonymously, then the U card may be omitted.

The Z card is the usual checksum over the rest of the attachment artifact.


<a name="event"></a>
<h2>7.0 Events</h2>

An event artifact associates a timeline comment and a page of text
(similar to a wiki page) with a point in time.  Events can be used
to record project milestones, release notes, blog entries, process
checkpoints, or news articles.
The following cards are allowed on an event artifact:

<blockquote>
<b>C</b> <i>comment</i><br>
<b>D</b> <i>time-and-date-stamp</i><br />
<b>E</b> <i>event-time</i> <i>event-id</i><br />
<b>P</b> <i>parent-artifact-id</i>+<br />
<b>T</b> <b>+</b><i>tag-name</i> <b>*</b> <i>value</i><br />
<b>U</b> <i>user-name</i><br />
<b>W</b> <i>size</i> <b>\n</b> <i>text</i> <b>\n</b><br />
<b>Z</b> <i>checksum</i>
</blockquote>

The C card contains text that is displayed on the timeline for the
event.  Exactly one C card is required on an event artifact.

A single D card is required to give the date and time when the 
event artifact was created.  This is different from the time at which
the event occurs.

A single E card gives the time of the event (the point on the timeline
where the event is displayed) and a unique identifier for the event.
When there are multiple artifacts with the same event-id, the one with
the most recent D card is the only one used.  The event-id must be a
40-character lower-case hexadecimal string.

The option P card specifies a prior event with the same event-id from
which the current event is an edit.  The P card is a hint to the system
that it might be space efficient to store one event as a delta of the
other.

An event might contain one or more T-cards used to set
[./branching.wiki#tags | tags or properties]
on the event.  The format of the T-card is the same as
described in [#ctrl | Control Artifacts] section above, except that the
second argument is the single characcter "<b>*</b>" instead of an
artifact ID and the name is always prefaced by "<b>+</b>".
The <b>*</b> in place of the artifact ID indicates that
the tag or property applies to the current artifact.  It is not
possible to encode the current artifact ID as part of an artifact,
since the act of inserting the artifact ID would change the artifact ID,
hence a <b>*</b> is used to represent "self".  The "<b>+</b>" on the
name means that tags can only be add and they can only be non-propagating
tags.  A an event, T cards are normally used to set the background
display color for timelines.

The optional U card gives name of the user who entered the event.

A single W card provides wiki text for the document associated with the
event.  The format of the W card is exactly the same as for a 
[#wikichng | wiki artifact].

The Z card is the usual checksum over the rest of the attachment artifact.


<a name="summary"></a>
<h2>8.0 Card Summary</h2>

The following table summaries the various kinds of cards that
appear on Fossil artifacts:

<table border=1 width="100%">
<tr>
<th rowspan=2 valign=bottom>Card Format</th>
<th colspan=7>Used By</th>
</tr>
<tr>
<th>Manifest</th>
<th>Cluster</th>
<th>Control</th>
<th>Wiki</th>
<th>Ticket</th>
<th>Attachment</th>
<th>Event</th>
</tr>
<tr>
<td><b>A</b> <i>filename target source</i></td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td align=center><b>X</b></td>
<td>&nbsp;</td>
</tr>
<tr>
<td><b>C</b> <i>comment-text</i></td>
<td align=center><b>X</b></td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td align=center><b>X</b></td>
<td align=center><b>X</b></td>
</tr>
<tr>
<td><b>D</b> <i>date-time-stamp</i></td>
<td align=center><b>X</b></td>
<td align=center>&nbsp;</td>
<td align=center><b>X</b></td>
<td align=center><b>X</b></td>
<td align=center><b>X</b></td>
<td align=center><b>X</b></td>
<td align=center><b>X</b></td>
</tr>
<tr>
<td><b>E</b> <i>event-time event-id</i></td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center><b>X</b></td>
</tr>
<tr>
<td><b>F</b> <i>filename uuid permissions oldname</i></td>
<td align=center><b>X</b></td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
</tr>
<tr>
................................................................................
<td><b>J</b> <i>name value</i></td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center><b>X</b></td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
</tr>
<tr>
<td><b>K</b> <i>ticket-uuid</i></td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center><b>X</b></td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
</tr>
<tr>
<td><b>L</b> <i>wiki-title</i></td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center><b>X</b></td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
</tr>
<tr>
<td><b>M</b> <i>uuid</i></td>
<td align=center>&nbsp;</td>
<td align=center><b>X</b></td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
</tr>
<tr>
<td><b>P</b> <i>uuid ...</i></td>
<td align=center><b>X</b></td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center><b>X</b></td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
</tr>
<tr>
<td><b>R</b> <i>md5sum</i></td>
<td align=center><b>X</b></td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<tr>
<td><b>T</b> (<b>+</b>|<b>*</b>|<b>-</b>)<i>tagname uuid value</i></td>
<td align=center><b>X</b></td>
<td align=center>&nbsp;</td>
<td align=center><b>X</b></td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center><b>X</b></td>
</tr>
<tr>
<td><b>U</b> <i>username</i></td>
<td align=center><b>X</b></td>
<td align=center>&nbsp;</td>
<td align=center><b>X</b></td>
<td align=center><b>X</b></td>
<td align=center><b>X</b></td>
<td align=center><b>X</b></td>
<td align=center><b>X</b></td>
</tr>
<tr>
<td><b>W</b> <i>size</i></td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center><b>X</b></td>
<td align=center>&nbsp;</td>
<td align=center>&nbsp;</td>
<td align=center><b>X</b></td>
</tr>
<tr>
<td><b>Z</b> <i>md5sum</i></td>
<td align=center><b>X</b></td>
<td align=center><b>X</b></td>
<td align=center><b>X</b></td>
<td align=center><b>X</b></td>
<td align=center><b>X</b></td>
<td align=center><b>X</b></td>
<td align=center><b>X</b></td>
</tr>
</table>

Changes to www/index.wiki.

38
39
40
41
42
43
44
45
46

47
48
49
50
51
52
53
...
109
110
111
112
113
114
115


116
117
118
119
120
121
122

There are plenty of open-source version control systems available on the
internet these days. What makes Fossil worthy of attention?

  1.  <b>Bug Tracking And Wiki</b> -
      In addition to doing [./concepts.wiki | distributed version control]
      like Git and Mercurial,
      Fossil also supports [./bugtheory.wiki | distributed bug tracking] and
      [./wikitheory.wiki | distributed wiki] all in a single

      integrated package.

  2.  <b>Web Interface</b> - 
      Fossil has a built-in and easy-to-use [./webui.wiki | web interface]
      that simplifies project tracking and promotes situational awareness.
      Simply type "fossil&nbsp;ui" from within any check-out and Fossil
      automatically opens your web browser in a page that gives detailed
................................................................................
     designed to be readable, searchable, and extensible by people
     not yet born.
  *  A tutorial on [./branching.wiki | branching], what it means and how
     to do it using fossil.
  *  The [./selfcheck.wiki | automatic self-check] mechanism
     helps insure project integrity.
  *  Fossil contains a [./wikitheory.wiki | built-in wiki].


  *  There is a
    [http://lists.fossil-scm.org:8080/cgi-bin/mailman/listinfo/fossil-users | mailing list] (with publicly readable
     [http://www.mail-archive.com/fossil-users@lists.fossil-scm.org | archives]
     available for discussing fossil issues.
  *  [./stats.wiki | Performance statistics] taken from real-world projects
     hosted on fossil.
  *  How to [./shunning.wiki | delete content] from a fossil repository.







|
|
>







 







>
>







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
...
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125

There are plenty of open-source version control systems available on the
internet these days. What makes Fossil worthy of attention?

  1.  <b>Bug Tracking And Wiki</b> -
      In addition to doing [./concepts.wiki | distributed version control]
      like Git and Mercurial,
      Fossil also supports [./bugtheory.wiki | distributed bug tracking],
      [./wikitheory.wiki | distributed wiki], and a
      [./event.wiki | distributed blog] mechanism all in a single
      integrated package.

  2.  <b>Web Interface</b> - 
      Fossil has a built-in and easy-to-use [./webui.wiki | web interface]
      that simplifies project tracking and promotes situational awareness.
      Simply type "fossil&nbsp;ui" from within any check-out and Fossil
      automatically opens your web browser in a page that gives detailed
................................................................................
     designed to be readable, searchable, and extensible by people
     not yet born.
  *  A tutorial on [./branching.wiki | branching], what it means and how
     to do it using fossil.
  *  The [./selfcheck.wiki | automatic self-check] mechanism
     helps insure project integrity.
  *  Fossil contains a [./wikitheory.wiki | built-in wiki].
  *  An [./event.wiki | Event] is a special kind of wiki page associated
     with a point in time rather than a name.
  *  There is a
    [http://lists.fossil-scm.org:8080/cgi-bin/mailman/listinfo/fossil-users | mailing list] (with publicly readable
     [http://www.mail-archive.com/fossil-users@lists.fossil-scm.org | archives]
     available for discussing fossil issues.
  *  [./stats.wiki | Performance statistics] taken from real-world projects
     hosted on fossil.
  *  How to [./shunning.wiki | delete content] from a fossil repository.

Changes to www/qandc.wiki.

61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
fossil repository <a href="http://www.sqlite.org/docsrc/">here</a>,
for example.
Other projects are also adopting fossil.  But fossil does not yet have
the massive user base of git or mercurial.
</blockquote>

<b>Fossil looks like the bug tracker that would be in your 
Linksys Router's administration screen.</p>

<blockquote>
<p>I take a pragmatic approach to software: form follows function.
To me, it is more important to have a reliable, fast, efficient,
enduring, and simple DVCS than one that looks pretty.</p>

<p>On the other hand, if you have patches that improve the appearance







|







61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
fossil repository <a href="http://www.sqlite.org/docsrc/">here</a>,
for example.
Other projects are also adopting fossil.  But fossil does not yet have
the massive user base of git or mercurial.
</blockquote>

<b>Fossil looks like the bug tracker that would be in your 
Linksys Router's administration screen.</b>

<blockquote>
<p>I take a pragmatic approach to software: form follows function.
To me, it is more important to have a reliable, fast, efficient,
enduring, and simple DVCS than one that looks pretty.</p>

<p>On the other hand, if you have patches that improve the appearance

Changes to www/wikitheory.wiki.

3
4
5
6
7
8
9

10
11
12
13
14
15
16
Fossil uses [/wiki_rules | wiki markup] for many things:

   *  Stand-alone wiki pages.
   *  Description and comments in [./bugtheory.wiki | bug reports].
   *  Check-in comments.
   *  [./embeddeddoc.wiki | Embedded documentation] files whose
      name ends in "wiki".


The [/wiki_rules | formatting rules] for fossil wiki
are designed to be simple and intuitive.  The idea is that wiki provides
paragraph breaks, numbered and bulleted lists, and hyperlinking for
simple documents together with a safe subset of HTML for more complex
formatting tasks.








>







3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Fossil uses [/wiki_rules | wiki markup] for many things:

   *  Stand-alone wiki pages.
   *  Description and comments in [./bugtheory.wiki | bug reports].
   *  Check-in comments.
   *  [./embeddeddoc.wiki | Embedded documentation] files whose
      name ends in "wiki".
   *  [./event.wiki | Event descriptions].

The [/wiki_rules | formatting rules] for fossil wiki
are designed to be simple and intuitive.  The idea is that wiki provides
paragraph breaks, numbered and bulleted lists, and hyperlinking for
simple documents together with a safe subset of HTML for more complex
formatting tasks.