Fossil SCM
merge from trunk and extending Makefile.dmc with event
Commit
a6dd0bf3e1f1417321dd0bf0886652c108dda400
Parent
f3f7f138154aef2…
25 files changed
+1
-1
+1
-1
+160
-142
+2
+89
-66
+12
-2
+1
+99
-7
+3
-3
+72
-66
+223
-268
+1
-1
+1
-1
+16
-8
+7
-3
+4
-2
+1
-1
+10
-4
+10
-4
+1
+35
+106
-13
+5
-2
+1
-1
+1
~
src/attach.c
~
src/blob.c
~
src/content.c
~
src/event.c
~
src/info.c
~
src/main.mk
~
src/makemake.tcl
~
src/manifest.c
~
src/printf.c
~
src/rebuild.c
~
src/sqlite3.c
~
src/sqlite3.h
~
src/style.c
~
src/timeline.c
~
src/wiki.c
~
src/xfer.c
~
win/Makefile.PellesCGMake
~
win/Makefile.dmc
~
win/Makefile.dmc
~
www/branching.wiki
~
www/event.wiki
~
www/fileformat.wiki
~
www/index.wiki
~
www/qandc.wiki
~
www/wikitheory.wiki
+1
-1
| --- src/attach.c | ||
| +++ src/attach.c | ||
| @@ -351,11 +351,11 @@ | ||
| 351 | 351 | cgi_redirect(zFrom); |
| 352 | 352 | } |
| 353 | 353 | style_header("Delete Attachment"); |
| 354 | 354 | @ <form action="%s(g.zBaseURL)/attachdelete" method="post"><div> |
| 355 | 355 | @ <p>Confirm that you want to delete the attachment named |
| 356 | - @ "%h(zFile)" on %s(zTkt?"ticket":"wiki page") %h(zTarget):<br /> | |
| 356 | + @ "%h(zFile)" on %s(zTkt?"ticket":"wiki page") %h(zTarget):<br /></p> | |
| 357 | 357 | if( zTkt ){ |
| 358 | 358 | @ <input type="hidden" name="tkt" value="%h(zTkt)" /> |
| 359 | 359 | }else{ |
| 360 | 360 | @ <input type="hidden" name="page" value="%h(zPage)" /> |
| 361 | 361 | } |
| 362 | 362 |
| --- src/attach.c | |
| +++ src/attach.c | |
| @@ -351,11 +351,11 @@ | |
| 351 | cgi_redirect(zFrom); |
| 352 | } |
| 353 | style_header("Delete Attachment"); |
| 354 | @ <form action="%s(g.zBaseURL)/attachdelete" method="post"><div> |
| 355 | @ <p>Confirm that you want to delete the attachment named |
| 356 | @ "%h(zFile)" on %s(zTkt?"ticket":"wiki page") %h(zTarget):<br /> |
| 357 | if( zTkt ){ |
| 358 | @ <input type="hidden" name="tkt" value="%h(zTkt)" /> |
| 359 | }else{ |
| 360 | @ <input type="hidden" name="page" value="%h(zPage)" /> |
| 361 | } |
| 362 |
| --- src/attach.c | |
| +++ src/attach.c | |
| @@ -351,11 +351,11 @@ | |
| 351 | cgi_redirect(zFrom); |
| 352 | } |
| 353 | style_header("Delete Attachment"); |
| 354 | @ <form action="%s(g.zBaseURL)/attachdelete" method="post"><div> |
| 355 | @ <p>Confirm that you want to delete the attachment named |
| 356 | @ "%h(zFile)" on %s(zTkt?"ticket":"wiki page") %h(zTarget):<br /></p> |
| 357 | if( zTkt ){ |
| 358 | @ <input type="hidden" name="tkt" value="%h(zTkt)" /> |
| 359 | }else{ |
| 360 | @ <input type="hidden" name="page" value="%h(zPage)" /> |
| 361 | } |
| 362 |
+1
-1
| --- src/blob.c | ||
| +++ src/blob.c | ||
| @@ -72,11 +72,11 @@ | ||
| 72 | 72 | |
| 73 | 73 | /* |
| 74 | 74 | ** We find that the built-in isspace() function does not work for |
| 75 | 75 | ** some international character sets. So here is a substitute. |
| 76 | 76 | */ |
| 77 | -static int blob_isspace(char c){ | |
| 77 | +int blob_isspace(char c){ | |
| 78 | 78 | return c==' ' || (c<='\r' && c>='\t'); |
| 79 | 79 | } |
| 80 | 80 | |
| 81 | 81 | /* |
| 82 | 82 | ** COMMAND: test-isspace |
| 83 | 83 |
| --- src/blob.c | |
| +++ src/blob.c | |
| @@ -72,11 +72,11 @@ | |
| 72 | |
| 73 | /* |
| 74 | ** We find that the built-in isspace() function does not work for |
| 75 | ** some international character sets. So here is a substitute. |
| 76 | */ |
| 77 | static int blob_isspace(char c){ |
| 78 | return c==' ' || (c<='\r' && c>='\t'); |
| 79 | } |
| 80 | |
| 81 | /* |
| 82 | ** COMMAND: test-isspace |
| 83 |
| --- src/blob.c | |
| +++ src/blob.c | |
| @@ -72,11 +72,11 @@ | |
| 72 | |
| 73 | /* |
| 74 | ** We find that the built-in isspace() function does not work for |
| 75 | ** some international character sets. So here is a substitute. |
| 76 | */ |
| 77 | int blob_isspace(char c){ |
| 78 | return c==' ' || (c<='\r' && c>='\t'); |
| 79 | } |
| 80 | |
| 81 | /* |
| 82 | ** COMMAND: test-isspace |
| 83 |
+160
-142
| --- src/content.c | ||
| +++ src/content.c | ||
| @@ -19,33 +19,25 @@ | ||
| 19 | 19 | */ |
| 20 | 20 | #include "config.h" |
| 21 | 21 | #include "content.h" |
| 22 | 22 | #include <assert.h> |
| 23 | 23 | |
| 24 | -/* | |
| 25 | -** Macros for debugging | |
| 26 | -*/ | |
| 27 | -#if 0 | |
| 28 | -# define CONTENT_TRACE(X) printf X; | |
| 29 | -#else | |
| 30 | -# define CONTENT_TRACE(X) | |
| 31 | -#endif | |
| 32 | - | |
| 33 | 24 | /* |
| 34 | 25 | ** The artifact retrival cache |
| 35 | 26 | */ |
| 36 | -#define MX_CACHE_CNT 50 /* Maximum number of positive cache entries */ | |
| 37 | -#define EXPELL_INTERVAL 5 /* How often to expell from a full cache */ | |
| 38 | 27 | static struct { |
| 39 | - int n; /* Current number of positive cache entries */ | |
| 28 | + i64 szTotal; /* Total size of all entries in the cache */ | |
| 29 | + int n; /* Current number of eache entries */ | |
| 30 | + int nAlloc; /* Number of slots allocated in a[] */ | |
| 40 | 31 | int nextAge; /* Age counter for implementing LRU */ |
| 41 | 32 | int skipCnt; /* Used to limit entries expelled from cache */ |
| 42 | - struct { /* One instance of this for each cache entry */ | |
| 33 | + struct cacheLine { /* One instance of this for each cache entry */ | |
| 43 | 34 | int rid; /* Artifact id */ |
| 44 | 35 | int age; /* Age. Newer is larger */ |
| 45 | 36 | Blob content; /* Content of the artifact */ |
| 46 | - } a[MX_CACHE_CNT]; /* The positive cache */ | |
| 37 | + } *a; /* The positive cache */ | |
| 38 | + Bag inCache; /* Set of artifacts currently in cache */ | |
| 47 | 39 | |
| 48 | 40 | /* |
| 49 | 41 | ** The missing artifact cache. |
| 50 | 42 | ** |
| 51 | 43 | ** Artifacts whose record ID are in missingCache cannot be retrieved |
| @@ -56,10 +48,54 @@ | ||
| 56 | 48 | */ |
| 57 | 49 | Bag missing; /* Cache of artifacts that are incomplete */ |
| 58 | 50 | Bag available; /* Cache of artifacts that are complete */ |
| 59 | 51 | } contentCache; |
| 60 | 52 | |
| 53 | +/* | |
| 54 | +** Remove the oldest element from the content cache | |
| 55 | +*/ | |
| 56 | +static void content_cache_expire_oldest(void){ | |
| 57 | + int i; | |
| 58 | + int mnAge = contentCache.nextAge; | |
| 59 | + int mn = -1; | |
| 60 | + for(i=0; i<contentCache.n; i++){ | |
| 61 | + if( contentCache.a[i].age<mnAge ){ | |
| 62 | + mnAge = contentCache.a[i].age; | |
| 63 | + mn = i; | |
| 64 | + } | |
| 65 | + } | |
| 66 | + if( mn>=0 ){ | |
| 67 | + bag_remove(&contentCache.inCache, contentCache.a[mn].rid); | |
| 68 | + contentCache.szTotal -= blob_size(&contentCache.a[mn].content); | |
| 69 | + blob_reset(&contentCache.a[mn].content); | |
| 70 | + contentCache.n--; | |
| 71 | + contentCache.a[mn] = contentCache.a[contentCache.n]; | |
| 72 | + } | |
| 73 | +} | |
| 74 | + | |
| 75 | +/* | |
| 76 | +** Add an entry to the content cache | |
| 77 | +*/ | |
| 78 | +void content_cache_insert(int rid, Blob *pBlob){ | |
| 79 | + struct cacheLine *p; | |
| 80 | + if( contentCache.n>500 || contentCache.szTotal>50000000 ){ | |
| 81 | + content_cache_expire_oldest(); | |
| 82 | + } | |
| 83 | + if( contentCache.n>=contentCache.nAlloc ){ | |
| 84 | + contentCache.nAlloc = contentCache.nAlloc*2 + 10; | |
| 85 | + contentCache.a = realloc(contentCache.a, | |
| 86 | + contentCache.nAlloc*sizeof(contentCache.a[0])); | |
| 87 | + if( contentCache.a==0 ) fossil_panic("out of memory"); | |
| 88 | + } | |
| 89 | + p = &contentCache.a[contentCache.n++]; | |
| 90 | + p->rid = rid; | |
| 91 | + p->age = contentCache.nextAge++; | |
| 92 | + contentCache.szTotal += blob_size(pBlob); | |
| 93 | + p->content = *pBlob; | |
| 94 | + blob_zero(pBlob); | |
| 95 | + bag_insert(&contentCache.inCache, rid); | |
| 96 | +} | |
| 61 | 97 | |
| 62 | 98 | /* |
| 63 | 99 | ** Clear the content cache. |
| 64 | 100 | */ |
| 65 | 101 | void content_clear_cache(void){ |
| @@ -67,11 +103,13 @@ | ||
| 67 | 103 | for(i=0; i<contentCache.n; i++){ |
| 68 | 104 | blob_reset(&contentCache.a[i].content); |
| 69 | 105 | } |
| 70 | 106 | bag_clear(&contentCache.missing); |
| 71 | 107 | bag_clear(&contentCache.available); |
| 108 | + bag_clear(&contentCache.inCache); | |
| 72 | 109 | contentCache.n = 0; |
| 110 | + contentCache.szTotal = 0; | |
| 73 | 111 | } |
| 74 | 112 | |
| 75 | 113 | /* |
| 76 | 114 | ** Return the srcid associated with rid. Or return 0 if rid is |
| 77 | 115 | ** original content and not a delta. |
| @@ -95,32 +133,31 @@ | ||
| 95 | 133 | ** true if it is. Return false if rid is a phantom or depends on |
| 96 | 134 | ** a phantom. |
| 97 | 135 | */ |
| 98 | 136 | int content_is_available(int rid){ |
| 99 | 137 | int srcid; |
| 100 | - if( bag_find(&contentCache.missing, rid) ){ | |
| 101 | - return 0; | |
| 102 | - } | |
| 103 | - if( bag_find(&contentCache.available, rid) ){ | |
| 104 | - return 1; | |
| 105 | - } | |
| 106 | - if( db_int(-1, "SELECT size FROM blob WHERE rid=%d", rid)<0 ){ | |
| 107 | - bag_insert(&contentCache.missing, rid); | |
| 108 | - return 0; | |
| 109 | - } | |
| 110 | - srcid = findSrcid(rid); | |
| 111 | - if( srcid==0 ){ | |
| 112 | - bag_insert(&contentCache.available, rid); | |
| 113 | - return 1; | |
| 114 | - } | |
| 115 | - if( content_is_available(srcid) ){ | |
| 116 | - bag_insert(&contentCache.available, rid); | |
| 117 | - return 1; | |
| 118 | - }else{ | |
| 119 | - bag_insert(&contentCache.missing, rid); | |
| 120 | - return 0; | |
| 121 | - } | |
| 138 | + int depth = 0; /* Limit to recursion depth */ | |
| 139 | + while( depth++ < 10000000 ){ | |
| 140 | + if( bag_find(&contentCache.missing, rid) ){ | |
| 141 | + return 0; | |
| 142 | + } | |
| 143 | + if( bag_find(&contentCache.available, rid) ){ | |
| 144 | + return 1; | |
| 145 | + } | |
| 146 | + if( db_int(-1, "SELECT size FROM blob WHERE rid=%d", rid)<0 ){ | |
| 147 | + bag_insert(&contentCache.missing, rid); | |
| 148 | + return 0; | |
| 149 | + } | |
| 150 | + srcid = findSrcid(rid); | |
| 151 | + if( srcid==0 ){ | |
| 152 | + bag_insert(&contentCache.available, rid); | |
| 153 | + return 1; | |
| 154 | + } | |
| 155 | + rid = srcid; | |
| 156 | + } | |
| 157 | + fossil_panic("delta-loop in repository"); | |
| 158 | + return 0; | |
| 122 | 159 | } |
| 123 | 160 | |
| 124 | 161 | /* |
| 125 | 162 | ** Mark artifact rid as being available now. Update the cache to |
| 126 | 163 | ** show that everything that was formerly unavailable because rid |
| @@ -163,113 +200,84 @@ | ||
| 163 | 200 | } |
| 164 | 201 | db_reset(&q); |
| 165 | 202 | return rc; |
| 166 | 203 | } |
| 167 | 204 | |
| 168 | - | |
| 169 | 205 | /* |
| 170 | 206 | ** Extract the content for ID rid and put it into the |
| 171 | 207 | ** uninitialized blob. Return 1 on success. If the record |
| 172 | 208 | ** is a phantom, zero pBlob and return 0. |
| 173 | 209 | */ |
| 174 | 210 | int content_get(int rid, Blob *pBlob){ |
| 175 | - Blob src; | |
| 176 | - int srcid; | |
| 177 | - int rc = 0; | |
| 211 | + int rc; | |
| 178 | 212 | int i; |
| 179 | - static Bag inProcess; | |
| 213 | + int nextRid; | |
| 180 | 214 | |
| 181 | 215 | assert( g.repositoryOpen ); |
| 182 | 216 | blob_zero(pBlob); |
| 183 | 217 | if( rid==0 ) return 0; |
| 184 | 218 | |
| 185 | 219 | /* Early out if we know the content is not available */ |
| 186 | 220 | if( bag_find(&contentCache.missing, rid) ){ |
| 187 | - CONTENT_TRACE(("%*smiss from cache: %d\n", | |
| 188 | - bag_count(&inProcess), "", rid)) | |
| 189 | 221 | return 0; |
| 190 | 222 | } |
| 191 | 223 | |
| 192 | 224 | /* Look for the artifact in the cache first */ |
| 193 | - for(i=0; i<contentCache.n; i++){ | |
| 194 | - if( contentCache.a[i].rid==rid ){ | |
| 195 | - *pBlob = contentCache.a[i].content; | |
| 196 | - blob_zero(&contentCache.a[i].content); | |
| 197 | - contentCache.n--; | |
| 198 | - if( i<contentCache.n ){ | |
| 199 | - contentCache.a[i] = contentCache.a[contentCache.n]; | |
| 200 | - } | |
| 201 | - CONTENT_TRACE(("%*scache: %d\n", | |
| 202 | - bag_count(&inProcess), "", rid)) | |
| 203 | - return 1; | |
| 204 | - } | |
| 205 | - } | |
| 206 | - | |
| 207 | - /* See if we need to apply a delta to find this artifact */ | |
| 208 | - srcid = findSrcid(rid); | |
| 209 | - CONTENT_TRACE(("%*ssearching for %d. Need %d.\n", | |
| 210 | - bag_count(&inProcess), "", rid, srcid)) | |
| 211 | - | |
| 212 | - | |
| 213 | - if( srcid ){ | |
| 214 | - /* Yes, a delta is required */ | |
| 215 | - if( bag_find(&inProcess, srcid) ){ | |
| 216 | - db_multi_exec( | |
| 217 | - "UPDATE blob SET content=NULL, size=-1 WHERE rid=%d;" | |
| 218 | - "DELETE FROM delta WHERE rid=%d;" | |
| 219 | - "INSERT OR IGNORE INTO phantom VALUES(%d);", | |
| 220 | - srcid, srcid, srcid | |
| 221 | - ); | |
| 222 | - blob_zero(pBlob); | |
| 223 | - return 0; | |
| 224 | - } | |
| 225 | - bag_insert(&inProcess, srcid); | |
| 226 | - | |
| 227 | - if( content_get(srcid, &src) ){ | |
| 228 | - Blob delta; | |
| 229 | - if( content_of_blob(rid, &delta) ){ | |
| 230 | - blob_init(pBlob,0,0); | |
| 231 | - blob_delta_apply(&src, &delta, pBlob); | |
| 225 | + if( bag_find(&contentCache.inCache, rid) ){ | |
| 226 | + for(i=0; i<contentCache.n; i++){ | |
| 227 | + if( contentCache.a[i].rid==rid ){ | |
| 228 | + blob_copy(pBlob, &contentCache.a[i].content); | |
| 229 | + contentCache.a[i].age = contentCache.nextAge++; | |
| 230 | + return 1; | |
| 231 | + } | |
| 232 | + } | |
| 233 | + } | |
| 234 | + | |
| 235 | + nextRid = findSrcid(rid); | |
| 236 | + if( nextRid==0 ){ | |
| 237 | + rc = content_of_blob(rid, pBlob); | |
| 238 | + }else{ | |
| 239 | + int n = 1; | |
| 240 | + int nAlloc = 10; | |
| 241 | + int *a = 0; | |
| 242 | + int mx; | |
| 243 | + Blob delta, next; | |
| 244 | + | |
| 245 | + a = malloc( sizeof(a[0])*nAlloc ); | |
| 246 | + if( a==0 ) fossil_panic("out of memory"); | |
| 247 | + a[0] = rid; | |
| 248 | + a[1] = nextRid; | |
| 249 | + n = 1; | |
| 250 | + while( !bag_find(&contentCache.inCache, nextRid) | |
| 251 | + && (nextRid = findSrcid(nextRid))>0 ){ | |
| 252 | + n++; | |
| 253 | + if( n>=nAlloc ){ | |
| 254 | + nAlloc = nAlloc*2 + 10; | |
| 255 | + a = realloc(a, nAlloc*sizeof(a[0])); | |
| 256 | + if( a==0 ) fossil_panic("out of memory"); | |
| 257 | + } | |
| 258 | + a[n] = nextRid; | |
| 259 | + } | |
| 260 | + mx = n; | |
| 261 | + rc = content_get(a[n], pBlob); | |
| 262 | + n--; | |
| 263 | + while( rc && n>=0 ){ | |
| 264 | + rc = content_of_blob(a[n], &delta); | |
| 265 | + if( rc ){ | |
| 266 | + blob_delta_apply(pBlob, &delta, &next); | |
| 232 | 267 | blob_reset(&delta); |
| 233 | - rc = 1; | |
| 234 | - } | |
| 235 | - | |
| 236 | - /* Save the srcid artifact in the cache */ | |
| 237 | - if( contentCache.n<MX_CACHE_CNT ){ | |
| 238 | - i = contentCache.n++; | |
| 239 | - }else if( ((contentCache.skipCnt++)%EXPELL_INTERVAL)!=0 ){ | |
| 240 | - i = -1; | |
| 241 | - }else{ | |
| 242 | - int j, best; | |
| 243 | - best = contentCache.nextAge+1; | |
| 244 | - i = -1; | |
| 245 | - for(j=0; j<contentCache.n; j++){ | |
| 246 | - if( contentCache.a[j].age<best ){ | |
| 247 | - i = j; | |
| 248 | - best = contentCache.a[j].age; | |
| 249 | - } | |
| 250 | - } | |
| 251 | - CONTENT_TRACE(("%*sexpell %d from cache\n", | |
| 252 | - bag_count(&inProcess), "", contentCache.a[i].rid)) | |
| 253 | - blob_reset(&contentCache.a[i].content); | |
| 254 | - } | |
| 255 | - if( i>=0 ){ | |
| 256 | - contentCache.a[i].content = src; | |
| 257 | - contentCache.a[i].age = contentCache.nextAge++; | |
| 258 | - contentCache.a[i].rid = srcid; | |
| 259 | - CONTENT_TRACE(("%*sadd %d to cache\n", | |
| 260 | - bag_count(&inProcess), "", srcid)) | |
| 261 | - }else{ | |
| 262 | - blob_reset(&src); | |
| 263 | - } | |
| 264 | - } | |
| 265 | - bag_remove(&inProcess, srcid); | |
| 266 | - }else{ | |
| 267 | - /* No delta required. Read content directly from the database */ | |
| 268 | - if( content_of_blob(rid, pBlob) ){ | |
| 269 | - rc = 1; | |
| 270 | - } | |
| 268 | + if( (mx-n)%8==0 ){ | |
| 269 | + content_cache_insert(a[n+1], pBlob); | |
| 270 | + }else{ | |
| 271 | + blob_reset(pBlob); | |
| 272 | + } | |
| 273 | + *pBlob = next; | |
| 274 | + } | |
| 275 | + n--; | |
| 276 | + } | |
| 277 | + free(a); | |
| 278 | + if( !rc ) blob_reset(pBlob); | |
| 271 | 279 | } |
| 272 | 280 | if( rc==0 ){ |
| 273 | 281 | bag_insert(&contentCache.missing, rid); |
| 274 | 282 | }else{ |
| 275 | 283 | bag_insert(&contentCache.available, rid); |
| @@ -320,35 +328,45 @@ | ||
| 320 | 328 | |
| 321 | 329 | /* |
| 322 | 330 | ** When a record is converted from a phantom to a real record, |
| 323 | 331 | ** if that record has other records that are derived by delta, |
| 324 | 332 | ** then call manifest_crosslink() on those other records. |
| 333 | +** | |
| 334 | +** Tail recursion is used to minimize stack depth. | |
| 325 | 335 | */ |
| 326 | 336 | void after_dephantomize(int rid, int linkFlag){ |
| 327 | 337 | Stmt q; |
| 328 | - int prevTid = 0; | |
| 329 | - | |
| 330 | - /* The prevTid variable is used to delay invoking this routine | |
| 331 | - ** recursively, if possible, until after the query has finalized, | |
| 332 | - ** in order to avoid having an excessive number of prepared statements. | |
| 333 | - ** This is most effective in the common case where the query returns | |
| 334 | - ** just one row. | |
| 335 | - */ | |
| 336 | - db_prepare(&q, "SELECT rid FROM delta WHERE srcid=%d", rid); | |
| 337 | - while( db_step(&q)==SQLITE_ROW ){ | |
| 338 | - int tid = db_column_int(&q, 0); | |
| 339 | - if( prevTid ) after_dephantomize(prevTid, 1); | |
| 340 | - prevTid = tid; | |
| 341 | - } | |
| 342 | - db_finalize(&q); | |
| 343 | - if( prevTid ) after_dephantomize(prevTid, 1); | |
| 344 | - if( linkFlag ){ | |
| 345 | - Blob content; | |
| 346 | - content_get(rid, &content); | |
| 347 | - manifest_crosslink(rid, &content); | |
| 348 | - blob_reset(&content); | |
| 349 | - } | |
| 338 | + int nChildAlloc = 0; | |
| 339 | + int *aChild = 0; | |
| 340 | + | |
| 341 | + while( rid ){ | |
| 342 | + int nChildUsed = 0; | |
| 343 | + int i; | |
| 344 | + if( linkFlag ){ | |
| 345 | + Blob content; | |
| 346 | + content_get(rid, &content); | |
| 347 | + manifest_crosslink(rid, &content); | |
| 348 | + blob_reset(&content); | |
| 349 | + } | |
| 350 | + db_prepare(&q, "SELECT rid FROM delta WHERE srcid=%d", rid); | |
| 351 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 352 | + int child = db_column_int(&q, 0); | |
| 353 | + if( nChildUsed>=nChildAlloc ){ | |
| 354 | + nChildAlloc = nChildAlloc*2 + 10; | |
| 355 | + aChild = realloc(aChild, nChildAlloc*sizeof(aChild)); | |
| 356 | + if( aChild==0 ) fossil_panic("out of memory"); | |
| 357 | + } | |
| 358 | + aChild[nChildUsed++] = child; | |
| 359 | + } | |
| 360 | + db_finalize(&q); | |
| 361 | + for(i=1; i<nChildUsed; i++){ | |
| 362 | + after_dephantomize(aChild[i], 1); | |
| 363 | + } | |
| 364 | + rid = nChildUsed>0 ? aChild[0] : 0; | |
| 365 | + linkFlag = 1; | |
| 366 | + } | |
| 367 | + free(aChild); | |
| 350 | 368 | } |
| 351 | 369 | |
| 352 | 370 | /* |
| 353 | 371 | ** Write content into the database. Return the record ID. If the |
| 354 | 372 | ** content is already in the database, just return the record ID. |
| 355 | 373 | |
| 356 | 374 | ADDED src/event.c |
| --- src/content.c | |
| +++ src/content.c | |
| @@ -19,33 +19,25 @@ | |
| 19 | */ |
| 20 | #include "config.h" |
| 21 | #include "content.h" |
| 22 | #include <assert.h> |
| 23 | |
| 24 | /* |
| 25 | ** Macros for debugging |
| 26 | */ |
| 27 | #if 0 |
| 28 | # define CONTENT_TRACE(X) printf X; |
| 29 | #else |
| 30 | # define CONTENT_TRACE(X) |
| 31 | #endif |
| 32 | |
| 33 | /* |
| 34 | ** The artifact retrival cache |
| 35 | */ |
| 36 | #define MX_CACHE_CNT 50 /* Maximum number of positive cache entries */ |
| 37 | #define EXPELL_INTERVAL 5 /* How often to expell from a full cache */ |
| 38 | static struct { |
| 39 | int n; /* Current number of positive cache entries */ |
| 40 | int nextAge; /* Age counter for implementing LRU */ |
| 41 | int skipCnt; /* Used to limit entries expelled from cache */ |
| 42 | struct { /* One instance of this for each cache entry */ |
| 43 | int rid; /* Artifact id */ |
| 44 | int age; /* Age. Newer is larger */ |
| 45 | Blob content; /* Content of the artifact */ |
| 46 | } a[MX_CACHE_CNT]; /* The positive cache */ |
| 47 | |
| 48 | /* |
| 49 | ** The missing artifact cache. |
| 50 | ** |
| 51 | ** Artifacts whose record ID are in missingCache cannot be retrieved |
| @@ -56,10 +48,54 @@ | |
| 56 | */ |
| 57 | Bag missing; /* Cache of artifacts that are incomplete */ |
| 58 | Bag available; /* Cache of artifacts that are complete */ |
| 59 | } contentCache; |
| 60 | |
| 61 | |
| 62 | /* |
| 63 | ** Clear the content cache. |
| 64 | */ |
| 65 | void content_clear_cache(void){ |
| @@ -67,11 +103,13 @@ | |
| 67 | for(i=0; i<contentCache.n; i++){ |
| 68 | blob_reset(&contentCache.a[i].content); |
| 69 | } |
| 70 | bag_clear(&contentCache.missing); |
| 71 | bag_clear(&contentCache.available); |
| 72 | contentCache.n = 0; |
| 73 | } |
| 74 | |
| 75 | /* |
| 76 | ** Return the srcid associated with rid. Or return 0 if rid is |
| 77 | ** original content and not a delta. |
| @@ -95,32 +133,31 @@ | |
| 95 | ** true if it is. Return false if rid is a phantom or depends on |
| 96 | ** a phantom. |
| 97 | */ |
| 98 | int content_is_available(int rid){ |
| 99 | int srcid; |
| 100 | if( bag_find(&contentCache.missing, rid) ){ |
| 101 | return 0; |
| 102 | } |
| 103 | if( bag_find(&contentCache.available, rid) ){ |
| 104 | return 1; |
| 105 | } |
| 106 | if( db_int(-1, "SELECT size FROM blob WHERE rid=%d", rid)<0 ){ |
| 107 | bag_insert(&contentCache.missing, rid); |
| 108 | return 0; |
| 109 | } |
| 110 | srcid = findSrcid(rid); |
| 111 | if( srcid==0 ){ |
| 112 | bag_insert(&contentCache.available, rid); |
| 113 | return 1; |
| 114 | } |
| 115 | if( content_is_available(srcid) ){ |
| 116 | bag_insert(&contentCache.available, rid); |
| 117 | return 1; |
| 118 | }else{ |
| 119 | bag_insert(&contentCache.missing, rid); |
| 120 | return 0; |
| 121 | } |
| 122 | } |
| 123 | |
| 124 | /* |
| 125 | ** Mark artifact rid as being available now. Update the cache to |
| 126 | ** show that everything that was formerly unavailable because rid |
| @@ -163,113 +200,84 @@ | |
| 163 | } |
| 164 | db_reset(&q); |
| 165 | return rc; |
| 166 | } |
| 167 | |
| 168 | |
| 169 | /* |
| 170 | ** Extract the content for ID rid and put it into the |
| 171 | ** uninitialized blob. Return 1 on success. If the record |
| 172 | ** is a phantom, zero pBlob and return 0. |
| 173 | */ |
| 174 | int content_get(int rid, Blob *pBlob){ |
| 175 | Blob src; |
| 176 | int srcid; |
| 177 | int rc = 0; |
| 178 | int i; |
| 179 | static Bag inProcess; |
| 180 | |
| 181 | assert( g.repositoryOpen ); |
| 182 | blob_zero(pBlob); |
| 183 | if( rid==0 ) return 0; |
| 184 | |
| 185 | /* Early out if we know the content is not available */ |
| 186 | if( bag_find(&contentCache.missing, rid) ){ |
| 187 | CONTENT_TRACE(("%*smiss from cache: %d\n", |
| 188 | bag_count(&inProcess), "", rid)) |
| 189 | return 0; |
| 190 | } |
| 191 | |
| 192 | /* Look for the artifact in the cache first */ |
| 193 | for(i=0; i<contentCache.n; i++){ |
| 194 | if( contentCache.a[i].rid==rid ){ |
| 195 | *pBlob = contentCache.a[i].content; |
| 196 | blob_zero(&contentCache.a[i].content); |
| 197 | contentCache.n--; |
| 198 | if( i<contentCache.n ){ |
| 199 | contentCache.a[i] = contentCache.a[contentCache.n]; |
| 200 | } |
| 201 | CONTENT_TRACE(("%*scache: %d\n", |
| 202 | bag_count(&inProcess), "", rid)) |
| 203 | return 1; |
| 204 | } |
| 205 | } |
| 206 | |
| 207 | /* See if we need to apply a delta to find this artifact */ |
| 208 | srcid = findSrcid(rid); |
| 209 | CONTENT_TRACE(("%*ssearching for %d. Need %d.\n", |
| 210 | bag_count(&inProcess), "", rid, srcid)) |
| 211 | |
| 212 | |
| 213 | if( srcid ){ |
| 214 | /* Yes, a delta is required */ |
| 215 | if( bag_find(&inProcess, srcid) ){ |
| 216 | db_multi_exec( |
| 217 | "UPDATE blob SET content=NULL, size=-1 WHERE rid=%d;" |
| 218 | "DELETE FROM delta WHERE rid=%d;" |
| 219 | "INSERT OR IGNORE INTO phantom VALUES(%d);", |
| 220 | srcid, srcid, srcid |
| 221 | ); |
| 222 | blob_zero(pBlob); |
| 223 | return 0; |
| 224 | } |
| 225 | bag_insert(&inProcess, srcid); |
| 226 | |
| 227 | if( content_get(srcid, &src) ){ |
| 228 | Blob delta; |
| 229 | if( content_of_blob(rid, &delta) ){ |
| 230 | blob_init(pBlob,0,0); |
| 231 | blob_delta_apply(&src, &delta, pBlob); |
| 232 | blob_reset(&delta); |
| 233 | rc = 1; |
| 234 | } |
| 235 | |
| 236 | /* Save the srcid artifact in the cache */ |
| 237 | if( contentCache.n<MX_CACHE_CNT ){ |
| 238 | i = contentCache.n++; |
| 239 | }else if( ((contentCache.skipCnt++)%EXPELL_INTERVAL)!=0 ){ |
| 240 | i = -1; |
| 241 | }else{ |
| 242 | int j, best; |
| 243 | best = contentCache.nextAge+1; |
| 244 | i = -1; |
| 245 | for(j=0; j<contentCache.n; j++){ |
| 246 | if( contentCache.a[j].age<best ){ |
| 247 | i = j; |
| 248 | best = contentCache.a[j].age; |
| 249 | } |
| 250 | } |
| 251 | CONTENT_TRACE(("%*sexpell %d from cache\n", |
| 252 | bag_count(&inProcess), "", contentCache.a[i].rid)) |
| 253 | blob_reset(&contentCache.a[i].content); |
| 254 | } |
| 255 | if( i>=0 ){ |
| 256 | contentCache.a[i].content = src; |
| 257 | contentCache.a[i].age = contentCache.nextAge++; |
| 258 | contentCache.a[i].rid = srcid; |
| 259 | CONTENT_TRACE(("%*sadd %d to cache\n", |
| 260 | bag_count(&inProcess), "", srcid)) |
| 261 | }else{ |
| 262 | blob_reset(&src); |
| 263 | } |
| 264 | } |
| 265 | bag_remove(&inProcess, srcid); |
| 266 | }else{ |
| 267 | /* No delta required. Read content directly from the database */ |
| 268 | if( content_of_blob(rid, pBlob) ){ |
| 269 | rc = 1; |
| 270 | } |
| 271 | } |
| 272 | if( rc==0 ){ |
| 273 | bag_insert(&contentCache.missing, rid); |
| 274 | }else{ |
| 275 | bag_insert(&contentCache.available, rid); |
| @@ -320,35 +328,45 @@ | |
| 320 | |
| 321 | /* |
| 322 | ** When a record is converted from a phantom to a real record, |
| 323 | ** if that record has other records that are derived by delta, |
| 324 | ** then call manifest_crosslink() on those other records. |
| 325 | */ |
| 326 | void after_dephantomize(int rid, int linkFlag){ |
| 327 | Stmt q; |
| 328 | int prevTid = 0; |
| 329 | |
| 330 | /* The prevTid variable is used to delay invoking this routine |
| 331 | ** recursively, if possible, until after the query has finalized, |
| 332 | ** in order to avoid having an excessive number of prepared statements. |
| 333 | ** This is most effective in the common case where the query returns |
| 334 | ** just one row. |
| 335 | */ |
| 336 | db_prepare(&q, "SELECT rid FROM delta WHERE srcid=%d", rid); |
| 337 | while( db_step(&q)==SQLITE_ROW ){ |
| 338 | int tid = db_column_int(&q, 0); |
| 339 | if( prevTid ) after_dephantomize(prevTid, 1); |
| 340 | prevTid = tid; |
| 341 | } |
| 342 | db_finalize(&q); |
| 343 | if( prevTid ) after_dephantomize(prevTid, 1); |
| 344 | if( linkFlag ){ |
| 345 | Blob content; |
| 346 | content_get(rid, &content); |
| 347 | manifest_crosslink(rid, &content); |
| 348 | blob_reset(&content); |
| 349 | } |
| 350 | } |
| 351 | |
| 352 | /* |
| 353 | ** Write content into the database. Return the record ID. If the |
| 354 | ** content is already in the database, just return the record ID. |
| 355 | |
| 356 | DDED src/event.c |
| --- src/content.c | |
| +++ src/content.c | |
| @@ -19,33 +19,25 @@ | |
| 19 | */ |
| 20 | #include "config.h" |
| 21 | #include "content.h" |
| 22 | #include <assert.h> |
| 23 | |
| 24 | /* |
| 25 | ** The artifact retrival cache |
| 26 | */ |
| 27 | static struct { |
| 28 | i64 szTotal; /* Total size of all entries in the cache */ |
| 29 | int n; /* Current number of eache entries */ |
| 30 | int nAlloc; /* Number of slots allocated in a[] */ |
| 31 | int nextAge; /* Age counter for implementing LRU */ |
| 32 | int skipCnt; /* Used to limit entries expelled from cache */ |
| 33 | struct cacheLine { /* One instance of this for each cache entry */ |
| 34 | int rid; /* Artifact id */ |
| 35 | int age; /* Age. Newer is larger */ |
| 36 | Blob content; /* Content of the artifact */ |
| 37 | } *a; /* The positive cache */ |
| 38 | Bag inCache; /* Set of artifacts currently in cache */ |
| 39 | |
| 40 | /* |
| 41 | ** The missing artifact cache. |
| 42 | ** |
| 43 | ** Artifacts whose record ID are in missingCache cannot be retrieved |
| @@ -56,10 +48,54 @@ | |
| 48 | */ |
| 49 | Bag missing; /* Cache of artifacts that are incomplete */ |
| 50 | Bag available; /* Cache of artifacts that are complete */ |
| 51 | } contentCache; |
| 52 | |
| 53 | /* |
| 54 | ** Remove the oldest element from the content cache |
| 55 | */ |
| 56 | static void content_cache_expire_oldest(void){ |
| 57 | int i; |
| 58 | int mnAge = contentCache.nextAge; |
| 59 | int mn = -1; |
| 60 | for(i=0; i<contentCache.n; i++){ |
| 61 | if( contentCache.a[i].age<mnAge ){ |
| 62 | mnAge = contentCache.a[i].age; |
| 63 | mn = i; |
| 64 | } |
| 65 | } |
| 66 | if( mn>=0 ){ |
| 67 | bag_remove(&contentCache.inCache, contentCache.a[mn].rid); |
| 68 | contentCache.szTotal -= blob_size(&contentCache.a[mn].content); |
| 69 | blob_reset(&contentCache.a[mn].content); |
| 70 | contentCache.n--; |
| 71 | contentCache.a[mn] = contentCache.a[contentCache.n]; |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | /* |
| 76 | ** Add an entry to the content cache |
| 77 | */ |
| 78 | void content_cache_insert(int rid, Blob *pBlob){ |
| 79 | struct cacheLine *p; |
| 80 | if( contentCache.n>500 || contentCache.szTotal>50000000 ){ |
| 81 | content_cache_expire_oldest(); |
| 82 | } |
| 83 | if( contentCache.n>=contentCache.nAlloc ){ |
| 84 | contentCache.nAlloc = contentCache.nAlloc*2 + 10; |
| 85 | contentCache.a = realloc(contentCache.a, |
| 86 | contentCache.nAlloc*sizeof(contentCache.a[0])); |
| 87 | if( contentCache.a==0 ) fossil_panic("out of memory"); |
| 88 | } |
| 89 | p = &contentCache.a[contentCache.n++]; |
| 90 | p->rid = rid; |
| 91 | p->age = contentCache.nextAge++; |
| 92 | contentCache.szTotal += blob_size(pBlob); |
| 93 | p->content = *pBlob; |
| 94 | blob_zero(pBlob); |
| 95 | bag_insert(&contentCache.inCache, rid); |
| 96 | } |
| 97 | |
| 98 | /* |
| 99 | ** Clear the content cache. |
| 100 | */ |
| 101 | void content_clear_cache(void){ |
| @@ -67,11 +103,13 @@ | |
| 103 | for(i=0; i<contentCache.n; i++){ |
| 104 | blob_reset(&contentCache.a[i].content); |
| 105 | } |
| 106 | bag_clear(&contentCache.missing); |
| 107 | bag_clear(&contentCache.available); |
| 108 | bag_clear(&contentCache.inCache); |
| 109 | contentCache.n = 0; |
| 110 | contentCache.szTotal = 0; |
| 111 | } |
| 112 | |
| 113 | /* |
| 114 | ** Return the srcid associated with rid. Or return 0 if rid is |
| 115 | ** original content and not a delta. |
| @@ -95,32 +133,31 @@ | |
| 133 | ** true if it is. Return false if rid is a phantom or depends on |
| 134 | ** a phantom. |
| 135 | */ |
| 136 | int content_is_available(int rid){ |
| 137 | int srcid; |
| 138 | int depth = 0; /* Limit to recursion depth */ |
| 139 | while( depth++ < 10000000 ){ |
| 140 | if( bag_find(&contentCache.missing, rid) ){ |
| 141 | return 0; |
| 142 | } |
| 143 | if( bag_find(&contentCache.available, rid) ){ |
| 144 | return 1; |
| 145 | } |
| 146 | if( db_int(-1, "SELECT size FROM blob WHERE rid=%d", rid)<0 ){ |
| 147 | bag_insert(&contentCache.missing, rid); |
| 148 | return 0; |
| 149 | } |
| 150 | srcid = findSrcid(rid); |
| 151 | if( srcid==0 ){ |
| 152 | bag_insert(&contentCache.available, rid); |
| 153 | return 1; |
| 154 | } |
| 155 | rid = srcid; |
| 156 | } |
| 157 | fossil_panic("delta-loop in repository"); |
| 158 | return 0; |
| 159 | } |
| 160 | |
| 161 | /* |
| 162 | ** Mark artifact rid as being available now. Update the cache to |
| 163 | ** show that everything that was formerly unavailable because rid |
| @@ -163,113 +200,84 @@ | |
| 200 | } |
| 201 | db_reset(&q); |
| 202 | return rc; |
| 203 | } |
| 204 | |
| 205 | /* |
| 206 | ** Extract the content for ID rid and put it into the |
| 207 | ** uninitialized blob. Return 1 on success. If the record |
| 208 | ** is a phantom, zero pBlob and return 0. |
| 209 | */ |
| 210 | int content_get(int rid, Blob *pBlob){ |
| 211 | int rc; |
| 212 | int i; |
| 213 | int nextRid; |
| 214 | |
| 215 | assert( g.repositoryOpen ); |
| 216 | blob_zero(pBlob); |
| 217 | if( rid==0 ) return 0; |
| 218 | |
| 219 | /* Early out if we know the content is not available */ |
| 220 | if( bag_find(&contentCache.missing, rid) ){ |
| 221 | return 0; |
| 222 | } |
| 223 | |
| 224 | /* Look for the artifact in the cache first */ |
| 225 | if( bag_find(&contentCache.inCache, rid) ){ |
| 226 | for(i=0; i<contentCache.n; i++){ |
| 227 | if( contentCache.a[i].rid==rid ){ |
| 228 | blob_copy(pBlob, &contentCache.a[i].content); |
| 229 | contentCache.a[i].age = contentCache.nextAge++; |
| 230 | return 1; |
| 231 | } |
| 232 | } |
| 233 | } |
| 234 | |
| 235 | nextRid = findSrcid(rid); |
| 236 | if( nextRid==0 ){ |
| 237 | rc = content_of_blob(rid, pBlob); |
| 238 | }else{ |
| 239 | int n = 1; |
| 240 | int nAlloc = 10; |
| 241 | int *a = 0; |
| 242 | int mx; |
| 243 | Blob delta, next; |
| 244 | |
| 245 | a = malloc( sizeof(a[0])*nAlloc ); |
| 246 | if( a==0 ) fossil_panic("out of memory"); |
| 247 | a[0] = rid; |
| 248 | a[1] = nextRid; |
| 249 | n = 1; |
| 250 | while( !bag_find(&contentCache.inCache, nextRid) |
| 251 | && (nextRid = findSrcid(nextRid))>0 ){ |
| 252 | n++; |
| 253 | if( n>=nAlloc ){ |
| 254 | nAlloc = nAlloc*2 + 10; |
| 255 | a = realloc(a, nAlloc*sizeof(a[0])); |
| 256 | if( a==0 ) fossil_panic("out of memory"); |
| 257 | } |
| 258 | a[n] = nextRid; |
| 259 | } |
| 260 | mx = n; |
| 261 | rc = content_get(a[n], pBlob); |
| 262 | n--; |
| 263 | while( rc && n>=0 ){ |
| 264 | rc = content_of_blob(a[n], &delta); |
| 265 | if( rc ){ |
| 266 | blob_delta_apply(pBlob, &delta, &next); |
| 267 | blob_reset(&delta); |
| 268 | if( (mx-n)%8==0 ){ |
| 269 | content_cache_insert(a[n+1], pBlob); |
| 270 | }else{ |
| 271 | blob_reset(pBlob); |
| 272 | } |
| 273 | *pBlob = next; |
| 274 | } |
| 275 | n--; |
| 276 | } |
| 277 | free(a); |
| 278 | if( !rc ) blob_reset(pBlob); |
| 279 | } |
| 280 | if( rc==0 ){ |
| 281 | bag_insert(&contentCache.missing, rid); |
| 282 | }else{ |
| 283 | bag_insert(&contentCache.available, rid); |
| @@ -320,35 +328,45 @@ | |
| 328 | |
| 329 | /* |
| 330 | ** When a record is converted from a phantom to a real record, |
| 331 | ** if that record has other records that are derived by delta, |
| 332 | ** then call manifest_crosslink() on those other records. |
| 333 | ** |
| 334 | ** Tail recursion is used to minimize stack depth. |
| 335 | */ |
| 336 | void after_dephantomize(int rid, int linkFlag){ |
| 337 | Stmt q; |
| 338 | int nChildAlloc = 0; |
| 339 | int *aChild = 0; |
| 340 | |
| 341 | while( rid ){ |
| 342 | int nChildUsed = 0; |
| 343 | int i; |
| 344 | if( linkFlag ){ |
| 345 | Blob content; |
| 346 | content_get(rid, &content); |
| 347 | manifest_crosslink(rid, &content); |
| 348 | blob_reset(&content); |
| 349 | } |
| 350 | db_prepare(&q, "SELECT rid FROM delta WHERE srcid=%d", rid); |
| 351 | while( db_step(&q)==SQLITE_ROW ){ |
| 352 | int child = db_column_int(&q, 0); |
| 353 | if( nChildUsed>=nChildAlloc ){ |
| 354 | nChildAlloc = nChildAlloc*2 + 10; |
| 355 | aChild = realloc(aChild, nChildAlloc*sizeof(aChild)); |
| 356 | if( aChild==0 ) fossil_panic("out of memory"); |
| 357 | } |
| 358 | aChild[nChildUsed++] = child; |
| 359 | } |
| 360 | db_finalize(&q); |
| 361 | for(i=1; i<nChildUsed; i++){ |
| 362 | after_dephantomize(aChild[i], 1); |
| 363 | } |
| 364 | rid = nChildUsed>0 ? aChild[0] : 0; |
| 365 | linkFlag = 1; |
| 366 | } |
| 367 | free(aChild); |
| 368 | } |
| 369 | |
| 370 | /* |
| 371 | ** Write content into the database. Return the record ID. If the |
| 372 | ** content is already in the database, just return the record ID. |
| 373 | |
| 374 | DDED src/event.c |
+2
| --- a/src/event.c | ||
| +++ b/src/event.c | ||
| @@ -0,0 +1,2 @@ | ||
| 1 | +mParsedblobblobmParsed?name=EVENTID&de='event-%q(); | |
| 2 | +} |
| --- a/src/event.c | |
| +++ b/src/event.c | |
| @@ -0,0 +1,2 @@ | |
| --- a/src/event.c | |
| +++ b/src/event.c | |
| @@ -0,0 +1,2 @@ | |
| 1 | mParsedblobblobmParsed?name=EVENTID&de='event-%q(); |
| 2 | } |
+89
-66
| --- src/info.c | ||
| +++ src/info.c | ||
| @@ -779,11 +779,11 @@ | ||
| 779 | 779 | } |
| 780 | 780 | } |
| 781 | 781 | db_finalize(&q); |
| 782 | 782 | if( nWiki==0 ){ |
| 783 | 783 | db_prepare(&q, |
| 784 | - "SELECT datetime(mtime), user, comment, type, uuid" | |
| 784 | + "SELECT datetime(mtime), user, comment, type, uuid, tagid" | |
| 785 | 785 | " FROM event, blob" |
| 786 | 786 | " WHERE event.objid=%d" |
| 787 | 787 | " AND blob.rid=%d", |
| 788 | 788 | rid, rid |
| 789 | 789 | ); |
| @@ -800,14 +800,19 @@ | ||
| 800 | 800 | @ Wiki edit |
| 801 | 801 | }else if( zType[0]=='t' ){ |
| 802 | 802 | @ Ticket change |
| 803 | 803 | }else if( zType[0]=='c' ){ |
| 804 | 804 | @ Manifest of check-in |
| 805 | + }else if( zType[0]=='e' ){ | |
| 806 | + @ Instance of event | |
| 807 | + hyperlink_to_event_tagid(db_column_int(&q, 5)); | |
| 805 | 808 | }else{ |
| 806 | 809 | @ Control file referencing |
| 807 | 810 | } |
| 808 | - hyperlink_to_uuid(zUuid); | |
| 811 | + if( zType[0]!='e' ){ | |
| 812 | + hyperlink_to_uuid(zUuid); | |
| 813 | + } | |
| 809 | 814 | @ - %w(zCom) by |
| 810 | 815 | hyperlink_to_user(zUser,zDate," on"); |
| 811 | 816 | hyperlink_to_date(zDate, "."); |
| 812 | 817 | if( pDownloadName && blob_size(pDownloadName)==0 ){ |
| 813 | 818 | blob_appendf(pDownloadName, "%.10s.txt", zUuid); |
| @@ -1260,10 +1265,90 @@ | ||
| 1260 | 1265 | }else |
| 1261 | 1266 | { |
| 1262 | 1267 | artifact_page(); |
| 1263 | 1268 | } |
| 1264 | 1269 | } |
| 1270 | + | |
| 1271 | +/* | |
| 1272 | +** Generate HTML that will present the user with a selection of | |
| 1273 | +** potential background colors for timeline entries. | |
| 1274 | +*/ | |
| 1275 | +void render_color_chooser( | |
| 1276 | + int fPropagate, /* Default value for propagation */ | |
| 1277 | + const char *zDefaultColor, /* The current default color */ | |
| 1278 | + const char *zIdPropagate, /* ID of form element checkbox. NULL for none */ | |
| 1279 | + const char *zId, /* The ID of the form element */ | |
| 1280 | + const char *zIdCustom /* ID of text box for custom color */ | |
| 1281 | +){ | |
| 1282 | + static const struct SampleColors { | |
| 1283 | + const char *zCName; | |
| 1284 | + const char *zColor; | |
| 1285 | + } aColor[] = { | |
| 1286 | + { "(none)", "" }, | |
| 1287 | + { "#f2dcdc", "#f2dcdc" }, | |
| 1288 | + { "#f0ffc0", "#f0ffc0" }, | |
| 1289 | + { "#bde5d6", "#bde5d6" }, | |
| 1290 | + { "#c0ffc0", "#c0ffc0" }, | |
| 1291 | + { "#c0fff0", "#c0fff0" }, | |
| 1292 | + { "#c0f0ff", "#c0f0ff" }, | |
| 1293 | + { "#d0c0ff", "#d0c0ff" }, | |
| 1294 | + { "#ffc0ff", "#ffc0ff" }, | |
| 1295 | + { "#ffc0d0", "#ffc0d0" }, | |
| 1296 | + { "#fff0c0", "#fff0c0" }, | |
| 1297 | + { "#c0c0c0", "#c0c0c0" }, | |
| 1298 | + { "custom", "##" }, | |
| 1299 | + }; | |
| 1300 | + int nColor = sizeof(aColor)/sizeof(aColor[0])-1; | |
| 1301 | + int stdClrFound = 0; | |
| 1302 | + int i; | |
| 1303 | + | |
| 1304 | + @ <table border="0" cellpadding="0" cellspacing="1"> | |
| 1305 | + if( zIdPropagate ){ | |
| 1306 | + @ <tr><td colspan="6" align="left"> | |
| 1307 | + if( fPropagate ){ | |
| 1308 | + @ <input type="checkbox" name="%s(zIdPropagate)" checked="checked" /> | |
| 1309 | + }else{ | |
| 1310 | + @ <input type="checkbox" name="%s(zIdPropagate)" /> | |
| 1311 | + } | |
| 1312 | + @ Propagate color to descendants</td></tr> | |
| 1313 | + } | |
| 1314 | + @ <tr> | |
| 1315 | + for(i=0; i<nColor; i++){ | |
| 1316 | + if( aColor[i].zColor[0] ){ | |
| 1317 | + @ <td style="background-color: %h(aColor[i].zColor);"> | |
| 1318 | + }else{ | |
| 1319 | + @ <td> | |
| 1320 | + } | |
| 1321 | + if( strcmp(zDefaultColor, aColor[i].zColor)==0 ){ | |
| 1322 | + @ <input type="radio" name="%s(zId)" value="%h(aColor[i].zColor)" | |
| 1323 | + @ checked="checked" /> | |
| 1324 | + stdClrFound=1; | |
| 1325 | + }else{ | |
| 1326 | + @ <input type="radio" name="%s(zId)" value="%h(aColor[i].zColor)" /> | |
| 1327 | + } | |
| 1328 | + @ %h(aColor[i].zCName)</td> | |
| 1329 | + if( (i%6)==5 && i+1<nColor ){ | |
| 1330 | + @ </tr><tr> | |
| 1331 | + } | |
| 1332 | + } | |
| 1333 | + @ </tr><tr> | |
| 1334 | + if (stdClrFound){ | |
| 1335 | + @ <td colspan="6"> | |
| 1336 | + @ <input type="radio" name="%s(zId)" value="%h(aColor[nColor].zColor)" /> | |
| 1337 | + }else{ | |
| 1338 | + @ <td style="background-color: %h(zDefaultColor);" colspan="6"> | |
| 1339 | + @ <input type="radio" name="%s(zId)" value="%h(aColor[nColor].zColor)" | |
| 1340 | + @ checked="checked" /> | |
| 1341 | + } | |
| 1342 | + @ %h(aColor[i].zCName) | |
| 1343 | + @ <input type="text" name="%s(zIdCustom)" | |
| 1344 | + @ id="%s(zIdCustom)" class="checkinUserColor" | |
| 1345 | + @ value="%h(stdClrFound?"":zDefaultColor)" /> | |
| 1346 | + @ </td> | |
| 1347 | + @ </tr> | |
| 1348 | + @ </table> | |
| 1349 | +} | |
| 1265 | 1350 | |
| 1266 | 1351 | /* |
| 1267 | 1352 | ** WEBPAGE: ci_edit |
| 1268 | 1353 | ** URL: ci_edit?r=RID&c=NEWCOMMENT&u=NEWUSER |
| 1269 | 1354 | ** |
| @@ -1290,31 +1375,10 @@ | ||
| 1290 | 1375 | const char *zCloseFlag; |
| 1291 | 1376 | int fPropagateColor; |
| 1292 | 1377 | char *zUuid; |
| 1293 | 1378 | Blob comment; |
| 1294 | 1379 | Stmt q; |
| 1295 | - static const struct SampleColors { | |
| 1296 | - const char *zCName; | |
| 1297 | - const char *zColor; | |
| 1298 | - } aColor[] = { | |
| 1299 | - { "(none)", "" }, | |
| 1300 | - { "#f2dcdc", "#f2dcdc" }, | |
| 1301 | - { "#f0ffc0", "#f0ffc0" }, | |
| 1302 | - { "#bde5d6", "#bde5d6" }, | |
| 1303 | - { "#c0ffc0", "#c0ffc0" }, | |
| 1304 | - { "#c0fff0", "#c0fff0" }, | |
| 1305 | - { "#c0f0ff", "#c0f0ff" }, | |
| 1306 | - { "#d0c0ff", "#d0c0ff" }, | |
| 1307 | - { "#ffc0ff", "#ffc0ff" }, | |
| 1308 | - { "#ffc0d0", "#ffc0d0" }, | |
| 1309 | - { "#fff0c0", "#fff0c0" }, | |
| 1310 | - { "#c0c0c0", "#c0c0c0" }, | |
| 1311 | - { "custom", "##" }, | |
| 1312 | - }; | |
| 1313 | - int nColor = sizeof(aColor)/sizeof(aColor[0])-1; | |
| 1314 | - int stdClrFound; | |
| 1315 | - int i; | |
| 1316 | 1380 | |
| 1317 | 1381 | login_check_credentials(); |
| 1318 | 1382 | if( !g.okWrite ){ login_needed(); return; } |
| 1319 | 1383 | rid = name_to_rid(P("r")); |
| 1320 | 1384 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| @@ -1334,11 +1398,11 @@ | ||
| 1334 | 1398 | if( zDate==0 ) fossil_redirect_home(); |
| 1335 | 1399 | zNewDate = PD("dt",zDate); |
| 1336 | 1400 | zColor = db_text("", "SELECT bgcolor" |
| 1337 | 1401 | " FROM event WHERE objid=%d", rid); |
| 1338 | 1402 | zNewColor = PD("clr",zColor); |
| 1339 | - if( strcmp(zNewColor,aColor[nColor].zColor)==0 ){ | |
| 1403 | + if( strcmp(zNewColor,"##")==0 ){ | |
| 1340 | 1404 | zNewColor = P("clrcust"); |
| 1341 | 1405 | } |
| 1342 | 1406 | fPropagateColor = P("pclr")!=0; |
| 1343 | 1407 | zNewTagFlag = P("newtag") ? " checked" : ""; |
| 1344 | 1408 | zNewTag = PD("tagname",""); |
| @@ -1501,52 +1565,11 @@ | ||
| 1501 | 1565 | @ <input type="text" name="dt" size="20" value="%h(zNewDate)" /> |
| 1502 | 1566 | @ </td></tr> |
| 1503 | 1567 | |
| 1504 | 1568 | @ <tr><td align="right" valign="top"><b>Background Color:</b></td> |
| 1505 | 1569 | @ <td valign="top"> |
| 1506 | - @ <table border="0" cellpadding="0" cellspacing="1"> | |
| 1507 | - @ <tr><td colspan="6" align="left"> | |
| 1508 | - if( fPropagateColor ){ | |
| 1509 | - @ <input type="checkbox" name="pclr" checked="checked" /> | |
| 1510 | - }else{ | |
| 1511 | - @ <input type="checkbox" name="pclr" /> | |
| 1512 | - } | |
| 1513 | - @ Propagate color to descendants</td></tr> | |
| 1514 | - @ <tr> | |
| 1515 | - for(i=0,stdClrFound=0; i<nColor; i++){ | |
| 1516 | - if( aColor[i].zColor[0] ){ | |
| 1517 | - @ <td style="background-color: %h(aColor[i].zColor);"> | |
| 1518 | - }else{ | |
| 1519 | - @ <td> | |
| 1520 | - } | |
| 1521 | - if( strcmp(zNewColor, aColor[i].zColor)==0 ){ | |
| 1522 | - @ <input type="radio" name="clr" value="%h(aColor[i].zColor)" | |
| 1523 | - @ checked="checked" /> | |
| 1524 | - stdClrFound=1; | |
| 1525 | - }else{ | |
| 1526 | - @ <input type="radio" name="clr" value="%h(aColor[i].zColor)" /> | |
| 1527 | - } | |
| 1528 | - @ %h(aColor[i].zCName)</td> | |
| 1529 | - if( (i%6)==5 && i+1<nColor ){ | |
| 1530 | - @ </tr><tr> | |
| 1531 | - } | |
| 1532 | - } | |
| 1533 | - @ </tr><tr> | |
| 1534 | - if (stdClrFound){ | |
| 1535 | - @ <td colspan="6"> | |
| 1536 | - @ <input type="radio" name="clr" value="%h(aColor[nColor].zColor)" /> | |
| 1537 | - }else{ | |
| 1538 | - @ <td style="background-color: %h(zNewColor);" colspan="6"> | |
| 1539 | - @ <input type="radio" name="clr" value="%h(aColor[nColor].zColor)" | |
| 1540 | - @ checked="checked" /> | |
| 1541 | - } | |
| 1542 | - @ %h(aColor[i].zCName) | |
| 1543 | - @ <input type="text" name="clrcust" id="clrcust" class="checkinUserColor" | |
| 1544 | - @ value="%h(stdClrFound?"":zNewColor)" /> | |
| 1545 | - @ </td> | |
| 1546 | - @ </tr> | |
| 1547 | - @ </table> | |
| 1570 | + render_color_chooser(fPropagateColor, zNewColor, "pclr", "clr", "clrcust"); | |
| 1548 | 1571 | @ </td></tr> |
| 1549 | 1572 | |
| 1550 | 1573 | @ <tr><td align="right" valign="top"><b>Tags:</b></td> |
| 1551 | 1574 | @ <td valign="top"> |
| 1552 | 1575 | @ <input type="checkbox" name="newtag"%s(zNewTagFlag) /> |
| 1553 | 1576 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -779,11 +779,11 @@ | |
| 779 | } |
| 780 | } |
| 781 | db_finalize(&q); |
| 782 | if( nWiki==0 ){ |
| 783 | db_prepare(&q, |
| 784 | "SELECT datetime(mtime), user, comment, type, uuid" |
| 785 | " FROM event, blob" |
| 786 | " WHERE event.objid=%d" |
| 787 | " AND blob.rid=%d", |
| 788 | rid, rid |
| 789 | ); |
| @@ -800,14 +800,19 @@ | |
| 800 | @ Wiki edit |
| 801 | }else if( zType[0]=='t' ){ |
| 802 | @ Ticket change |
| 803 | }else if( zType[0]=='c' ){ |
| 804 | @ Manifest of check-in |
| 805 | }else{ |
| 806 | @ Control file referencing |
| 807 | } |
| 808 | hyperlink_to_uuid(zUuid); |
| 809 | @ - %w(zCom) by |
| 810 | hyperlink_to_user(zUser,zDate," on"); |
| 811 | hyperlink_to_date(zDate, "."); |
| 812 | if( pDownloadName && blob_size(pDownloadName)==0 ){ |
| 813 | blob_appendf(pDownloadName, "%.10s.txt", zUuid); |
| @@ -1260,10 +1265,90 @@ | |
| 1260 | }else |
| 1261 | { |
| 1262 | artifact_page(); |
| 1263 | } |
| 1264 | } |
| 1265 | |
| 1266 | /* |
| 1267 | ** WEBPAGE: ci_edit |
| 1268 | ** URL: ci_edit?r=RID&c=NEWCOMMENT&u=NEWUSER |
| 1269 | ** |
| @@ -1290,31 +1375,10 @@ | |
| 1290 | const char *zCloseFlag; |
| 1291 | int fPropagateColor; |
| 1292 | char *zUuid; |
| 1293 | Blob comment; |
| 1294 | Stmt q; |
| 1295 | static const struct SampleColors { |
| 1296 | const char *zCName; |
| 1297 | const char *zColor; |
| 1298 | } aColor[] = { |
| 1299 | { "(none)", "" }, |
| 1300 | { "#f2dcdc", "#f2dcdc" }, |
| 1301 | { "#f0ffc0", "#f0ffc0" }, |
| 1302 | { "#bde5d6", "#bde5d6" }, |
| 1303 | { "#c0ffc0", "#c0ffc0" }, |
| 1304 | { "#c0fff0", "#c0fff0" }, |
| 1305 | { "#c0f0ff", "#c0f0ff" }, |
| 1306 | { "#d0c0ff", "#d0c0ff" }, |
| 1307 | { "#ffc0ff", "#ffc0ff" }, |
| 1308 | { "#ffc0d0", "#ffc0d0" }, |
| 1309 | { "#fff0c0", "#fff0c0" }, |
| 1310 | { "#c0c0c0", "#c0c0c0" }, |
| 1311 | { "custom", "##" }, |
| 1312 | }; |
| 1313 | int nColor = sizeof(aColor)/sizeof(aColor[0])-1; |
| 1314 | int stdClrFound; |
| 1315 | int i; |
| 1316 | |
| 1317 | login_check_credentials(); |
| 1318 | if( !g.okWrite ){ login_needed(); return; } |
| 1319 | rid = name_to_rid(P("r")); |
| 1320 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| @@ -1334,11 +1398,11 @@ | |
| 1334 | if( zDate==0 ) fossil_redirect_home(); |
| 1335 | zNewDate = PD("dt",zDate); |
| 1336 | zColor = db_text("", "SELECT bgcolor" |
| 1337 | " FROM event WHERE objid=%d", rid); |
| 1338 | zNewColor = PD("clr",zColor); |
| 1339 | if( strcmp(zNewColor,aColor[nColor].zColor)==0 ){ |
| 1340 | zNewColor = P("clrcust"); |
| 1341 | } |
| 1342 | fPropagateColor = P("pclr")!=0; |
| 1343 | zNewTagFlag = P("newtag") ? " checked" : ""; |
| 1344 | zNewTag = PD("tagname",""); |
| @@ -1501,52 +1565,11 @@ | |
| 1501 | @ <input type="text" name="dt" size="20" value="%h(zNewDate)" /> |
| 1502 | @ </td></tr> |
| 1503 | |
| 1504 | @ <tr><td align="right" valign="top"><b>Background Color:</b></td> |
| 1505 | @ <td valign="top"> |
| 1506 | @ <table border="0" cellpadding="0" cellspacing="1"> |
| 1507 | @ <tr><td colspan="6" align="left"> |
| 1508 | if( fPropagateColor ){ |
| 1509 | @ <input type="checkbox" name="pclr" checked="checked" /> |
| 1510 | }else{ |
| 1511 | @ <input type="checkbox" name="pclr" /> |
| 1512 | } |
| 1513 | @ Propagate color to descendants</td></tr> |
| 1514 | @ <tr> |
| 1515 | for(i=0,stdClrFound=0; i<nColor; i++){ |
| 1516 | if( aColor[i].zColor[0] ){ |
| 1517 | @ <td style="background-color: %h(aColor[i].zColor);"> |
| 1518 | }else{ |
| 1519 | @ <td> |
| 1520 | } |
| 1521 | if( strcmp(zNewColor, aColor[i].zColor)==0 ){ |
| 1522 | @ <input type="radio" name="clr" value="%h(aColor[i].zColor)" |
| 1523 | @ checked="checked" /> |
| 1524 | stdClrFound=1; |
| 1525 | }else{ |
| 1526 | @ <input type="radio" name="clr" value="%h(aColor[i].zColor)" /> |
| 1527 | } |
| 1528 | @ %h(aColor[i].zCName)</td> |
| 1529 | if( (i%6)==5 && i+1<nColor ){ |
| 1530 | @ </tr><tr> |
| 1531 | } |
| 1532 | } |
| 1533 | @ </tr><tr> |
| 1534 | if (stdClrFound){ |
| 1535 | @ <td colspan="6"> |
| 1536 | @ <input type="radio" name="clr" value="%h(aColor[nColor].zColor)" /> |
| 1537 | }else{ |
| 1538 | @ <td style="background-color: %h(zNewColor);" colspan="6"> |
| 1539 | @ <input type="radio" name="clr" value="%h(aColor[nColor].zColor)" |
| 1540 | @ checked="checked" /> |
| 1541 | } |
| 1542 | @ %h(aColor[i].zCName) |
| 1543 | @ <input type="text" name="clrcust" id="clrcust" class="checkinUserColor" |
| 1544 | @ value="%h(stdClrFound?"":zNewColor)" /> |
| 1545 | @ </td> |
| 1546 | @ </tr> |
| 1547 | @ </table> |
| 1548 | @ </td></tr> |
| 1549 | |
| 1550 | @ <tr><td align="right" valign="top"><b>Tags:</b></td> |
| 1551 | @ <td valign="top"> |
| 1552 | @ <input type="checkbox" name="newtag"%s(zNewTagFlag) /> |
| 1553 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -779,11 +779,11 @@ | |
| 779 | } |
| 780 | } |
| 781 | db_finalize(&q); |
| 782 | if( nWiki==0 ){ |
| 783 | db_prepare(&q, |
| 784 | "SELECT datetime(mtime), user, comment, type, uuid, tagid" |
| 785 | " FROM event, blob" |
| 786 | " WHERE event.objid=%d" |
| 787 | " AND blob.rid=%d", |
| 788 | rid, rid |
| 789 | ); |
| @@ -800,14 +800,19 @@ | |
| 800 | @ Wiki edit |
| 801 | }else if( zType[0]=='t' ){ |
| 802 | @ Ticket change |
| 803 | }else if( zType[0]=='c' ){ |
| 804 | @ Manifest of check-in |
| 805 | }else if( zType[0]=='e' ){ |
| 806 | @ Instance of event |
| 807 | hyperlink_to_event_tagid(db_column_int(&q, 5)); |
| 808 | }else{ |
| 809 | @ Control file referencing |
| 810 | } |
| 811 | if( zType[0]!='e' ){ |
| 812 | hyperlink_to_uuid(zUuid); |
| 813 | } |
| 814 | @ - %w(zCom) by |
| 815 | hyperlink_to_user(zUser,zDate," on"); |
| 816 | hyperlink_to_date(zDate, "."); |
| 817 | if( pDownloadName && blob_size(pDownloadName)==0 ){ |
| 818 | blob_appendf(pDownloadName, "%.10s.txt", zUuid); |
| @@ -1260,10 +1265,90 @@ | |
| 1265 | }else |
| 1266 | { |
| 1267 | artifact_page(); |
| 1268 | } |
| 1269 | } |
| 1270 | |
| 1271 | /* |
| 1272 | ** Generate HTML that will present the user with a selection of |
| 1273 | ** potential background colors for timeline entries. |
| 1274 | */ |
| 1275 | void render_color_chooser( |
| 1276 | int fPropagate, /* Default value for propagation */ |
| 1277 | const char *zDefaultColor, /* The current default color */ |
| 1278 | const char *zIdPropagate, /* ID of form element checkbox. NULL for none */ |
| 1279 | const char *zId, /* The ID of the form element */ |
| 1280 | const char *zIdCustom /* ID of text box for custom color */ |
| 1281 | ){ |
| 1282 | static const struct SampleColors { |
| 1283 | const char *zCName; |
| 1284 | const char *zColor; |
| 1285 | } aColor[] = { |
| 1286 | { "(none)", "" }, |
| 1287 | { "#f2dcdc", "#f2dcdc" }, |
| 1288 | { "#f0ffc0", "#f0ffc0" }, |
| 1289 | { "#bde5d6", "#bde5d6" }, |
| 1290 | { "#c0ffc0", "#c0ffc0" }, |
| 1291 | { "#c0fff0", "#c0fff0" }, |
| 1292 | { "#c0f0ff", "#c0f0ff" }, |
| 1293 | { "#d0c0ff", "#d0c0ff" }, |
| 1294 | { "#ffc0ff", "#ffc0ff" }, |
| 1295 | { "#ffc0d0", "#ffc0d0" }, |
| 1296 | { "#fff0c0", "#fff0c0" }, |
| 1297 | { "#c0c0c0", "#c0c0c0" }, |
| 1298 | { "custom", "##" }, |
| 1299 | }; |
| 1300 | int nColor = sizeof(aColor)/sizeof(aColor[0])-1; |
| 1301 | int stdClrFound = 0; |
| 1302 | int i; |
| 1303 | |
| 1304 | @ <table border="0" cellpadding="0" cellspacing="1"> |
| 1305 | if( zIdPropagate ){ |
| 1306 | @ <tr><td colspan="6" align="left"> |
| 1307 | if( fPropagate ){ |
| 1308 | @ <input type="checkbox" name="%s(zIdPropagate)" checked="checked" /> |
| 1309 | }else{ |
| 1310 | @ <input type="checkbox" name="%s(zIdPropagate)" /> |
| 1311 | } |
| 1312 | @ Propagate color to descendants</td></tr> |
| 1313 | } |
| 1314 | @ <tr> |
| 1315 | for(i=0; i<nColor; i++){ |
| 1316 | if( aColor[i].zColor[0] ){ |
| 1317 | @ <td style="background-color: %h(aColor[i].zColor);"> |
| 1318 | }else{ |
| 1319 | @ <td> |
| 1320 | } |
| 1321 | if( strcmp(zDefaultColor, aColor[i].zColor)==0 ){ |
| 1322 | @ <input type="radio" name="%s(zId)" value="%h(aColor[i].zColor)" |
| 1323 | @ checked="checked" /> |
| 1324 | stdClrFound=1; |
| 1325 | }else{ |
| 1326 | @ <input type="radio" name="%s(zId)" value="%h(aColor[i].zColor)" /> |
| 1327 | } |
| 1328 | @ %h(aColor[i].zCName)</td> |
| 1329 | if( (i%6)==5 && i+1<nColor ){ |
| 1330 | @ </tr><tr> |
| 1331 | } |
| 1332 | } |
| 1333 | @ </tr><tr> |
| 1334 | if (stdClrFound){ |
| 1335 | @ <td colspan="6"> |
| 1336 | @ <input type="radio" name="%s(zId)" value="%h(aColor[nColor].zColor)" /> |
| 1337 | }else{ |
| 1338 | @ <td style="background-color: %h(zDefaultColor);" colspan="6"> |
| 1339 | @ <input type="radio" name="%s(zId)" value="%h(aColor[nColor].zColor)" |
| 1340 | @ checked="checked" /> |
| 1341 | } |
| 1342 | @ %h(aColor[i].zCName) |
| 1343 | @ <input type="text" name="%s(zIdCustom)" |
| 1344 | @ id="%s(zIdCustom)" class="checkinUserColor" |
| 1345 | @ value="%h(stdClrFound?"":zDefaultColor)" /> |
| 1346 | @ </td> |
| 1347 | @ </tr> |
| 1348 | @ </table> |
| 1349 | } |
| 1350 | |
| 1351 | /* |
| 1352 | ** WEBPAGE: ci_edit |
| 1353 | ** URL: ci_edit?r=RID&c=NEWCOMMENT&u=NEWUSER |
| 1354 | ** |
| @@ -1290,31 +1375,10 @@ | |
| 1375 | const char *zCloseFlag; |
| 1376 | int fPropagateColor; |
| 1377 | char *zUuid; |
| 1378 | Blob comment; |
| 1379 | Stmt q; |
| 1380 | |
| 1381 | login_check_credentials(); |
| 1382 | if( !g.okWrite ){ login_needed(); return; } |
| 1383 | rid = name_to_rid(P("r")); |
| 1384 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| @@ -1334,11 +1398,11 @@ | |
| 1398 | if( zDate==0 ) fossil_redirect_home(); |
| 1399 | zNewDate = PD("dt",zDate); |
| 1400 | zColor = db_text("", "SELECT bgcolor" |
| 1401 | " FROM event WHERE objid=%d", rid); |
| 1402 | zNewColor = PD("clr",zColor); |
| 1403 | if( strcmp(zNewColor,"##")==0 ){ |
| 1404 | zNewColor = P("clrcust"); |
| 1405 | } |
| 1406 | fPropagateColor = P("pclr")!=0; |
| 1407 | zNewTagFlag = P("newtag") ? " checked" : ""; |
| 1408 | zNewTag = PD("tagname",""); |
| @@ -1501,52 +1565,11 @@ | |
| 1565 | @ <input type="text" name="dt" size="20" value="%h(zNewDate)" /> |
| 1566 | @ </td></tr> |
| 1567 | |
| 1568 | @ <tr><td align="right" valign="top"><b>Background Color:</b></td> |
| 1569 | @ <td valign="top"> |
| 1570 | render_color_chooser(fPropagateColor, zNewColor, "pclr", "clr", "clrcust"); |
| 1571 | @ </td></tr> |
| 1572 | |
| 1573 | @ <tr><td align="right" valign="top"><b>Tags:</b></td> |
| 1574 | @ <td valign="top"> |
| 1575 | @ <input type="checkbox" name="newtag"%s(zNewTagFlag) /> |
| 1576 |
+12
-2
| --- src/main.mk | ||
| +++ src/main.mk | ||
| @@ -35,10 +35,11 @@ | ||
| 35 | 35 | $(SRCDIR)/descendants.c \ |
| 36 | 36 | $(SRCDIR)/diff.c \ |
| 37 | 37 | $(SRCDIR)/diffcmd.c \ |
| 38 | 38 | $(SRCDIR)/doc.c \ |
| 39 | 39 | $(SRCDIR)/encode.c \ |
| 40 | + $(SRCDIR)/event.c \ | |
| 40 | 41 | $(SRCDIR)/file.c \ |
| 41 | 42 | $(SRCDIR)/finfo.c \ |
| 42 | 43 | $(SRCDIR)/graph.c \ |
| 43 | 44 | $(SRCDIR)/http.c \ |
| 44 | 45 | $(SRCDIR)/http_socket.c \ |
| @@ -108,10 +109,11 @@ | ||
| 108 | 109 | descendants_.c \ |
| 109 | 110 | diff_.c \ |
| 110 | 111 | diffcmd_.c \ |
| 111 | 112 | doc_.c \ |
| 112 | 113 | encode_.c \ |
| 114 | + event_.c \ | |
| 113 | 115 | file_.c \ |
| 114 | 116 | finfo_.c \ |
| 115 | 117 | graph_.c \ |
| 116 | 118 | http_.c \ |
| 117 | 119 | http_socket_.c \ |
| @@ -181,10 +183,11 @@ | ||
| 181 | 183 | $(OBJDIR)/descendants.o \ |
| 182 | 184 | $(OBJDIR)/diff.o \ |
| 183 | 185 | $(OBJDIR)/diffcmd.o \ |
| 184 | 186 | $(OBJDIR)/doc.o \ |
| 185 | 187 | $(OBJDIR)/encode.o \ |
| 188 | + $(OBJDIR)/event.o \ | |
| 186 | 189 | $(OBJDIR)/file.o \ |
| 187 | 190 | $(OBJDIR)/finfo.o \ |
| 188 | 191 | $(OBJDIR)/graph.o \ |
| 189 | 192 | $(OBJDIR)/http.o \ |
| 190 | 193 | $(OBJDIR)/http_socket.o \ |
| @@ -273,16 +276,16 @@ | ||
| 273 | 276 | # noop |
| 274 | 277 | |
| 275 | 278 | clean: |
| 276 | 279 | rm -f $(OBJDIR)/*.o *_.c $(APPNAME) VERSION.h |
| 277 | 280 | rm -f translate makeheaders mkindex page_index.h headers |
| 278 | - 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 | |
| 281 | + 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 | |
| 279 | 282 | |
| 280 | 283 | page_index.h: $(TRANS_SRC) mkindex |
| 281 | 284 | ./mkindex $(TRANS_SRC) >$@ |
| 282 | 285 | headers: page_index.h makeheaders VERSION.h |
| 283 | - ./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 | |
| 286 | + ./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 | |
| 284 | 287 | touch headers |
| 285 | 288 | headers: Makefile |
| 286 | 289 | Makefile: |
| 287 | 290 | add_.c: $(SRCDIR)/add.c translate |
| 288 | 291 | ./translate $(SRCDIR)/add.c >add_.c |
| @@ -450,10 +453,17 @@ | ||
| 450 | 453 | |
| 451 | 454 | $(OBJDIR)/encode.o: encode_.c encode.h $(SRCDIR)/config.h |
| 452 | 455 | $(XTCC) -o $(OBJDIR)/encode.o -c encode_.c |
| 453 | 456 | |
| 454 | 457 | encode.h: headers |
| 458 | +event_.c: $(SRCDIR)/event.c translate | |
| 459 | + ./translate $(SRCDIR)/event.c >event_.c | |
| 460 | + | |
| 461 | +$(OBJDIR)/event.o: event_.c event.h $(SRCDIR)/config.h | |
| 462 | + $(XTCC) -o $(OBJDIR)/event.o -c event_.c | |
| 463 | + | |
| 464 | +event.h: headers | |
| 455 | 465 | file_.c: $(SRCDIR)/file.c translate |
| 456 | 466 | ./translate $(SRCDIR)/file.c >file_.c |
| 457 | 467 | |
| 458 | 468 | $(OBJDIR)/file.o: file_.c file.h $(SRCDIR)/config.h |
| 459 | 469 | $(XTCC) -o $(OBJDIR)/file.o -c file_.c |
| 460 | 470 |
| --- src/main.mk | |
| +++ src/main.mk | |
| @@ -35,10 +35,11 @@ | |
| 35 | $(SRCDIR)/descendants.c \ |
| 36 | $(SRCDIR)/diff.c \ |
| 37 | $(SRCDIR)/diffcmd.c \ |
| 38 | $(SRCDIR)/doc.c \ |
| 39 | $(SRCDIR)/encode.c \ |
| 40 | $(SRCDIR)/file.c \ |
| 41 | $(SRCDIR)/finfo.c \ |
| 42 | $(SRCDIR)/graph.c \ |
| 43 | $(SRCDIR)/http.c \ |
| 44 | $(SRCDIR)/http_socket.c \ |
| @@ -108,10 +109,11 @@ | |
| 108 | descendants_.c \ |
| 109 | diff_.c \ |
| 110 | diffcmd_.c \ |
| 111 | doc_.c \ |
| 112 | encode_.c \ |
| 113 | file_.c \ |
| 114 | finfo_.c \ |
| 115 | graph_.c \ |
| 116 | http_.c \ |
| 117 | http_socket_.c \ |
| @@ -181,10 +183,11 @@ | |
| 181 | $(OBJDIR)/descendants.o \ |
| 182 | $(OBJDIR)/diff.o \ |
| 183 | $(OBJDIR)/diffcmd.o \ |
| 184 | $(OBJDIR)/doc.o \ |
| 185 | $(OBJDIR)/encode.o \ |
| 186 | $(OBJDIR)/file.o \ |
| 187 | $(OBJDIR)/finfo.o \ |
| 188 | $(OBJDIR)/graph.o \ |
| 189 | $(OBJDIR)/http.o \ |
| 190 | $(OBJDIR)/http_socket.o \ |
| @@ -273,16 +276,16 @@ | |
| 273 | # noop |
| 274 | |
| 275 | clean: |
| 276 | rm -f $(OBJDIR)/*.o *_.c $(APPNAME) VERSION.h |
| 277 | rm -f translate makeheaders mkindex page_index.h headers |
| 278 | 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 |
| 279 | |
| 280 | page_index.h: $(TRANS_SRC) mkindex |
| 281 | ./mkindex $(TRANS_SRC) >$@ |
| 282 | headers: page_index.h makeheaders VERSION.h |
| 283 | ./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 |
| 284 | touch headers |
| 285 | headers: Makefile |
| 286 | Makefile: |
| 287 | add_.c: $(SRCDIR)/add.c translate |
| 288 | ./translate $(SRCDIR)/add.c >add_.c |
| @@ -450,10 +453,17 @@ | |
| 450 | |
| 451 | $(OBJDIR)/encode.o: encode_.c encode.h $(SRCDIR)/config.h |
| 452 | $(XTCC) -o $(OBJDIR)/encode.o -c encode_.c |
| 453 | |
| 454 | encode.h: headers |
| 455 | file_.c: $(SRCDIR)/file.c translate |
| 456 | ./translate $(SRCDIR)/file.c >file_.c |
| 457 | |
| 458 | $(OBJDIR)/file.o: file_.c file.h $(SRCDIR)/config.h |
| 459 | $(XTCC) -o $(OBJDIR)/file.o -c file_.c |
| 460 |
| --- src/main.mk | |
| +++ src/main.mk | |
| @@ -35,10 +35,11 @@ | |
| 35 | $(SRCDIR)/descendants.c \ |
| 36 | $(SRCDIR)/diff.c \ |
| 37 | $(SRCDIR)/diffcmd.c \ |
| 38 | $(SRCDIR)/doc.c \ |
| 39 | $(SRCDIR)/encode.c \ |
| 40 | $(SRCDIR)/event.c \ |
| 41 | $(SRCDIR)/file.c \ |
| 42 | $(SRCDIR)/finfo.c \ |
| 43 | $(SRCDIR)/graph.c \ |
| 44 | $(SRCDIR)/http.c \ |
| 45 | $(SRCDIR)/http_socket.c \ |
| @@ -108,10 +109,11 @@ | |
| 109 | descendants_.c \ |
| 110 | diff_.c \ |
| 111 | diffcmd_.c \ |
| 112 | doc_.c \ |
| 113 | encode_.c \ |
| 114 | event_.c \ |
| 115 | file_.c \ |
| 116 | finfo_.c \ |
| 117 | graph_.c \ |
| 118 | http_.c \ |
| 119 | http_socket_.c \ |
| @@ -181,10 +183,11 @@ | |
| 183 | $(OBJDIR)/descendants.o \ |
| 184 | $(OBJDIR)/diff.o \ |
| 185 | $(OBJDIR)/diffcmd.o \ |
| 186 | $(OBJDIR)/doc.o \ |
| 187 | $(OBJDIR)/encode.o \ |
| 188 | $(OBJDIR)/event.o \ |
| 189 | $(OBJDIR)/file.o \ |
| 190 | $(OBJDIR)/finfo.o \ |
| 191 | $(OBJDIR)/graph.o \ |
| 192 | $(OBJDIR)/http.o \ |
| 193 | $(OBJDIR)/http_socket.o \ |
| @@ -273,16 +276,16 @@ | |
| 276 | # noop |
| 277 | |
| 278 | clean: |
| 279 | rm -f $(OBJDIR)/*.o *_.c $(APPNAME) VERSION.h |
| 280 | rm -f translate makeheaders mkindex page_index.h headers |
| 281 | 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 |
| 282 | |
| 283 | page_index.h: $(TRANS_SRC) mkindex |
| 284 | ./mkindex $(TRANS_SRC) >$@ |
| 285 | headers: page_index.h makeheaders VERSION.h |
| 286 | ./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 |
| 287 | touch headers |
| 288 | headers: Makefile |
| 289 | Makefile: |
| 290 | add_.c: $(SRCDIR)/add.c translate |
| 291 | ./translate $(SRCDIR)/add.c >add_.c |
| @@ -450,10 +453,17 @@ | |
| 453 | |
| 454 | $(OBJDIR)/encode.o: encode_.c encode.h $(SRCDIR)/config.h |
| 455 | $(XTCC) -o $(OBJDIR)/encode.o -c encode_.c |
| 456 | |
| 457 | encode.h: headers |
| 458 | event_.c: $(SRCDIR)/event.c translate |
| 459 | ./translate $(SRCDIR)/event.c >event_.c |
| 460 | |
| 461 | $(OBJDIR)/event.o: event_.c event.h $(SRCDIR)/config.h |
| 462 | $(XTCC) -o $(OBJDIR)/event.o -c event_.c |
| 463 | |
| 464 | event.h: headers |
| 465 | file_.c: $(SRCDIR)/file.c translate |
| 466 | ./translate $(SRCDIR)/file.c >file_.c |
| 467 | |
| 468 | $(OBJDIR)/file.o: file_.c file.h $(SRCDIR)/config.h |
| 469 | $(XTCC) -o $(OBJDIR)/file.o -c file_.c |
| 470 |
+1
| --- src/makemake.tcl | ||
| +++ src/makemake.tcl | ||
| @@ -29,10 +29,11 @@ | ||
| 29 | 29 | descendants |
| 30 | 30 | diff |
| 31 | 31 | diffcmd |
| 32 | 32 | doc |
| 33 | 33 | encode |
| 34 | + event | |
| 34 | 35 | file |
| 35 | 36 | finfo |
| 36 | 37 | graph |
| 37 | 38 | http |
| 38 | 39 | http_socket |
| 39 | 40 |
| --- src/makemake.tcl | |
| +++ src/makemake.tcl | |
| @@ -29,10 +29,11 @@ | |
| 29 | descendants |
| 30 | diff |
| 31 | diffcmd |
| 32 | doc |
| 33 | encode |
| 34 | file |
| 35 | finfo |
| 36 | graph |
| 37 | http |
| 38 | http_socket |
| 39 |
| --- src/makemake.tcl | |
| +++ src/makemake.tcl | |
| @@ -29,10 +29,11 @@ | |
| 29 | descendants |
| 30 | diff |
| 31 | diffcmd |
| 32 | doc |
| 33 | encode |
| 34 | event |
| 35 | file |
| 36 | finfo |
| 37 | graph |
| 38 | http |
| 39 | http_socket |
| 40 |
+99
-7
| --- src/manifest.c | ||
| +++ src/manifest.c | ||
| @@ -32,10 +32,11 @@ | ||
| 32 | 32 | #define CFTYPE_CLUSTER 2 |
| 33 | 33 | #define CFTYPE_CONTROL 3 |
| 34 | 34 | #define CFTYPE_WIKI 4 |
| 35 | 35 | #define CFTYPE_TICKET 5 |
| 36 | 36 | #define CFTYPE_ATTACHMENT 6 |
| 37 | +#define CFTYPE_EVENT 7 | |
| 37 | 38 | |
| 38 | 39 | /* |
| 39 | 40 | ** A parsed manifest or cluster. |
| 40 | 41 | */ |
| 41 | 42 | struct Manifest { |
| @@ -45,10 +46,12 @@ | ||
| 45 | 46 | double rDate; /* Date and time from D card. 0.0 if no D card. */ |
| 46 | 47 | char *zUser; /* Name of the user from the U card. */ |
| 47 | 48 | char *zRepoCksum; /* MD5 checksum of the baseline content. R card. */ |
| 48 | 49 | char *zWiki; /* Text of the wiki page. W card. */ |
| 49 | 50 | char *zWikiTitle; /* Name of the wiki page. L card. */ |
| 51 | + double rEventDate; /* Date of an event. E card. */ | |
| 52 | + char *zEventId; /* UUID for an event. E card. */ | |
| 50 | 53 | char *zTicketUuid; /* UUID for a ticket. K card. */ |
| 51 | 54 | char *zAttachName; /* Filename of an attachment. A card. */ |
| 52 | 55 | char *zAttachSrc; /* UUID of document being attached. A card. */ |
| 53 | 56 | char *zAttachTarget; /* Ticket or wiki that attachment applies to. A card */ |
| 54 | 57 | int nFile; /* Number of F cards */ |
| @@ -230,10 +233,35 @@ | ||
| 230 | 233 | if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; |
| 231 | 234 | zDate = blob_terminate(&a1); |
| 232 | 235 | p->rDate = db_double(0.0, "SELECT julianday(%Q)", zDate); |
| 233 | 236 | break; |
| 234 | 237 | } |
| 238 | + | |
| 239 | + /* | |
| 240 | + ** E <timestamp> <uuid> | |
| 241 | + ** | |
| 242 | + ** An "event" card that contains the timestamp of the event in the | |
| 243 | + ** format YYYY-MM-DDtHH:MM:SS and a unique identifier for the event. | |
| 244 | + ** The event timestamp is distinct from the D timestamp. The D | |
| 245 | + ** timestamp is when the artifact was created whereas the E timestamp | |
| 246 | + ** is when the specific event is said to occur. | |
| 247 | + */ | |
| 248 | + case 'E': { | |
| 249 | + char *zEDate; | |
| 250 | + md5sum_step_text(blob_buffer(&line), blob_size(&line)); | |
| 251 | + if( p->rEventDate!=0.0 ) goto manifest_syntax_error; | |
| 252 | + if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; | |
| 253 | + if( blob_token(&line, &a2)==0 ) goto manifest_syntax_error; | |
| 254 | + if( blob_token(&line, &a3)!=0 ) goto manifest_syntax_error; | |
| 255 | + zEDate = blob_terminate(&a1); | |
| 256 | + p->rEventDate = db_double(0.0, "SELECT julianday(%Q)", zEDate); | |
| 257 | + if( p->rEventDate<=0.0 ) goto manifest_syntax_error; | |
| 258 | + if( blob_size(&a2)!=UUID_SIZE ) goto manifest_syntax_error; | |
| 259 | + p->zEventId = blob_terminate(&a2); | |
| 260 | + if( !validate16(p->zEventId, UUID_SIZE) ) goto manifest_syntax_error; | |
| 261 | + break; | |
| 262 | + } | |
| 235 | 263 | |
| 236 | 264 | /* |
| 237 | 265 | ** F <filename> <uuid> ?<permissions>? ?<old-name>? |
| 238 | 266 | ** |
| 239 | 267 | ** Identifies a file in a manifest. Multiple F lines are |
| @@ -563,15 +591,16 @@ | ||
| 563 | 591 | } |
| 564 | 592 | if( !seenHeader ) goto manifest_syntax_error; |
| 565 | 593 | |
| 566 | 594 | if( p->nFile>0 || p->zRepoCksum!=0 ){ |
| 567 | 595 | if( p->nCChild>0 ) goto manifest_syntax_error; |
| 568 | - if( p->rDate==0.0 ) goto manifest_syntax_error; | |
| 596 | + if( p->rDate<=0.0 ) goto manifest_syntax_error; | |
| 569 | 597 | if( p->nField>0 ) goto manifest_syntax_error; |
| 570 | 598 | if( p->zTicketUuid ) goto manifest_syntax_error; |
| 571 | 599 | if( p->zWiki ) goto manifest_syntax_error; |
| 572 | 600 | if( p->zWikiTitle ) goto manifest_syntax_error; |
| 601 | + if( p->zEventId ) goto manifest_syntax_error; | |
| 573 | 602 | if( p->zTicketUuid ) goto manifest_syntax_error; |
| 574 | 603 | if( p->zAttachName ) goto manifest_syntax_error; |
| 575 | 604 | p->type = CFTYPE_MANIFEST; |
| 576 | 605 | }else if( p->nCChild>0 ){ |
| 577 | 606 | if( p->rDate>0.0 ) goto manifest_syntax_error; |
| @@ -581,26 +610,41 @@ | ||
| 581 | 610 | if( p->nParent>0 ) goto manifest_syntax_error; |
| 582 | 611 | if( p->nField>0 ) goto manifest_syntax_error; |
| 583 | 612 | if( p->zTicketUuid ) goto manifest_syntax_error; |
| 584 | 613 | if( p->zWiki ) goto manifest_syntax_error; |
| 585 | 614 | if( p->zWikiTitle ) goto manifest_syntax_error; |
| 615 | + if( p->zEventId ) goto manifest_syntax_error; | |
| 586 | 616 | if( p->zAttachName ) goto manifest_syntax_error; |
| 587 | 617 | if( !seenZ ) goto manifest_syntax_error; |
| 588 | 618 | p->type = CFTYPE_CLUSTER; |
| 589 | 619 | }else if( p->nField>0 ){ |
| 590 | - if( p->rDate==0.0 ) goto manifest_syntax_error; | |
| 620 | + if( p->rDate<=0.0 ) goto manifest_syntax_error; | |
| 591 | 621 | if( p->zWiki ) goto manifest_syntax_error; |
| 592 | 622 | if( p->zWikiTitle ) goto manifest_syntax_error; |
| 623 | + if( p->zEventId ) goto manifest_syntax_error; | |
| 593 | 624 | if( p->nCChild>0 ) goto manifest_syntax_error; |
| 594 | 625 | if( p->nTag>0 ) goto manifest_syntax_error; |
| 595 | 626 | if( p->zTicketUuid==0 ) goto manifest_syntax_error; |
| 596 | 627 | if( p->zUser==0 ) goto manifest_syntax_error; |
| 597 | 628 | if( p->zAttachName ) goto manifest_syntax_error; |
| 598 | 629 | if( !seenZ ) goto manifest_syntax_error; |
| 599 | 630 | p->type = CFTYPE_TICKET; |
| 631 | + }else if( p->zEventId ){ | |
| 632 | + if( p->rDate<=0.0 ) goto manifest_syntax_error; | |
| 633 | + if( p->nCChild>0 ) goto manifest_syntax_error; | |
| 634 | + if( p->zTicketUuid!=0 ) goto manifest_syntax_error; | |
| 635 | + if( p->zWikiTitle!=0 ) goto manifest_syntax_error; | |
| 636 | + if( p->zWiki==0 ) goto manifest_syntax_error; | |
| 637 | + if( p->zAttachName ) goto manifest_syntax_error; | |
| 638 | + for(i=0; i<p->nTag; i++){ | |
| 639 | + if( p->aTag[i].zName[0]!='+' ) goto manifest_syntax_error; | |
| 640 | + if( p->aTag[i].zUuid!=0 ) goto manifest_syntax_error; | |
| 641 | + } | |
| 642 | + if( !seenZ ) goto manifest_syntax_error; | |
| 643 | + p->type = CFTYPE_EVENT; | |
| 600 | 644 | }else if( p->zWiki!=0 ){ |
| 601 | - if( p->rDate==0.0 ) goto manifest_syntax_error; | |
| 645 | + if( p->rDate<=0.0 ) goto manifest_syntax_error; | |
| 602 | 646 | if( p->nCChild>0 ) goto manifest_syntax_error; |
| 603 | 647 | if( p->nTag>0 ) goto manifest_syntax_error; |
| 604 | 648 | if( p->zTicketUuid!=0 ) goto manifest_syntax_error; |
| 605 | 649 | if( p->zWikiTitle==0 ) goto manifest_syntax_error; |
| 606 | 650 | if( p->zAttachName ) goto manifest_syntax_error; |
| @@ -614,11 +658,11 @@ | ||
| 614 | 658 | if( p->zAttachName ) goto manifest_syntax_error; |
| 615 | 659 | if( !seenZ ) goto manifest_syntax_error; |
| 616 | 660 | p->type = CFTYPE_CONTROL; |
| 617 | 661 | }else if( p->zAttachName ){ |
| 618 | 662 | if( p->nCChild>0 ) goto manifest_syntax_error; |
| 619 | - if( p->rDate==0.0 ) goto manifest_syntax_error; | |
| 663 | + if( p->rDate<=0.0 ) goto manifest_syntax_error; | |
| 620 | 664 | if( p->zTicketUuid ) goto manifest_syntax_error; |
| 621 | 665 | if( p->zWikiTitle ) goto manifest_syntax_error; |
| 622 | 666 | if( !seenZ ) goto manifest_syntax_error; |
| 623 | 667 | p->type = CFTYPE_ATTACHMENT; |
| 624 | 668 | }else{ |
| @@ -625,14 +669,12 @@ | ||
| 625 | 669 | if( p->nCChild>0 ) goto manifest_syntax_error; |
| 626 | 670 | if( p->rDate<=0.0 ) goto manifest_syntax_error; |
| 627 | 671 | if( p->nParent>0 ) goto manifest_syntax_error; |
| 628 | 672 | if( p->nField>0 ) goto manifest_syntax_error; |
| 629 | 673 | if( p->zTicketUuid ) goto manifest_syntax_error; |
| 630 | - if( p->zWiki ) goto manifest_syntax_error; | |
| 631 | 674 | if( p->zWikiTitle ) goto manifest_syntax_error; |
| 632 | 675 | if( p->zTicketUuid ) goto manifest_syntax_error; |
| 633 | - if( p->zAttachName ) goto manifest_syntax_error; | |
| 634 | 676 | p->type = CFTYPE_MANIFEST; |
| 635 | 677 | } |
| 636 | 678 | md5sum_init(); |
| 637 | 679 | return 1; |
| 638 | 680 | |
| @@ -964,10 +1006,12 @@ | ||
| 964 | 1006 | ** * Manifest |
| 965 | 1007 | ** * Control |
| 966 | 1008 | ** * Wiki Page |
| 967 | 1009 | ** * Ticket Change |
| 968 | 1010 | ** * Cluster |
| 1011 | +** * Attachment | |
| 1012 | +** * Event | |
| 969 | 1013 | ** |
| 970 | 1014 | ** If the input is a control artifact, then make appropriate entries |
| 971 | 1015 | ** in the auxiliary tables of the database in order to crosslink the |
| 972 | 1016 | ** artifact. |
| 973 | 1017 | ** |
| @@ -1043,11 +1087,14 @@ | ||
| 1043 | 1087 | if( mid>0 ){ |
| 1044 | 1088 | db_multi_exec("DELETE FROM unclustered WHERE rid=%d", mid); |
| 1045 | 1089 | } |
| 1046 | 1090 | } |
| 1047 | 1091 | } |
| 1048 | - if( m.type==CFTYPE_CONTROL || m.type==CFTYPE_MANIFEST ){ | |
| 1092 | + if( m.type==CFTYPE_CONTROL | |
| 1093 | + || m.type==CFTYPE_MANIFEST | |
| 1094 | + || m.type==CFTYPE_EVENT | |
| 1095 | + ){ | |
| 1049 | 1096 | for(i=0; i<m.nTag; i++){ |
| 1050 | 1097 | int tid; |
| 1051 | 1098 | int type; |
| 1052 | 1099 | if( m.aTag[i].zUuid ){ |
| 1053 | 1100 | tid = uuid_to_rid(m.aTag[i].zUuid, 1); |
| @@ -1109,10 +1156,55 @@ | ||
| 1109 | 1156 | TAG_BGCOLOR, rid, |
| 1110 | 1157 | TAG_USER, rid, |
| 1111 | 1158 | TAG_COMMENT, rid |
| 1112 | 1159 | ); |
| 1113 | 1160 | free(zComment); |
| 1161 | + } | |
| 1162 | + if( m.type==CFTYPE_EVENT ){ | |
| 1163 | + char *zTag = mprintf("event-%s", m.zEventId); | |
| 1164 | + int tagid = tag_findid(zTag, 1); | |
| 1165 | + int prior, subsequent; | |
| 1166 | + int nWiki; | |
| 1167 | + char zLength[40]; | |
| 1168 | + while( isspace(m.zWiki[0]) ) m.zWiki++; | |
| 1169 | + nWiki = strlen(m.zWiki); | |
| 1170 | + sqlite3_snprintf(sizeof(zLength), zLength, "%d", nWiki); | |
| 1171 | + tag_insert(zTag, 1, zLength, rid, m.rDate, rid); | |
| 1172 | + free(zTag); | |
| 1173 | + prior = db_int(0, | |
| 1174 | + "SELECT rid FROM tagxref" | |
| 1175 | + " WHERE tagid=%d AND mtime<%.17g" | |
| 1176 | + " ORDER BY mtime DESC", | |
| 1177 | + tagid, m.rDate | |
| 1178 | + ); | |
| 1179 | + if( prior ){ | |
| 1180 | + content_deltify(prior, rid, 0); | |
| 1181 | + db_multi_exec( | |
| 1182 | + "DELETE FROM event" | |
| 1183 | + " WHERE type='e'" | |
| 1184 | + " AND tagid=%d" | |
| 1185 | + " AND objid IN (SELECT rid FROM tagxref WHERE tagid=%d)", | |
| 1186 | + tagid, tagid | |
| 1187 | + ); | |
| 1188 | + } | |
| 1189 | + subsequent = db_int(0, | |
| 1190 | + "SELECT rid FROM tagxref" | |
| 1191 | + " WHERE tagid=%d AND mtime>%.17g" | |
| 1192 | + " ORDER BY mtime", | |
| 1193 | + tagid, m.rDate | |
| 1194 | + ); | |
| 1195 | + if( subsequent ){ | |
| 1196 | + content_deltify(rid, subsequent, 0); | |
| 1197 | + }else{ | |
| 1198 | + db_multi_exec( | |
| 1199 | + "REPLACE INTO event(type,mtime,objid,tagid,user,comment,bgcolor)" | |
| 1200 | + "VALUES('e',%.17g,%d,%d,%Q,%Q," | |
| 1201 | + " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d));", | |
| 1202 | + m.rEventDate, rid, tagid, m.zUser, m.zComment, | |
| 1203 | + TAG_BGCOLOR, rid | |
| 1204 | + ); | |
| 1205 | + } | |
| 1114 | 1206 | } |
| 1115 | 1207 | if( m.type==CFTYPE_TICKET ){ |
| 1116 | 1208 | char *zTag; |
| 1117 | 1209 | |
| 1118 | 1210 | assert( manifest_crosslink_busy==1 ); |
| 1119 | 1211 |
| --- src/manifest.c | |
| +++ src/manifest.c | |
| @@ -32,10 +32,11 @@ | |
| 32 | #define CFTYPE_CLUSTER 2 |
| 33 | #define CFTYPE_CONTROL 3 |
| 34 | #define CFTYPE_WIKI 4 |
| 35 | #define CFTYPE_TICKET 5 |
| 36 | #define CFTYPE_ATTACHMENT 6 |
| 37 | |
| 38 | /* |
| 39 | ** A parsed manifest or cluster. |
| 40 | */ |
| 41 | struct Manifest { |
| @@ -45,10 +46,12 @@ | |
| 45 | double rDate; /* Date and time from D card. 0.0 if no D card. */ |
| 46 | char *zUser; /* Name of the user from the U card. */ |
| 47 | char *zRepoCksum; /* MD5 checksum of the baseline content. R card. */ |
| 48 | char *zWiki; /* Text of the wiki page. W card. */ |
| 49 | char *zWikiTitle; /* Name of the wiki page. L card. */ |
| 50 | char *zTicketUuid; /* UUID for a ticket. K card. */ |
| 51 | char *zAttachName; /* Filename of an attachment. A card. */ |
| 52 | char *zAttachSrc; /* UUID of document being attached. A card. */ |
| 53 | char *zAttachTarget; /* Ticket or wiki that attachment applies to. A card */ |
| 54 | int nFile; /* Number of F cards */ |
| @@ -230,10 +233,35 @@ | |
| 230 | if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; |
| 231 | zDate = blob_terminate(&a1); |
| 232 | p->rDate = db_double(0.0, "SELECT julianday(%Q)", zDate); |
| 233 | break; |
| 234 | } |
| 235 | |
| 236 | /* |
| 237 | ** F <filename> <uuid> ?<permissions>? ?<old-name>? |
| 238 | ** |
| 239 | ** Identifies a file in a manifest. Multiple F lines are |
| @@ -563,15 +591,16 @@ | |
| 563 | } |
| 564 | if( !seenHeader ) goto manifest_syntax_error; |
| 565 | |
| 566 | if( p->nFile>0 || p->zRepoCksum!=0 ){ |
| 567 | if( p->nCChild>0 ) goto manifest_syntax_error; |
| 568 | if( p->rDate==0.0 ) goto manifest_syntax_error; |
| 569 | if( p->nField>0 ) goto manifest_syntax_error; |
| 570 | if( p->zTicketUuid ) goto manifest_syntax_error; |
| 571 | if( p->zWiki ) goto manifest_syntax_error; |
| 572 | if( p->zWikiTitle ) goto manifest_syntax_error; |
| 573 | if( p->zTicketUuid ) goto manifest_syntax_error; |
| 574 | if( p->zAttachName ) goto manifest_syntax_error; |
| 575 | p->type = CFTYPE_MANIFEST; |
| 576 | }else if( p->nCChild>0 ){ |
| 577 | if( p->rDate>0.0 ) goto manifest_syntax_error; |
| @@ -581,26 +610,41 @@ | |
| 581 | if( p->nParent>0 ) goto manifest_syntax_error; |
| 582 | if( p->nField>0 ) goto manifest_syntax_error; |
| 583 | if( p->zTicketUuid ) goto manifest_syntax_error; |
| 584 | if( p->zWiki ) goto manifest_syntax_error; |
| 585 | if( p->zWikiTitle ) goto manifest_syntax_error; |
| 586 | if( p->zAttachName ) goto manifest_syntax_error; |
| 587 | if( !seenZ ) goto manifest_syntax_error; |
| 588 | p->type = CFTYPE_CLUSTER; |
| 589 | }else if( p->nField>0 ){ |
| 590 | if( p->rDate==0.0 ) goto manifest_syntax_error; |
| 591 | if( p->zWiki ) goto manifest_syntax_error; |
| 592 | if( p->zWikiTitle ) goto manifest_syntax_error; |
| 593 | if( p->nCChild>0 ) goto manifest_syntax_error; |
| 594 | if( p->nTag>0 ) goto manifest_syntax_error; |
| 595 | if( p->zTicketUuid==0 ) goto manifest_syntax_error; |
| 596 | if( p->zUser==0 ) goto manifest_syntax_error; |
| 597 | if( p->zAttachName ) goto manifest_syntax_error; |
| 598 | if( !seenZ ) goto manifest_syntax_error; |
| 599 | p->type = CFTYPE_TICKET; |
| 600 | }else if( p->zWiki!=0 ){ |
| 601 | if( p->rDate==0.0 ) goto manifest_syntax_error; |
| 602 | if( p->nCChild>0 ) goto manifest_syntax_error; |
| 603 | if( p->nTag>0 ) goto manifest_syntax_error; |
| 604 | if( p->zTicketUuid!=0 ) goto manifest_syntax_error; |
| 605 | if( p->zWikiTitle==0 ) goto manifest_syntax_error; |
| 606 | if( p->zAttachName ) goto manifest_syntax_error; |
| @@ -614,11 +658,11 @@ | |
| 614 | if( p->zAttachName ) goto manifest_syntax_error; |
| 615 | if( !seenZ ) goto manifest_syntax_error; |
| 616 | p->type = CFTYPE_CONTROL; |
| 617 | }else if( p->zAttachName ){ |
| 618 | if( p->nCChild>0 ) goto manifest_syntax_error; |
| 619 | if( p->rDate==0.0 ) goto manifest_syntax_error; |
| 620 | if( p->zTicketUuid ) goto manifest_syntax_error; |
| 621 | if( p->zWikiTitle ) goto manifest_syntax_error; |
| 622 | if( !seenZ ) goto manifest_syntax_error; |
| 623 | p->type = CFTYPE_ATTACHMENT; |
| 624 | }else{ |
| @@ -625,14 +669,12 @@ | |
| 625 | if( p->nCChild>0 ) goto manifest_syntax_error; |
| 626 | if( p->rDate<=0.0 ) goto manifest_syntax_error; |
| 627 | if( p->nParent>0 ) goto manifest_syntax_error; |
| 628 | if( p->nField>0 ) goto manifest_syntax_error; |
| 629 | if( p->zTicketUuid ) goto manifest_syntax_error; |
| 630 | if( p->zWiki ) goto manifest_syntax_error; |
| 631 | if( p->zWikiTitle ) goto manifest_syntax_error; |
| 632 | if( p->zTicketUuid ) goto manifest_syntax_error; |
| 633 | if( p->zAttachName ) goto manifest_syntax_error; |
| 634 | p->type = CFTYPE_MANIFEST; |
| 635 | } |
| 636 | md5sum_init(); |
| 637 | return 1; |
| 638 | |
| @@ -964,10 +1006,12 @@ | |
| 964 | ** * Manifest |
| 965 | ** * Control |
| 966 | ** * Wiki Page |
| 967 | ** * Ticket Change |
| 968 | ** * Cluster |
| 969 | ** |
| 970 | ** If the input is a control artifact, then make appropriate entries |
| 971 | ** in the auxiliary tables of the database in order to crosslink the |
| 972 | ** artifact. |
| 973 | ** |
| @@ -1043,11 +1087,14 @@ | |
| 1043 | if( mid>0 ){ |
| 1044 | db_multi_exec("DELETE FROM unclustered WHERE rid=%d", mid); |
| 1045 | } |
| 1046 | } |
| 1047 | } |
| 1048 | if( m.type==CFTYPE_CONTROL || m.type==CFTYPE_MANIFEST ){ |
| 1049 | for(i=0; i<m.nTag; i++){ |
| 1050 | int tid; |
| 1051 | int type; |
| 1052 | if( m.aTag[i].zUuid ){ |
| 1053 | tid = uuid_to_rid(m.aTag[i].zUuid, 1); |
| @@ -1109,10 +1156,55 @@ | |
| 1109 | TAG_BGCOLOR, rid, |
| 1110 | TAG_USER, rid, |
| 1111 | TAG_COMMENT, rid |
| 1112 | ); |
| 1113 | free(zComment); |
| 1114 | } |
| 1115 | if( m.type==CFTYPE_TICKET ){ |
| 1116 | char *zTag; |
| 1117 | |
| 1118 | assert( manifest_crosslink_busy==1 ); |
| 1119 |
| --- src/manifest.c | |
| +++ src/manifest.c | |
| @@ -32,10 +32,11 @@ | |
| 32 | #define CFTYPE_CLUSTER 2 |
| 33 | #define CFTYPE_CONTROL 3 |
| 34 | #define CFTYPE_WIKI 4 |
| 35 | #define CFTYPE_TICKET 5 |
| 36 | #define CFTYPE_ATTACHMENT 6 |
| 37 | #define CFTYPE_EVENT 7 |
| 38 | |
| 39 | /* |
| 40 | ** A parsed manifest or cluster. |
| 41 | */ |
| 42 | struct Manifest { |
| @@ -45,10 +46,12 @@ | |
| 46 | double rDate; /* Date and time from D card. 0.0 if no D card. */ |
| 47 | char *zUser; /* Name of the user from the U card. */ |
| 48 | char *zRepoCksum; /* MD5 checksum of the baseline content. R card. */ |
| 49 | char *zWiki; /* Text of the wiki page. W card. */ |
| 50 | char *zWikiTitle; /* Name of the wiki page. L card. */ |
| 51 | double rEventDate; /* Date of an event. E card. */ |
| 52 | char *zEventId; /* UUID for an event. E card. */ |
| 53 | char *zTicketUuid; /* UUID for a ticket. K card. */ |
| 54 | char *zAttachName; /* Filename of an attachment. A card. */ |
| 55 | char *zAttachSrc; /* UUID of document being attached. A card. */ |
| 56 | char *zAttachTarget; /* Ticket or wiki that attachment applies to. A card */ |
| 57 | int nFile; /* Number of F cards */ |
| @@ -230,10 +233,35 @@ | |
| 233 | if( blob_token(&line, &a2)!=0 ) goto manifest_syntax_error; |
| 234 | zDate = blob_terminate(&a1); |
| 235 | p->rDate = db_double(0.0, "SELECT julianday(%Q)", zDate); |
| 236 | break; |
| 237 | } |
| 238 | |
| 239 | /* |
| 240 | ** E <timestamp> <uuid> |
| 241 | ** |
| 242 | ** An "event" card that contains the timestamp of the event in the |
| 243 | ** format YYYY-MM-DDtHH:MM:SS and a unique identifier for the event. |
| 244 | ** The event timestamp is distinct from the D timestamp. The D |
| 245 | ** timestamp is when the artifact was created whereas the E timestamp |
| 246 | ** is when the specific event is said to occur. |
| 247 | */ |
| 248 | case 'E': { |
| 249 | char *zEDate; |
| 250 | md5sum_step_text(blob_buffer(&line), blob_size(&line)); |
| 251 | if( p->rEventDate!=0.0 ) goto manifest_syntax_error; |
| 252 | if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error; |
| 253 | if( blob_token(&line, &a2)==0 ) goto manifest_syntax_error; |
| 254 | if( blob_token(&line, &a3)!=0 ) goto manifest_syntax_error; |
| 255 | zEDate = blob_terminate(&a1); |
| 256 | p->rEventDate = db_double(0.0, "SELECT julianday(%Q)", zEDate); |
| 257 | if( p->rEventDate<=0.0 ) goto manifest_syntax_error; |
| 258 | if( blob_size(&a2)!=UUID_SIZE ) goto manifest_syntax_error; |
| 259 | p->zEventId = blob_terminate(&a2); |
| 260 | if( !validate16(p->zEventId, UUID_SIZE) ) goto manifest_syntax_error; |
| 261 | break; |
| 262 | } |
| 263 | |
| 264 | /* |
| 265 | ** F <filename> <uuid> ?<permissions>? ?<old-name>? |
| 266 | ** |
| 267 | ** Identifies a file in a manifest. Multiple F lines are |
| @@ -563,15 +591,16 @@ | |
| 591 | } |
| 592 | if( !seenHeader ) goto manifest_syntax_error; |
| 593 | |
| 594 | if( p->nFile>0 || p->zRepoCksum!=0 ){ |
| 595 | if( p->nCChild>0 ) goto manifest_syntax_error; |
| 596 | if( p->rDate<=0.0 ) goto manifest_syntax_error; |
| 597 | if( p->nField>0 ) goto manifest_syntax_error; |
| 598 | if( p->zTicketUuid ) goto manifest_syntax_error; |
| 599 | if( p->zWiki ) goto manifest_syntax_error; |
| 600 | if( p->zWikiTitle ) goto manifest_syntax_error; |
| 601 | if( p->zEventId ) goto manifest_syntax_error; |
| 602 | if( p->zTicketUuid ) goto manifest_syntax_error; |
| 603 | if( p->zAttachName ) goto manifest_syntax_error; |
| 604 | p->type = CFTYPE_MANIFEST; |
| 605 | }else if( p->nCChild>0 ){ |
| 606 | if( p->rDate>0.0 ) goto manifest_syntax_error; |
| @@ -581,26 +610,41 @@ | |
| 610 | if( p->nParent>0 ) goto manifest_syntax_error; |
| 611 | if( p->nField>0 ) goto manifest_syntax_error; |
| 612 | if( p->zTicketUuid ) goto manifest_syntax_error; |
| 613 | if( p->zWiki ) goto manifest_syntax_error; |
| 614 | if( p->zWikiTitle ) goto manifest_syntax_error; |
| 615 | if( p->zEventId ) goto manifest_syntax_error; |
| 616 | if( p->zAttachName ) goto manifest_syntax_error; |
| 617 | if( !seenZ ) goto manifest_syntax_error; |
| 618 | p->type = CFTYPE_CLUSTER; |
| 619 | }else if( p->nField>0 ){ |
| 620 | if( p->rDate<=0.0 ) goto manifest_syntax_error; |
| 621 | if( p->zWiki ) goto manifest_syntax_error; |
| 622 | if( p->zWikiTitle ) goto manifest_syntax_error; |
| 623 | if( p->zEventId ) goto manifest_syntax_error; |
| 624 | if( p->nCChild>0 ) goto manifest_syntax_error; |
| 625 | if( p->nTag>0 ) goto manifest_syntax_error; |
| 626 | if( p->zTicketUuid==0 ) goto manifest_syntax_error; |
| 627 | if( p->zUser==0 ) goto manifest_syntax_error; |
| 628 | if( p->zAttachName ) goto manifest_syntax_error; |
| 629 | if( !seenZ ) goto manifest_syntax_error; |
| 630 | p->type = CFTYPE_TICKET; |
| 631 | }else if( p->zEventId ){ |
| 632 | if( p->rDate<=0.0 ) goto manifest_syntax_error; |
| 633 | if( p->nCChild>0 ) goto manifest_syntax_error; |
| 634 | if( p->zTicketUuid!=0 ) goto manifest_syntax_error; |
| 635 | if( p->zWikiTitle!=0 ) goto manifest_syntax_error; |
| 636 | if( p->zWiki==0 ) goto manifest_syntax_error; |
| 637 | if( p->zAttachName ) goto manifest_syntax_error; |
| 638 | for(i=0; i<p->nTag; i++){ |
| 639 | if( p->aTag[i].zName[0]!='+' ) goto manifest_syntax_error; |
| 640 | if( p->aTag[i].zUuid!=0 ) goto manifest_syntax_error; |
| 641 | } |
| 642 | if( !seenZ ) goto manifest_syntax_error; |
| 643 | p->type = CFTYPE_EVENT; |
| 644 | }else if( p->zWiki!=0 ){ |
| 645 | if( p->rDate<=0.0 ) goto manifest_syntax_error; |
| 646 | if( p->nCChild>0 ) goto manifest_syntax_error; |
| 647 | if( p->nTag>0 ) goto manifest_syntax_error; |
| 648 | if( p->zTicketUuid!=0 ) goto manifest_syntax_error; |
| 649 | if( p->zWikiTitle==0 ) goto manifest_syntax_error; |
| 650 | if( p->zAttachName ) goto manifest_syntax_error; |
| @@ -614,11 +658,11 @@ | |
| 658 | if( p->zAttachName ) goto manifest_syntax_error; |
| 659 | if( !seenZ ) goto manifest_syntax_error; |
| 660 | p->type = CFTYPE_CONTROL; |
| 661 | }else if( p->zAttachName ){ |
| 662 | if( p->nCChild>0 ) goto manifest_syntax_error; |
| 663 | if( p->rDate<=0.0 ) goto manifest_syntax_error; |
| 664 | if( p->zTicketUuid ) goto manifest_syntax_error; |
| 665 | if( p->zWikiTitle ) goto manifest_syntax_error; |
| 666 | if( !seenZ ) goto manifest_syntax_error; |
| 667 | p->type = CFTYPE_ATTACHMENT; |
| 668 | }else{ |
| @@ -625,14 +669,12 @@ | |
| 669 | if( p->nCChild>0 ) goto manifest_syntax_error; |
| 670 | if( p->rDate<=0.0 ) goto manifest_syntax_error; |
| 671 | if( p->nParent>0 ) goto manifest_syntax_error; |
| 672 | if( p->nField>0 ) goto manifest_syntax_error; |
| 673 | if( p->zTicketUuid ) goto manifest_syntax_error; |
| 674 | if( p->zWikiTitle ) goto manifest_syntax_error; |
| 675 | if( p->zTicketUuid ) goto manifest_syntax_error; |
| 676 | p->type = CFTYPE_MANIFEST; |
| 677 | } |
| 678 | md5sum_init(); |
| 679 | return 1; |
| 680 | |
| @@ -964,10 +1006,12 @@ | |
| 1006 | ** * Manifest |
| 1007 | ** * Control |
| 1008 | ** * Wiki Page |
| 1009 | ** * Ticket Change |
| 1010 | ** * Cluster |
| 1011 | ** * Attachment |
| 1012 | ** * Event |
| 1013 | ** |
| 1014 | ** If the input is a control artifact, then make appropriate entries |
| 1015 | ** in the auxiliary tables of the database in order to crosslink the |
| 1016 | ** artifact. |
| 1017 | ** |
| @@ -1043,11 +1087,14 @@ | |
| 1087 | if( mid>0 ){ |
| 1088 | db_multi_exec("DELETE FROM unclustered WHERE rid=%d", mid); |
| 1089 | } |
| 1090 | } |
| 1091 | } |
| 1092 | if( m.type==CFTYPE_CONTROL |
| 1093 | || m.type==CFTYPE_MANIFEST |
| 1094 | || m.type==CFTYPE_EVENT |
| 1095 | ){ |
| 1096 | for(i=0; i<m.nTag; i++){ |
| 1097 | int tid; |
| 1098 | int type; |
| 1099 | if( m.aTag[i].zUuid ){ |
| 1100 | tid = uuid_to_rid(m.aTag[i].zUuid, 1); |
| @@ -1109,10 +1156,55 @@ | |
| 1156 | TAG_BGCOLOR, rid, |
| 1157 | TAG_USER, rid, |
| 1158 | TAG_COMMENT, rid |
| 1159 | ); |
| 1160 | free(zComment); |
| 1161 | } |
| 1162 | if( m.type==CFTYPE_EVENT ){ |
| 1163 | char *zTag = mprintf("event-%s", m.zEventId); |
| 1164 | int tagid = tag_findid(zTag, 1); |
| 1165 | int prior, subsequent; |
| 1166 | int nWiki; |
| 1167 | char zLength[40]; |
| 1168 | while( isspace(m.zWiki[0]) ) m.zWiki++; |
| 1169 | nWiki = strlen(m.zWiki); |
| 1170 | sqlite3_snprintf(sizeof(zLength), zLength, "%d", nWiki); |
| 1171 | tag_insert(zTag, 1, zLength, rid, m.rDate, rid); |
| 1172 | free(zTag); |
| 1173 | prior = db_int(0, |
| 1174 | "SELECT rid FROM tagxref" |
| 1175 | " WHERE tagid=%d AND mtime<%.17g" |
| 1176 | " ORDER BY mtime DESC", |
| 1177 | tagid, m.rDate |
| 1178 | ); |
| 1179 | if( prior ){ |
| 1180 | content_deltify(prior, rid, 0); |
| 1181 | db_multi_exec( |
| 1182 | "DELETE FROM event" |
| 1183 | " WHERE type='e'" |
| 1184 | " AND tagid=%d" |
| 1185 | " AND objid IN (SELECT rid FROM tagxref WHERE tagid=%d)", |
| 1186 | tagid, tagid |
| 1187 | ); |
| 1188 | } |
| 1189 | subsequent = db_int(0, |
| 1190 | "SELECT rid FROM tagxref" |
| 1191 | " WHERE tagid=%d AND mtime>%.17g" |
| 1192 | " ORDER BY mtime", |
| 1193 | tagid, m.rDate |
| 1194 | ); |
| 1195 | if( subsequent ){ |
| 1196 | content_deltify(rid, subsequent, 0); |
| 1197 | }else{ |
| 1198 | db_multi_exec( |
| 1199 | "REPLACE INTO event(type,mtime,objid,tagid,user,comment,bgcolor)" |
| 1200 | "VALUES('e',%.17g,%d,%d,%Q,%Q," |
| 1201 | " (SELECT value FROM tagxref WHERE tagid=%d AND rid=%d));", |
| 1202 | m.rEventDate, rid, tagid, m.zUser, m.zComment, |
| 1203 | TAG_BGCOLOR, rid |
| 1204 | ); |
| 1205 | } |
| 1206 | } |
| 1207 | if( m.type==CFTYPE_TICKET ){ |
| 1208 | char *zTag; |
| 1209 | |
| 1210 | assert( manifest_crosslink_busy==1 ); |
| 1211 |
+3
-3
| --- src/printf.c | ||
| +++ src/printf.c | ||
| @@ -44,13 +44,13 @@ | ||
| 44 | 44 | #define etHTMLIZE 16 /* Make text safe for HTML */ |
| 45 | 45 | #define etHTTPIZE 17 /* Make text safe for HTTP. "/" encoded as %2f */ |
| 46 | 46 | #define etURLIZE 18 /* Make text safe for HTTP. "/" not encoded */ |
| 47 | 47 | #define etFOSSILIZE 19 /* The fossil header encoding format. */ |
| 48 | 48 | #define etPATH 20 /* Path type */ |
| 49 | -#define etWIKISTR 21 /* Wiki text rendered from a char* */ | |
| 50 | -#define etWIKIBLOB 22 /* Wiki text rendered from a Blob* */ | |
| 51 | -#define etSTRINGID 23 /* String with length limit for a UUID prefix */ | |
| 49 | +#define etWIKISTR 21 /* Wiki text rendered from a char*: %w */ | |
| 50 | +#define etWIKIBLOB 22 /* Wiki text rendered from a Blob*: %W */ | |
| 51 | +#define etSTRINGID 23 /* String with length limit for a UUID prefix: %S */ | |
| 52 | 52 | |
| 53 | 53 | |
| 54 | 54 | /* |
| 55 | 55 | ** An "etByte" is an 8-bit unsigned value. |
| 56 | 56 | */ |
| 57 | 57 |
| --- src/printf.c | |
| +++ src/printf.c | |
| @@ -44,13 +44,13 @@ | |
| 44 | #define etHTMLIZE 16 /* Make text safe for HTML */ |
| 45 | #define etHTTPIZE 17 /* Make text safe for HTTP. "/" encoded as %2f */ |
| 46 | #define etURLIZE 18 /* Make text safe for HTTP. "/" not encoded */ |
| 47 | #define etFOSSILIZE 19 /* The fossil header encoding format. */ |
| 48 | #define etPATH 20 /* Path type */ |
| 49 | #define etWIKISTR 21 /* Wiki text rendered from a char* */ |
| 50 | #define etWIKIBLOB 22 /* Wiki text rendered from a Blob* */ |
| 51 | #define etSTRINGID 23 /* String with length limit for a UUID prefix */ |
| 52 | |
| 53 | |
| 54 | /* |
| 55 | ** An "etByte" is an 8-bit unsigned value. |
| 56 | */ |
| 57 |
| --- src/printf.c | |
| +++ src/printf.c | |
| @@ -44,13 +44,13 @@ | |
| 44 | #define etHTMLIZE 16 /* Make text safe for HTML */ |
| 45 | #define etHTTPIZE 17 /* Make text safe for HTTP. "/" encoded as %2f */ |
| 46 | #define etURLIZE 18 /* Make text safe for HTTP. "/" not encoded */ |
| 47 | #define etFOSSILIZE 19 /* The fossil header encoding format. */ |
| 48 | #define etPATH 20 /* Path type */ |
| 49 | #define etWIKISTR 21 /* Wiki text rendered from a char*: %w */ |
| 50 | #define etWIKIBLOB 22 /* Wiki text rendered from a Blob*: %W */ |
| 51 | #define etSTRINGID 23 /* String with length limit for a UUID prefix: %S */ |
| 52 | |
| 53 | |
| 54 | /* |
| 55 | ** An "etByte" is an 8-bit unsigned value. |
| 56 | */ |
| 57 |
+72
-66
| --- src/rebuild.c | ||
| +++ src/rebuild.c | ||
| @@ -121,76 +121,82 @@ | ||
| 121 | 121 | Bag children; |
| 122 | 122 | Blob copy; |
| 123 | 123 | Blob *pUse; |
| 124 | 124 | int nChild, i, cid; |
| 125 | 125 | |
| 126 | - /* Fix up the "blob.size" field if needed. */ | |
| 127 | - if( size!=blob_size(pBase) ){ | |
| 128 | - db_multi_exec( | |
| 129 | - "UPDATE blob SET size=%d WHERE rid=%d", blob_size(pBase), rid | |
| 130 | - ); | |
| 131 | - } | |
| 132 | - | |
| 133 | - /* Find all children of artifact rid */ | |
| 134 | - db_static_prepare(&q1, "SELECT rid FROM delta WHERE srcid=:rid"); | |
| 135 | - db_bind_int(&q1, ":rid", rid); | |
| 136 | - bag_init(&children); | |
| 137 | - while( db_step(&q1)==SQLITE_ROW ){ | |
| 138 | - int cid = db_column_int(&q1, 0); | |
| 139 | - if( !bag_find(&bagDone, cid) ){ | |
| 140 | - bag_insert(&children, cid); | |
| 141 | - } | |
| 142 | - } | |
| 143 | - nChild = bag_count(&children); | |
| 144 | - db_reset(&q1); | |
| 145 | - | |
| 146 | - /* Crosslink the artifact */ | |
| 147 | - if( nChild==0 ){ | |
| 148 | - pUse = pBase; | |
| 149 | - }else{ | |
| 150 | - blob_copy(©, pBase); | |
| 151 | - pUse = © | |
| 152 | - } | |
| 153 | - if( zFNameFormat==0 ){ | |
| 154 | - /* We are doing "fossil rebuild" */ | |
| 155 | - manifest_crosslink(rid, pUse); | |
| 156 | - }else{ | |
| 157 | - /* We are doing "fossil deconstruct" */ | |
| 158 | - char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); | |
| 159 | - char *zFile = mprintf(zFNameFormat, zUuid, zUuid+prefixLength); | |
| 160 | - blob_write_to_file(pUse,zFile); | |
| 161 | - free(zFile); | |
| 162 | - free(zUuid); | |
| 163 | - } | |
| 164 | - blob_reset(pUse); | |
| 165 | - rebuild_step_done(rid); | |
| 166 | - | |
| 167 | - /* Call all children recursively */ | |
| 168 | - for(cid=bag_first(&children), i=1; cid; cid=bag_next(&children, cid), i++){ | |
| 169 | - Stmt q2; | |
| 170 | - int sz; | |
| 171 | - if( nChild==i ){ | |
| 172 | - pUse = pBase; | |
| 173 | - }else{ | |
| 174 | - blob_copy(©, pBase); | |
| 175 | - pUse = © | |
| 176 | - } | |
| 177 | - db_prepare(&q2, "SELECT content, size FROM blob WHERE rid=%d", cid); | |
| 178 | - if( db_step(&q2)==SQLITE_ROW && (sz = db_column_int(&q2,1))>=0 ){ | |
| 179 | - Blob delta; | |
| 180 | - db_ephemeral_blob(&q2, 0, &delta); | |
| 181 | - blob_uncompress(&delta, &delta); | |
| 182 | - blob_delta_apply(pUse, &delta, pUse); | |
| 183 | - blob_reset(&delta); | |
| 184 | - db_finalize(&q2); | |
| 185 | - rebuild_step(cid, sz, pUse); | |
| 186 | - }else{ | |
| 187 | - db_finalize(&q2); | |
| 188 | - blob_reset(pUse); | |
| 189 | - } | |
| 190 | - } | |
| 191 | - bag_clear(&children); | |
| 126 | + while( rid>0 ){ | |
| 127 | + | |
| 128 | + /* Fix up the "blob.size" field if needed. */ | |
| 129 | + if( size!=blob_size(pBase) ){ | |
| 130 | + db_multi_exec( | |
| 131 | + "UPDATE blob SET size=%d WHERE rid=%d", blob_size(pBase), rid | |
| 132 | + ); | |
| 133 | + } | |
| 134 | + | |
| 135 | + /* Find all children of artifact rid */ | |
| 136 | + db_static_prepare(&q1, "SELECT rid FROM delta WHERE srcid=:rid"); | |
| 137 | + db_bind_int(&q1, ":rid", rid); | |
| 138 | + bag_init(&children); | |
| 139 | + while( db_step(&q1)==SQLITE_ROW ){ | |
| 140 | + int cid = db_column_int(&q1, 0); | |
| 141 | + if( !bag_find(&bagDone, cid) ){ | |
| 142 | + bag_insert(&children, cid); | |
| 143 | + } | |
| 144 | + } | |
| 145 | + nChild = bag_count(&children); | |
| 146 | + db_reset(&q1); | |
| 147 | + | |
| 148 | + /* Crosslink the artifact */ | |
| 149 | + if( nChild==0 ){ | |
| 150 | + pUse = pBase; | |
| 151 | + }else{ | |
| 152 | + blob_copy(©, pBase); | |
| 153 | + pUse = © | |
| 154 | + } | |
| 155 | + if( zFNameFormat==0 ){ | |
| 156 | + /* We are doing "fossil rebuild" */ | |
| 157 | + manifest_crosslink(rid, pUse); | |
| 158 | + }else{ | |
| 159 | + /* We are doing "fossil deconstruct" */ | |
| 160 | + char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); | |
| 161 | + char *zFile = mprintf(zFNameFormat, zUuid, zUuid+prefixLength); | |
| 162 | + blob_write_to_file(pUse,zFile); | |
| 163 | + free(zFile); | |
| 164 | + free(zUuid); | |
| 165 | + } | |
| 166 | + blob_reset(pUse); | |
| 167 | + rebuild_step_done(rid); | |
| 168 | + | |
| 169 | + /* Call all children recursively */ | |
| 170 | + rid = 0; | |
| 171 | + for(cid=bag_first(&children), i=1; cid; cid=bag_next(&children, cid), i++){ | |
| 172 | + Stmt q2; | |
| 173 | + int sz; | |
| 174 | + db_prepare(&q2, "SELECT content, size FROM blob WHERE rid=%d", cid); | |
| 175 | + if( db_step(&q2)==SQLITE_ROW && (sz = db_column_int(&q2,1))>=0 ){ | |
| 176 | + Blob delta, next; | |
| 177 | + db_ephemeral_blob(&q2, 0, &delta); | |
| 178 | + blob_uncompress(&delta, &delta); | |
| 179 | + blob_delta_apply(pBase, &delta, &next); | |
| 180 | + blob_reset(&delta); | |
| 181 | + db_finalize(&q2); | |
| 182 | + if( i<nChild ){ | |
| 183 | + rebuild_step(cid, sz, &next); | |
| 184 | + }else{ | |
| 185 | + /* Tail recursion */ | |
| 186 | + rid = cid; | |
| 187 | + size = sz; | |
| 188 | + blob_reset(pBase); | |
| 189 | + *pBase = next; | |
| 190 | + } | |
| 191 | + }else{ | |
| 192 | + db_finalize(&q2); | |
| 193 | + blob_reset(pBase); | |
| 194 | + } | |
| 195 | + } | |
| 196 | + bag_clear(&children); | |
| 197 | + } | |
| 192 | 198 | } |
| 193 | 199 | |
| 194 | 200 | /* |
| 195 | 201 | ** Check to see if the "sym-trunk" tag exists. If not, create it |
| 196 | 202 | ** and attach it to the very first check-in. |
| 197 | 203 |
| --- src/rebuild.c | |
| +++ src/rebuild.c | |
| @@ -121,76 +121,82 @@ | |
| 121 | Bag children; |
| 122 | Blob copy; |
| 123 | Blob *pUse; |
| 124 | int nChild, i, cid; |
| 125 | |
| 126 | /* Fix up the "blob.size" field if needed. */ |
| 127 | if( size!=blob_size(pBase) ){ |
| 128 | db_multi_exec( |
| 129 | "UPDATE blob SET size=%d WHERE rid=%d", blob_size(pBase), rid |
| 130 | ); |
| 131 | } |
| 132 | |
| 133 | /* Find all children of artifact rid */ |
| 134 | db_static_prepare(&q1, "SELECT rid FROM delta WHERE srcid=:rid"); |
| 135 | db_bind_int(&q1, ":rid", rid); |
| 136 | bag_init(&children); |
| 137 | while( db_step(&q1)==SQLITE_ROW ){ |
| 138 | int cid = db_column_int(&q1, 0); |
| 139 | if( !bag_find(&bagDone, cid) ){ |
| 140 | bag_insert(&children, cid); |
| 141 | } |
| 142 | } |
| 143 | nChild = bag_count(&children); |
| 144 | db_reset(&q1); |
| 145 | |
| 146 | /* Crosslink the artifact */ |
| 147 | if( nChild==0 ){ |
| 148 | pUse = pBase; |
| 149 | }else{ |
| 150 | blob_copy(©, pBase); |
| 151 | pUse = © |
| 152 | } |
| 153 | if( zFNameFormat==0 ){ |
| 154 | /* We are doing "fossil rebuild" */ |
| 155 | manifest_crosslink(rid, pUse); |
| 156 | }else{ |
| 157 | /* We are doing "fossil deconstruct" */ |
| 158 | char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 159 | char *zFile = mprintf(zFNameFormat, zUuid, zUuid+prefixLength); |
| 160 | blob_write_to_file(pUse,zFile); |
| 161 | free(zFile); |
| 162 | free(zUuid); |
| 163 | } |
| 164 | blob_reset(pUse); |
| 165 | rebuild_step_done(rid); |
| 166 | |
| 167 | /* Call all children recursively */ |
| 168 | for(cid=bag_first(&children), i=1; cid; cid=bag_next(&children, cid), i++){ |
| 169 | Stmt q2; |
| 170 | int sz; |
| 171 | if( nChild==i ){ |
| 172 | pUse = pBase; |
| 173 | }else{ |
| 174 | blob_copy(©, pBase); |
| 175 | pUse = © |
| 176 | } |
| 177 | db_prepare(&q2, "SELECT content, size FROM blob WHERE rid=%d", cid); |
| 178 | if( db_step(&q2)==SQLITE_ROW && (sz = db_column_int(&q2,1))>=0 ){ |
| 179 | Blob delta; |
| 180 | db_ephemeral_blob(&q2, 0, &delta); |
| 181 | blob_uncompress(&delta, &delta); |
| 182 | blob_delta_apply(pUse, &delta, pUse); |
| 183 | blob_reset(&delta); |
| 184 | db_finalize(&q2); |
| 185 | rebuild_step(cid, sz, pUse); |
| 186 | }else{ |
| 187 | db_finalize(&q2); |
| 188 | blob_reset(pUse); |
| 189 | } |
| 190 | } |
| 191 | bag_clear(&children); |
| 192 | } |
| 193 | |
| 194 | /* |
| 195 | ** Check to see if the "sym-trunk" tag exists. If not, create it |
| 196 | ** and attach it to the very first check-in. |
| 197 |
| --- src/rebuild.c | |
| +++ src/rebuild.c | |
| @@ -121,76 +121,82 @@ | |
| 121 | Bag children; |
| 122 | Blob copy; |
| 123 | Blob *pUse; |
| 124 | int nChild, i, cid; |
| 125 | |
| 126 | while( rid>0 ){ |
| 127 | |
| 128 | /* Fix up the "blob.size" field if needed. */ |
| 129 | if( size!=blob_size(pBase) ){ |
| 130 | db_multi_exec( |
| 131 | "UPDATE blob SET size=%d WHERE rid=%d", blob_size(pBase), rid |
| 132 | ); |
| 133 | } |
| 134 | |
| 135 | /* Find all children of artifact rid */ |
| 136 | db_static_prepare(&q1, "SELECT rid FROM delta WHERE srcid=:rid"); |
| 137 | db_bind_int(&q1, ":rid", rid); |
| 138 | bag_init(&children); |
| 139 | while( db_step(&q1)==SQLITE_ROW ){ |
| 140 | int cid = db_column_int(&q1, 0); |
| 141 | if( !bag_find(&bagDone, cid) ){ |
| 142 | bag_insert(&children, cid); |
| 143 | } |
| 144 | } |
| 145 | nChild = bag_count(&children); |
| 146 | db_reset(&q1); |
| 147 | |
| 148 | /* Crosslink the artifact */ |
| 149 | if( nChild==0 ){ |
| 150 | pUse = pBase; |
| 151 | }else{ |
| 152 | blob_copy(©, pBase); |
| 153 | pUse = © |
| 154 | } |
| 155 | if( zFNameFormat==0 ){ |
| 156 | /* We are doing "fossil rebuild" */ |
| 157 | manifest_crosslink(rid, pUse); |
| 158 | }else{ |
| 159 | /* We are doing "fossil deconstruct" */ |
| 160 | char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 161 | char *zFile = mprintf(zFNameFormat, zUuid, zUuid+prefixLength); |
| 162 | blob_write_to_file(pUse,zFile); |
| 163 | free(zFile); |
| 164 | free(zUuid); |
| 165 | } |
| 166 | blob_reset(pUse); |
| 167 | rebuild_step_done(rid); |
| 168 | |
| 169 | /* Call all children recursively */ |
| 170 | rid = 0; |
| 171 | for(cid=bag_first(&children), i=1; cid; cid=bag_next(&children, cid), i++){ |
| 172 | Stmt q2; |
| 173 | int sz; |
| 174 | db_prepare(&q2, "SELECT content, size FROM blob WHERE rid=%d", cid); |
| 175 | if( db_step(&q2)==SQLITE_ROW && (sz = db_column_int(&q2,1))>=0 ){ |
| 176 | Blob delta, next; |
| 177 | db_ephemeral_blob(&q2, 0, &delta); |
| 178 | blob_uncompress(&delta, &delta); |
| 179 | blob_delta_apply(pBase, &delta, &next); |
| 180 | blob_reset(&delta); |
| 181 | db_finalize(&q2); |
| 182 | if( i<nChild ){ |
| 183 | rebuild_step(cid, sz, &next); |
| 184 | }else{ |
| 185 | /* Tail recursion */ |
| 186 | rid = cid; |
| 187 | size = sz; |
| 188 | blob_reset(pBase); |
| 189 | *pBase = next; |
| 190 | } |
| 191 | }else{ |
| 192 | db_finalize(&q2); |
| 193 | blob_reset(pBase); |
| 194 | } |
| 195 | } |
| 196 | bag_clear(&children); |
| 197 | } |
| 198 | } |
| 199 | |
| 200 | /* |
| 201 | ** Check to see if the "sym-trunk" tag exists. If not, create it |
| 202 | ** and attach it to the very first check-in. |
| 203 |
+223
-268
| --- src/sqlite3.c | ||
| +++ src/sqlite3.c | ||
| @@ -650,11 +650,11 @@ | ||
| 650 | 650 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 651 | 651 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 652 | 652 | */ |
| 653 | 653 | #define SQLITE_VERSION "3.7.3" |
| 654 | 654 | #define SQLITE_VERSION_NUMBER 3007003 |
| 655 | -#define SQLITE_SOURCE_ID "2010-09-29 23:09:23 1ef0dc9328f47506cb2dcd142150e96cb4755216" | |
| 655 | +#define SQLITE_SOURCE_ID "2010-10-04 23:55:51 ece641eb8951c6314cedbdb3243f91cb199c3239" | |
| 656 | 656 | |
| 657 | 657 | /* |
| 658 | 658 | ** CAPI3REF: Run-Time Library Version Numbers |
| 659 | 659 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 660 | 660 | ** |
| @@ -10570,11 +10570,10 @@ | ||
| 10570 | 10570 | |
| 10571 | 10571 | /* |
| 10572 | 10572 | ** Internal function prototypes |
| 10573 | 10573 | */ |
| 10574 | 10574 | SQLITE_PRIVATE int sqlite3StrICmp(const char *, const char *); |
| 10575 | -SQLITE_PRIVATE int sqlite3IsNumber(const char*, int*, u8); | |
| 10576 | 10575 | SQLITE_PRIVATE int sqlite3Strlen30(const char*); |
| 10577 | 10576 | #define sqlite3StrNICmp sqlite3_strnicmp |
| 10578 | 10577 | |
| 10579 | 10578 | SQLITE_PRIVATE int sqlite3MallocInit(void); |
| 10580 | 10579 | SQLITE_PRIVATE void sqlite3MallocEnd(void); |
| @@ -10890,13 +10889,12 @@ | ||
| 10890 | 10889 | SQLITE_PRIVATE int sqlite3FixSrcList(DbFixer*, SrcList*); |
| 10891 | 10890 | SQLITE_PRIVATE int sqlite3FixSelect(DbFixer*, Select*); |
| 10892 | 10891 | SQLITE_PRIVATE int sqlite3FixExpr(DbFixer*, Expr*); |
| 10893 | 10892 | SQLITE_PRIVATE int sqlite3FixExprList(DbFixer*, ExprList*); |
| 10894 | 10893 | SQLITE_PRIVATE int sqlite3FixTriggerStep(DbFixer*, TriggerStep*); |
| 10895 | -SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*); | |
| 10894 | +SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*, int, u8); | |
| 10896 | 10895 | SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*); |
| 10897 | -SQLITE_PRIVATE int sqlite3FitsIn64Bits(const char *, int); | |
| 10898 | 10896 | SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nChar); |
| 10899 | 10897 | SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *pData, int nByte); |
| 10900 | 10898 | SQLITE_PRIVATE int sqlite3Utf8Read(const u8*, const u8**); |
| 10901 | 10899 | |
| 10902 | 10900 | /* |
| @@ -10938,11 +10936,11 @@ | ||
| 10938 | 10936 | SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(Vdbe *, Index *); |
| 10939 | 10937 | SQLITE_PRIVATE void sqlite3TableAffinityStr(Vdbe *, Table *); |
| 10940 | 10938 | SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2); |
| 10941 | 10939 | SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity); |
| 10942 | 10940 | SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr); |
| 10943 | -SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*); | |
| 10941 | +SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*, int, u8); | |
| 10944 | 10942 | SQLITE_PRIVATE void sqlite3Error(sqlite3*, int, const char*,...); |
| 10945 | 10943 | SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n); |
| 10946 | 10944 | SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **); |
| 10947 | 10945 | SQLITE_PRIVATE const char *sqlite3ErrStr(int); |
| 10948 | 10946 | SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse); |
| @@ -12637,16 +12635,10 @@ | ||
| 12637 | 12635 | end_getDigits: |
| 12638 | 12636 | va_end(ap); |
| 12639 | 12637 | return cnt; |
| 12640 | 12638 | } |
| 12641 | 12639 | |
| 12642 | -/* | |
| 12643 | -** Read text from z[] and convert into a floating point number. Return | |
| 12644 | -** the number of digits converted. | |
| 12645 | -*/ | |
| 12646 | -#define getValue sqlite3AtoF | |
| 12647 | - | |
| 12648 | 12640 | /* |
| 12649 | 12641 | ** Parse a timezone extension on the end of a date-time. |
| 12650 | 12642 | ** The extension is of the form: |
| 12651 | 12643 | ** |
| 12652 | 12644 | ** (+/-)HH:MM |
| @@ -12844,21 +12836,19 @@ | ||
| 12844 | 12836 | static int parseDateOrTime( |
| 12845 | 12837 | sqlite3_context *context, |
| 12846 | 12838 | const char *zDate, |
| 12847 | 12839 | DateTime *p |
| 12848 | 12840 | ){ |
| 12849 | - int isRealNum; /* Return from sqlite3IsNumber(). Not used */ | |
| 12841 | + double r; | |
| 12850 | 12842 | if( parseYyyyMmDd(zDate,p)==0 ){ |
| 12851 | 12843 | return 0; |
| 12852 | 12844 | }else if( parseHhMmSs(zDate, p)==0 ){ |
| 12853 | 12845 | return 0; |
| 12854 | 12846 | }else if( sqlite3StrICmp(zDate,"now")==0){ |
| 12855 | 12847 | setDateTimeToCurrent(context, p); |
| 12856 | 12848 | return 0; |
| 12857 | - }else if( sqlite3IsNumber(zDate, &isRealNum, SQLITE_UTF8) ){ | |
| 12858 | - double r; | |
| 12859 | - getValue(zDate, &r); | |
| 12849 | + }else if( sqlite3AtoF(zDate, &r, sqlite3Strlen30(zDate), SQLITE_UTF8) ){ | |
| 12860 | 12850 | p->iJD = (sqlite3_int64)(r*86400000.0 + 0.5); |
| 12861 | 12851 | p->validJD = 1; |
| 12862 | 12852 | return 0; |
| 12863 | 12853 | } |
| 12864 | 12854 | return 1; |
| @@ -13075,12 +13065,13 @@ | ||
| 13075 | 13065 | ** |
| 13076 | 13066 | ** Move the date to the same time on the next occurrence of |
| 13077 | 13067 | ** weekday N where 0==Sunday, 1==Monday, and so forth. If the |
| 13078 | 13068 | ** date is already on the appropriate weekday, this is a no-op. |
| 13079 | 13069 | */ |
| 13080 | - if( strncmp(z, "weekday ", 8)==0 && getValue(&z[8],&r)>0 | |
| 13081 | - && (n=(int)r)==r && n>=0 && r<7 ){ | |
| 13070 | + if( strncmp(z, "weekday ", 8)==0 | |
| 13071 | + && sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8) | |
| 13072 | + && (n=(int)r)==r && n>=0 && r<7 ){ | |
| 13082 | 13073 | sqlite3_int64 Z; |
| 13083 | 13074 | computeYMD_HMS(p); |
| 13084 | 13075 | p->validTZ = 0; |
| 13085 | 13076 | p->validJD = 0; |
| 13086 | 13077 | computeJD(p); |
| @@ -13131,12 +13122,15 @@ | ||
| 13131 | 13122 | case '6': |
| 13132 | 13123 | case '7': |
| 13133 | 13124 | case '8': |
| 13134 | 13125 | case '9': { |
| 13135 | 13126 | double rRounder; |
| 13136 | - n = getValue(z, &r); | |
| 13137 | - assert( n>=1 ); | |
| 13127 | + for(n=1; z[n] && z[n]!=':' && !sqlite3Isspace(z[n]); n++){} | |
| 13128 | + if( !sqlite3AtoF(z, &r, n, SQLITE_UTF8) ){ | |
| 13129 | + rc = 1; | |
| 13130 | + break; | |
| 13131 | + } | |
| 13138 | 13132 | if( z[n]==':' ){ |
| 13139 | 13133 | /* A modifier of the form (+|-)HH:MM:SS.FFF adds (or subtracts) the |
| 13140 | 13134 | ** specified number of hours, minutes, seconds, and fractional seconds |
| 13141 | 13135 | ** to the time. The ".FFF" may be omitted. The ":SS.FFF" may be |
| 13142 | 13136 | ** omitted. |
| @@ -17502,11 +17496,11 @@ | ||
| 17502 | 17496 | sqlite3MemoryAlarm(softHeapLimitEnforcer, 0, n); |
| 17503 | 17497 | }else{ |
| 17504 | 17498 | sqlite3MemoryAlarm(0, 0, 0); |
| 17505 | 17499 | } |
| 17506 | 17500 | excess = sqlite3_memory_used() - n; |
| 17507 | - if( excess>0 ) sqlite3_release_memory(excess & 0x7fffffff); | |
| 17501 | + if( excess>0 ) sqlite3_release_memory((int)(excess & 0x7fffffff)); | |
| 17508 | 17502 | return priorLimit; |
| 17509 | 17503 | } |
| 17510 | 17504 | SQLITE_API void sqlite3_soft_heap_limit(int n){ |
| 17511 | 17505 | if( n<0 ) n = 0; |
| 17512 | 17506 | sqlite3_soft_heap_limit64(n); |
| @@ -20096,125 +20090,115 @@ | ||
| 20096 | 20090 | while( N-- > 0 && *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; } |
| 20097 | 20091 | return N<0 ? 0 : UpperToLower[*a] - UpperToLower[*b]; |
| 20098 | 20092 | } |
| 20099 | 20093 | |
| 20100 | 20094 | /* |
| 20101 | -** Return TRUE if z is a pure numeric string. Return FALSE and leave | |
| 20102 | -** *realnum unchanged if the string contains any character which is not | |
| 20103 | -** part of a number. | |
| 20104 | -** | |
| 20105 | -** If the string is pure numeric, set *realnum to TRUE if the string | |
| 20106 | -** contains the '.' character or an "E+000" style exponentiation suffix. | |
| 20107 | -** Otherwise set *realnum to FALSE. Note that just becaue *realnum is | |
| 20108 | -** false does not mean that the number can be successfully converted into | |
| 20109 | -** an integer - it might be too big. | |
| 20110 | -** | |
| 20111 | -** An empty string is considered non-numeric. | |
| 20112 | -*/ | |
| 20113 | -SQLITE_PRIVATE int sqlite3IsNumber(const char *z, int *realnum, u8 enc){ | |
| 20095 | +** The string z[] is an text representation of a real number. | |
| 20096 | +** Convert this string to a double and write it into *pResult. | |
| 20097 | +** | |
| 20098 | +** The string z[] is length bytes in length (bytes, not characters) and | |
| 20099 | +** uses the encoding enc. The string is not necessarily zero-terminated. | |
| 20100 | +** | |
| 20101 | +** Return TRUE if the result is a valid real number (or integer) and FALSE | |
| 20102 | +** if the string is empty or contains extraneous text. Valid numbers | |
| 20103 | +** are in one of these formats: | |
| 20104 | +** | |
| 20105 | +** [+-]digits[E[+-]digits] | |
| 20106 | +** [+-]digits.[digits][E[+-]digits] | |
| 20107 | +** [+-].digits[E[+-]digits] | |
| 20108 | +** | |
| 20109 | +** Leading and trailing whitespace is ignored for the purpose of determining | |
| 20110 | +** validity. | |
| 20111 | +** | |
| 20112 | +** If some prefix of the input string is a valid number, this routine | |
| 20113 | +** returns FALSE but it still converts the prefix and writes the result | |
| 20114 | +** into *pResult. | |
| 20115 | +*/ | |
| 20116 | +SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){ | |
| 20117 | +#ifndef SQLITE_OMIT_FLOATING_POINT | |
| 20114 | 20118 | int incr = (enc==SQLITE_UTF8?1:2); |
| 20115 | - if( enc==SQLITE_UTF16BE ) z++; | |
| 20116 | - if( *z=='-' || *z=='+' ) z += incr; | |
| 20117 | - if( !sqlite3Isdigit(*z) ){ | |
| 20118 | - return 0; | |
| 20119 | - } | |
| 20120 | - z += incr; | |
| 20121 | - *realnum = 0; | |
| 20122 | - while( sqlite3Isdigit(*z) ){ z += incr; } | |
| 20123 | -#ifndef SQLITE_OMIT_FLOATING_POINT | |
| 20124 | - if( *z=='.' ){ | |
| 20125 | - z += incr; | |
| 20126 | - if( !sqlite3Isdigit(*z) ) return 0; | |
| 20127 | - while( sqlite3Isdigit(*z) ){ z += incr; } | |
| 20128 | - *realnum = 1; | |
| 20129 | - } | |
| 20130 | - if( *z=='e' || *z=='E' ){ | |
| 20131 | - z += incr; | |
| 20132 | - if( *z=='+' || *z=='-' ) z += incr; | |
| 20133 | - if( !sqlite3Isdigit(*z) ) return 0; | |
| 20134 | - while( sqlite3Isdigit(*z) ){ z += incr; } | |
| 20135 | - *realnum = 1; | |
| 20136 | - } | |
| 20137 | -#endif | |
| 20138 | - return *z==0; | |
| 20139 | -} | |
| 20140 | - | |
| 20141 | -/* | |
| 20142 | -** The string z[] is an ASCII representation of a real number. | |
| 20143 | -** Convert this string to a double. | |
| 20144 | -** | |
| 20145 | -** This routine assumes that z[] really is a valid number. If it | |
| 20146 | -** is not, the result is undefined. | |
| 20147 | -** | |
| 20148 | -** This routine is used instead of the library atof() function because | |
| 20149 | -** the library atof() might want to use "," as the decimal point instead | |
| 20150 | -** of "." depending on how locale is set. But that would cause problems | |
| 20151 | -** for SQL. So this routine always uses "." regardless of locale. | |
| 20152 | -*/ | |
| 20153 | -SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult){ | |
| 20154 | -#ifndef SQLITE_OMIT_FLOATING_POINT | |
| 20155 | - const char *zBegin = z; | |
| 20119 | + const char *zEnd = z + length; | |
| 20156 | 20120 | /* sign * significand * (10 ^ (esign * exponent)) */ |
| 20157 | - int sign = 1; /* sign of significand */ | |
| 20158 | - i64 s = 0; /* significand */ | |
| 20159 | - int d = 0; /* adjust exponent for shifting decimal point */ | |
| 20160 | - int esign = 1; /* sign of exponent */ | |
| 20161 | - int e = 0; /* exponent */ | |
| 20121 | + int sign = 1; /* sign of significand */ | |
| 20122 | + i64 s = 0; /* significand */ | |
| 20123 | + int d = 0; /* adjust exponent for shifting decimal point */ | |
| 20124 | + int esign = 1; /* sign of exponent */ | |
| 20125 | + int e = 0; /* exponent */ | |
| 20126 | + int eValid = 1; /* True exponent is either not used or is well-formed */ | |
| 20162 | 20127 | double result; |
| 20163 | 20128 | int nDigits = 0; |
| 20164 | 20129 | |
| 20130 | + *pResult = 0.0; /* Default return value, in case of an error */ | |
| 20131 | + | |
| 20132 | + if( enc==SQLITE_UTF16BE ) z++; | |
| 20133 | + | |
| 20165 | 20134 | /* skip leading spaces */ |
| 20166 | - while( sqlite3Isspace(*z) ) z++; | |
| 20135 | + while( z<zEnd && sqlite3Isspace(*z) ) z+=incr; | |
| 20136 | + if( z>=zEnd ) return 0; | |
| 20137 | + | |
| 20167 | 20138 | /* get sign of significand */ |
| 20168 | 20139 | if( *z=='-' ){ |
| 20169 | 20140 | sign = -1; |
| 20170 | - z++; | |
| 20141 | + z+=incr; | |
| 20171 | 20142 | }else if( *z=='+' ){ |
| 20172 | - z++; | |
| 20143 | + z+=incr; | |
| 20173 | 20144 | } |
| 20145 | + | |
| 20174 | 20146 | /* skip leading zeroes */ |
| 20175 | - while( z[0]=='0' ) z++, nDigits++; | |
| 20147 | + while( z<zEnd && z[0]=='0' ) z+=incr, nDigits++; | |
| 20176 | 20148 | |
| 20177 | 20149 | /* copy max significant digits to significand */ |
| 20178 | - while( sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){ | |
| 20150 | + while( z<zEnd && sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){ | |
| 20179 | 20151 | s = s*10 + (*z - '0'); |
| 20180 | - z++, nDigits++; | |
| 20152 | + z+=incr, nDigits++; | |
| 20181 | 20153 | } |
| 20154 | + | |
| 20182 | 20155 | /* skip non-significant significand digits |
| 20183 | 20156 | ** (increase exponent by d to shift decimal left) */ |
| 20184 | - while( sqlite3Isdigit(*z) ) z++, nDigits++, d++; | |
| 20157 | + while( z<zEnd && sqlite3Isdigit(*z) ) z+=incr, nDigits++, d++; | |
| 20158 | + if( z>=zEnd ) goto do_atof_calc; | |
| 20185 | 20159 | |
| 20186 | 20160 | /* if decimal point is present */ |
| 20187 | 20161 | if( *z=='.' ){ |
| 20188 | - z++; | |
| 20162 | + z+=incr; | |
| 20189 | 20163 | /* copy digits from after decimal to significand |
| 20190 | 20164 | ** (decrease exponent by d to shift decimal right) */ |
| 20191 | - while( sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){ | |
| 20165 | + while( z<zEnd && sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){ | |
| 20192 | 20166 | s = s*10 + (*z - '0'); |
| 20193 | - z++, nDigits++, d--; | |
| 20167 | + z+=incr, nDigits++, d--; | |
| 20194 | 20168 | } |
| 20195 | 20169 | /* skip non-significant digits */ |
| 20196 | - while( sqlite3Isdigit(*z) ) z++, nDigits++; | |
| 20170 | + while( z<zEnd && sqlite3Isdigit(*z) ) z+=incr, nDigits++; | |
| 20197 | 20171 | } |
| 20172 | + if( z>=zEnd ) goto do_atof_calc; | |
| 20198 | 20173 | |
| 20199 | 20174 | /* if exponent is present */ |
| 20200 | 20175 | if( *z=='e' || *z=='E' ){ |
| 20201 | - z++; | |
| 20176 | + z+=incr; | |
| 20177 | + eValid = 0; | |
| 20178 | + if( z>=zEnd ) goto do_atof_calc; | |
| 20202 | 20179 | /* get sign of exponent */ |
| 20203 | 20180 | if( *z=='-' ){ |
| 20204 | 20181 | esign = -1; |
| 20205 | - z++; | |
| 20182 | + z+=incr; | |
| 20206 | 20183 | }else if( *z=='+' ){ |
| 20207 | - z++; | |
| 20184 | + z+=incr; | |
| 20208 | 20185 | } |
| 20209 | 20186 | /* copy digits to exponent */ |
| 20210 | - while( sqlite3Isdigit(*z) ){ | |
| 20187 | + while( z<zEnd && sqlite3Isdigit(*z) ){ | |
| 20211 | 20188 | e = e*10 + (*z - '0'); |
| 20212 | - z++; | |
| 20189 | + z+=incr; | |
| 20190 | + eValid = 1; | |
| 20213 | 20191 | } |
| 20214 | 20192 | } |
| 20215 | 20193 | |
| 20194 | + /* skip trailing spaces */ | |
| 20195 | + if( nDigits && eValid ){ | |
| 20196 | + while( z<zEnd && sqlite3Isspace(*z) ) z+=incr; | |
| 20197 | + } | |
| 20198 | + | |
| 20199 | +do_atof_calc: | |
| 20216 | 20200 | /* adjust exponent by d, and update sign */ |
| 20217 | 20201 | e = (e*esign) + d; |
| 20218 | 20202 | if( e<0 ) { |
| 20219 | 20203 | esign = -1; |
| 20220 | 20204 | e *= -1; |
| @@ -20269,132 +20253,104 @@ | ||
| 20269 | 20253 | } |
| 20270 | 20254 | |
| 20271 | 20255 | /* store the result */ |
| 20272 | 20256 | *pResult = result; |
| 20273 | 20257 | |
| 20274 | - /* return number of characters used */ | |
| 20275 | - return (int)(z - zBegin); | |
| 20258 | + /* return true if number and no extra non-whitespace chracters after */ | |
| 20259 | + return z>=zEnd && nDigits>0 && eValid; | |
| 20276 | 20260 | #else |
| 20277 | - return sqlite3Atoi64(z, pResult); | |
| 20261 | + return !sqlite3Atoi64(z, pResult, length, enc); | |
| 20278 | 20262 | #endif /* SQLITE_OMIT_FLOATING_POINT */ |
| 20279 | 20263 | } |
| 20280 | 20264 | |
| 20281 | 20265 | /* |
| 20282 | 20266 | ** Compare the 19-character string zNum against the text representation |
| 20283 | 20267 | ** value 2^63: 9223372036854775808. Return negative, zero, or positive |
| 20284 | 20268 | ** if zNum is less than, equal to, or greater than the string. |
| 20269 | +** Note that zNum must contain exactly 19 characters. | |
| 20285 | 20270 | ** |
| 20286 | 20271 | ** Unlike memcmp() this routine is guaranteed to return the difference |
| 20287 | 20272 | ** in the values of the last digit if the only difference is in the |
| 20288 | 20273 | ** last digit. So, for example, |
| 20289 | 20274 | ** |
| 20290 | -** compare2pow63("9223372036854775800") | |
| 20275 | +** compare2pow63("9223372036854775800", 1) | |
| 20291 | 20276 | ** |
| 20292 | 20277 | ** will return -8. |
| 20293 | 20278 | */ |
| 20294 | -static int compare2pow63(const char *zNum){ | |
| 20295 | - int c; | |
| 20296 | - c = memcmp(zNum,"922337203685477580",18)*10; | |
| 20279 | +static int compare2pow63(const char *zNum, int incr){ | |
| 20280 | + int c = 0; | |
| 20281 | + int i; | |
| 20282 | + /* 012345678901234567 */ | |
| 20283 | + const char *pow63 = "922337203685477580"; | |
| 20284 | + for(i=0; c==0 && i<18; i++){ | |
| 20285 | + c = (zNum[i*incr]-pow63[i])*10; | |
| 20286 | + } | |
| 20297 | 20287 | if( c==0 ){ |
| 20298 | - c = zNum[18] - '8'; | |
| 20288 | + c = zNum[18*incr] - '8'; | |
| 20299 | 20289 | testcase( c==(-1) ); |
| 20300 | 20290 | testcase( c==0 ); |
| 20301 | 20291 | testcase( c==(+1) ); |
| 20302 | 20292 | } |
| 20303 | 20293 | return c; |
| 20304 | 20294 | } |
| 20305 | 20295 | |
| 20306 | 20296 | |
| 20307 | 20297 | /* |
| 20308 | -** Return TRUE if zNum is a 64-bit signed integer and write | |
| 20309 | -** the value of the integer into *pNum. If zNum is not an integer | |
| 20310 | -** or is an integer that is too large to be expressed with 64 bits, | |
| 20311 | -** then return false. | |
| 20298 | +** Convert zNum to a 64-bit signed integer and write | |
| 20299 | +** the value of the integer into *pNum. | |
| 20300 | +** If zNum is exactly 9223372036854665808, return 2. | |
| 20301 | +** This is a special case as the context will determine | |
| 20302 | +** if it is too big (used as a negative). | |
| 20303 | +** If zNum is not an integer or is an integer that | |
| 20304 | +** is too large to be expressed with 64 bits, | |
| 20305 | +** then return 1. Otherwise return 0. | |
| 20312 | 20306 | ** |
| 20313 | -** When this routine was originally written it dealt with only | |
| 20314 | -** 32-bit numbers. At that time, it was much faster than the | |
| 20315 | -** atoi() library routine in RedHat 7.2. | |
| 20307 | +** length is the number of bytes in the string (bytes, not characters). | |
| 20308 | +** The string is not necessarily zero-terminated. The encoding is | |
| 20309 | +** given by enc. | |
| 20316 | 20310 | */ |
| 20317 | -SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum){ | |
| 20311 | +SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){ | |
| 20312 | + int incr = (enc==SQLITE_UTF8?1:2); | |
| 20318 | 20313 | i64 v = 0; |
| 20319 | - int neg; | |
| 20320 | - int i, c; | |
| 20314 | + int neg = 0; /* assume positive */ | |
| 20315 | + int i; | |
| 20316 | + int c = 0; | |
| 20321 | 20317 | const char *zStart; |
| 20322 | - while( sqlite3Isspace(*zNum) ) zNum++; | |
| 20318 | + const char *zEnd = zNum + length; | |
| 20319 | + if( enc==SQLITE_UTF16BE ) zNum++; | |
| 20320 | + while( zNum<zEnd && sqlite3Isspace(*zNum) ) zNum+=incr; | |
| 20321 | + if( zNum>=zEnd ) goto do_atoi_calc; | |
| 20323 | 20322 | if( *zNum=='-' ){ |
| 20324 | 20323 | neg = 1; |
| 20325 | - zNum++; | |
| 20324 | + zNum+=incr; | |
| 20326 | 20325 | }else if( *zNum=='+' ){ |
| 20327 | - neg = 0; | |
| 20328 | - zNum++; | |
| 20329 | - }else{ | |
| 20330 | - neg = 0; | |
| 20326 | + zNum+=incr; | |
| 20331 | 20327 | } |
| 20328 | +do_atoi_calc: | |
| 20332 | 20329 | zStart = zNum; |
| 20333 | - while( zNum[0]=='0' ){ zNum++; } /* Skip over leading zeros. Ticket #2454 */ | |
| 20334 | - for(i=0; (c=zNum[i])>='0' && c<='9'; i++){ | |
| 20330 | + while( zNum<zEnd && zNum[0]=='0' ){ zNum+=incr; } /* Skip leading zeros. */ | |
| 20331 | + for(i=0; &zNum[i]<zEnd && (c=zNum[i])>='0' && c<='9'; i+=incr){ | |
| 20335 | 20332 | v = v*10 + c - '0'; |
| 20336 | 20333 | } |
| 20337 | 20334 | *pNum = neg ? -v : v; |
| 20338 | 20335 | testcase( i==18 ); |
| 20339 | 20336 | testcase( i==19 ); |
| 20340 | 20337 | testcase( i==20 ); |
| 20341 | - if( c!=0 || (i==0 && zStart==zNum) || i>19 ){ | |
| 20338 | + if( (c!=0 && &zNum[i]<zEnd) || (i==0 && zStart==zNum) || i>19*incr ){ | |
| 20342 | 20339 | /* zNum is empty or contains non-numeric text or is longer |
| 20343 | - ** than 19 digits (thus guaranting that it is too large) */ | |
| 20344 | - return 0; | |
| 20345 | - }else if( i<19 ){ | |
| 20340 | + ** than 19 digits (thus guaranteeing that it is too large) */ | |
| 20341 | + return 1; | |
| 20342 | + }else if( i<19*incr ){ | |
| 20346 | 20343 | /* Less than 19 digits, so we know that it fits in 64 bits */ |
| 20347 | - return 1; | |
| 20344 | + return 0; | |
| 20348 | 20345 | }else{ |
| 20349 | 20346 | /* 19-digit numbers must be no larger than 9223372036854775807 if positive |
| 20350 | 20347 | ** or 9223372036854775808 if negative. Note that 9223372036854665808 |
| 20351 | - ** is 2^63. */ | |
| 20352 | - return compare2pow63(zNum)<neg; | |
| 20353 | - } | |
| 20354 | -} | |
| 20355 | - | |
| 20356 | -/* | |
| 20357 | -** The string zNum represents an unsigned integer. The zNum string | |
| 20358 | -** consists of one or more digit characters and is terminated by | |
| 20359 | -** a zero character. Any stray characters in zNum result in undefined | |
| 20360 | -** behavior. | |
| 20361 | -** | |
| 20362 | -** If the unsigned integer that zNum represents will fit in a | |
| 20363 | -** 64-bit signed integer, return TRUE. Otherwise return FALSE. | |
| 20364 | -** | |
| 20365 | -** If the negFlag parameter is true, that means that zNum really represents | |
| 20366 | -** a negative number. (The leading "-" is omitted from zNum.) This | |
| 20367 | -** parameter is needed to determine a boundary case. A string | |
| 20368 | -** of "9223373036854775808" returns false if negFlag is false or true | |
| 20369 | -** if negFlag is true. | |
| 20370 | -** | |
| 20371 | -** Leading zeros are ignored. | |
| 20372 | -*/ | |
| 20373 | -SQLITE_PRIVATE int sqlite3FitsIn64Bits(const char *zNum, int negFlag){ | |
| 20374 | - int i; | |
| 20375 | - int neg = 0; | |
| 20376 | - | |
| 20377 | - assert( zNum[0]>='0' && zNum[0]<='9' ); /* zNum is an unsigned number */ | |
| 20378 | - | |
| 20379 | - if( negFlag ) neg = 1-neg; | |
| 20380 | - while( *zNum=='0' ){ | |
| 20381 | - zNum++; /* Skip leading zeros. Ticket #2454 */ | |
| 20382 | - } | |
| 20383 | - for(i=0; zNum[i]; i++){ assert( zNum[i]>='0' && zNum[i]<='9' ); } | |
| 20384 | - testcase( i==18 ); | |
| 20385 | - testcase( i==19 ); | |
| 20386 | - testcase( i==20 ); | |
| 20387 | - if( i<19 ){ | |
| 20388 | - /* Guaranteed to fit if less than 19 digits */ | |
| 20389 | - return 1; | |
| 20390 | - }else if( i>19 ){ | |
| 20391 | - /* Guaranteed to be too big if greater than 19 digits */ | |
| 20392 | - return 0; | |
| 20393 | - }else{ | |
| 20394 | - /* Compare against 2^63. */ | |
| 20395 | - return compare2pow63(zNum)<neg; | |
| 20348 | + ** is 2^63. Return 1 if to large */ | |
| 20349 | + c=compare2pow63(zNum, incr); | |
| 20350 | + if( c==0 && neg==0 ) return 2; /* too big, exactly 9223372036854665808 */ | |
| 20351 | + return c<neg ? 0 : 1; | |
| 20396 | 20352 | } |
| 20397 | 20353 | } |
| 20398 | 20354 | |
| 20399 | 20355 | /* |
| 20400 | 20356 | ** If zNum represents an integer that will fit in 32-bits, then set |
| @@ -54149,17 +54105,13 @@ | ||
| 54149 | 54105 | return pMem->u.i; |
| 54150 | 54106 | }else if( flags & MEM_Real ){ |
| 54151 | 54107 | return doubleToInt64(pMem->r); |
| 54152 | 54108 | }else if( flags & (MEM_Str|MEM_Blob) ){ |
| 54153 | 54109 | i64 value; |
| 54154 | - pMem->flags |= MEM_Str; | |
| 54155 | - if( sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8) | |
| 54156 | - || sqlite3VdbeMemNulTerminate(pMem) ){ | |
| 54157 | - return 0; | |
| 54158 | - } | |
| 54159 | - assert( pMem->z ); | |
| 54160 | - sqlite3Atoi64(pMem->z, &value); | |
| 54110 | + assert( pMem->z || pMem->n==0 ); | |
| 54111 | + testcase( pMem->z==0 ); | |
| 54112 | + sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc); | |
| 54161 | 54113 | return value; |
| 54162 | 54114 | }else{ |
| 54163 | 54115 | return 0; |
| 54164 | 54116 | } |
| 54165 | 54117 | } |
| @@ -54185,11 +54137,11 @@ | ||
| 54185 | 54137 | || sqlite3VdbeMemNulTerminate(pMem) ){ |
| 54186 | 54138 | /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ |
| 54187 | 54139 | return (double)0; |
| 54188 | 54140 | } |
| 54189 | 54141 | assert( pMem->z ); |
| 54190 | - sqlite3AtoF(pMem->z, &val); | |
| 54142 | + sqlite3AtoF(pMem->z, &val, pMem->n, SQLITE_UTF8); | |
| 54191 | 54143 | return val; |
| 54192 | 54144 | }else{ |
| 54193 | 54145 | /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ |
| 54194 | 54146 | return (double)0; |
| 54195 | 54147 | } |
| @@ -54258,25 +54210,23 @@ | ||
| 54258 | 54210 | ** Every effort is made to force the conversion, even if the input |
| 54259 | 54211 | ** is a string that does not look completely like a number. Convert |
| 54260 | 54212 | ** as much of the string as we can and ignore the rest. |
| 54261 | 54213 | */ |
| 54262 | 54214 | SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){ |
| 54263 | - int rc; | |
| 54264 | - assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 ); | |
| 54265 | - assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 ); | |
| 54266 | - assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); | |
| 54267 | - rc = sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8); | |
| 54268 | - if( rc ) return rc; | |
| 54269 | - rc = sqlite3VdbeMemNulTerminate(pMem); | |
| 54270 | - if( rc ) return rc; | |
| 54271 | - if( sqlite3Atoi64(pMem->z, &pMem->u.i) ){ | |
| 54272 | - MemSetTypeFlag(pMem, MEM_Int); | |
| 54273 | - }else{ | |
| 54274 | - pMem->r = sqlite3VdbeRealValue(pMem); | |
| 54275 | - MemSetTypeFlag(pMem, MEM_Real); | |
| 54276 | - sqlite3VdbeIntegerAffinity(pMem); | |
| 54277 | - } | |
| 54215 | + if( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 ){ | |
| 54216 | + assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 ); | |
| 54217 | + assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); | |
| 54218 | + if( 0==sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc) ){ | |
| 54219 | + MemSetTypeFlag(pMem, MEM_Int); | |
| 54220 | + }else{ | |
| 54221 | + pMem->r = sqlite3VdbeRealValue(pMem); | |
| 54222 | + MemSetTypeFlag(pMem, MEM_Real); | |
| 54223 | + sqlite3VdbeIntegerAffinity(pMem); | |
| 54224 | + } | |
| 54225 | + } | |
| 54226 | + assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))!=0 ); | |
| 54227 | + pMem->flags &= ~(MEM_Str|MEM_Blob); | |
| 54278 | 54228 | return SQLITE_OK; |
| 54279 | 54229 | } |
| 54280 | 54230 | |
| 54281 | 54231 | /* |
| 54282 | 54232 | ** Delete any previous value and set the value stored in *pMem to NULL. |
| @@ -54815,10 +54765,12 @@ | ||
| 54815 | 54765 | sqlite3_value **ppVal /* Write the new value here */ |
| 54816 | 54766 | ){ |
| 54817 | 54767 | int op; |
| 54818 | 54768 | char *zVal = 0; |
| 54819 | 54769 | sqlite3_value *pVal = 0; |
| 54770 | + int negInt = 1; | |
| 54771 | + const char *zNeg = ""; | |
| 54820 | 54772 | |
| 54821 | 54773 | if( !pExpr ){ |
| 54822 | 54774 | *ppVal = 0; |
| 54823 | 54775 | return SQLITE_OK; |
| 54824 | 54776 | } |
| @@ -54831,35 +54783,50 @@ | ||
| 54831 | 54783 | #ifdef SQLITE_ENABLE_STAT2 |
| 54832 | 54784 | if( op==TK_REGISTER ) op = pExpr->op2; |
| 54833 | 54785 | #else |
| 54834 | 54786 | if( NEVER(op==TK_REGISTER) ) op = pExpr->op2; |
| 54835 | 54787 | #endif |
| 54788 | + | |
| 54789 | + /* Handle negative integers in a single step. This is needed in the | |
| 54790 | + ** case when the value is -9223372036854775808. | |
| 54791 | + */ | |
| 54792 | + if( op==TK_UMINUS | |
| 54793 | + && (pExpr->pLeft->op==TK_INTEGER || pExpr->pLeft->op==TK_FLOAT) ){ | |
| 54794 | + pExpr = pExpr->pLeft; | |
| 54795 | + op = pExpr->op; | |
| 54796 | + negInt = -1; | |
| 54797 | + zNeg = "-"; | |
| 54798 | + } | |
| 54836 | 54799 | |
| 54837 | 54800 | if( op==TK_STRING || op==TK_FLOAT || op==TK_INTEGER ){ |
| 54838 | 54801 | pVal = sqlite3ValueNew(db); |
| 54839 | 54802 | if( pVal==0 ) goto no_mem; |
| 54840 | 54803 | if( ExprHasProperty(pExpr, EP_IntValue) ){ |
| 54841 | - sqlite3VdbeMemSetInt64(pVal, (i64)pExpr->u.iValue); | |
| 54804 | + sqlite3VdbeMemSetInt64(pVal, (i64)pExpr->u.iValue*negInt); | |
| 54842 | 54805 | }else{ |
| 54843 | - zVal = sqlite3DbStrDup(db, pExpr->u.zToken); | |
| 54806 | + zVal = sqlite3MPrintf(db, "%s%s", zNeg, pExpr->u.zToken); | |
| 54844 | 54807 | if( zVal==0 ) goto no_mem; |
| 54845 | 54808 | sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC); |
| 54846 | 54809 | if( op==TK_FLOAT ) pVal->type = SQLITE_FLOAT; |
| 54847 | 54810 | } |
| 54848 | 54811 | if( (op==TK_INTEGER || op==TK_FLOAT ) && affinity==SQLITE_AFF_NONE ){ |
| 54849 | 54812 | sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, SQLITE_UTF8); |
| 54850 | 54813 | }else{ |
| 54851 | 54814 | sqlite3ValueApplyAffinity(pVal, affinity, SQLITE_UTF8); |
| 54852 | 54815 | } |
| 54816 | + if( pVal->flags & (MEM_Int|MEM_Real) ) pVal->flags &= ~MEM_Str; | |
| 54853 | 54817 | if( enc!=SQLITE_UTF8 ){ |
| 54854 | 54818 | sqlite3VdbeChangeEncoding(pVal, enc); |
| 54855 | 54819 | } |
| 54856 | 54820 | }else if( op==TK_UMINUS ) { |
| 54821 | + /* This branch happens for multiple negative signs. Ex: -(-5) */ | |
| 54857 | 54822 | if( SQLITE_OK==sqlite3ValueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal) ){ |
| 54823 | + sqlite3VdbeMemNumerify(pVal); | |
| 54858 | 54824 | pVal->u.i = -1 * pVal->u.i; |
| 54859 | 54825 | /* (double)-1 In case of SQLITE_OMIT_FLOATING_POINT... */ |
| 54860 | 54826 | pVal->r = (double)-1 * pVal->r; |
| 54827 | + sqlite3ValueApplyAffinity(pVal, affinity, enc); | |
| 54861 | 54828 | } |
| 54862 | 54829 | } |
| 54863 | 54830 | #ifndef SQLITE_OMIT_BLOB_LITERAL |
| 54864 | 54831 | else if( op==TK_BLOB ){ |
| 54865 | 54832 | int nVal; |
| @@ -59770,35 +59737,21 @@ | ||
| 59770 | 59737 | ** looks like a number, convert it into a number. If it does not |
| 59771 | 59738 | ** look like a number, leave it alone. |
| 59772 | 59739 | */ |
| 59773 | 59740 | static void applyNumericAffinity(Mem *pRec){ |
| 59774 | 59741 | if( (pRec->flags & (MEM_Real|MEM_Int))==0 ){ |
| 59775 | - int realnum; | |
| 59742 | + double rValue; | |
| 59743 | + i64 iValue; | |
| 59776 | 59744 | u8 enc = pRec->enc; |
| 59777 | - sqlite3VdbeMemNulTerminate(pRec); | |
| 59778 | - if( (pRec->flags&MEM_Str) && sqlite3IsNumber(pRec->z, &realnum, enc) ){ | |
| 59779 | - i64 value; | |
| 59780 | - char *zUtf8 = pRec->z; | |
| 59781 | -#ifndef SQLITE_OMIT_UTF16 | |
| 59782 | - if( enc!=SQLITE_UTF8 ){ | |
| 59783 | - assert( pRec->db ); | |
| 59784 | - zUtf8 = sqlite3Utf16to8(pRec->db, pRec->z, pRec->n, enc); | |
| 59785 | - if( !zUtf8 ) return; | |
| 59786 | - } | |
| 59787 | -#endif | |
| 59788 | - if( !realnum && sqlite3Atoi64(zUtf8, &value) ){ | |
| 59789 | - pRec->u.i = value; | |
| 59790 | - MemSetTypeFlag(pRec, MEM_Int); | |
| 59791 | - }else{ | |
| 59792 | - sqlite3AtoF(zUtf8, &pRec->r); | |
| 59793 | - MemSetTypeFlag(pRec, MEM_Real); | |
| 59794 | - } | |
| 59795 | -#ifndef SQLITE_OMIT_UTF16 | |
| 59796 | - if( enc!=SQLITE_UTF8 ){ | |
| 59797 | - sqlite3DbFree(pRec->db, zUtf8); | |
| 59798 | - } | |
| 59799 | -#endif | |
| 59745 | + if( (pRec->flags&MEM_Str)==0 ) return; | |
| 59746 | + if( sqlite3AtoF(pRec->z, &rValue, pRec->n, enc)==0 ) return; | |
| 59747 | + if( 0==sqlite3Atoi64(pRec->z, &iValue, pRec->n, enc) ){ | |
| 59748 | + pRec->u.i = iValue; | |
| 59749 | + pRec->flags |= MEM_Int; | |
| 59750 | + }else{ | |
| 59751 | + pRec->r = rValue; | |
| 59752 | + pRec->flags |= MEM_Real; | |
| 59800 | 59753 | } |
| 59801 | 59754 | } |
| 59802 | 59755 | } |
| 59803 | 59756 | |
| 59804 | 59757 | /* |
| @@ -61580,11 +61533,10 @@ | ||
| 61580 | 61533 | ** integers, for space efficiency, but after extraction we want them |
| 61581 | 61534 | ** to have only a real value. |
| 61582 | 61535 | */ |
| 61583 | 61536 | case OP_RealAffinity: { /* in1 */ |
| 61584 | 61537 | pIn1 = &aMem[pOp->p1]; |
| 61585 | - memAboutToChange(p, pIn1); | |
| 61586 | 61538 | if( pIn1->flags & MEM_Int ){ |
| 61587 | 61539 | sqlite3VdbeMemRealify(pIn1); |
| 61588 | 61540 | } |
| 61589 | 61541 | break; |
| 61590 | 61542 | } |
| @@ -61623,11 +61575,10 @@ | ||
| 61623 | 61575 | ** |
| 61624 | 61576 | ** A NULL value is not changed by this routine. It remains NULL. |
| 61625 | 61577 | */ |
| 61626 | 61578 | case OP_ToBlob: { /* same as TK_TO_BLOB, in1 */ |
| 61627 | 61579 | pIn1 = &aMem[pOp->p1]; |
| 61628 | - memAboutToChange(p, pIn1); | |
| 61629 | 61580 | if( pIn1->flags & MEM_Null ) break; |
| 61630 | 61581 | if( (pIn1->flags & MEM_Blob)==0 ){ |
| 61631 | 61582 | applyAffinity(pIn1, SQLITE_AFF_TEXT, encoding); |
| 61632 | 61583 | assert( pIn1->flags & MEM_Str || db->mallocFailed ); |
| 61633 | 61584 | MemSetTypeFlag(pIn1, MEM_Blob); |
| @@ -61648,14 +61599,11 @@ | ||
| 61648 | 61599 | ** |
| 61649 | 61600 | ** A NULL value is not changed by this routine. It remains NULL. |
| 61650 | 61601 | */ |
| 61651 | 61602 | case OP_ToNumeric: { /* same as TK_TO_NUMERIC, in1 */ |
| 61652 | 61603 | pIn1 = &aMem[pOp->p1]; |
| 61653 | - memAboutToChange(p, pIn1); | |
| 61654 | - if( (pIn1->flags & (MEM_Null|MEM_Int|MEM_Real))==0 ){ | |
| 61655 | - sqlite3VdbeMemNumerify(pIn1); | |
| 61656 | - } | |
| 61604 | + sqlite3VdbeMemNumerify(pIn1); | |
| 61657 | 61605 | break; |
| 61658 | 61606 | } |
| 61659 | 61607 | #endif /* SQLITE_OMIT_CAST */ |
| 61660 | 61608 | |
| 61661 | 61609 | /* Opcode: ToInt P1 * * * * |
| @@ -61667,11 +61615,10 @@ | ||
| 61667 | 61615 | ** |
| 61668 | 61616 | ** A NULL value is not changed by this routine. It remains NULL. |
| 61669 | 61617 | */ |
| 61670 | 61618 | case OP_ToInt: { /* same as TK_TO_INT, in1 */ |
| 61671 | 61619 | pIn1 = &aMem[pOp->p1]; |
| 61672 | - memAboutToChange(p, pIn1); | |
| 61673 | 61620 | if( (pIn1->flags & MEM_Null)==0 ){ |
| 61674 | 61621 | sqlite3VdbeMemIntegerify(pIn1); |
| 61675 | 61622 | } |
| 61676 | 61623 | break; |
| 61677 | 61624 | } |
| @@ -61781,12 +61728,10 @@ | ||
| 61781 | 61728 | u16 flags3; /* Copy of initial value of pIn3->flags */ |
| 61782 | 61729 | #endif /* local variables moved into u.ai */ |
| 61783 | 61730 | |
| 61784 | 61731 | pIn1 = &aMem[pOp->p1]; |
| 61785 | 61732 | pIn3 = &aMem[pOp->p3]; |
| 61786 | - memAboutToChange(p, pIn1); | |
| 61787 | - memAboutToChange(p, pIn3); | |
| 61788 | 61733 | u.ai.flags1 = pIn1->flags; |
| 61789 | 61734 | u.ai.flags3 = pIn3->flags; |
| 61790 | 61735 | if( (pIn1->flags | pIn3->flags)&MEM_Null ){ |
| 61791 | 61736 | /* One or both operands are NULL */ |
| 61792 | 61737 | if( pOp->p5 & SQLITE_NULLEQ ){ |
| @@ -62415,11 +62360,10 @@ | ||
| 62415 | 62360 | assert( u.an.zAffinity[pOp->p2]==0 ); |
| 62416 | 62361 | pIn1 = &aMem[pOp->p1]; |
| 62417 | 62362 | while( (u.an.cAff = *(u.an.zAffinity++))!=0 ){ |
| 62418 | 62363 | assert( pIn1 <= &p->aMem[p->nMem] ); |
| 62419 | 62364 | assert( memIsValid(pIn1) ); |
| 62420 | - memAboutToChange(p, pIn1); | |
| 62421 | 62365 | ExpandBlob(pIn1); |
| 62422 | 62366 | applyAffinity(pIn1, u.an.cAff, encoding); |
| 62423 | 62367 | pIn1++; |
| 62424 | 62368 | } |
| 62425 | 62369 | break; |
| @@ -62495,11 +62439,10 @@ | ||
| 62495 | 62439 | ** out how much space is required for the new record. |
| 62496 | 62440 | */ |
| 62497 | 62441 | for(u.ao.pRec=u.ao.pData0; u.ao.pRec<=u.ao.pLast; u.ao.pRec++){ |
| 62498 | 62442 | assert( memIsValid(u.ao.pRec) ); |
| 62499 | 62443 | if( u.ao.zAffinity ){ |
| 62500 | - memAboutToChange(p, u.ao.pRec); | |
| 62501 | 62444 | applyAffinity(u.ao.pRec, u.ao.zAffinity[u.ao.pRec-u.ao.pData0], encoding); |
| 62502 | 62445 | } |
| 62503 | 62446 | if( u.ao.pRec->flags&MEM_Zero && u.ao.pRec->n>0 ){ |
| 62504 | 62447 | sqlite3VdbeMemExpandBlob(u.ao.pRec); |
| 62505 | 62448 | } |
| @@ -68880,11 +68823,11 @@ | ||
| 68880 | 68823 | pExpr->iColumn = (ynVar)(++pParse->nVar); |
| 68881 | 68824 | }else if( z[0]=='?' ){ |
| 68882 | 68825 | /* Wildcard of the form "?nnn". Convert "nnn" to an integer and |
| 68883 | 68826 | ** use it as the variable number */ |
| 68884 | 68827 | i64 i; |
| 68885 | - int bOk = sqlite3Atoi64(&z[1], &i); | |
| 68828 | + int bOk = 0==sqlite3Atoi64(&z[1], &i, sqlite3Strlen30(&z[1]), SQLITE_UTF8); | |
| 68886 | 68829 | pExpr->iColumn = (ynVar)i; |
| 68887 | 68830 | testcase( i==0 ); |
| 68888 | 68831 | testcase( i==1 ); |
| 68889 | 68832 | testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]-1 ); |
| 68890 | 68833 | testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ); |
| @@ -70243,11 +70186,11 @@ | ||
| 70243 | 70186 | */ |
| 70244 | 70187 | static void codeReal(Vdbe *v, const char *z, int negateFlag, int iMem){ |
| 70245 | 70188 | if( ALWAYS(z!=0) ){ |
| 70246 | 70189 | double value; |
| 70247 | 70190 | char *zV; |
| 70248 | - sqlite3AtoF(z, &value); | |
| 70191 | + sqlite3AtoF(z, &value, sqlite3Strlen30(z), SQLITE_UTF8); | |
| 70249 | 70192 | assert( !sqlite3IsNaN(value) ); /* The new AtoF never returns NaN */ |
| 70250 | 70193 | if( negateFlag ) value = -value; |
| 70251 | 70194 | zV = dup8bytes(v, (char*)&value); |
| 70252 | 70195 | sqlite3VdbeAddOp4(v, OP_Real, 0, iMem, 0, zV, P4_REAL); |
| 70253 | 70196 | } |
| @@ -70257,28 +70200,27 @@ | ||
| 70257 | 70200 | |
| 70258 | 70201 | /* |
| 70259 | 70202 | ** Generate an instruction that will put the integer describe by |
| 70260 | 70203 | ** text z[0..n-1] into register iMem. |
| 70261 | 70204 | ** |
| 70262 | -** The z[] string will probably not be zero-terminated. But the | |
| 70263 | -** z[n] character is guaranteed to be something that does not look | |
| 70264 | -** like the continuation of the number. | |
| 70205 | +** Expr.u.zToken is always UTF8 and zero-terminated. | |
| 70265 | 70206 | */ |
| 70266 | 70207 | static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){ |
| 70267 | 70208 | Vdbe *v = pParse->pVdbe; |
| 70268 | 70209 | if( pExpr->flags & EP_IntValue ){ |
| 70269 | 70210 | int i = pExpr->u.iValue; |
| 70270 | 70211 | if( negFlag ) i = -i; |
| 70271 | 70212 | sqlite3VdbeAddOp2(v, OP_Integer, i, iMem); |
| 70272 | 70213 | }else{ |
| 70214 | + int c; | |
| 70215 | + i64 value; | |
| 70273 | 70216 | const char *z = pExpr->u.zToken; |
| 70274 | 70217 | assert( z!=0 ); |
| 70275 | - if( sqlite3FitsIn64Bits(z, negFlag) ){ | |
| 70276 | - i64 value; | |
| 70218 | + c = sqlite3Atoi64(z, &value, sqlite3Strlen30(z), SQLITE_UTF8); | |
| 70219 | + if( c==0 || (c==2 && negFlag) ){ | |
| 70277 | 70220 | char *zV; |
| 70278 | - sqlite3Atoi64(z, &value); | |
| 70279 | - if( negFlag ) value = -value; | |
| 70221 | + if( negFlag ){ value = -value; } | |
| 70280 | 70222 | zV = dup8bytes(v, (char*)&value); |
| 70281 | 70223 | sqlite3VdbeAddOp4(v, OP_Int64, 0, iMem, 0, zV, P4_INT64); |
| 70282 | 70224 | }else{ |
| 70283 | 70225 | #ifdef SQLITE_OMIT_FLOATING_POINT |
| 70284 | 70226 | sqlite3ErrorMsg(pParse, "oversized integer: %s%s", negFlag ? "-" : "", z); |
| @@ -79414,11 +79356,11 @@ | ||
| 79414 | 79356 | zBuf = sqlite3_mprintf("%.*f",n,r); |
| 79415 | 79357 | if( zBuf==0 ){ |
| 79416 | 79358 | sqlite3_result_error_nomem(context); |
| 79417 | 79359 | return; |
| 79418 | 79360 | } |
| 79419 | - sqlite3AtoF(zBuf, &r); | |
| 79361 | + sqlite3AtoF(zBuf, &r, sqlite3Strlen30(zBuf), SQLITE_UTF8); | |
| 79420 | 79362 | sqlite3_free(zBuf); |
| 79421 | 79363 | } |
| 79422 | 79364 | sqlite3_result_double(context, r); |
| 79423 | 79365 | } |
| 79424 | 79366 | #endif |
| @@ -85472,11 +85414,11 @@ | ||
| 85472 | 85414 | */ |
| 85473 | 85415 | if( sqlite3StrICmp(zLeft,"journal_size_limit")==0 ){ |
| 85474 | 85416 | Pager *pPager = sqlite3BtreePager(pDb->pBt); |
| 85475 | 85417 | i64 iLimit = -2; |
| 85476 | 85418 | if( zRight ){ |
| 85477 | - sqlite3Atoi64(zRight, &iLimit); | |
| 85419 | + sqlite3Atoi64(zRight, &iLimit, 1000000, SQLITE_UTF8); | |
| 85478 | 85420 | if( iLimit<-1 ) iLimit = -1; |
| 85479 | 85421 | } |
| 85480 | 85422 | iLimit = sqlite3PagerJournalSizeLimit(pPager, iLimit); |
| 85481 | 85423 | returnSingleInt(pParse, "journal_size_limit", iLimit); |
| 85482 | 85424 | }else |
| @@ -96380,11 +96322,12 @@ | ||
| 96380 | 96322 | |
| 96381 | 96323 | /* |
| 96382 | 96324 | ** Required because bestIndex() is called by bestOrClauseIndex() |
| 96383 | 96325 | */ |
| 96384 | 96326 | static void bestIndex( |
| 96385 | - Parse*, WhereClause*, struct SrcList_item*, Bitmask, ExprList*, WhereCost*); | |
| 96327 | + Parse*, WhereClause*, struct SrcList_item*, | |
| 96328 | + Bitmask, Bitmask, ExprList*, WhereCost*); | |
| 96386 | 96329 | |
| 96387 | 96330 | /* |
| 96388 | 96331 | ** This routine attempts to find an scanning strategy that can be used |
| 96389 | 96332 | ** to optimize an 'OR' expression that is part of a WHERE clause. |
| 96390 | 96333 | ** |
| @@ -96393,11 +96336,12 @@ | ||
| 96393 | 96336 | */ |
| 96394 | 96337 | static void bestOrClauseIndex( |
| 96395 | 96338 | Parse *pParse, /* The parsing context */ |
| 96396 | 96339 | WhereClause *pWC, /* The WHERE clause */ |
| 96397 | 96340 | struct SrcList_item *pSrc, /* The FROM clause term to search */ |
| 96398 | - Bitmask notReady, /* Mask of cursors that are not available */ | |
| 96341 | + Bitmask notReady, /* Mask of cursors not available for indexing */ | |
| 96342 | + Bitmask notValid, /* Cursors not available for any purpose */ | |
| 96399 | 96343 | ExprList *pOrderBy, /* The ORDER BY clause */ |
| 96400 | 96344 | WhereCost *pCost /* Lowest cost query plan */ |
| 96401 | 96345 | ){ |
| 96402 | 96346 | #ifndef SQLITE_OMIT_OR_OPTIMIZATION |
| 96403 | 96347 | const int iCur = pSrc->iCursor; /* The cursor of the table to be accessed */ |
| @@ -96429,19 +96373,19 @@ | ||
| 96429 | 96373 | WHERETRACE(("... Multi-index OR testing for term %d of %d....\n", |
| 96430 | 96374 | (pOrTerm - pOrWC->a), (pTerm - pWC->a) |
| 96431 | 96375 | )); |
| 96432 | 96376 | if( pOrTerm->eOperator==WO_AND ){ |
| 96433 | 96377 | WhereClause *pAndWC = &pOrTerm->u.pAndInfo->wc; |
| 96434 | - bestIndex(pParse, pAndWC, pSrc, notReady, 0, &sTermCost); | |
| 96378 | + bestIndex(pParse, pAndWC, pSrc, notReady, notValid, 0, &sTermCost); | |
| 96435 | 96379 | }else if( pOrTerm->leftCursor==iCur ){ |
| 96436 | 96380 | WhereClause tempWC; |
| 96437 | 96381 | tempWC.pParse = pWC->pParse; |
| 96438 | 96382 | tempWC.pMaskSet = pWC->pMaskSet; |
| 96439 | 96383 | tempWC.op = TK_AND; |
| 96440 | 96384 | tempWC.a = pOrTerm; |
| 96441 | 96385 | tempWC.nTerm = 1; |
| 96442 | - bestIndex(pParse, &tempWC, pSrc, notReady, 0, &sTermCost); | |
| 96386 | + bestIndex(pParse, &tempWC, pSrc, notReady, notValid, 0, &sTermCost); | |
| 96443 | 96387 | }else{ |
| 96444 | 96388 | continue; |
| 96445 | 96389 | } |
| 96446 | 96390 | rTotal += sTermCost.rCost; |
| 96447 | 96391 | nRow += sTermCost.nRow; |
| @@ -96884,11 +96828,12 @@ | ||
| 96884 | 96828 | */ |
| 96885 | 96829 | static void bestVirtualIndex( |
| 96886 | 96830 | Parse *pParse, /* The parsing context */ |
| 96887 | 96831 | WhereClause *pWC, /* The WHERE clause */ |
| 96888 | 96832 | struct SrcList_item *pSrc, /* The FROM clause term to search */ |
| 96889 | - Bitmask notReady, /* Mask of cursors that are not available */ | |
| 96833 | + Bitmask notReady, /* Mask of cursors not available for index */ | |
| 96834 | + Bitmask notValid, /* Cursors not valid for any purpose */ | |
| 96890 | 96835 | ExprList *pOrderBy, /* The order by clause */ |
| 96891 | 96836 | WhereCost *pCost, /* Lowest cost query plan */ |
| 96892 | 96837 | sqlite3_index_info **ppIdxInfo /* Index information passed to xBestIndex */ |
| 96893 | 96838 | ){ |
| 96894 | 96839 | Table *pTab = pSrc->pTab; |
| @@ -97014,11 +96959,11 @@ | ||
| 97014 | 96959 | pIdxInfo->nOrderBy = nOrderBy; |
| 97015 | 96960 | |
| 97016 | 96961 | /* Try to find a more efficient access pattern by using multiple indexes |
| 97017 | 96962 | ** to optimize an OR expression within the WHERE clause. |
| 97018 | 96963 | */ |
| 97019 | - bestOrClauseIndex(pParse, pWC, pSrc, notReady, pOrderBy, pCost); | |
| 96964 | + bestOrClauseIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost); | |
| 97020 | 96965 | } |
| 97021 | 96966 | #endif /* SQLITE_OMIT_VIRTUALTABLE */ |
| 97022 | 96967 | |
| 97023 | 96968 | /* |
| 97024 | 96969 | ** Argument pIdx is a pointer to an index structure that has an array of |
| @@ -97295,11 +97240,12 @@ | ||
| 97295 | 97240 | */ |
| 97296 | 97241 | static void bestBtreeIndex( |
| 97297 | 97242 | Parse *pParse, /* The parsing context */ |
| 97298 | 97243 | WhereClause *pWC, /* The WHERE clause */ |
| 97299 | 97244 | struct SrcList_item *pSrc, /* The FROM clause term to search */ |
| 97300 | - Bitmask notReady, /* Mask of cursors that are not available */ | |
| 97245 | + Bitmask notReady, /* Mask of cursors not available for indexing */ | |
| 97246 | + Bitmask notValid, /* Cursors not available for any purpose */ | |
| 97301 | 97247 | ExprList *pOrderBy, /* The ORDER BY clause */ |
| 97302 | 97248 | WhereCost *pCost /* Lowest cost query plan */ |
| 97303 | 97249 | ){ |
| 97304 | 97250 | int iCur = pSrc->iCursor; /* The cursor of the table to be accessed */ |
| 97305 | 97251 | Index *pProbe; /* An index we are evaluating */ |
| @@ -97557,29 +97503,29 @@ | ||
| 97557 | 97503 | ** of output rows, adjust the nRow value accordingly. This only |
| 97558 | 97504 | ** matters if the current index is the least costly, so do not bother |
| 97559 | 97505 | ** with this step if we already know this index will not be chosen. |
| 97560 | 97506 | ** Also, never reduce the output row count below 2 using this step. |
| 97561 | 97507 | ** |
| 97562 | - ** Do not reduce the output row count if pSrc is the only table that | |
| 97563 | - ** is notReady; if notReady is a power of two. This will be the case | |
| 97564 | - ** when the main sqlite3WhereBegin() loop is scanning for a table with | |
| 97565 | - ** and "optimal" index, and on such a scan the output row count | |
| 97566 | - ** reduction is not valid because it does not update the "pCost->used" | |
| 97567 | - ** bitmap. The notReady bitmap will also be a power of two when we | |
| 97568 | - ** are scanning for the last table in a 64-way join. We are willing | |
| 97569 | - ** to bypass this optimization in that corner case. | |
| 97508 | + ** It is critical that the notValid mask be used here instead of | |
| 97509 | + ** the notReady mask. When computing an "optimal" index, the notReady | |
| 97510 | + ** mask will only have one bit set - the bit for the current table. | |
| 97511 | + ** The notValid mask, on the other hand, always has all bits set for | |
| 97512 | + ** tables that are not in outer loops. If notReady is used here instead | |
| 97513 | + ** of notValid, then a optimal index that depends on inner joins loops | |
| 97514 | + ** might be selected even when there exists an optimal index that has | |
| 97515 | + ** no such dependency. | |
| 97570 | 97516 | */ |
| 97571 | - if( nRow>2 && cost<=pCost->rCost && (notReady & (notReady-1))!=0 ){ | |
| 97517 | + if( nRow>2 && cost<=pCost->rCost ){ | |
| 97572 | 97518 | int k; /* Loop counter */ |
| 97573 | 97519 | int nSkipEq = nEq; /* Number of == constraints to skip */ |
| 97574 | 97520 | int nSkipRange = nBound; /* Number of < constraints to skip */ |
| 97575 | 97521 | Bitmask thisTab; /* Bitmap for pSrc */ |
| 97576 | 97522 | |
| 97577 | 97523 | thisTab = getMask(pWC->pMaskSet, iCur); |
| 97578 | 97524 | for(pTerm=pWC->a, k=pWC->nTerm; nRow>2 && k; k--, pTerm++){ |
| 97579 | 97525 | if( pTerm->wtFlags & TERM_VIRTUAL ) continue; |
| 97580 | - if( (pTerm->prereqAll & notReady)!=thisTab ) continue; | |
| 97526 | + if( (pTerm->prereqAll & notValid)!=thisTab ) continue; | |
| 97581 | 97527 | if( pTerm->eOperator & (WO_EQ|WO_IN|WO_ISNULL) ){ |
| 97582 | 97528 | if( nSkipEq ){ |
| 97583 | 97529 | /* Ignore the first nEq equality matches since the index |
| 97584 | 97530 | ** has already accounted for these */ |
| 97585 | 97531 | nSkipEq--; |
| @@ -97657,11 +97603,11 @@ | ||
| 97657 | 97603 | WHERETRACE(("best index is: %s\n", |
| 97658 | 97604 | ((pCost->plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ? "none" : |
| 97659 | 97605 | pCost->plan.u.pIdx ? pCost->plan.u.pIdx->zName : "ipk") |
| 97660 | 97606 | )); |
| 97661 | 97607 | |
| 97662 | - bestOrClauseIndex(pParse, pWC, pSrc, notReady, pOrderBy, pCost); | |
| 97608 | + bestOrClauseIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost); | |
| 97663 | 97609 | bestAutomaticIndex(pParse, pWC, pSrc, notReady, pCost); |
| 97664 | 97610 | pCost->plan.wsFlags |= eqTermMask; |
| 97665 | 97611 | } |
| 97666 | 97612 | |
| 97667 | 97613 | /* |
| @@ -97672,26 +97618,27 @@ | ||
| 97672 | 97618 | */ |
| 97673 | 97619 | static void bestIndex( |
| 97674 | 97620 | Parse *pParse, /* The parsing context */ |
| 97675 | 97621 | WhereClause *pWC, /* The WHERE clause */ |
| 97676 | 97622 | struct SrcList_item *pSrc, /* The FROM clause term to search */ |
| 97677 | - Bitmask notReady, /* Mask of cursors that are not available */ | |
| 97623 | + Bitmask notReady, /* Mask of cursors not available for indexing */ | |
| 97624 | + Bitmask notValid, /* Cursors not available for any purpose */ | |
| 97678 | 97625 | ExprList *pOrderBy, /* The ORDER BY clause */ |
| 97679 | 97626 | WhereCost *pCost /* Lowest cost query plan */ |
| 97680 | 97627 | ){ |
| 97681 | 97628 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| 97682 | 97629 | if( IsVirtual(pSrc->pTab) ){ |
| 97683 | 97630 | sqlite3_index_info *p = 0; |
| 97684 | - bestVirtualIndex(pParse, pWC, pSrc, notReady, pOrderBy, pCost, &p); | |
| 97631 | + bestVirtualIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost,&p); | |
| 97685 | 97632 | if( p->needToFreeIdxStr ){ |
| 97686 | 97633 | sqlite3_free(p->idxStr); |
| 97687 | 97634 | } |
| 97688 | 97635 | sqlite3DbFree(pParse->db, p); |
| 97689 | 97636 | }else |
| 97690 | 97637 | #endif |
| 97691 | 97638 | { |
| 97692 | - bestBtreeIndex(pParse, pWC, pSrc, notReady, pOrderBy, pCost); | |
| 97639 | + bestBtreeIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost); | |
| 97693 | 97640 | } |
| 97694 | 97641 | } |
| 97695 | 97642 | |
| 97696 | 97643 | /* |
| 97697 | 97644 | ** Disable a term in the WHERE clause. Except, do not disable the term |
| @@ -98902,14 +98849,20 @@ | ||
| 98902 | 98849 | ** by waiting for other tables to run first. This "optimal" test works |
| 98903 | 98850 | ** by first assuming that the FROM clause is on the inner loop and finding |
| 98904 | 98851 | ** its query plan, then checking to see if that query plan uses any |
| 98905 | 98852 | ** other FROM clause terms that are notReady. If no notReady terms are |
| 98906 | 98853 | ** used then the "optimal" query plan works. |
| 98854 | + ** | |
| 98855 | + ** Note that the WhereCost.nRow parameter for an optimal scan might | |
| 98856 | + ** not be as small as it would be if the table really were the innermost | |
| 98857 | + ** join. The nRow value can be reduced by WHERE clause constraints | |
| 98858 | + ** that do not use indices. But this nRow reduction only happens if the | |
| 98859 | + ** table really is the innermost join. | |
| 98907 | 98860 | ** |
| 98908 | 98861 | ** The second loop iteration is only performed if no optimal scan |
| 98909 | - ** strategies were found by the first loop. This 2nd iteration is used to | |
| 98910 | - ** search for the lowest cost scan overall. | |
| 98862 | + ** strategies were found by the first iteration. This second iteration | |
| 98863 | + ** is used to search for the lowest cost scan overall. | |
| 98911 | 98864 | ** |
| 98912 | 98865 | ** Previous versions of SQLite performed only the second iteration - |
| 98913 | 98866 | ** the next outermost loop was always that with the lowest overall |
| 98914 | 98867 | ** cost. However, this meant that SQLite could select the wrong plan |
| 98915 | 98868 | ** for scripts such as the following: |
| @@ -98925,11 +98878,11 @@ | ||
| 98925 | 98878 | ** algorithm may choose to use t2 for the outer loop, which is a much |
| 98926 | 98879 | ** costlier approach. |
| 98927 | 98880 | */ |
| 98928 | 98881 | nUnconstrained = 0; |
| 98929 | 98882 | notIndexed = 0; |
| 98930 | - for(isOptimal=(iFrom<nTabList-1); isOptimal>=0; isOptimal--){ | |
| 98883 | + for(isOptimal=(iFrom<nTabList-1); isOptimal>=0 && bestJ<0; isOptimal--){ | |
| 98931 | 98884 | Bitmask mask; /* Mask of tables not yet ready */ |
| 98932 | 98885 | for(j=iFrom, pTabItem=&pTabList->a[j]; j<nTabList; j++, pTabItem++){ |
| 98933 | 98886 | int doNotReorder; /* True if this table should not be reordered */ |
| 98934 | 98887 | WhereCost sCost; /* Cost information from best[Virtual]Index() */ |
| 98935 | 98888 | ExprList *pOrderBy; /* ORDER BY clause for index to optimize */ |
| @@ -98947,15 +98900,17 @@ | ||
| 98947 | 98900 | |
| 98948 | 98901 | assert( pTabItem->pTab ); |
| 98949 | 98902 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| 98950 | 98903 | if( IsVirtual(pTabItem->pTab) ){ |
| 98951 | 98904 | sqlite3_index_info **pp = &pWInfo->a[j].pIdxInfo; |
| 98952 | - bestVirtualIndex(pParse, pWC, pTabItem, mask, pOrderBy, &sCost, pp); | |
| 98905 | + bestVirtualIndex(pParse, pWC, pTabItem, mask, notReady, pOrderBy, | |
| 98906 | + &sCost, pp); | |
| 98953 | 98907 | }else |
| 98954 | 98908 | #endif |
| 98955 | 98909 | { |
| 98956 | - bestBtreeIndex(pParse, pWC, pTabItem, mask, pOrderBy, &sCost); | |
| 98910 | + bestBtreeIndex(pParse, pWC, pTabItem, mask, notReady, pOrderBy, | |
| 98911 | + &sCost); | |
| 98957 | 98912 | } |
| 98958 | 98913 | assert( isOptimal || (sCost.used¬Ready)==0 ); |
| 98959 | 98914 | |
| 98960 | 98915 | /* If an INDEXED BY clause is present, then the plan must use that |
| 98961 | 98916 | ** index if it uses any index at all */ |
| 98962 | 98917 |
| --- src/sqlite3.c | |
| +++ src/sqlite3.c | |
| @@ -650,11 +650,11 @@ | |
| 650 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 651 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 652 | */ |
| 653 | #define SQLITE_VERSION "3.7.3" |
| 654 | #define SQLITE_VERSION_NUMBER 3007003 |
| 655 | #define SQLITE_SOURCE_ID "2010-09-29 23:09:23 1ef0dc9328f47506cb2dcd142150e96cb4755216" |
| 656 | |
| 657 | /* |
| 658 | ** CAPI3REF: Run-Time Library Version Numbers |
| 659 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 660 | ** |
| @@ -10570,11 +10570,10 @@ | |
| 10570 | |
| 10571 | /* |
| 10572 | ** Internal function prototypes |
| 10573 | */ |
| 10574 | SQLITE_PRIVATE int sqlite3StrICmp(const char *, const char *); |
| 10575 | SQLITE_PRIVATE int sqlite3IsNumber(const char*, int*, u8); |
| 10576 | SQLITE_PRIVATE int sqlite3Strlen30(const char*); |
| 10577 | #define sqlite3StrNICmp sqlite3_strnicmp |
| 10578 | |
| 10579 | SQLITE_PRIVATE int sqlite3MallocInit(void); |
| 10580 | SQLITE_PRIVATE void sqlite3MallocEnd(void); |
| @@ -10890,13 +10889,12 @@ | |
| 10890 | SQLITE_PRIVATE int sqlite3FixSrcList(DbFixer*, SrcList*); |
| 10891 | SQLITE_PRIVATE int sqlite3FixSelect(DbFixer*, Select*); |
| 10892 | SQLITE_PRIVATE int sqlite3FixExpr(DbFixer*, Expr*); |
| 10893 | SQLITE_PRIVATE int sqlite3FixExprList(DbFixer*, ExprList*); |
| 10894 | SQLITE_PRIVATE int sqlite3FixTriggerStep(DbFixer*, TriggerStep*); |
| 10895 | SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*); |
| 10896 | SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*); |
| 10897 | SQLITE_PRIVATE int sqlite3FitsIn64Bits(const char *, int); |
| 10898 | SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nChar); |
| 10899 | SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *pData, int nByte); |
| 10900 | SQLITE_PRIVATE int sqlite3Utf8Read(const u8*, const u8**); |
| 10901 | |
| 10902 | /* |
| @@ -10938,11 +10936,11 @@ | |
| 10938 | SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(Vdbe *, Index *); |
| 10939 | SQLITE_PRIVATE void sqlite3TableAffinityStr(Vdbe *, Table *); |
| 10940 | SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2); |
| 10941 | SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity); |
| 10942 | SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr); |
| 10943 | SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*); |
| 10944 | SQLITE_PRIVATE void sqlite3Error(sqlite3*, int, const char*,...); |
| 10945 | SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n); |
| 10946 | SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **); |
| 10947 | SQLITE_PRIVATE const char *sqlite3ErrStr(int); |
| 10948 | SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse); |
| @@ -12637,16 +12635,10 @@ | |
| 12637 | end_getDigits: |
| 12638 | va_end(ap); |
| 12639 | return cnt; |
| 12640 | } |
| 12641 | |
| 12642 | /* |
| 12643 | ** Read text from z[] and convert into a floating point number. Return |
| 12644 | ** the number of digits converted. |
| 12645 | */ |
| 12646 | #define getValue sqlite3AtoF |
| 12647 | |
| 12648 | /* |
| 12649 | ** Parse a timezone extension on the end of a date-time. |
| 12650 | ** The extension is of the form: |
| 12651 | ** |
| 12652 | ** (+/-)HH:MM |
| @@ -12844,21 +12836,19 @@ | |
| 12844 | static int parseDateOrTime( |
| 12845 | sqlite3_context *context, |
| 12846 | const char *zDate, |
| 12847 | DateTime *p |
| 12848 | ){ |
| 12849 | int isRealNum; /* Return from sqlite3IsNumber(). Not used */ |
| 12850 | if( parseYyyyMmDd(zDate,p)==0 ){ |
| 12851 | return 0; |
| 12852 | }else if( parseHhMmSs(zDate, p)==0 ){ |
| 12853 | return 0; |
| 12854 | }else if( sqlite3StrICmp(zDate,"now")==0){ |
| 12855 | setDateTimeToCurrent(context, p); |
| 12856 | return 0; |
| 12857 | }else if( sqlite3IsNumber(zDate, &isRealNum, SQLITE_UTF8) ){ |
| 12858 | double r; |
| 12859 | getValue(zDate, &r); |
| 12860 | p->iJD = (sqlite3_int64)(r*86400000.0 + 0.5); |
| 12861 | p->validJD = 1; |
| 12862 | return 0; |
| 12863 | } |
| 12864 | return 1; |
| @@ -13075,12 +13065,13 @@ | |
| 13075 | ** |
| 13076 | ** Move the date to the same time on the next occurrence of |
| 13077 | ** weekday N where 0==Sunday, 1==Monday, and so forth. If the |
| 13078 | ** date is already on the appropriate weekday, this is a no-op. |
| 13079 | */ |
| 13080 | if( strncmp(z, "weekday ", 8)==0 && getValue(&z[8],&r)>0 |
| 13081 | && (n=(int)r)==r && n>=0 && r<7 ){ |
| 13082 | sqlite3_int64 Z; |
| 13083 | computeYMD_HMS(p); |
| 13084 | p->validTZ = 0; |
| 13085 | p->validJD = 0; |
| 13086 | computeJD(p); |
| @@ -13131,12 +13122,15 @@ | |
| 13131 | case '6': |
| 13132 | case '7': |
| 13133 | case '8': |
| 13134 | case '9': { |
| 13135 | double rRounder; |
| 13136 | n = getValue(z, &r); |
| 13137 | assert( n>=1 ); |
| 13138 | if( z[n]==':' ){ |
| 13139 | /* A modifier of the form (+|-)HH:MM:SS.FFF adds (or subtracts) the |
| 13140 | ** specified number of hours, minutes, seconds, and fractional seconds |
| 13141 | ** to the time. The ".FFF" may be omitted. The ":SS.FFF" may be |
| 13142 | ** omitted. |
| @@ -17502,11 +17496,11 @@ | |
| 17502 | sqlite3MemoryAlarm(softHeapLimitEnforcer, 0, n); |
| 17503 | }else{ |
| 17504 | sqlite3MemoryAlarm(0, 0, 0); |
| 17505 | } |
| 17506 | excess = sqlite3_memory_used() - n; |
| 17507 | if( excess>0 ) sqlite3_release_memory(excess & 0x7fffffff); |
| 17508 | return priorLimit; |
| 17509 | } |
| 17510 | SQLITE_API void sqlite3_soft_heap_limit(int n){ |
| 17511 | if( n<0 ) n = 0; |
| 17512 | sqlite3_soft_heap_limit64(n); |
| @@ -20096,125 +20090,115 @@ | |
| 20096 | while( N-- > 0 && *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; } |
| 20097 | return N<0 ? 0 : UpperToLower[*a] - UpperToLower[*b]; |
| 20098 | } |
| 20099 | |
| 20100 | /* |
| 20101 | ** Return TRUE if z is a pure numeric string. Return FALSE and leave |
| 20102 | ** *realnum unchanged if the string contains any character which is not |
| 20103 | ** part of a number. |
| 20104 | ** |
| 20105 | ** If the string is pure numeric, set *realnum to TRUE if the string |
| 20106 | ** contains the '.' character or an "E+000" style exponentiation suffix. |
| 20107 | ** Otherwise set *realnum to FALSE. Note that just becaue *realnum is |
| 20108 | ** false does not mean that the number can be successfully converted into |
| 20109 | ** an integer - it might be too big. |
| 20110 | ** |
| 20111 | ** An empty string is considered non-numeric. |
| 20112 | */ |
| 20113 | SQLITE_PRIVATE int sqlite3IsNumber(const char *z, int *realnum, u8 enc){ |
| 20114 | int incr = (enc==SQLITE_UTF8?1:2); |
| 20115 | if( enc==SQLITE_UTF16BE ) z++; |
| 20116 | if( *z=='-' || *z=='+' ) z += incr; |
| 20117 | if( !sqlite3Isdigit(*z) ){ |
| 20118 | return 0; |
| 20119 | } |
| 20120 | z += incr; |
| 20121 | *realnum = 0; |
| 20122 | while( sqlite3Isdigit(*z) ){ z += incr; } |
| 20123 | #ifndef SQLITE_OMIT_FLOATING_POINT |
| 20124 | if( *z=='.' ){ |
| 20125 | z += incr; |
| 20126 | if( !sqlite3Isdigit(*z) ) return 0; |
| 20127 | while( sqlite3Isdigit(*z) ){ z += incr; } |
| 20128 | *realnum = 1; |
| 20129 | } |
| 20130 | if( *z=='e' || *z=='E' ){ |
| 20131 | z += incr; |
| 20132 | if( *z=='+' || *z=='-' ) z += incr; |
| 20133 | if( !sqlite3Isdigit(*z) ) return 0; |
| 20134 | while( sqlite3Isdigit(*z) ){ z += incr; } |
| 20135 | *realnum = 1; |
| 20136 | } |
| 20137 | #endif |
| 20138 | return *z==0; |
| 20139 | } |
| 20140 | |
| 20141 | /* |
| 20142 | ** The string z[] is an ASCII representation of a real number. |
| 20143 | ** Convert this string to a double. |
| 20144 | ** |
| 20145 | ** This routine assumes that z[] really is a valid number. If it |
| 20146 | ** is not, the result is undefined. |
| 20147 | ** |
| 20148 | ** This routine is used instead of the library atof() function because |
| 20149 | ** the library atof() might want to use "," as the decimal point instead |
| 20150 | ** of "." depending on how locale is set. But that would cause problems |
| 20151 | ** for SQL. So this routine always uses "." regardless of locale. |
| 20152 | */ |
| 20153 | SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult){ |
| 20154 | #ifndef SQLITE_OMIT_FLOATING_POINT |
| 20155 | const char *zBegin = z; |
| 20156 | /* sign * significand * (10 ^ (esign * exponent)) */ |
| 20157 | int sign = 1; /* sign of significand */ |
| 20158 | i64 s = 0; /* significand */ |
| 20159 | int d = 0; /* adjust exponent for shifting decimal point */ |
| 20160 | int esign = 1; /* sign of exponent */ |
| 20161 | int e = 0; /* exponent */ |
| 20162 | double result; |
| 20163 | int nDigits = 0; |
| 20164 | |
| 20165 | /* skip leading spaces */ |
| 20166 | while( sqlite3Isspace(*z) ) z++; |
| 20167 | /* get sign of significand */ |
| 20168 | if( *z=='-' ){ |
| 20169 | sign = -1; |
| 20170 | z++; |
| 20171 | }else if( *z=='+' ){ |
| 20172 | z++; |
| 20173 | } |
| 20174 | /* skip leading zeroes */ |
| 20175 | while( z[0]=='0' ) z++, nDigits++; |
| 20176 | |
| 20177 | /* copy max significant digits to significand */ |
| 20178 | while( sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){ |
| 20179 | s = s*10 + (*z - '0'); |
| 20180 | z++, nDigits++; |
| 20181 | } |
| 20182 | /* skip non-significant significand digits |
| 20183 | ** (increase exponent by d to shift decimal left) */ |
| 20184 | while( sqlite3Isdigit(*z) ) z++, nDigits++, d++; |
| 20185 | |
| 20186 | /* if decimal point is present */ |
| 20187 | if( *z=='.' ){ |
| 20188 | z++; |
| 20189 | /* copy digits from after decimal to significand |
| 20190 | ** (decrease exponent by d to shift decimal right) */ |
| 20191 | while( sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){ |
| 20192 | s = s*10 + (*z - '0'); |
| 20193 | z++, nDigits++, d--; |
| 20194 | } |
| 20195 | /* skip non-significant digits */ |
| 20196 | while( sqlite3Isdigit(*z) ) z++, nDigits++; |
| 20197 | } |
| 20198 | |
| 20199 | /* if exponent is present */ |
| 20200 | if( *z=='e' || *z=='E' ){ |
| 20201 | z++; |
| 20202 | /* get sign of exponent */ |
| 20203 | if( *z=='-' ){ |
| 20204 | esign = -1; |
| 20205 | z++; |
| 20206 | }else if( *z=='+' ){ |
| 20207 | z++; |
| 20208 | } |
| 20209 | /* copy digits to exponent */ |
| 20210 | while( sqlite3Isdigit(*z) ){ |
| 20211 | e = e*10 + (*z - '0'); |
| 20212 | z++; |
| 20213 | } |
| 20214 | } |
| 20215 | |
| 20216 | /* adjust exponent by d, and update sign */ |
| 20217 | e = (e*esign) + d; |
| 20218 | if( e<0 ) { |
| 20219 | esign = -1; |
| 20220 | e *= -1; |
| @@ -20269,132 +20253,104 @@ | |
| 20269 | } |
| 20270 | |
| 20271 | /* store the result */ |
| 20272 | *pResult = result; |
| 20273 | |
| 20274 | /* return number of characters used */ |
| 20275 | return (int)(z - zBegin); |
| 20276 | #else |
| 20277 | return sqlite3Atoi64(z, pResult); |
| 20278 | #endif /* SQLITE_OMIT_FLOATING_POINT */ |
| 20279 | } |
| 20280 | |
| 20281 | /* |
| 20282 | ** Compare the 19-character string zNum against the text representation |
| 20283 | ** value 2^63: 9223372036854775808. Return negative, zero, or positive |
| 20284 | ** if zNum is less than, equal to, or greater than the string. |
| 20285 | ** |
| 20286 | ** Unlike memcmp() this routine is guaranteed to return the difference |
| 20287 | ** in the values of the last digit if the only difference is in the |
| 20288 | ** last digit. So, for example, |
| 20289 | ** |
| 20290 | ** compare2pow63("9223372036854775800") |
| 20291 | ** |
| 20292 | ** will return -8. |
| 20293 | */ |
| 20294 | static int compare2pow63(const char *zNum){ |
| 20295 | int c; |
| 20296 | c = memcmp(zNum,"922337203685477580",18)*10; |
| 20297 | if( c==0 ){ |
| 20298 | c = zNum[18] - '8'; |
| 20299 | testcase( c==(-1) ); |
| 20300 | testcase( c==0 ); |
| 20301 | testcase( c==(+1) ); |
| 20302 | } |
| 20303 | return c; |
| 20304 | } |
| 20305 | |
| 20306 | |
| 20307 | /* |
| 20308 | ** Return TRUE if zNum is a 64-bit signed integer and write |
| 20309 | ** the value of the integer into *pNum. If zNum is not an integer |
| 20310 | ** or is an integer that is too large to be expressed with 64 bits, |
| 20311 | ** then return false. |
| 20312 | ** |
| 20313 | ** When this routine was originally written it dealt with only |
| 20314 | ** 32-bit numbers. At that time, it was much faster than the |
| 20315 | ** atoi() library routine in RedHat 7.2. |
| 20316 | */ |
| 20317 | SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum){ |
| 20318 | i64 v = 0; |
| 20319 | int neg; |
| 20320 | int i, c; |
| 20321 | const char *zStart; |
| 20322 | while( sqlite3Isspace(*zNum) ) zNum++; |
| 20323 | if( *zNum=='-' ){ |
| 20324 | neg = 1; |
| 20325 | zNum++; |
| 20326 | }else if( *zNum=='+' ){ |
| 20327 | neg = 0; |
| 20328 | zNum++; |
| 20329 | }else{ |
| 20330 | neg = 0; |
| 20331 | } |
| 20332 | zStart = zNum; |
| 20333 | while( zNum[0]=='0' ){ zNum++; } /* Skip over leading zeros. Ticket #2454 */ |
| 20334 | for(i=0; (c=zNum[i])>='0' && c<='9'; i++){ |
| 20335 | v = v*10 + c - '0'; |
| 20336 | } |
| 20337 | *pNum = neg ? -v : v; |
| 20338 | testcase( i==18 ); |
| 20339 | testcase( i==19 ); |
| 20340 | testcase( i==20 ); |
| 20341 | if( c!=0 || (i==0 && zStart==zNum) || i>19 ){ |
| 20342 | /* zNum is empty or contains non-numeric text or is longer |
| 20343 | ** than 19 digits (thus guaranting that it is too large) */ |
| 20344 | return 0; |
| 20345 | }else if( i<19 ){ |
| 20346 | /* Less than 19 digits, so we know that it fits in 64 bits */ |
| 20347 | return 1; |
| 20348 | }else{ |
| 20349 | /* 19-digit numbers must be no larger than 9223372036854775807 if positive |
| 20350 | ** or 9223372036854775808 if negative. Note that 9223372036854665808 |
| 20351 | ** is 2^63. */ |
| 20352 | return compare2pow63(zNum)<neg; |
| 20353 | } |
| 20354 | } |
| 20355 | |
| 20356 | /* |
| 20357 | ** The string zNum represents an unsigned integer. The zNum string |
| 20358 | ** consists of one or more digit characters and is terminated by |
| 20359 | ** a zero character. Any stray characters in zNum result in undefined |
| 20360 | ** behavior. |
| 20361 | ** |
| 20362 | ** If the unsigned integer that zNum represents will fit in a |
| 20363 | ** 64-bit signed integer, return TRUE. Otherwise return FALSE. |
| 20364 | ** |
| 20365 | ** If the negFlag parameter is true, that means that zNum really represents |
| 20366 | ** a negative number. (The leading "-" is omitted from zNum.) This |
| 20367 | ** parameter is needed to determine a boundary case. A string |
| 20368 | ** of "9223373036854775808" returns false if negFlag is false or true |
| 20369 | ** if negFlag is true. |
| 20370 | ** |
| 20371 | ** Leading zeros are ignored. |
| 20372 | */ |
| 20373 | SQLITE_PRIVATE int sqlite3FitsIn64Bits(const char *zNum, int negFlag){ |
| 20374 | int i; |
| 20375 | int neg = 0; |
| 20376 | |
| 20377 | assert( zNum[0]>='0' && zNum[0]<='9' ); /* zNum is an unsigned number */ |
| 20378 | |
| 20379 | if( negFlag ) neg = 1-neg; |
| 20380 | while( *zNum=='0' ){ |
| 20381 | zNum++; /* Skip leading zeros. Ticket #2454 */ |
| 20382 | } |
| 20383 | for(i=0; zNum[i]; i++){ assert( zNum[i]>='0' && zNum[i]<='9' ); } |
| 20384 | testcase( i==18 ); |
| 20385 | testcase( i==19 ); |
| 20386 | testcase( i==20 ); |
| 20387 | if( i<19 ){ |
| 20388 | /* Guaranteed to fit if less than 19 digits */ |
| 20389 | return 1; |
| 20390 | }else if( i>19 ){ |
| 20391 | /* Guaranteed to be too big if greater than 19 digits */ |
| 20392 | return 0; |
| 20393 | }else{ |
| 20394 | /* Compare against 2^63. */ |
| 20395 | return compare2pow63(zNum)<neg; |
| 20396 | } |
| 20397 | } |
| 20398 | |
| 20399 | /* |
| 20400 | ** If zNum represents an integer that will fit in 32-bits, then set |
| @@ -54149,17 +54105,13 @@ | |
| 54149 | return pMem->u.i; |
| 54150 | }else if( flags & MEM_Real ){ |
| 54151 | return doubleToInt64(pMem->r); |
| 54152 | }else if( flags & (MEM_Str|MEM_Blob) ){ |
| 54153 | i64 value; |
| 54154 | pMem->flags |= MEM_Str; |
| 54155 | if( sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8) |
| 54156 | || sqlite3VdbeMemNulTerminate(pMem) ){ |
| 54157 | return 0; |
| 54158 | } |
| 54159 | assert( pMem->z ); |
| 54160 | sqlite3Atoi64(pMem->z, &value); |
| 54161 | return value; |
| 54162 | }else{ |
| 54163 | return 0; |
| 54164 | } |
| 54165 | } |
| @@ -54185,11 +54137,11 @@ | |
| 54185 | || sqlite3VdbeMemNulTerminate(pMem) ){ |
| 54186 | /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ |
| 54187 | return (double)0; |
| 54188 | } |
| 54189 | assert( pMem->z ); |
| 54190 | sqlite3AtoF(pMem->z, &val); |
| 54191 | return val; |
| 54192 | }else{ |
| 54193 | /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ |
| 54194 | return (double)0; |
| 54195 | } |
| @@ -54258,25 +54210,23 @@ | |
| 54258 | ** Every effort is made to force the conversion, even if the input |
| 54259 | ** is a string that does not look completely like a number. Convert |
| 54260 | ** as much of the string as we can and ignore the rest. |
| 54261 | */ |
| 54262 | SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){ |
| 54263 | int rc; |
| 54264 | assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 ); |
| 54265 | assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 ); |
| 54266 | assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); |
| 54267 | rc = sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8); |
| 54268 | if( rc ) return rc; |
| 54269 | rc = sqlite3VdbeMemNulTerminate(pMem); |
| 54270 | if( rc ) return rc; |
| 54271 | if( sqlite3Atoi64(pMem->z, &pMem->u.i) ){ |
| 54272 | MemSetTypeFlag(pMem, MEM_Int); |
| 54273 | }else{ |
| 54274 | pMem->r = sqlite3VdbeRealValue(pMem); |
| 54275 | MemSetTypeFlag(pMem, MEM_Real); |
| 54276 | sqlite3VdbeIntegerAffinity(pMem); |
| 54277 | } |
| 54278 | return SQLITE_OK; |
| 54279 | } |
| 54280 | |
| 54281 | /* |
| 54282 | ** Delete any previous value and set the value stored in *pMem to NULL. |
| @@ -54815,10 +54765,12 @@ | |
| 54815 | sqlite3_value **ppVal /* Write the new value here */ |
| 54816 | ){ |
| 54817 | int op; |
| 54818 | char *zVal = 0; |
| 54819 | sqlite3_value *pVal = 0; |
| 54820 | |
| 54821 | if( !pExpr ){ |
| 54822 | *ppVal = 0; |
| 54823 | return SQLITE_OK; |
| 54824 | } |
| @@ -54831,35 +54783,50 @@ | |
| 54831 | #ifdef SQLITE_ENABLE_STAT2 |
| 54832 | if( op==TK_REGISTER ) op = pExpr->op2; |
| 54833 | #else |
| 54834 | if( NEVER(op==TK_REGISTER) ) op = pExpr->op2; |
| 54835 | #endif |
| 54836 | |
| 54837 | if( op==TK_STRING || op==TK_FLOAT || op==TK_INTEGER ){ |
| 54838 | pVal = sqlite3ValueNew(db); |
| 54839 | if( pVal==0 ) goto no_mem; |
| 54840 | if( ExprHasProperty(pExpr, EP_IntValue) ){ |
| 54841 | sqlite3VdbeMemSetInt64(pVal, (i64)pExpr->u.iValue); |
| 54842 | }else{ |
| 54843 | zVal = sqlite3DbStrDup(db, pExpr->u.zToken); |
| 54844 | if( zVal==0 ) goto no_mem; |
| 54845 | sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC); |
| 54846 | if( op==TK_FLOAT ) pVal->type = SQLITE_FLOAT; |
| 54847 | } |
| 54848 | if( (op==TK_INTEGER || op==TK_FLOAT ) && affinity==SQLITE_AFF_NONE ){ |
| 54849 | sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, SQLITE_UTF8); |
| 54850 | }else{ |
| 54851 | sqlite3ValueApplyAffinity(pVal, affinity, SQLITE_UTF8); |
| 54852 | } |
| 54853 | if( enc!=SQLITE_UTF8 ){ |
| 54854 | sqlite3VdbeChangeEncoding(pVal, enc); |
| 54855 | } |
| 54856 | }else if( op==TK_UMINUS ) { |
| 54857 | if( SQLITE_OK==sqlite3ValueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal) ){ |
| 54858 | pVal->u.i = -1 * pVal->u.i; |
| 54859 | /* (double)-1 In case of SQLITE_OMIT_FLOATING_POINT... */ |
| 54860 | pVal->r = (double)-1 * pVal->r; |
| 54861 | } |
| 54862 | } |
| 54863 | #ifndef SQLITE_OMIT_BLOB_LITERAL |
| 54864 | else if( op==TK_BLOB ){ |
| 54865 | int nVal; |
| @@ -59770,35 +59737,21 @@ | |
| 59770 | ** looks like a number, convert it into a number. If it does not |
| 59771 | ** look like a number, leave it alone. |
| 59772 | */ |
| 59773 | static void applyNumericAffinity(Mem *pRec){ |
| 59774 | if( (pRec->flags & (MEM_Real|MEM_Int))==0 ){ |
| 59775 | int realnum; |
| 59776 | u8 enc = pRec->enc; |
| 59777 | sqlite3VdbeMemNulTerminate(pRec); |
| 59778 | if( (pRec->flags&MEM_Str) && sqlite3IsNumber(pRec->z, &realnum, enc) ){ |
| 59779 | i64 value; |
| 59780 | char *zUtf8 = pRec->z; |
| 59781 | #ifndef SQLITE_OMIT_UTF16 |
| 59782 | if( enc!=SQLITE_UTF8 ){ |
| 59783 | assert( pRec->db ); |
| 59784 | zUtf8 = sqlite3Utf16to8(pRec->db, pRec->z, pRec->n, enc); |
| 59785 | if( !zUtf8 ) return; |
| 59786 | } |
| 59787 | #endif |
| 59788 | if( !realnum && sqlite3Atoi64(zUtf8, &value) ){ |
| 59789 | pRec->u.i = value; |
| 59790 | MemSetTypeFlag(pRec, MEM_Int); |
| 59791 | }else{ |
| 59792 | sqlite3AtoF(zUtf8, &pRec->r); |
| 59793 | MemSetTypeFlag(pRec, MEM_Real); |
| 59794 | } |
| 59795 | #ifndef SQLITE_OMIT_UTF16 |
| 59796 | if( enc!=SQLITE_UTF8 ){ |
| 59797 | sqlite3DbFree(pRec->db, zUtf8); |
| 59798 | } |
| 59799 | #endif |
| 59800 | } |
| 59801 | } |
| 59802 | } |
| 59803 | |
| 59804 | /* |
| @@ -61580,11 +61533,10 @@ | |
| 61580 | ** integers, for space efficiency, but after extraction we want them |
| 61581 | ** to have only a real value. |
| 61582 | */ |
| 61583 | case OP_RealAffinity: { /* in1 */ |
| 61584 | pIn1 = &aMem[pOp->p1]; |
| 61585 | memAboutToChange(p, pIn1); |
| 61586 | if( pIn1->flags & MEM_Int ){ |
| 61587 | sqlite3VdbeMemRealify(pIn1); |
| 61588 | } |
| 61589 | break; |
| 61590 | } |
| @@ -61623,11 +61575,10 @@ | |
| 61623 | ** |
| 61624 | ** A NULL value is not changed by this routine. It remains NULL. |
| 61625 | */ |
| 61626 | case OP_ToBlob: { /* same as TK_TO_BLOB, in1 */ |
| 61627 | pIn1 = &aMem[pOp->p1]; |
| 61628 | memAboutToChange(p, pIn1); |
| 61629 | if( pIn1->flags & MEM_Null ) break; |
| 61630 | if( (pIn1->flags & MEM_Blob)==0 ){ |
| 61631 | applyAffinity(pIn1, SQLITE_AFF_TEXT, encoding); |
| 61632 | assert( pIn1->flags & MEM_Str || db->mallocFailed ); |
| 61633 | MemSetTypeFlag(pIn1, MEM_Blob); |
| @@ -61648,14 +61599,11 @@ | |
| 61648 | ** |
| 61649 | ** A NULL value is not changed by this routine. It remains NULL. |
| 61650 | */ |
| 61651 | case OP_ToNumeric: { /* same as TK_TO_NUMERIC, in1 */ |
| 61652 | pIn1 = &aMem[pOp->p1]; |
| 61653 | memAboutToChange(p, pIn1); |
| 61654 | if( (pIn1->flags & (MEM_Null|MEM_Int|MEM_Real))==0 ){ |
| 61655 | sqlite3VdbeMemNumerify(pIn1); |
| 61656 | } |
| 61657 | break; |
| 61658 | } |
| 61659 | #endif /* SQLITE_OMIT_CAST */ |
| 61660 | |
| 61661 | /* Opcode: ToInt P1 * * * * |
| @@ -61667,11 +61615,10 @@ | |
| 61667 | ** |
| 61668 | ** A NULL value is not changed by this routine. It remains NULL. |
| 61669 | */ |
| 61670 | case OP_ToInt: { /* same as TK_TO_INT, in1 */ |
| 61671 | pIn1 = &aMem[pOp->p1]; |
| 61672 | memAboutToChange(p, pIn1); |
| 61673 | if( (pIn1->flags & MEM_Null)==0 ){ |
| 61674 | sqlite3VdbeMemIntegerify(pIn1); |
| 61675 | } |
| 61676 | break; |
| 61677 | } |
| @@ -61781,12 +61728,10 @@ | |
| 61781 | u16 flags3; /* Copy of initial value of pIn3->flags */ |
| 61782 | #endif /* local variables moved into u.ai */ |
| 61783 | |
| 61784 | pIn1 = &aMem[pOp->p1]; |
| 61785 | pIn3 = &aMem[pOp->p3]; |
| 61786 | memAboutToChange(p, pIn1); |
| 61787 | memAboutToChange(p, pIn3); |
| 61788 | u.ai.flags1 = pIn1->flags; |
| 61789 | u.ai.flags3 = pIn3->flags; |
| 61790 | if( (pIn1->flags | pIn3->flags)&MEM_Null ){ |
| 61791 | /* One or both operands are NULL */ |
| 61792 | if( pOp->p5 & SQLITE_NULLEQ ){ |
| @@ -62415,11 +62360,10 @@ | |
| 62415 | assert( u.an.zAffinity[pOp->p2]==0 ); |
| 62416 | pIn1 = &aMem[pOp->p1]; |
| 62417 | while( (u.an.cAff = *(u.an.zAffinity++))!=0 ){ |
| 62418 | assert( pIn1 <= &p->aMem[p->nMem] ); |
| 62419 | assert( memIsValid(pIn1) ); |
| 62420 | memAboutToChange(p, pIn1); |
| 62421 | ExpandBlob(pIn1); |
| 62422 | applyAffinity(pIn1, u.an.cAff, encoding); |
| 62423 | pIn1++; |
| 62424 | } |
| 62425 | break; |
| @@ -62495,11 +62439,10 @@ | |
| 62495 | ** out how much space is required for the new record. |
| 62496 | */ |
| 62497 | for(u.ao.pRec=u.ao.pData0; u.ao.pRec<=u.ao.pLast; u.ao.pRec++){ |
| 62498 | assert( memIsValid(u.ao.pRec) ); |
| 62499 | if( u.ao.zAffinity ){ |
| 62500 | memAboutToChange(p, u.ao.pRec); |
| 62501 | applyAffinity(u.ao.pRec, u.ao.zAffinity[u.ao.pRec-u.ao.pData0], encoding); |
| 62502 | } |
| 62503 | if( u.ao.pRec->flags&MEM_Zero && u.ao.pRec->n>0 ){ |
| 62504 | sqlite3VdbeMemExpandBlob(u.ao.pRec); |
| 62505 | } |
| @@ -68880,11 +68823,11 @@ | |
| 68880 | pExpr->iColumn = (ynVar)(++pParse->nVar); |
| 68881 | }else if( z[0]=='?' ){ |
| 68882 | /* Wildcard of the form "?nnn". Convert "nnn" to an integer and |
| 68883 | ** use it as the variable number */ |
| 68884 | i64 i; |
| 68885 | int bOk = sqlite3Atoi64(&z[1], &i); |
| 68886 | pExpr->iColumn = (ynVar)i; |
| 68887 | testcase( i==0 ); |
| 68888 | testcase( i==1 ); |
| 68889 | testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]-1 ); |
| 68890 | testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ); |
| @@ -70243,11 +70186,11 @@ | |
| 70243 | */ |
| 70244 | static void codeReal(Vdbe *v, const char *z, int negateFlag, int iMem){ |
| 70245 | if( ALWAYS(z!=0) ){ |
| 70246 | double value; |
| 70247 | char *zV; |
| 70248 | sqlite3AtoF(z, &value); |
| 70249 | assert( !sqlite3IsNaN(value) ); /* The new AtoF never returns NaN */ |
| 70250 | if( negateFlag ) value = -value; |
| 70251 | zV = dup8bytes(v, (char*)&value); |
| 70252 | sqlite3VdbeAddOp4(v, OP_Real, 0, iMem, 0, zV, P4_REAL); |
| 70253 | } |
| @@ -70257,28 +70200,27 @@ | |
| 70257 | |
| 70258 | /* |
| 70259 | ** Generate an instruction that will put the integer describe by |
| 70260 | ** text z[0..n-1] into register iMem. |
| 70261 | ** |
| 70262 | ** The z[] string will probably not be zero-terminated. But the |
| 70263 | ** z[n] character is guaranteed to be something that does not look |
| 70264 | ** like the continuation of the number. |
| 70265 | */ |
| 70266 | static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){ |
| 70267 | Vdbe *v = pParse->pVdbe; |
| 70268 | if( pExpr->flags & EP_IntValue ){ |
| 70269 | int i = pExpr->u.iValue; |
| 70270 | if( negFlag ) i = -i; |
| 70271 | sqlite3VdbeAddOp2(v, OP_Integer, i, iMem); |
| 70272 | }else{ |
| 70273 | const char *z = pExpr->u.zToken; |
| 70274 | assert( z!=0 ); |
| 70275 | if( sqlite3FitsIn64Bits(z, negFlag) ){ |
| 70276 | i64 value; |
| 70277 | char *zV; |
| 70278 | sqlite3Atoi64(z, &value); |
| 70279 | if( negFlag ) value = -value; |
| 70280 | zV = dup8bytes(v, (char*)&value); |
| 70281 | sqlite3VdbeAddOp4(v, OP_Int64, 0, iMem, 0, zV, P4_INT64); |
| 70282 | }else{ |
| 70283 | #ifdef SQLITE_OMIT_FLOATING_POINT |
| 70284 | sqlite3ErrorMsg(pParse, "oversized integer: %s%s", negFlag ? "-" : "", z); |
| @@ -79414,11 +79356,11 @@ | |
| 79414 | zBuf = sqlite3_mprintf("%.*f",n,r); |
| 79415 | if( zBuf==0 ){ |
| 79416 | sqlite3_result_error_nomem(context); |
| 79417 | return; |
| 79418 | } |
| 79419 | sqlite3AtoF(zBuf, &r); |
| 79420 | sqlite3_free(zBuf); |
| 79421 | } |
| 79422 | sqlite3_result_double(context, r); |
| 79423 | } |
| 79424 | #endif |
| @@ -85472,11 +85414,11 @@ | |
| 85472 | */ |
| 85473 | if( sqlite3StrICmp(zLeft,"journal_size_limit")==0 ){ |
| 85474 | Pager *pPager = sqlite3BtreePager(pDb->pBt); |
| 85475 | i64 iLimit = -2; |
| 85476 | if( zRight ){ |
| 85477 | sqlite3Atoi64(zRight, &iLimit); |
| 85478 | if( iLimit<-1 ) iLimit = -1; |
| 85479 | } |
| 85480 | iLimit = sqlite3PagerJournalSizeLimit(pPager, iLimit); |
| 85481 | returnSingleInt(pParse, "journal_size_limit", iLimit); |
| 85482 | }else |
| @@ -96380,11 +96322,12 @@ | |
| 96380 | |
| 96381 | /* |
| 96382 | ** Required because bestIndex() is called by bestOrClauseIndex() |
| 96383 | */ |
| 96384 | static void bestIndex( |
| 96385 | Parse*, WhereClause*, struct SrcList_item*, Bitmask, ExprList*, WhereCost*); |
| 96386 | |
| 96387 | /* |
| 96388 | ** This routine attempts to find an scanning strategy that can be used |
| 96389 | ** to optimize an 'OR' expression that is part of a WHERE clause. |
| 96390 | ** |
| @@ -96393,11 +96336,12 @@ | |
| 96393 | */ |
| 96394 | static void bestOrClauseIndex( |
| 96395 | Parse *pParse, /* The parsing context */ |
| 96396 | WhereClause *pWC, /* The WHERE clause */ |
| 96397 | struct SrcList_item *pSrc, /* The FROM clause term to search */ |
| 96398 | Bitmask notReady, /* Mask of cursors that are not available */ |
| 96399 | ExprList *pOrderBy, /* The ORDER BY clause */ |
| 96400 | WhereCost *pCost /* Lowest cost query plan */ |
| 96401 | ){ |
| 96402 | #ifndef SQLITE_OMIT_OR_OPTIMIZATION |
| 96403 | const int iCur = pSrc->iCursor; /* The cursor of the table to be accessed */ |
| @@ -96429,19 +96373,19 @@ | |
| 96429 | WHERETRACE(("... Multi-index OR testing for term %d of %d....\n", |
| 96430 | (pOrTerm - pOrWC->a), (pTerm - pWC->a) |
| 96431 | )); |
| 96432 | if( pOrTerm->eOperator==WO_AND ){ |
| 96433 | WhereClause *pAndWC = &pOrTerm->u.pAndInfo->wc; |
| 96434 | bestIndex(pParse, pAndWC, pSrc, notReady, 0, &sTermCost); |
| 96435 | }else if( pOrTerm->leftCursor==iCur ){ |
| 96436 | WhereClause tempWC; |
| 96437 | tempWC.pParse = pWC->pParse; |
| 96438 | tempWC.pMaskSet = pWC->pMaskSet; |
| 96439 | tempWC.op = TK_AND; |
| 96440 | tempWC.a = pOrTerm; |
| 96441 | tempWC.nTerm = 1; |
| 96442 | bestIndex(pParse, &tempWC, pSrc, notReady, 0, &sTermCost); |
| 96443 | }else{ |
| 96444 | continue; |
| 96445 | } |
| 96446 | rTotal += sTermCost.rCost; |
| 96447 | nRow += sTermCost.nRow; |
| @@ -96884,11 +96828,12 @@ | |
| 96884 | */ |
| 96885 | static void bestVirtualIndex( |
| 96886 | Parse *pParse, /* The parsing context */ |
| 96887 | WhereClause *pWC, /* The WHERE clause */ |
| 96888 | struct SrcList_item *pSrc, /* The FROM clause term to search */ |
| 96889 | Bitmask notReady, /* Mask of cursors that are not available */ |
| 96890 | ExprList *pOrderBy, /* The order by clause */ |
| 96891 | WhereCost *pCost, /* Lowest cost query plan */ |
| 96892 | sqlite3_index_info **ppIdxInfo /* Index information passed to xBestIndex */ |
| 96893 | ){ |
| 96894 | Table *pTab = pSrc->pTab; |
| @@ -97014,11 +96959,11 @@ | |
| 97014 | pIdxInfo->nOrderBy = nOrderBy; |
| 97015 | |
| 97016 | /* Try to find a more efficient access pattern by using multiple indexes |
| 97017 | ** to optimize an OR expression within the WHERE clause. |
| 97018 | */ |
| 97019 | bestOrClauseIndex(pParse, pWC, pSrc, notReady, pOrderBy, pCost); |
| 97020 | } |
| 97021 | #endif /* SQLITE_OMIT_VIRTUALTABLE */ |
| 97022 | |
| 97023 | /* |
| 97024 | ** Argument pIdx is a pointer to an index structure that has an array of |
| @@ -97295,11 +97240,12 @@ | |
| 97295 | */ |
| 97296 | static void bestBtreeIndex( |
| 97297 | Parse *pParse, /* The parsing context */ |
| 97298 | WhereClause *pWC, /* The WHERE clause */ |
| 97299 | struct SrcList_item *pSrc, /* The FROM clause term to search */ |
| 97300 | Bitmask notReady, /* Mask of cursors that are not available */ |
| 97301 | ExprList *pOrderBy, /* The ORDER BY clause */ |
| 97302 | WhereCost *pCost /* Lowest cost query plan */ |
| 97303 | ){ |
| 97304 | int iCur = pSrc->iCursor; /* The cursor of the table to be accessed */ |
| 97305 | Index *pProbe; /* An index we are evaluating */ |
| @@ -97557,29 +97503,29 @@ | |
| 97557 | ** of output rows, adjust the nRow value accordingly. This only |
| 97558 | ** matters if the current index is the least costly, so do not bother |
| 97559 | ** with this step if we already know this index will not be chosen. |
| 97560 | ** Also, never reduce the output row count below 2 using this step. |
| 97561 | ** |
| 97562 | ** Do not reduce the output row count if pSrc is the only table that |
| 97563 | ** is notReady; if notReady is a power of two. This will be the case |
| 97564 | ** when the main sqlite3WhereBegin() loop is scanning for a table with |
| 97565 | ** and "optimal" index, and on such a scan the output row count |
| 97566 | ** reduction is not valid because it does not update the "pCost->used" |
| 97567 | ** bitmap. The notReady bitmap will also be a power of two when we |
| 97568 | ** are scanning for the last table in a 64-way join. We are willing |
| 97569 | ** to bypass this optimization in that corner case. |
| 97570 | */ |
| 97571 | if( nRow>2 && cost<=pCost->rCost && (notReady & (notReady-1))!=0 ){ |
| 97572 | int k; /* Loop counter */ |
| 97573 | int nSkipEq = nEq; /* Number of == constraints to skip */ |
| 97574 | int nSkipRange = nBound; /* Number of < constraints to skip */ |
| 97575 | Bitmask thisTab; /* Bitmap for pSrc */ |
| 97576 | |
| 97577 | thisTab = getMask(pWC->pMaskSet, iCur); |
| 97578 | for(pTerm=pWC->a, k=pWC->nTerm; nRow>2 && k; k--, pTerm++){ |
| 97579 | if( pTerm->wtFlags & TERM_VIRTUAL ) continue; |
| 97580 | if( (pTerm->prereqAll & notReady)!=thisTab ) continue; |
| 97581 | if( pTerm->eOperator & (WO_EQ|WO_IN|WO_ISNULL) ){ |
| 97582 | if( nSkipEq ){ |
| 97583 | /* Ignore the first nEq equality matches since the index |
| 97584 | ** has already accounted for these */ |
| 97585 | nSkipEq--; |
| @@ -97657,11 +97603,11 @@ | |
| 97657 | WHERETRACE(("best index is: %s\n", |
| 97658 | ((pCost->plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ? "none" : |
| 97659 | pCost->plan.u.pIdx ? pCost->plan.u.pIdx->zName : "ipk") |
| 97660 | )); |
| 97661 | |
| 97662 | bestOrClauseIndex(pParse, pWC, pSrc, notReady, pOrderBy, pCost); |
| 97663 | bestAutomaticIndex(pParse, pWC, pSrc, notReady, pCost); |
| 97664 | pCost->plan.wsFlags |= eqTermMask; |
| 97665 | } |
| 97666 | |
| 97667 | /* |
| @@ -97672,26 +97618,27 @@ | |
| 97672 | */ |
| 97673 | static void bestIndex( |
| 97674 | Parse *pParse, /* The parsing context */ |
| 97675 | WhereClause *pWC, /* The WHERE clause */ |
| 97676 | struct SrcList_item *pSrc, /* The FROM clause term to search */ |
| 97677 | Bitmask notReady, /* Mask of cursors that are not available */ |
| 97678 | ExprList *pOrderBy, /* The ORDER BY clause */ |
| 97679 | WhereCost *pCost /* Lowest cost query plan */ |
| 97680 | ){ |
| 97681 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| 97682 | if( IsVirtual(pSrc->pTab) ){ |
| 97683 | sqlite3_index_info *p = 0; |
| 97684 | bestVirtualIndex(pParse, pWC, pSrc, notReady, pOrderBy, pCost, &p); |
| 97685 | if( p->needToFreeIdxStr ){ |
| 97686 | sqlite3_free(p->idxStr); |
| 97687 | } |
| 97688 | sqlite3DbFree(pParse->db, p); |
| 97689 | }else |
| 97690 | #endif |
| 97691 | { |
| 97692 | bestBtreeIndex(pParse, pWC, pSrc, notReady, pOrderBy, pCost); |
| 97693 | } |
| 97694 | } |
| 97695 | |
| 97696 | /* |
| 97697 | ** Disable a term in the WHERE clause. Except, do not disable the term |
| @@ -98902,14 +98849,20 @@ | |
| 98902 | ** by waiting for other tables to run first. This "optimal" test works |
| 98903 | ** by first assuming that the FROM clause is on the inner loop and finding |
| 98904 | ** its query plan, then checking to see if that query plan uses any |
| 98905 | ** other FROM clause terms that are notReady. If no notReady terms are |
| 98906 | ** used then the "optimal" query plan works. |
| 98907 | ** |
| 98908 | ** The second loop iteration is only performed if no optimal scan |
| 98909 | ** strategies were found by the first loop. This 2nd iteration is used to |
| 98910 | ** search for the lowest cost scan overall. |
| 98911 | ** |
| 98912 | ** Previous versions of SQLite performed only the second iteration - |
| 98913 | ** the next outermost loop was always that with the lowest overall |
| 98914 | ** cost. However, this meant that SQLite could select the wrong plan |
| 98915 | ** for scripts such as the following: |
| @@ -98925,11 +98878,11 @@ | |
| 98925 | ** algorithm may choose to use t2 for the outer loop, which is a much |
| 98926 | ** costlier approach. |
| 98927 | */ |
| 98928 | nUnconstrained = 0; |
| 98929 | notIndexed = 0; |
| 98930 | for(isOptimal=(iFrom<nTabList-1); isOptimal>=0; isOptimal--){ |
| 98931 | Bitmask mask; /* Mask of tables not yet ready */ |
| 98932 | for(j=iFrom, pTabItem=&pTabList->a[j]; j<nTabList; j++, pTabItem++){ |
| 98933 | int doNotReorder; /* True if this table should not be reordered */ |
| 98934 | WhereCost sCost; /* Cost information from best[Virtual]Index() */ |
| 98935 | ExprList *pOrderBy; /* ORDER BY clause for index to optimize */ |
| @@ -98947,15 +98900,17 @@ | |
| 98947 | |
| 98948 | assert( pTabItem->pTab ); |
| 98949 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| 98950 | if( IsVirtual(pTabItem->pTab) ){ |
| 98951 | sqlite3_index_info **pp = &pWInfo->a[j].pIdxInfo; |
| 98952 | bestVirtualIndex(pParse, pWC, pTabItem, mask, pOrderBy, &sCost, pp); |
| 98953 | }else |
| 98954 | #endif |
| 98955 | { |
| 98956 | bestBtreeIndex(pParse, pWC, pTabItem, mask, pOrderBy, &sCost); |
| 98957 | } |
| 98958 | assert( isOptimal || (sCost.used¬Ready)==0 ); |
| 98959 | |
| 98960 | /* If an INDEXED BY clause is present, then the plan must use that |
| 98961 | ** index if it uses any index at all */ |
| 98962 |
| --- src/sqlite3.c | |
| +++ src/sqlite3.c | |
| @@ -650,11 +650,11 @@ | |
| 650 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 651 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 652 | */ |
| 653 | #define SQLITE_VERSION "3.7.3" |
| 654 | #define SQLITE_VERSION_NUMBER 3007003 |
| 655 | #define SQLITE_SOURCE_ID "2010-10-04 23:55:51 ece641eb8951c6314cedbdb3243f91cb199c3239" |
| 656 | |
| 657 | /* |
| 658 | ** CAPI3REF: Run-Time Library Version Numbers |
| 659 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 660 | ** |
| @@ -10570,11 +10570,10 @@ | |
| 10570 | |
| 10571 | /* |
| 10572 | ** Internal function prototypes |
| 10573 | */ |
| 10574 | SQLITE_PRIVATE int sqlite3StrICmp(const char *, const char *); |
| 10575 | SQLITE_PRIVATE int sqlite3Strlen30(const char*); |
| 10576 | #define sqlite3StrNICmp sqlite3_strnicmp |
| 10577 | |
| 10578 | SQLITE_PRIVATE int sqlite3MallocInit(void); |
| 10579 | SQLITE_PRIVATE void sqlite3MallocEnd(void); |
| @@ -10890,13 +10889,12 @@ | |
| 10889 | SQLITE_PRIVATE int sqlite3FixSrcList(DbFixer*, SrcList*); |
| 10890 | SQLITE_PRIVATE int sqlite3FixSelect(DbFixer*, Select*); |
| 10891 | SQLITE_PRIVATE int sqlite3FixExpr(DbFixer*, Expr*); |
| 10892 | SQLITE_PRIVATE int sqlite3FixExprList(DbFixer*, ExprList*); |
| 10893 | SQLITE_PRIVATE int sqlite3FixTriggerStep(DbFixer*, TriggerStep*); |
| 10894 | SQLITE_PRIVATE int sqlite3AtoF(const char *z, double*, int, u8); |
| 10895 | SQLITE_PRIVATE int sqlite3GetInt32(const char *, int*); |
| 10896 | SQLITE_PRIVATE int sqlite3Utf16ByteLen(const void *pData, int nChar); |
| 10897 | SQLITE_PRIVATE int sqlite3Utf8CharLen(const char *pData, int nByte); |
| 10898 | SQLITE_PRIVATE int sqlite3Utf8Read(const u8*, const u8**); |
| 10899 | |
| 10900 | /* |
| @@ -10938,11 +10936,11 @@ | |
| 10936 | SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(Vdbe *, Index *); |
| 10937 | SQLITE_PRIVATE void sqlite3TableAffinityStr(Vdbe *, Table *); |
| 10938 | SQLITE_PRIVATE char sqlite3CompareAffinity(Expr *pExpr, char aff2); |
| 10939 | SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity); |
| 10940 | SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr); |
| 10941 | SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*, int, u8); |
| 10942 | SQLITE_PRIVATE void sqlite3Error(sqlite3*, int, const char*,...); |
| 10943 | SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n); |
| 10944 | SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **); |
| 10945 | SQLITE_PRIVATE const char *sqlite3ErrStr(int); |
| 10946 | SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse); |
| @@ -12637,16 +12635,10 @@ | |
| 12635 | end_getDigits: |
| 12636 | va_end(ap); |
| 12637 | return cnt; |
| 12638 | } |
| 12639 | |
| 12640 | /* |
| 12641 | ** Parse a timezone extension on the end of a date-time. |
| 12642 | ** The extension is of the form: |
| 12643 | ** |
| 12644 | ** (+/-)HH:MM |
| @@ -12844,21 +12836,19 @@ | |
| 12836 | static int parseDateOrTime( |
| 12837 | sqlite3_context *context, |
| 12838 | const char *zDate, |
| 12839 | DateTime *p |
| 12840 | ){ |
| 12841 | double r; |
| 12842 | if( parseYyyyMmDd(zDate,p)==0 ){ |
| 12843 | return 0; |
| 12844 | }else if( parseHhMmSs(zDate, p)==0 ){ |
| 12845 | return 0; |
| 12846 | }else if( sqlite3StrICmp(zDate,"now")==0){ |
| 12847 | setDateTimeToCurrent(context, p); |
| 12848 | return 0; |
| 12849 | }else if( sqlite3AtoF(zDate, &r, sqlite3Strlen30(zDate), SQLITE_UTF8) ){ |
| 12850 | p->iJD = (sqlite3_int64)(r*86400000.0 + 0.5); |
| 12851 | p->validJD = 1; |
| 12852 | return 0; |
| 12853 | } |
| 12854 | return 1; |
| @@ -13075,12 +13065,13 @@ | |
| 13065 | ** |
| 13066 | ** Move the date to the same time on the next occurrence of |
| 13067 | ** weekday N where 0==Sunday, 1==Monday, and so forth. If the |
| 13068 | ** date is already on the appropriate weekday, this is a no-op. |
| 13069 | */ |
| 13070 | if( strncmp(z, "weekday ", 8)==0 |
| 13071 | && sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8) |
| 13072 | && (n=(int)r)==r && n>=0 && r<7 ){ |
| 13073 | sqlite3_int64 Z; |
| 13074 | computeYMD_HMS(p); |
| 13075 | p->validTZ = 0; |
| 13076 | p->validJD = 0; |
| 13077 | computeJD(p); |
| @@ -13131,12 +13122,15 @@ | |
| 13122 | case '6': |
| 13123 | case '7': |
| 13124 | case '8': |
| 13125 | case '9': { |
| 13126 | double rRounder; |
| 13127 | for(n=1; z[n] && z[n]!=':' && !sqlite3Isspace(z[n]); n++){} |
| 13128 | if( !sqlite3AtoF(z, &r, n, SQLITE_UTF8) ){ |
| 13129 | rc = 1; |
| 13130 | break; |
| 13131 | } |
| 13132 | if( z[n]==':' ){ |
| 13133 | /* A modifier of the form (+|-)HH:MM:SS.FFF adds (or subtracts) the |
| 13134 | ** specified number of hours, minutes, seconds, and fractional seconds |
| 13135 | ** to the time. The ".FFF" may be omitted. The ":SS.FFF" may be |
| 13136 | ** omitted. |
| @@ -17502,11 +17496,11 @@ | |
| 17496 | sqlite3MemoryAlarm(softHeapLimitEnforcer, 0, n); |
| 17497 | }else{ |
| 17498 | sqlite3MemoryAlarm(0, 0, 0); |
| 17499 | } |
| 17500 | excess = sqlite3_memory_used() - n; |
| 17501 | if( excess>0 ) sqlite3_release_memory((int)(excess & 0x7fffffff)); |
| 17502 | return priorLimit; |
| 17503 | } |
| 17504 | SQLITE_API void sqlite3_soft_heap_limit(int n){ |
| 17505 | if( n<0 ) n = 0; |
| 17506 | sqlite3_soft_heap_limit64(n); |
| @@ -20096,125 +20090,115 @@ | |
| 20090 | while( N-- > 0 && *a!=0 && UpperToLower[*a]==UpperToLower[*b]){ a++; b++; } |
| 20091 | return N<0 ? 0 : UpperToLower[*a] - UpperToLower[*b]; |
| 20092 | } |
| 20093 | |
| 20094 | /* |
| 20095 | ** The string z[] is an text representation of a real number. |
| 20096 | ** Convert this string to a double and write it into *pResult. |
| 20097 | ** |
| 20098 | ** The string z[] is length bytes in length (bytes, not characters) and |
| 20099 | ** uses the encoding enc. The string is not necessarily zero-terminated. |
| 20100 | ** |
| 20101 | ** Return TRUE if the result is a valid real number (or integer) and FALSE |
| 20102 | ** if the string is empty or contains extraneous text. Valid numbers |
| 20103 | ** are in one of these formats: |
| 20104 | ** |
| 20105 | ** [+-]digits[E[+-]digits] |
| 20106 | ** [+-]digits.[digits][E[+-]digits] |
| 20107 | ** [+-].digits[E[+-]digits] |
| 20108 | ** |
| 20109 | ** Leading and trailing whitespace is ignored for the purpose of determining |
| 20110 | ** validity. |
| 20111 | ** |
| 20112 | ** If some prefix of the input string is a valid number, this routine |
| 20113 | ** returns FALSE but it still converts the prefix and writes the result |
| 20114 | ** into *pResult. |
| 20115 | */ |
| 20116 | SQLITE_PRIVATE int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){ |
| 20117 | #ifndef SQLITE_OMIT_FLOATING_POINT |
| 20118 | int incr = (enc==SQLITE_UTF8?1:2); |
| 20119 | const char *zEnd = z + length; |
| 20120 | /* sign * significand * (10 ^ (esign * exponent)) */ |
| 20121 | int sign = 1; /* sign of significand */ |
| 20122 | i64 s = 0; /* significand */ |
| 20123 | int d = 0; /* adjust exponent for shifting decimal point */ |
| 20124 | int esign = 1; /* sign of exponent */ |
| 20125 | int e = 0; /* exponent */ |
| 20126 | int eValid = 1; /* True exponent is either not used or is well-formed */ |
| 20127 | double result; |
| 20128 | int nDigits = 0; |
| 20129 | |
| 20130 | *pResult = 0.0; /* Default return value, in case of an error */ |
| 20131 | |
| 20132 | if( enc==SQLITE_UTF16BE ) z++; |
| 20133 | |
| 20134 | /* skip leading spaces */ |
| 20135 | while( z<zEnd && sqlite3Isspace(*z) ) z+=incr; |
| 20136 | if( z>=zEnd ) return 0; |
| 20137 | |
| 20138 | /* get sign of significand */ |
| 20139 | if( *z=='-' ){ |
| 20140 | sign = -1; |
| 20141 | z+=incr; |
| 20142 | }else if( *z=='+' ){ |
| 20143 | z+=incr; |
| 20144 | } |
| 20145 | |
| 20146 | /* skip leading zeroes */ |
| 20147 | while( z<zEnd && z[0]=='0' ) z+=incr, nDigits++; |
| 20148 | |
| 20149 | /* copy max significant digits to significand */ |
| 20150 | while( z<zEnd && sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){ |
| 20151 | s = s*10 + (*z - '0'); |
| 20152 | z+=incr, nDigits++; |
| 20153 | } |
| 20154 | |
| 20155 | /* skip non-significant significand digits |
| 20156 | ** (increase exponent by d to shift decimal left) */ |
| 20157 | while( z<zEnd && sqlite3Isdigit(*z) ) z+=incr, nDigits++, d++; |
| 20158 | if( z>=zEnd ) goto do_atof_calc; |
| 20159 | |
| 20160 | /* if decimal point is present */ |
| 20161 | if( *z=='.' ){ |
| 20162 | z+=incr; |
| 20163 | /* copy digits from after decimal to significand |
| 20164 | ** (decrease exponent by d to shift decimal right) */ |
| 20165 | while( z<zEnd && sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){ |
| 20166 | s = s*10 + (*z - '0'); |
| 20167 | z+=incr, nDigits++, d--; |
| 20168 | } |
| 20169 | /* skip non-significant digits */ |
| 20170 | while( z<zEnd && sqlite3Isdigit(*z) ) z+=incr, nDigits++; |
| 20171 | } |
| 20172 | if( z>=zEnd ) goto do_atof_calc; |
| 20173 | |
| 20174 | /* if exponent is present */ |
| 20175 | if( *z=='e' || *z=='E' ){ |
| 20176 | z+=incr; |
| 20177 | eValid = 0; |
| 20178 | if( z>=zEnd ) goto do_atof_calc; |
| 20179 | /* get sign of exponent */ |
| 20180 | if( *z=='-' ){ |
| 20181 | esign = -1; |
| 20182 | z+=incr; |
| 20183 | }else if( *z=='+' ){ |
| 20184 | z+=incr; |
| 20185 | } |
| 20186 | /* copy digits to exponent */ |
| 20187 | while( z<zEnd && sqlite3Isdigit(*z) ){ |
| 20188 | e = e*10 + (*z - '0'); |
| 20189 | z+=incr; |
| 20190 | eValid = 1; |
| 20191 | } |
| 20192 | } |
| 20193 | |
| 20194 | /* skip trailing spaces */ |
| 20195 | if( nDigits && eValid ){ |
| 20196 | while( z<zEnd && sqlite3Isspace(*z) ) z+=incr; |
| 20197 | } |
| 20198 | |
| 20199 | do_atof_calc: |
| 20200 | /* adjust exponent by d, and update sign */ |
| 20201 | e = (e*esign) + d; |
| 20202 | if( e<0 ) { |
| 20203 | esign = -1; |
| 20204 | e *= -1; |
| @@ -20269,132 +20253,104 @@ | |
| 20253 | } |
| 20254 | |
| 20255 | /* store the result */ |
| 20256 | *pResult = result; |
| 20257 | |
| 20258 | /* return true if number and no extra non-whitespace chracters after */ |
| 20259 | return z>=zEnd && nDigits>0 && eValid; |
| 20260 | #else |
| 20261 | return !sqlite3Atoi64(z, pResult, length, enc); |
| 20262 | #endif /* SQLITE_OMIT_FLOATING_POINT */ |
| 20263 | } |
| 20264 | |
| 20265 | /* |
| 20266 | ** Compare the 19-character string zNum against the text representation |
| 20267 | ** value 2^63: 9223372036854775808. Return negative, zero, or positive |
| 20268 | ** if zNum is less than, equal to, or greater than the string. |
| 20269 | ** Note that zNum must contain exactly 19 characters. |
| 20270 | ** |
| 20271 | ** Unlike memcmp() this routine is guaranteed to return the difference |
| 20272 | ** in the values of the last digit if the only difference is in the |
| 20273 | ** last digit. So, for example, |
| 20274 | ** |
| 20275 | ** compare2pow63("9223372036854775800", 1) |
| 20276 | ** |
| 20277 | ** will return -8. |
| 20278 | */ |
| 20279 | static int compare2pow63(const char *zNum, int incr){ |
| 20280 | int c = 0; |
| 20281 | int i; |
| 20282 | /* 012345678901234567 */ |
| 20283 | const char *pow63 = "922337203685477580"; |
| 20284 | for(i=0; c==0 && i<18; i++){ |
| 20285 | c = (zNum[i*incr]-pow63[i])*10; |
| 20286 | } |
| 20287 | if( c==0 ){ |
| 20288 | c = zNum[18*incr] - '8'; |
| 20289 | testcase( c==(-1) ); |
| 20290 | testcase( c==0 ); |
| 20291 | testcase( c==(+1) ); |
| 20292 | } |
| 20293 | return c; |
| 20294 | } |
| 20295 | |
| 20296 | |
| 20297 | /* |
| 20298 | ** Convert zNum to a 64-bit signed integer and write |
| 20299 | ** the value of the integer into *pNum. |
| 20300 | ** If zNum is exactly 9223372036854665808, return 2. |
| 20301 | ** This is a special case as the context will determine |
| 20302 | ** if it is too big (used as a negative). |
| 20303 | ** If zNum is not an integer or is an integer that |
| 20304 | ** is too large to be expressed with 64 bits, |
| 20305 | ** then return 1. Otherwise return 0. |
| 20306 | ** |
| 20307 | ** length is the number of bytes in the string (bytes, not characters). |
| 20308 | ** The string is not necessarily zero-terminated. The encoding is |
| 20309 | ** given by enc. |
| 20310 | */ |
| 20311 | SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){ |
| 20312 | int incr = (enc==SQLITE_UTF8?1:2); |
| 20313 | i64 v = 0; |
| 20314 | int neg = 0; /* assume positive */ |
| 20315 | int i; |
| 20316 | int c = 0; |
| 20317 | const char *zStart; |
| 20318 | const char *zEnd = zNum + length; |
| 20319 | if( enc==SQLITE_UTF16BE ) zNum++; |
| 20320 | while( zNum<zEnd && sqlite3Isspace(*zNum) ) zNum+=incr; |
| 20321 | if( zNum>=zEnd ) goto do_atoi_calc; |
| 20322 | if( *zNum=='-' ){ |
| 20323 | neg = 1; |
| 20324 | zNum+=incr; |
| 20325 | }else if( *zNum=='+' ){ |
| 20326 | zNum+=incr; |
| 20327 | } |
| 20328 | do_atoi_calc: |
| 20329 | zStart = zNum; |
| 20330 | while( zNum<zEnd && zNum[0]=='0' ){ zNum+=incr; } /* Skip leading zeros. */ |
| 20331 | for(i=0; &zNum[i]<zEnd && (c=zNum[i])>='0' && c<='9'; i+=incr){ |
| 20332 | v = v*10 + c - '0'; |
| 20333 | } |
| 20334 | *pNum = neg ? -v : v; |
| 20335 | testcase( i==18 ); |
| 20336 | testcase( i==19 ); |
| 20337 | testcase( i==20 ); |
| 20338 | if( (c!=0 && &zNum[i]<zEnd) || (i==0 && zStart==zNum) || i>19*incr ){ |
| 20339 | /* zNum is empty or contains non-numeric text or is longer |
| 20340 | ** than 19 digits (thus guaranteeing that it is too large) */ |
| 20341 | return 1; |
| 20342 | }else if( i<19*incr ){ |
| 20343 | /* Less than 19 digits, so we know that it fits in 64 bits */ |
| 20344 | return 0; |
| 20345 | }else{ |
| 20346 | /* 19-digit numbers must be no larger than 9223372036854775807 if positive |
| 20347 | ** or 9223372036854775808 if negative. Note that 9223372036854665808 |
| 20348 | ** is 2^63. Return 1 if to large */ |
| 20349 | c=compare2pow63(zNum, incr); |
| 20350 | if( c==0 && neg==0 ) return 2; /* too big, exactly 9223372036854665808 */ |
| 20351 | return c<neg ? 0 : 1; |
| 20352 | } |
| 20353 | } |
| 20354 | |
| 20355 | /* |
| 20356 | ** If zNum represents an integer that will fit in 32-bits, then set |
| @@ -54149,17 +54105,13 @@ | |
| 54105 | return pMem->u.i; |
| 54106 | }else if( flags & MEM_Real ){ |
| 54107 | return doubleToInt64(pMem->r); |
| 54108 | }else if( flags & (MEM_Str|MEM_Blob) ){ |
| 54109 | i64 value; |
| 54110 | assert( pMem->z || pMem->n==0 ); |
| 54111 | testcase( pMem->z==0 ); |
| 54112 | sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc); |
| 54113 | return value; |
| 54114 | }else{ |
| 54115 | return 0; |
| 54116 | } |
| 54117 | } |
| @@ -54185,11 +54137,11 @@ | |
| 54137 | || sqlite3VdbeMemNulTerminate(pMem) ){ |
| 54138 | /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ |
| 54139 | return (double)0; |
| 54140 | } |
| 54141 | assert( pMem->z ); |
| 54142 | sqlite3AtoF(pMem->z, &val, pMem->n, SQLITE_UTF8); |
| 54143 | return val; |
| 54144 | }else{ |
| 54145 | /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */ |
| 54146 | return (double)0; |
| 54147 | } |
| @@ -54258,25 +54210,23 @@ | |
| 54210 | ** Every effort is made to force the conversion, even if the input |
| 54211 | ** is a string that does not look completely like a number. Convert |
| 54212 | ** as much of the string as we can and ignore the rest. |
| 54213 | */ |
| 54214 | SQLITE_PRIVATE int sqlite3VdbeMemNumerify(Mem *pMem){ |
| 54215 | if( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 ){ |
| 54216 | assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 ); |
| 54217 | assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); |
| 54218 | if( 0==sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc) ){ |
| 54219 | MemSetTypeFlag(pMem, MEM_Int); |
| 54220 | }else{ |
| 54221 | pMem->r = sqlite3VdbeRealValue(pMem); |
| 54222 | MemSetTypeFlag(pMem, MEM_Real); |
| 54223 | sqlite3VdbeIntegerAffinity(pMem); |
| 54224 | } |
| 54225 | } |
| 54226 | assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))!=0 ); |
| 54227 | pMem->flags &= ~(MEM_Str|MEM_Blob); |
| 54228 | return SQLITE_OK; |
| 54229 | } |
| 54230 | |
| 54231 | /* |
| 54232 | ** Delete any previous value and set the value stored in *pMem to NULL. |
| @@ -54815,10 +54765,12 @@ | |
| 54765 | sqlite3_value **ppVal /* Write the new value here */ |
| 54766 | ){ |
| 54767 | int op; |
| 54768 | char *zVal = 0; |
| 54769 | sqlite3_value *pVal = 0; |
| 54770 | int negInt = 1; |
| 54771 | const char *zNeg = ""; |
| 54772 | |
| 54773 | if( !pExpr ){ |
| 54774 | *ppVal = 0; |
| 54775 | return SQLITE_OK; |
| 54776 | } |
| @@ -54831,35 +54783,50 @@ | |
| 54783 | #ifdef SQLITE_ENABLE_STAT2 |
| 54784 | if( op==TK_REGISTER ) op = pExpr->op2; |
| 54785 | #else |
| 54786 | if( NEVER(op==TK_REGISTER) ) op = pExpr->op2; |
| 54787 | #endif |
| 54788 | |
| 54789 | /* Handle negative integers in a single step. This is needed in the |
| 54790 | ** case when the value is -9223372036854775808. |
| 54791 | */ |
| 54792 | if( op==TK_UMINUS |
| 54793 | && (pExpr->pLeft->op==TK_INTEGER || pExpr->pLeft->op==TK_FLOAT) ){ |
| 54794 | pExpr = pExpr->pLeft; |
| 54795 | op = pExpr->op; |
| 54796 | negInt = -1; |
| 54797 | zNeg = "-"; |
| 54798 | } |
| 54799 | |
| 54800 | if( op==TK_STRING || op==TK_FLOAT || op==TK_INTEGER ){ |
| 54801 | pVal = sqlite3ValueNew(db); |
| 54802 | if( pVal==0 ) goto no_mem; |
| 54803 | if( ExprHasProperty(pExpr, EP_IntValue) ){ |
| 54804 | sqlite3VdbeMemSetInt64(pVal, (i64)pExpr->u.iValue*negInt); |
| 54805 | }else{ |
| 54806 | zVal = sqlite3MPrintf(db, "%s%s", zNeg, pExpr->u.zToken); |
| 54807 | if( zVal==0 ) goto no_mem; |
| 54808 | sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC); |
| 54809 | if( op==TK_FLOAT ) pVal->type = SQLITE_FLOAT; |
| 54810 | } |
| 54811 | if( (op==TK_INTEGER || op==TK_FLOAT ) && affinity==SQLITE_AFF_NONE ){ |
| 54812 | sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, SQLITE_UTF8); |
| 54813 | }else{ |
| 54814 | sqlite3ValueApplyAffinity(pVal, affinity, SQLITE_UTF8); |
| 54815 | } |
| 54816 | if( pVal->flags & (MEM_Int|MEM_Real) ) pVal->flags &= ~MEM_Str; |
| 54817 | if( enc!=SQLITE_UTF8 ){ |
| 54818 | sqlite3VdbeChangeEncoding(pVal, enc); |
| 54819 | } |
| 54820 | }else if( op==TK_UMINUS ) { |
| 54821 | /* This branch happens for multiple negative signs. Ex: -(-5) */ |
| 54822 | if( SQLITE_OK==sqlite3ValueFromExpr(db,pExpr->pLeft,enc,affinity,&pVal) ){ |
| 54823 | sqlite3VdbeMemNumerify(pVal); |
| 54824 | pVal->u.i = -1 * pVal->u.i; |
| 54825 | /* (double)-1 In case of SQLITE_OMIT_FLOATING_POINT... */ |
| 54826 | pVal->r = (double)-1 * pVal->r; |
| 54827 | sqlite3ValueApplyAffinity(pVal, affinity, enc); |
| 54828 | } |
| 54829 | } |
| 54830 | #ifndef SQLITE_OMIT_BLOB_LITERAL |
| 54831 | else if( op==TK_BLOB ){ |
| 54832 | int nVal; |
| @@ -59770,35 +59737,21 @@ | |
| 59737 | ** looks like a number, convert it into a number. If it does not |
| 59738 | ** look like a number, leave it alone. |
| 59739 | */ |
| 59740 | static void applyNumericAffinity(Mem *pRec){ |
| 59741 | if( (pRec->flags & (MEM_Real|MEM_Int))==0 ){ |
| 59742 | double rValue; |
| 59743 | i64 iValue; |
| 59744 | u8 enc = pRec->enc; |
| 59745 | if( (pRec->flags&MEM_Str)==0 ) return; |
| 59746 | if( sqlite3AtoF(pRec->z, &rValue, pRec->n, enc)==0 ) return; |
| 59747 | if( 0==sqlite3Atoi64(pRec->z, &iValue, pRec->n, enc) ){ |
| 59748 | pRec->u.i = iValue; |
| 59749 | pRec->flags |= MEM_Int; |
| 59750 | }else{ |
| 59751 | pRec->r = rValue; |
| 59752 | pRec->flags |= MEM_Real; |
| 59753 | } |
| 59754 | } |
| 59755 | } |
| 59756 | |
| 59757 | /* |
| @@ -61580,11 +61533,10 @@ | |
| 61533 | ** integers, for space efficiency, but after extraction we want them |
| 61534 | ** to have only a real value. |
| 61535 | */ |
| 61536 | case OP_RealAffinity: { /* in1 */ |
| 61537 | pIn1 = &aMem[pOp->p1]; |
| 61538 | if( pIn1->flags & MEM_Int ){ |
| 61539 | sqlite3VdbeMemRealify(pIn1); |
| 61540 | } |
| 61541 | break; |
| 61542 | } |
| @@ -61623,11 +61575,10 @@ | |
| 61575 | ** |
| 61576 | ** A NULL value is not changed by this routine. It remains NULL. |
| 61577 | */ |
| 61578 | case OP_ToBlob: { /* same as TK_TO_BLOB, in1 */ |
| 61579 | pIn1 = &aMem[pOp->p1]; |
| 61580 | if( pIn1->flags & MEM_Null ) break; |
| 61581 | if( (pIn1->flags & MEM_Blob)==0 ){ |
| 61582 | applyAffinity(pIn1, SQLITE_AFF_TEXT, encoding); |
| 61583 | assert( pIn1->flags & MEM_Str || db->mallocFailed ); |
| 61584 | MemSetTypeFlag(pIn1, MEM_Blob); |
| @@ -61648,14 +61599,11 @@ | |
| 61599 | ** |
| 61600 | ** A NULL value is not changed by this routine. It remains NULL. |
| 61601 | */ |
| 61602 | case OP_ToNumeric: { /* same as TK_TO_NUMERIC, in1 */ |
| 61603 | pIn1 = &aMem[pOp->p1]; |
| 61604 | sqlite3VdbeMemNumerify(pIn1); |
| 61605 | break; |
| 61606 | } |
| 61607 | #endif /* SQLITE_OMIT_CAST */ |
| 61608 | |
| 61609 | /* Opcode: ToInt P1 * * * * |
| @@ -61667,11 +61615,10 @@ | |
| 61615 | ** |
| 61616 | ** A NULL value is not changed by this routine. It remains NULL. |
| 61617 | */ |
| 61618 | case OP_ToInt: { /* same as TK_TO_INT, in1 */ |
| 61619 | pIn1 = &aMem[pOp->p1]; |
| 61620 | if( (pIn1->flags & MEM_Null)==0 ){ |
| 61621 | sqlite3VdbeMemIntegerify(pIn1); |
| 61622 | } |
| 61623 | break; |
| 61624 | } |
| @@ -61781,12 +61728,10 @@ | |
| 61728 | u16 flags3; /* Copy of initial value of pIn3->flags */ |
| 61729 | #endif /* local variables moved into u.ai */ |
| 61730 | |
| 61731 | pIn1 = &aMem[pOp->p1]; |
| 61732 | pIn3 = &aMem[pOp->p3]; |
| 61733 | u.ai.flags1 = pIn1->flags; |
| 61734 | u.ai.flags3 = pIn3->flags; |
| 61735 | if( (pIn1->flags | pIn3->flags)&MEM_Null ){ |
| 61736 | /* One or both operands are NULL */ |
| 61737 | if( pOp->p5 & SQLITE_NULLEQ ){ |
| @@ -62415,11 +62360,10 @@ | |
| 62360 | assert( u.an.zAffinity[pOp->p2]==0 ); |
| 62361 | pIn1 = &aMem[pOp->p1]; |
| 62362 | while( (u.an.cAff = *(u.an.zAffinity++))!=0 ){ |
| 62363 | assert( pIn1 <= &p->aMem[p->nMem] ); |
| 62364 | assert( memIsValid(pIn1) ); |
| 62365 | ExpandBlob(pIn1); |
| 62366 | applyAffinity(pIn1, u.an.cAff, encoding); |
| 62367 | pIn1++; |
| 62368 | } |
| 62369 | break; |
| @@ -62495,11 +62439,10 @@ | |
| 62439 | ** out how much space is required for the new record. |
| 62440 | */ |
| 62441 | for(u.ao.pRec=u.ao.pData0; u.ao.pRec<=u.ao.pLast; u.ao.pRec++){ |
| 62442 | assert( memIsValid(u.ao.pRec) ); |
| 62443 | if( u.ao.zAffinity ){ |
| 62444 | applyAffinity(u.ao.pRec, u.ao.zAffinity[u.ao.pRec-u.ao.pData0], encoding); |
| 62445 | } |
| 62446 | if( u.ao.pRec->flags&MEM_Zero && u.ao.pRec->n>0 ){ |
| 62447 | sqlite3VdbeMemExpandBlob(u.ao.pRec); |
| 62448 | } |
| @@ -68880,11 +68823,11 @@ | |
| 68823 | pExpr->iColumn = (ynVar)(++pParse->nVar); |
| 68824 | }else if( z[0]=='?' ){ |
| 68825 | /* Wildcard of the form "?nnn". Convert "nnn" to an integer and |
| 68826 | ** use it as the variable number */ |
| 68827 | i64 i; |
| 68828 | int bOk = 0==sqlite3Atoi64(&z[1], &i, sqlite3Strlen30(&z[1]), SQLITE_UTF8); |
| 68829 | pExpr->iColumn = (ynVar)i; |
| 68830 | testcase( i==0 ); |
| 68831 | testcase( i==1 ); |
| 68832 | testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER]-1 ); |
| 68833 | testcase( i==db->aLimit[SQLITE_LIMIT_VARIABLE_NUMBER] ); |
| @@ -70243,11 +70186,11 @@ | |
| 70186 | */ |
| 70187 | static void codeReal(Vdbe *v, const char *z, int negateFlag, int iMem){ |
| 70188 | if( ALWAYS(z!=0) ){ |
| 70189 | double value; |
| 70190 | char *zV; |
| 70191 | sqlite3AtoF(z, &value, sqlite3Strlen30(z), SQLITE_UTF8); |
| 70192 | assert( !sqlite3IsNaN(value) ); /* The new AtoF never returns NaN */ |
| 70193 | if( negateFlag ) value = -value; |
| 70194 | zV = dup8bytes(v, (char*)&value); |
| 70195 | sqlite3VdbeAddOp4(v, OP_Real, 0, iMem, 0, zV, P4_REAL); |
| 70196 | } |
| @@ -70257,28 +70200,27 @@ | |
| 70200 | |
| 70201 | /* |
| 70202 | ** Generate an instruction that will put the integer describe by |
| 70203 | ** text z[0..n-1] into register iMem. |
| 70204 | ** |
| 70205 | ** Expr.u.zToken is always UTF8 and zero-terminated. |
| 70206 | */ |
| 70207 | static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){ |
| 70208 | Vdbe *v = pParse->pVdbe; |
| 70209 | if( pExpr->flags & EP_IntValue ){ |
| 70210 | int i = pExpr->u.iValue; |
| 70211 | if( negFlag ) i = -i; |
| 70212 | sqlite3VdbeAddOp2(v, OP_Integer, i, iMem); |
| 70213 | }else{ |
| 70214 | int c; |
| 70215 | i64 value; |
| 70216 | const char *z = pExpr->u.zToken; |
| 70217 | assert( z!=0 ); |
| 70218 | c = sqlite3Atoi64(z, &value, sqlite3Strlen30(z), SQLITE_UTF8); |
| 70219 | if( c==0 || (c==2 && negFlag) ){ |
| 70220 | char *zV; |
| 70221 | if( negFlag ){ value = -value; } |
| 70222 | zV = dup8bytes(v, (char*)&value); |
| 70223 | sqlite3VdbeAddOp4(v, OP_Int64, 0, iMem, 0, zV, P4_INT64); |
| 70224 | }else{ |
| 70225 | #ifdef SQLITE_OMIT_FLOATING_POINT |
| 70226 | sqlite3ErrorMsg(pParse, "oversized integer: %s%s", negFlag ? "-" : "", z); |
| @@ -79414,11 +79356,11 @@ | |
| 79356 | zBuf = sqlite3_mprintf("%.*f",n,r); |
| 79357 | if( zBuf==0 ){ |
| 79358 | sqlite3_result_error_nomem(context); |
| 79359 | return; |
| 79360 | } |
| 79361 | sqlite3AtoF(zBuf, &r, sqlite3Strlen30(zBuf), SQLITE_UTF8); |
| 79362 | sqlite3_free(zBuf); |
| 79363 | } |
| 79364 | sqlite3_result_double(context, r); |
| 79365 | } |
| 79366 | #endif |
| @@ -85472,11 +85414,11 @@ | |
| 85414 | */ |
| 85415 | if( sqlite3StrICmp(zLeft,"journal_size_limit")==0 ){ |
| 85416 | Pager *pPager = sqlite3BtreePager(pDb->pBt); |
| 85417 | i64 iLimit = -2; |
| 85418 | if( zRight ){ |
| 85419 | sqlite3Atoi64(zRight, &iLimit, 1000000, SQLITE_UTF8); |
| 85420 | if( iLimit<-1 ) iLimit = -1; |
| 85421 | } |
| 85422 | iLimit = sqlite3PagerJournalSizeLimit(pPager, iLimit); |
| 85423 | returnSingleInt(pParse, "journal_size_limit", iLimit); |
| 85424 | }else |
| @@ -96380,11 +96322,12 @@ | |
| 96322 | |
| 96323 | /* |
| 96324 | ** Required because bestIndex() is called by bestOrClauseIndex() |
| 96325 | */ |
| 96326 | static void bestIndex( |
| 96327 | Parse*, WhereClause*, struct SrcList_item*, |
| 96328 | Bitmask, Bitmask, ExprList*, WhereCost*); |
| 96329 | |
| 96330 | /* |
| 96331 | ** This routine attempts to find an scanning strategy that can be used |
| 96332 | ** to optimize an 'OR' expression that is part of a WHERE clause. |
| 96333 | ** |
| @@ -96393,11 +96336,12 @@ | |
| 96336 | */ |
| 96337 | static void bestOrClauseIndex( |
| 96338 | Parse *pParse, /* The parsing context */ |
| 96339 | WhereClause *pWC, /* The WHERE clause */ |
| 96340 | struct SrcList_item *pSrc, /* The FROM clause term to search */ |
| 96341 | Bitmask notReady, /* Mask of cursors not available for indexing */ |
| 96342 | Bitmask notValid, /* Cursors not available for any purpose */ |
| 96343 | ExprList *pOrderBy, /* The ORDER BY clause */ |
| 96344 | WhereCost *pCost /* Lowest cost query plan */ |
| 96345 | ){ |
| 96346 | #ifndef SQLITE_OMIT_OR_OPTIMIZATION |
| 96347 | const int iCur = pSrc->iCursor; /* The cursor of the table to be accessed */ |
| @@ -96429,19 +96373,19 @@ | |
| 96373 | WHERETRACE(("... Multi-index OR testing for term %d of %d....\n", |
| 96374 | (pOrTerm - pOrWC->a), (pTerm - pWC->a) |
| 96375 | )); |
| 96376 | if( pOrTerm->eOperator==WO_AND ){ |
| 96377 | WhereClause *pAndWC = &pOrTerm->u.pAndInfo->wc; |
| 96378 | bestIndex(pParse, pAndWC, pSrc, notReady, notValid, 0, &sTermCost); |
| 96379 | }else if( pOrTerm->leftCursor==iCur ){ |
| 96380 | WhereClause tempWC; |
| 96381 | tempWC.pParse = pWC->pParse; |
| 96382 | tempWC.pMaskSet = pWC->pMaskSet; |
| 96383 | tempWC.op = TK_AND; |
| 96384 | tempWC.a = pOrTerm; |
| 96385 | tempWC.nTerm = 1; |
| 96386 | bestIndex(pParse, &tempWC, pSrc, notReady, notValid, 0, &sTermCost); |
| 96387 | }else{ |
| 96388 | continue; |
| 96389 | } |
| 96390 | rTotal += sTermCost.rCost; |
| 96391 | nRow += sTermCost.nRow; |
| @@ -96884,11 +96828,12 @@ | |
| 96828 | */ |
| 96829 | static void bestVirtualIndex( |
| 96830 | Parse *pParse, /* The parsing context */ |
| 96831 | WhereClause *pWC, /* The WHERE clause */ |
| 96832 | struct SrcList_item *pSrc, /* The FROM clause term to search */ |
| 96833 | Bitmask notReady, /* Mask of cursors not available for index */ |
| 96834 | Bitmask notValid, /* Cursors not valid for any purpose */ |
| 96835 | ExprList *pOrderBy, /* The order by clause */ |
| 96836 | WhereCost *pCost, /* Lowest cost query plan */ |
| 96837 | sqlite3_index_info **ppIdxInfo /* Index information passed to xBestIndex */ |
| 96838 | ){ |
| 96839 | Table *pTab = pSrc->pTab; |
| @@ -97014,11 +96959,11 @@ | |
| 96959 | pIdxInfo->nOrderBy = nOrderBy; |
| 96960 | |
| 96961 | /* Try to find a more efficient access pattern by using multiple indexes |
| 96962 | ** to optimize an OR expression within the WHERE clause. |
| 96963 | */ |
| 96964 | bestOrClauseIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost); |
| 96965 | } |
| 96966 | #endif /* SQLITE_OMIT_VIRTUALTABLE */ |
| 96967 | |
| 96968 | /* |
| 96969 | ** Argument pIdx is a pointer to an index structure that has an array of |
| @@ -97295,11 +97240,12 @@ | |
| 97240 | */ |
| 97241 | static void bestBtreeIndex( |
| 97242 | Parse *pParse, /* The parsing context */ |
| 97243 | WhereClause *pWC, /* The WHERE clause */ |
| 97244 | struct SrcList_item *pSrc, /* The FROM clause term to search */ |
| 97245 | Bitmask notReady, /* Mask of cursors not available for indexing */ |
| 97246 | Bitmask notValid, /* Cursors not available for any purpose */ |
| 97247 | ExprList *pOrderBy, /* The ORDER BY clause */ |
| 97248 | WhereCost *pCost /* Lowest cost query plan */ |
| 97249 | ){ |
| 97250 | int iCur = pSrc->iCursor; /* The cursor of the table to be accessed */ |
| 97251 | Index *pProbe; /* An index we are evaluating */ |
| @@ -97557,29 +97503,29 @@ | |
| 97503 | ** of output rows, adjust the nRow value accordingly. This only |
| 97504 | ** matters if the current index is the least costly, so do not bother |
| 97505 | ** with this step if we already know this index will not be chosen. |
| 97506 | ** Also, never reduce the output row count below 2 using this step. |
| 97507 | ** |
| 97508 | ** It is critical that the notValid mask be used here instead of |
| 97509 | ** the notReady mask. When computing an "optimal" index, the notReady |
| 97510 | ** mask will only have one bit set - the bit for the current table. |
| 97511 | ** The notValid mask, on the other hand, always has all bits set for |
| 97512 | ** tables that are not in outer loops. If notReady is used here instead |
| 97513 | ** of notValid, then a optimal index that depends on inner joins loops |
| 97514 | ** might be selected even when there exists an optimal index that has |
| 97515 | ** no such dependency. |
| 97516 | */ |
| 97517 | if( nRow>2 && cost<=pCost->rCost ){ |
| 97518 | int k; /* Loop counter */ |
| 97519 | int nSkipEq = nEq; /* Number of == constraints to skip */ |
| 97520 | int nSkipRange = nBound; /* Number of < constraints to skip */ |
| 97521 | Bitmask thisTab; /* Bitmap for pSrc */ |
| 97522 | |
| 97523 | thisTab = getMask(pWC->pMaskSet, iCur); |
| 97524 | for(pTerm=pWC->a, k=pWC->nTerm; nRow>2 && k; k--, pTerm++){ |
| 97525 | if( pTerm->wtFlags & TERM_VIRTUAL ) continue; |
| 97526 | if( (pTerm->prereqAll & notValid)!=thisTab ) continue; |
| 97527 | if( pTerm->eOperator & (WO_EQ|WO_IN|WO_ISNULL) ){ |
| 97528 | if( nSkipEq ){ |
| 97529 | /* Ignore the first nEq equality matches since the index |
| 97530 | ** has already accounted for these */ |
| 97531 | nSkipEq--; |
| @@ -97657,11 +97603,11 @@ | |
| 97603 | WHERETRACE(("best index is: %s\n", |
| 97604 | ((pCost->plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ? "none" : |
| 97605 | pCost->plan.u.pIdx ? pCost->plan.u.pIdx->zName : "ipk") |
| 97606 | )); |
| 97607 | |
| 97608 | bestOrClauseIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost); |
| 97609 | bestAutomaticIndex(pParse, pWC, pSrc, notReady, pCost); |
| 97610 | pCost->plan.wsFlags |= eqTermMask; |
| 97611 | } |
| 97612 | |
| 97613 | /* |
| @@ -97672,26 +97618,27 @@ | |
| 97618 | */ |
| 97619 | static void bestIndex( |
| 97620 | Parse *pParse, /* The parsing context */ |
| 97621 | WhereClause *pWC, /* The WHERE clause */ |
| 97622 | struct SrcList_item *pSrc, /* The FROM clause term to search */ |
| 97623 | Bitmask notReady, /* Mask of cursors not available for indexing */ |
| 97624 | Bitmask notValid, /* Cursors not available for any purpose */ |
| 97625 | ExprList *pOrderBy, /* The ORDER BY clause */ |
| 97626 | WhereCost *pCost /* Lowest cost query plan */ |
| 97627 | ){ |
| 97628 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| 97629 | if( IsVirtual(pSrc->pTab) ){ |
| 97630 | sqlite3_index_info *p = 0; |
| 97631 | bestVirtualIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost,&p); |
| 97632 | if( p->needToFreeIdxStr ){ |
| 97633 | sqlite3_free(p->idxStr); |
| 97634 | } |
| 97635 | sqlite3DbFree(pParse->db, p); |
| 97636 | }else |
| 97637 | #endif |
| 97638 | { |
| 97639 | bestBtreeIndex(pParse, pWC, pSrc, notReady, notValid, pOrderBy, pCost); |
| 97640 | } |
| 97641 | } |
| 97642 | |
| 97643 | /* |
| 97644 | ** Disable a term in the WHERE clause. Except, do not disable the term |
| @@ -98902,14 +98849,20 @@ | |
| 98849 | ** by waiting for other tables to run first. This "optimal" test works |
| 98850 | ** by first assuming that the FROM clause is on the inner loop and finding |
| 98851 | ** its query plan, then checking to see if that query plan uses any |
| 98852 | ** other FROM clause terms that are notReady. If no notReady terms are |
| 98853 | ** used then the "optimal" query plan works. |
| 98854 | ** |
| 98855 | ** Note that the WhereCost.nRow parameter for an optimal scan might |
| 98856 | ** not be as small as it would be if the table really were the innermost |
| 98857 | ** join. The nRow value can be reduced by WHERE clause constraints |
| 98858 | ** that do not use indices. But this nRow reduction only happens if the |
| 98859 | ** table really is the innermost join. |
| 98860 | ** |
| 98861 | ** The second loop iteration is only performed if no optimal scan |
| 98862 | ** strategies were found by the first iteration. This second iteration |
| 98863 | ** is used to search for the lowest cost scan overall. |
| 98864 | ** |
| 98865 | ** Previous versions of SQLite performed only the second iteration - |
| 98866 | ** the next outermost loop was always that with the lowest overall |
| 98867 | ** cost. However, this meant that SQLite could select the wrong plan |
| 98868 | ** for scripts such as the following: |
| @@ -98925,11 +98878,11 @@ | |
| 98878 | ** algorithm may choose to use t2 for the outer loop, which is a much |
| 98879 | ** costlier approach. |
| 98880 | */ |
| 98881 | nUnconstrained = 0; |
| 98882 | notIndexed = 0; |
| 98883 | for(isOptimal=(iFrom<nTabList-1); isOptimal>=0 && bestJ<0; isOptimal--){ |
| 98884 | Bitmask mask; /* Mask of tables not yet ready */ |
| 98885 | for(j=iFrom, pTabItem=&pTabList->a[j]; j<nTabList; j++, pTabItem++){ |
| 98886 | int doNotReorder; /* True if this table should not be reordered */ |
| 98887 | WhereCost sCost; /* Cost information from best[Virtual]Index() */ |
| 98888 | ExprList *pOrderBy; /* ORDER BY clause for index to optimize */ |
| @@ -98947,15 +98900,17 @@ | |
| 98900 | |
| 98901 | assert( pTabItem->pTab ); |
| 98902 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| 98903 | if( IsVirtual(pTabItem->pTab) ){ |
| 98904 | sqlite3_index_info **pp = &pWInfo->a[j].pIdxInfo; |
| 98905 | bestVirtualIndex(pParse, pWC, pTabItem, mask, notReady, pOrderBy, |
| 98906 | &sCost, pp); |
| 98907 | }else |
| 98908 | #endif |
| 98909 | { |
| 98910 | bestBtreeIndex(pParse, pWC, pTabItem, mask, notReady, pOrderBy, |
| 98911 | &sCost); |
| 98912 | } |
| 98913 | assert( isOptimal || (sCost.used¬Ready)==0 ); |
| 98914 | |
| 98915 | /* If an INDEXED BY clause is present, then the plan must use that |
| 98916 | ** index if it uses any index at all */ |
| 98917 |
+1
-1
| --- src/sqlite3.h | ||
| +++ src/sqlite3.h | ||
| @@ -107,11 +107,11 @@ | ||
| 107 | 107 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 108 | 108 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 109 | 109 | */ |
| 110 | 110 | #define SQLITE_VERSION "3.7.3" |
| 111 | 111 | #define SQLITE_VERSION_NUMBER 3007003 |
| 112 | -#define SQLITE_SOURCE_ID "2010-09-29 23:09:23 1ef0dc9328f47506cb2dcd142150e96cb4755216" | |
| 112 | +#define SQLITE_SOURCE_ID "2010-10-04 23:55:51 ece641eb8951c6314cedbdb3243f91cb199c3239" | |
| 113 | 113 | |
| 114 | 114 | /* |
| 115 | 115 | ** CAPI3REF: Run-Time Library Version Numbers |
| 116 | 116 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 117 | 117 | ** |
| 118 | 118 |
| --- src/sqlite3.h | |
| +++ src/sqlite3.h | |
| @@ -107,11 +107,11 @@ | |
| 107 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 108 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 109 | */ |
| 110 | #define SQLITE_VERSION "3.7.3" |
| 111 | #define SQLITE_VERSION_NUMBER 3007003 |
| 112 | #define SQLITE_SOURCE_ID "2010-09-29 23:09:23 1ef0dc9328f47506cb2dcd142150e96cb4755216" |
| 113 | |
| 114 | /* |
| 115 | ** CAPI3REF: Run-Time Library Version Numbers |
| 116 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 117 | ** |
| 118 |
| --- src/sqlite3.h | |
| +++ src/sqlite3.h | |
| @@ -107,11 +107,11 @@ | |
| 107 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 108 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 109 | */ |
| 110 | #define SQLITE_VERSION "3.7.3" |
| 111 | #define SQLITE_VERSION_NUMBER 3007003 |
| 112 | #define SQLITE_SOURCE_ID "2010-10-04 23:55:51 ece641eb8951c6314cedbdb3243f91cb199c3239" |
| 113 | |
| 114 | /* |
| 115 | ** CAPI3REF: Run-Time Library Version Numbers |
| 116 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 117 | ** |
| 118 |
+1
-1
| --- src/style.c | ||
| +++ src/style.c | ||
| @@ -198,11 +198,11 @@ | ||
| 198 | 198 | @ media="screen" /> |
| 199 | 199 | @ </head> |
| 200 | 200 | @ <body> |
| 201 | 201 | @ <div class="header"> |
| 202 | 202 | @ <div class="logo"> |
| 203 | -@ <img src="$baseurl/logo" alt="logo"> | |
| 203 | +@ <img src="$baseurl/logo" alt="logo" /> | |
| 204 | 204 | @ </div> |
| 205 | 205 | @ <div class="title"><small>$<project_name></small><br />$<title></div> |
| 206 | 206 | @ <div class="status"><th1> |
| 207 | 207 | @ if {[info exists login]} { |
| 208 | 208 | @ puts "Logged in as $login" |
| 209 | 209 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -198,11 +198,11 @@ | |
| 198 | @ media="screen" /> |
| 199 | @ </head> |
| 200 | @ <body> |
| 201 | @ <div class="header"> |
| 202 | @ <div class="logo"> |
| 203 | @ <img src="$baseurl/logo" alt="logo"> |
| 204 | @ </div> |
| 205 | @ <div class="title"><small>$<project_name></small><br />$<title></div> |
| 206 | @ <div class="status"><th1> |
| 207 | @ if {[info exists login]} { |
| 208 | @ puts "Logged in as $login" |
| 209 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -198,11 +198,11 @@ | |
| 198 | @ media="screen" /> |
| 199 | @ </head> |
| 200 | @ <body> |
| 201 | @ <div class="header"> |
| 202 | @ <div class="logo"> |
| 203 | @ <img src="$baseurl/logo" alt="logo" /> |
| 204 | @ </div> |
| 205 | @ <div class="title"><small>$<project_name></small><br />$<title></div> |
| 206 | @ <div class="status"><th1> |
| 207 | @ if {[info exists login]} { |
| 208 | @ puts "Logged in as $login" |
| 209 |
+16
-8
| --- src/timeline.c | ||
| +++ src/timeline.c | ||
| @@ -165,11 +165,11 @@ | ||
| 165 | 165 | ** 4. User |
| 166 | 166 | ** 5. True if is a leaf |
| 167 | 167 | ** 6. background color |
| 168 | 168 | ** 7. type ("ci", "w", "t") |
| 169 | 169 | ** 8. list of symbolic tags. |
| 170 | -** 9. tagid for ticket or wiki | |
| 170 | +** 9. tagid for ticket or wiki or event | |
| 171 | 171 | ** 10. Short comment to user for repeated tickets and wiki |
| 172 | 172 | */ |
| 173 | 173 | void www_print_timeline( |
| 174 | 174 | Stmt *pQuery, /* Query to implement the timeline */ |
| 175 | 175 | int tmFlags, /* Flags controlling display behavior */ |
| @@ -288,10 +288,12 @@ | ||
| 288 | 288 | @ <span class="timelineLeaf">Closed-Leaf:</span> |
| 289 | 289 | }else{ |
| 290 | 290 | @ <span class="timelineLeaf">Leaf:</span> |
| 291 | 291 | } |
| 292 | 292 | } |
| 293 | + }else if( zType[0]=='e' && tagid ){ | |
| 294 | + hyperlink_to_event_tagid(tagid); | |
| 293 | 295 | }else if( (tmFlags & TIMELINE_ARTID)!=0 ){ |
| 294 | 296 | hyperlink_to_uuid(zUuid); |
| 295 | 297 | } |
| 296 | 298 | db_column_blob(pQuery, commentColumn, &comment); |
| 297 | 299 | if( mxWikiLen>0 && blob_size(&comment)>mxWikiLen ){ |
| @@ -639,11 +641,11 @@ | ||
| 639 | 641 | ** p=RID artifact RID and up to COUNT parents and ancestors |
| 640 | 642 | ** d=RID artifact RID and up to COUNT descendants |
| 641 | 643 | ** t=TAGID show only check-ins with the given tagid |
| 642 | 644 | ** r=TAGID show check-ins related to tagid |
| 643 | 645 | ** u=USER only if belonging to this user |
| 644 | -** y=TYPE 'ci', 'w', 't' | |
| 646 | +** y=TYPE 'ci', 'w', 't', 'e' | |
| 645 | 647 | ** s=TEXT string search (comment and brief) |
| 646 | 648 | ** ng Suppress the graph if present |
| 647 | 649 | ** |
| 648 | 650 | ** p= and d= can appear individually or together. If either p= or d= |
| 649 | 651 | ** appear, then u=, y=, a=, and b= are ignored. |
| @@ -749,22 +751,22 @@ | ||
| 749 | 751 | }else{ |
| 750 | 752 | blob_appendf(&desc, " of check-in [%.10s]", zUuid); |
| 751 | 753 | } |
| 752 | 754 | }else{ |
| 753 | 755 | int n; |
| 754 | - const char *zEType = "event"; | |
| 756 | + const char *zEType = "timeline item"; | |
| 755 | 757 | char *zDate; |
| 756 | 758 | char *zNEntry = mprintf("%d", nEntry); |
| 757 | 759 | url_initialize(&url, "timeline"); |
| 758 | 760 | url_add_parameter(&url, "n", zNEntry); |
| 759 | 761 | if( tagid>0 ){ |
| 760 | - zType = "ci"; | |
| 762 | + if( zType[0]!='e' ) zType = "ci"; | |
| 761 | 763 | blob_appendf(&sql, |
| 762 | 764 | "AND (EXISTS(SELECT 1 FROM tagxref" |
| 763 | 765 | " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)", tagid); |
| 764 | 766 | |
| 765 | - if( zBrName ){ | |
| 767 | + if( zBrName && zType[0]=='c' ){ | |
| 766 | 768 | /* The next two blob_appendf() calls add SQL that causes checkins that |
| 767 | 769 | ** are not part of the branch which are parents or childen of the branch |
| 768 | 770 | ** to be included in the report. This related check-ins are useful |
| 769 | 771 | ** in helping to visualize what has happened on a quiescent branch |
| 770 | 772 | ** that is infrequently merged with a much more activate branch. |
| @@ -781,10 +783,11 @@ | ||
| 781 | 783 | } |
| 782 | 784 | blob_appendf(&sql, ")"); |
| 783 | 785 | } |
| 784 | 786 | if( (zType[0]=='w' && !g.okRdWiki) |
| 785 | 787 | || (zType[0]=='t' && !g.okRdTkt) |
| 788 | + || (zType[0]=='e' && !g.okRdWiki) | |
| 786 | 789 | || (zType[0]=='c' && !g.okRead) |
| 787 | 790 | ){ |
| 788 | 791 | zType = "all"; |
| 789 | 792 | } |
| 790 | 793 | if( zType[0]=='a' ){ |
| @@ -794,11 +797,11 @@ | ||
| 794 | 797 | if( g.okRead ){ |
| 795 | 798 | blob_appendf(&sql, "%c'ci'", cSep); |
| 796 | 799 | cSep = ','; |
| 797 | 800 | } |
| 798 | 801 | if( g.okRdWiki ){ |
| 799 | - blob_appendf(&sql, "%c'w'", cSep); | |
| 802 | + blob_appendf(&sql, "%c'w','e'", cSep); | |
| 800 | 803 | cSep = ','; |
| 801 | 804 | } |
| 802 | 805 | if( g.okRdTkt ){ |
| 803 | 806 | blob_appendf(&sql, "%c't'", cSep); |
| 804 | 807 | cSep = ','; |
| @@ -812,10 +815,12 @@ | ||
| 812 | 815 | zEType = "checkin"; |
| 813 | 816 | }else if( zType[0]=='w' ){ |
| 814 | 817 | zEType = "wiki edit"; |
| 815 | 818 | }else if( zType[0]=='t' ){ |
| 816 | 819 | zEType = "ticket change"; |
| 820 | + }else if( zType[0]=='e' ){ | |
| 821 | + zEType = "event"; | |
| 817 | 822 | } |
| 818 | 823 | } |
| 819 | 824 | if( zUser ){ |
| 820 | 825 | blob_appendf(&sql, " AND event.user=%Q", zUser); |
| 821 | 826 | url_add_parameter(&url, "u", zUser); |
| @@ -926,16 +931,19 @@ | ||
| 926 | 931 | timeline_submenu(&url, "Checkins Only", "y", "ci", 0); |
| 927 | 932 | } |
| 928 | 933 | if( zType[0]!='t' && g.okRdTkt ){ |
| 929 | 934 | timeline_submenu(&url, "Tickets Only", "y", "t", 0); |
| 930 | 935 | } |
| 936 | + if( zType[0]!='e' && g.okRdWiki ){ | |
| 937 | + timeline_submenu(&url, "Events Only", "y", "e", 0); | |
| 938 | + } | |
| 931 | 939 | } |
| 932 | 940 | if( nEntry>20 ){ |
| 933 | - timeline_submenu(&url, "20 Events", "n", "20", 0); | |
| 941 | + timeline_submenu(&url, "20 Entries", "n", "20", 0); | |
| 934 | 942 | } |
| 935 | 943 | if( nEntry<200 ){ |
| 936 | - timeline_submenu(&url, "200 Events", "n", "200", 0); | |
| 944 | + timeline_submenu(&url, "200 Entries", "n", "200", 0); | |
| 937 | 945 | } |
| 938 | 946 | } |
| 939 | 947 | } |
| 940 | 948 | blob_zero(&sql); |
| 941 | 949 | db_prepare(&q, "SELECT * FROM timeline ORDER BY timestamp DESC /*scan*/"); |
| 942 | 950 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -165,11 +165,11 @@ | |
| 165 | ** 4. User |
| 166 | ** 5. True if is a leaf |
| 167 | ** 6. background color |
| 168 | ** 7. type ("ci", "w", "t") |
| 169 | ** 8. list of symbolic tags. |
| 170 | ** 9. tagid for ticket or wiki |
| 171 | ** 10. Short comment to user for repeated tickets and wiki |
| 172 | */ |
| 173 | void www_print_timeline( |
| 174 | Stmt *pQuery, /* Query to implement the timeline */ |
| 175 | int tmFlags, /* Flags controlling display behavior */ |
| @@ -288,10 +288,12 @@ | |
| 288 | @ <span class="timelineLeaf">Closed-Leaf:</span> |
| 289 | }else{ |
| 290 | @ <span class="timelineLeaf">Leaf:</span> |
| 291 | } |
| 292 | } |
| 293 | }else if( (tmFlags & TIMELINE_ARTID)!=0 ){ |
| 294 | hyperlink_to_uuid(zUuid); |
| 295 | } |
| 296 | db_column_blob(pQuery, commentColumn, &comment); |
| 297 | if( mxWikiLen>0 && blob_size(&comment)>mxWikiLen ){ |
| @@ -639,11 +641,11 @@ | |
| 639 | ** p=RID artifact RID and up to COUNT parents and ancestors |
| 640 | ** d=RID artifact RID and up to COUNT descendants |
| 641 | ** t=TAGID show only check-ins with the given tagid |
| 642 | ** r=TAGID show check-ins related to tagid |
| 643 | ** u=USER only if belonging to this user |
| 644 | ** y=TYPE 'ci', 'w', 't' |
| 645 | ** s=TEXT string search (comment and brief) |
| 646 | ** ng Suppress the graph if present |
| 647 | ** |
| 648 | ** p= and d= can appear individually or together. If either p= or d= |
| 649 | ** appear, then u=, y=, a=, and b= are ignored. |
| @@ -749,22 +751,22 @@ | |
| 749 | }else{ |
| 750 | blob_appendf(&desc, " of check-in [%.10s]", zUuid); |
| 751 | } |
| 752 | }else{ |
| 753 | int n; |
| 754 | const char *zEType = "event"; |
| 755 | char *zDate; |
| 756 | char *zNEntry = mprintf("%d", nEntry); |
| 757 | url_initialize(&url, "timeline"); |
| 758 | url_add_parameter(&url, "n", zNEntry); |
| 759 | if( tagid>0 ){ |
| 760 | zType = "ci"; |
| 761 | blob_appendf(&sql, |
| 762 | "AND (EXISTS(SELECT 1 FROM tagxref" |
| 763 | " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)", tagid); |
| 764 | |
| 765 | if( zBrName ){ |
| 766 | /* The next two blob_appendf() calls add SQL that causes checkins that |
| 767 | ** are not part of the branch which are parents or childen of the branch |
| 768 | ** to be included in the report. This related check-ins are useful |
| 769 | ** in helping to visualize what has happened on a quiescent branch |
| 770 | ** that is infrequently merged with a much more activate branch. |
| @@ -781,10 +783,11 @@ | |
| 781 | } |
| 782 | blob_appendf(&sql, ")"); |
| 783 | } |
| 784 | if( (zType[0]=='w' && !g.okRdWiki) |
| 785 | || (zType[0]=='t' && !g.okRdTkt) |
| 786 | || (zType[0]=='c' && !g.okRead) |
| 787 | ){ |
| 788 | zType = "all"; |
| 789 | } |
| 790 | if( zType[0]=='a' ){ |
| @@ -794,11 +797,11 @@ | |
| 794 | if( g.okRead ){ |
| 795 | blob_appendf(&sql, "%c'ci'", cSep); |
| 796 | cSep = ','; |
| 797 | } |
| 798 | if( g.okRdWiki ){ |
| 799 | blob_appendf(&sql, "%c'w'", cSep); |
| 800 | cSep = ','; |
| 801 | } |
| 802 | if( g.okRdTkt ){ |
| 803 | blob_appendf(&sql, "%c't'", cSep); |
| 804 | cSep = ','; |
| @@ -812,10 +815,12 @@ | |
| 812 | zEType = "checkin"; |
| 813 | }else if( zType[0]=='w' ){ |
| 814 | zEType = "wiki edit"; |
| 815 | }else if( zType[0]=='t' ){ |
| 816 | zEType = "ticket change"; |
| 817 | } |
| 818 | } |
| 819 | if( zUser ){ |
| 820 | blob_appendf(&sql, " AND event.user=%Q", zUser); |
| 821 | url_add_parameter(&url, "u", zUser); |
| @@ -926,16 +931,19 @@ | |
| 926 | timeline_submenu(&url, "Checkins Only", "y", "ci", 0); |
| 927 | } |
| 928 | if( zType[0]!='t' && g.okRdTkt ){ |
| 929 | timeline_submenu(&url, "Tickets Only", "y", "t", 0); |
| 930 | } |
| 931 | } |
| 932 | if( nEntry>20 ){ |
| 933 | timeline_submenu(&url, "20 Events", "n", "20", 0); |
| 934 | } |
| 935 | if( nEntry<200 ){ |
| 936 | timeline_submenu(&url, "200 Events", "n", "200", 0); |
| 937 | } |
| 938 | } |
| 939 | } |
| 940 | blob_zero(&sql); |
| 941 | db_prepare(&q, "SELECT * FROM timeline ORDER BY timestamp DESC /*scan*/"); |
| 942 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -165,11 +165,11 @@ | |
| 165 | ** 4. User |
| 166 | ** 5. True if is a leaf |
| 167 | ** 6. background color |
| 168 | ** 7. type ("ci", "w", "t") |
| 169 | ** 8. list of symbolic tags. |
| 170 | ** 9. tagid for ticket or wiki or event |
| 171 | ** 10. Short comment to user for repeated tickets and wiki |
| 172 | */ |
| 173 | void www_print_timeline( |
| 174 | Stmt *pQuery, /* Query to implement the timeline */ |
| 175 | int tmFlags, /* Flags controlling display behavior */ |
| @@ -288,10 +288,12 @@ | |
| 288 | @ <span class="timelineLeaf">Closed-Leaf:</span> |
| 289 | }else{ |
| 290 | @ <span class="timelineLeaf">Leaf:</span> |
| 291 | } |
| 292 | } |
| 293 | }else if( zType[0]=='e' && tagid ){ |
| 294 | hyperlink_to_event_tagid(tagid); |
| 295 | }else if( (tmFlags & TIMELINE_ARTID)!=0 ){ |
| 296 | hyperlink_to_uuid(zUuid); |
| 297 | } |
| 298 | db_column_blob(pQuery, commentColumn, &comment); |
| 299 | if( mxWikiLen>0 && blob_size(&comment)>mxWikiLen ){ |
| @@ -639,11 +641,11 @@ | |
| 641 | ** p=RID artifact RID and up to COUNT parents and ancestors |
| 642 | ** d=RID artifact RID and up to COUNT descendants |
| 643 | ** t=TAGID show only check-ins with the given tagid |
| 644 | ** r=TAGID show check-ins related to tagid |
| 645 | ** u=USER only if belonging to this user |
| 646 | ** y=TYPE 'ci', 'w', 't', 'e' |
| 647 | ** s=TEXT string search (comment and brief) |
| 648 | ** ng Suppress the graph if present |
| 649 | ** |
| 650 | ** p= and d= can appear individually or together. If either p= or d= |
| 651 | ** appear, then u=, y=, a=, and b= are ignored. |
| @@ -749,22 +751,22 @@ | |
| 751 | }else{ |
| 752 | blob_appendf(&desc, " of check-in [%.10s]", zUuid); |
| 753 | } |
| 754 | }else{ |
| 755 | int n; |
| 756 | const char *zEType = "timeline item"; |
| 757 | char *zDate; |
| 758 | char *zNEntry = mprintf("%d", nEntry); |
| 759 | url_initialize(&url, "timeline"); |
| 760 | url_add_parameter(&url, "n", zNEntry); |
| 761 | if( tagid>0 ){ |
| 762 | if( zType[0]!='e' ) zType = "ci"; |
| 763 | blob_appendf(&sql, |
| 764 | "AND (EXISTS(SELECT 1 FROM tagxref" |
| 765 | " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)", tagid); |
| 766 | |
| 767 | if( zBrName && zType[0]=='c' ){ |
| 768 | /* The next two blob_appendf() calls add SQL that causes checkins that |
| 769 | ** are not part of the branch which are parents or childen of the branch |
| 770 | ** to be included in the report. This related check-ins are useful |
| 771 | ** in helping to visualize what has happened on a quiescent branch |
| 772 | ** that is infrequently merged with a much more activate branch. |
| @@ -781,10 +783,11 @@ | |
| 783 | } |
| 784 | blob_appendf(&sql, ")"); |
| 785 | } |
| 786 | if( (zType[0]=='w' && !g.okRdWiki) |
| 787 | || (zType[0]=='t' && !g.okRdTkt) |
| 788 | || (zType[0]=='e' && !g.okRdWiki) |
| 789 | || (zType[0]=='c' && !g.okRead) |
| 790 | ){ |
| 791 | zType = "all"; |
| 792 | } |
| 793 | if( zType[0]=='a' ){ |
| @@ -794,11 +797,11 @@ | |
| 797 | if( g.okRead ){ |
| 798 | blob_appendf(&sql, "%c'ci'", cSep); |
| 799 | cSep = ','; |
| 800 | } |
| 801 | if( g.okRdWiki ){ |
| 802 | blob_appendf(&sql, "%c'w','e'", cSep); |
| 803 | cSep = ','; |
| 804 | } |
| 805 | if( g.okRdTkt ){ |
| 806 | blob_appendf(&sql, "%c't'", cSep); |
| 807 | cSep = ','; |
| @@ -812,10 +815,12 @@ | |
| 815 | zEType = "checkin"; |
| 816 | }else if( zType[0]=='w' ){ |
| 817 | zEType = "wiki edit"; |
| 818 | }else if( zType[0]=='t' ){ |
| 819 | zEType = "ticket change"; |
| 820 | }else if( zType[0]=='e' ){ |
| 821 | zEType = "event"; |
| 822 | } |
| 823 | } |
| 824 | if( zUser ){ |
| 825 | blob_appendf(&sql, " AND event.user=%Q", zUser); |
| 826 | url_add_parameter(&url, "u", zUser); |
| @@ -926,16 +931,19 @@ | |
| 931 | timeline_submenu(&url, "Checkins Only", "y", "ci", 0); |
| 932 | } |
| 933 | if( zType[0]!='t' && g.okRdTkt ){ |
| 934 | timeline_submenu(&url, "Tickets Only", "y", "t", 0); |
| 935 | } |
| 936 | if( zType[0]!='e' && g.okRdWiki ){ |
| 937 | timeline_submenu(&url, "Events Only", "y", "e", 0); |
| 938 | } |
| 939 | } |
| 940 | if( nEntry>20 ){ |
| 941 | timeline_submenu(&url, "20 Entries", "n", "20", 0); |
| 942 | } |
| 943 | if( nEntry<200 ){ |
| 944 | timeline_submenu(&url, "200 Entries", "n", "200", 0); |
| 945 | } |
| 946 | } |
| 947 | } |
| 948 | blob_zero(&sql); |
| 949 | db_prepare(&q, "SELECT * FROM timeline ORDER BY timestamp DESC /*scan*/"); |
| 950 |
+7
-3
| --- src/wiki.c | ||
| +++ src/wiki.c | ||
| @@ -106,11 +106,11 @@ | ||
| 106 | 106 | @ <p>This is a stub home-page for the project. |
| 107 | 107 | @ To fill in this page, first go to |
| 108 | 108 | @ <a href="%s(g.zBaseURL)/setup_config">setup/config</a> |
| 109 | 109 | @ and establish a "Project Name". Then create a |
| 110 | 110 | @ wiki page with that name. The content of that wiki page |
| 111 | - @ will be displayed in place of this message. | |
| 111 | + @ will be displayed in place of this message.</p> | |
| 112 | 112 | style_footer(); |
| 113 | 113 | } |
| 114 | 114 | |
| 115 | 115 | /* |
| 116 | 116 | ** Return true if the given pagename is the name of the sandbox |
| @@ -153,10 +153,13 @@ | ||
| 153 | 153 | @ wiki.</li> |
| 154 | 154 | @ <li> Use the <a href="%s(g.zBaseURL)/wiki?name=Sandbox">Sandbox</a> |
| 155 | 155 | @ to experiment.</li> |
| 156 | 156 | if( g.okNewWiki ){ |
| 157 | 157 | @ <li> Create a <a href="%s(g.zBaseURL)/wikinew">new wiki page</a>.</li> |
| 158 | + if( g.okWrite ){ | |
| 159 | + @ <li> Create a <a href="%s(g.zTop)/eventedit">new event</a>.</li> | |
| 160 | + } | |
| 158 | 161 | } |
| 159 | 162 | @ <li> <a href="%s(g.zBaseURL)/wcontent">List of All Wiki Pages</a> |
| 160 | 163 | @ available on this server.</li> |
| 161 | 164 | @ <li> <form method="get" action="%s(g.zBaseURL)/wfind"><div> |
| 162 | 165 | @ Search wiki titles: <input type="text" name="title"/> |
| @@ -223,16 +226,16 @@ | ||
| 223 | 226 | while( db_step(&q)==SQLITE_ROW ){ |
| 224 | 227 | const char *zDate = db_column_text(&q, 0); |
| 225 | 228 | const char *zFile = db_column_text(&q, 1); |
| 226 | 229 | const char *zUser = db_column_text(&q, 2); |
| 227 | 230 | if( cnt==0 ){ |
| 228 | - @ <hr><h2>Attachments:</h2> | |
| 231 | + @ <hr /><h2>Attachments:</h2> | |
| 229 | 232 | @ <ul> |
| 230 | 233 | } |
| 231 | 234 | cnt++; |
| 235 | + @ <li> | |
| 232 | 236 | if( g.okHistory && g.okRead ){ |
| 233 | - @ <li> | |
| 234 | 237 | @ <a href="%s(g.zTop)/attachview?page=%s(zPageName)&file=%t(zFile)"> |
| 235 | 238 | @ %h(zFile)</a> |
| 236 | 239 | }else{ |
| 237 | 240 | @ <li>%h(zFile) |
| 238 | 241 | } |
| @@ -239,10 +242,11 @@ | ||
| 239 | 242 | @ added by %h(zUser) on |
| 240 | 243 | hyperlink_to_date(zDate, "."); |
| 241 | 244 | if( g.okWrWiki && g.okAttach ){ |
| 242 | 245 | @ [<a href="%s(g.zTop)/attachdelete?page=%s(zPageName)&file=%t(zFile)&from=%s(g.zTop)/wiki%%3fname=%s(zPageName)">delete</a>] |
| 243 | 246 | } |
| 247 | + @ </li> | |
| 244 | 248 | } |
| 245 | 249 | if( cnt ){ |
| 246 | 250 | @ </ul> |
| 247 | 251 | } |
| 248 | 252 | db_finalize(&q); |
| 249 | 253 |
| --- src/wiki.c | |
| +++ src/wiki.c | |
| @@ -106,11 +106,11 @@ | |
| 106 | @ <p>This is a stub home-page for the project. |
| 107 | @ To fill in this page, first go to |
| 108 | @ <a href="%s(g.zBaseURL)/setup_config">setup/config</a> |
| 109 | @ and establish a "Project Name". Then create a |
| 110 | @ wiki page with that name. The content of that wiki page |
| 111 | @ will be displayed in place of this message. |
| 112 | style_footer(); |
| 113 | } |
| 114 | |
| 115 | /* |
| 116 | ** Return true if the given pagename is the name of the sandbox |
| @@ -153,10 +153,13 @@ | |
| 153 | @ wiki.</li> |
| 154 | @ <li> Use the <a href="%s(g.zBaseURL)/wiki?name=Sandbox">Sandbox</a> |
| 155 | @ to experiment.</li> |
| 156 | if( g.okNewWiki ){ |
| 157 | @ <li> Create a <a href="%s(g.zBaseURL)/wikinew">new wiki page</a>.</li> |
| 158 | } |
| 159 | @ <li> <a href="%s(g.zBaseURL)/wcontent">List of All Wiki Pages</a> |
| 160 | @ available on this server.</li> |
| 161 | @ <li> <form method="get" action="%s(g.zBaseURL)/wfind"><div> |
| 162 | @ Search wiki titles: <input type="text" name="title"/> |
| @@ -223,16 +226,16 @@ | |
| 223 | while( db_step(&q)==SQLITE_ROW ){ |
| 224 | const char *zDate = db_column_text(&q, 0); |
| 225 | const char *zFile = db_column_text(&q, 1); |
| 226 | const char *zUser = db_column_text(&q, 2); |
| 227 | if( cnt==0 ){ |
| 228 | @ <hr><h2>Attachments:</h2> |
| 229 | @ <ul> |
| 230 | } |
| 231 | cnt++; |
| 232 | if( g.okHistory && g.okRead ){ |
| 233 | @ <li> |
| 234 | @ <a href="%s(g.zTop)/attachview?page=%s(zPageName)&file=%t(zFile)"> |
| 235 | @ %h(zFile)</a> |
| 236 | }else{ |
| 237 | @ <li>%h(zFile) |
| 238 | } |
| @@ -239,10 +242,11 @@ | |
| 239 | @ added by %h(zUser) on |
| 240 | hyperlink_to_date(zDate, "."); |
| 241 | if( g.okWrWiki && g.okAttach ){ |
| 242 | @ [<a href="%s(g.zTop)/attachdelete?page=%s(zPageName)&file=%t(zFile)&from=%s(g.zTop)/wiki%%3fname=%s(zPageName)">delete</a>] |
| 243 | } |
| 244 | } |
| 245 | if( cnt ){ |
| 246 | @ </ul> |
| 247 | } |
| 248 | db_finalize(&q); |
| 249 |
| --- src/wiki.c | |
| +++ src/wiki.c | |
| @@ -106,11 +106,11 @@ | |
| 106 | @ <p>This is a stub home-page for the project. |
| 107 | @ To fill in this page, first go to |
| 108 | @ <a href="%s(g.zBaseURL)/setup_config">setup/config</a> |
| 109 | @ and establish a "Project Name". Then create a |
| 110 | @ wiki page with that name. The content of that wiki page |
| 111 | @ will be displayed in place of this message.</p> |
| 112 | style_footer(); |
| 113 | } |
| 114 | |
| 115 | /* |
| 116 | ** Return true if the given pagename is the name of the sandbox |
| @@ -153,10 +153,13 @@ | |
| 153 | @ wiki.</li> |
| 154 | @ <li> Use the <a href="%s(g.zBaseURL)/wiki?name=Sandbox">Sandbox</a> |
| 155 | @ to experiment.</li> |
| 156 | if( g.okNewWiki ){ |
| 157 | @ <li> Create a <a href="%s(g.zBaseURL)/wikinew">new wiki page</a>.</li> |
| 158 | if( g.okWrite ){ |
| 159 | @ <li> Create a <a href="%s(g.zTop)/eventedit">new event</a>.</li> |
| 160 | } |
| 161 | } |
| 162 | @ <li> <a href="%s(g.zBaseURL)/wcontent">List of All Wiki Pages</a> |
| 163 | @ available on this server.</li> |
| 164 | @ <li> <form method="get" action="%s(g.zBaseURL)/wfind"><div> |
| 165 | @ Search wiki titles: <input type="text" name="title"/> |
| @@ -223,16 +226,16 @@ | |
| 226 | while( db_step(&q)==SQLITE_ROW ){ |
| 227 | const char *zDate = db_column_text(&q, 0); |
| 228 | const char *zFile = db_column_text(&q, 1); |
| 229 | const char *zUser = db_column_text(&q, 2); |
| 230 | if( cnt==0 ){ |
| 231 | @ <hr /><h2>Attachments:</h2> |
| 232 | @ <ul> |
| 233 | } |
| 234 | cnt++; |
| 235 | @ <li> |
| 236 | if( g.okHistory && g.okRead ){ |
| 237 | @ <a href="%s(g.zTop)/attachview?page=%s(zPageName)&file=%t(zFile)"> |
| 238 | @ %h(zFile)</a> |
| 239 | }else{ |
| 240 | @ <li>%h(zFile) |
| 241 | } |
| @@ -239,10 +242,11 @@ | |
| 242 | @ added by %h(zUser) on |
| 243 | hyperlink_to_date(zDate, "."); |
| 244 | if( g.okWrWiki && g.okAttach ){ |
| 245 | @ [<a href="%s(g.zTop)/attachdelete?page=%s(zPageName)&file=%t(zFile)&from=%s(g.zTop)/wiki%%3fname=%s(zPageName)">delete</a>] |
| 246 | } |
| 247 | @ </li> |
| 248 | } |
| 249 | if( cnt ){ |
| 250 | @ </ul> |
| 251 | } |
| 252 | db_finalize(&q); |
| 253 |
+4
-2
| --- src/xfer.c | ||
| +++ src/xfer.c | ||
| @@ -119,22 +119,24 @@ | ||
| 119 | 119 | if( uuid_is_shunned(blob_str(&pXfer->aToken[1])) ){ |
| 120 | 120 | /* Ignore files that have been shunned */ |
| 121 | 121 | return; |
| 122 | 122 | } |
| 123 | 123 | if( pXfer->nToken==4 ){ |
| 124 | - Blob src; | |
| 124 | + Blob src, next; | |
| 125 | 125 | srcid = rid_from_uuid(&pXfer->aToken[2], 1); |
| 126 | 126 | if( content_get(srcid, &src)==0 ){ |
| 127 | 127 | rid = content_put(&content, blob_str(&pXfer->aToken[1]), srcid); |
| 128 | 128 | pXfer->nDanglingFile++; |
| 129 | 129 | db_multi_exec("DELETE FROM phantom WHERE rid=%d", rid); |
| 130 | 130 | content_make_public(rid); |
| 131 | 131 | return; |
| 132 | 132 | } |
| 133 | 133 | pXfer->nDeltaRcvd++; |
| 134 | - blob_delta_apply(&src, &content, &content); | |
| 134 | + blob_delta_apply(&src, &content, &next); | |
| 135 | 135 | blob_reset(&src); |
| 136 | + blob_reset(&content); | |
| 137 | + content = next; | |
| 136 | 138 | }else{ |
| 137 | 139 | pXfer->nFileRcvd++; |
| 138 | 140 | } |
| 139 | 141 | sha1sum_blob(&content, &hash); |
| 140 | 142 | if( !blob_eq_str(&pXfer->aToken[1], blob_str(&hash), -1) ){ |
| 141 | 143 |
| --- src/xfer.c | |
| +++ src/xfer.c | |
| @@ -119,22 +119,24 @@ | |
| 119 | if( uuid_is_shunned(blob_str(&pXfer->aToken[1])) ){ |
| 120 | /* Ignore files that have been shunned */ |
| 121 | return; |
| 122 | } |
| 123 | if( pXfer->nToken==4 ){ |
| 124 | Blob src; |
| 125 | srcid = rid_from_uuid(&pXfer->aToken[2], 1); |
| 126 | if( content_get(srcid, &src)==0 ){ |
| 127 | rid = content_put(&content, blob_str(&pXfer->aToken[1]), srcid); |
| 128 | pXfer->nDanglingFile++; |
| 129 | db_multi_exec("DELETE FROM phantom WHERE rid=%d", rid); |
| 130 | content_make_public(rid); |
| 131 | return; |
| 132 | } |
| 133 | pXfer->nDeltaRcvd++; |
| 134 | blob_delta_apply(&src, &content, &content); |
| 135 | blob_reset(&src); |
| 136 | }else{ |
| 137 | pXfer->nFileRcvd++; |
| 138 | } |
| 139 | sha1sum_blob(&content, &hash); |
| 140 | if( !blob_eq_str(&pXfer->aToken[1], blob_str(&hash), -1) ){ |
| 141 |
| --- src/xfer.c | |
| +++ src/xfer.c | |
| @@ -119,22 +119,24 @@ | |
| 119 | if( uuid_is_shunned(blob_str(&pXfer->aToken[1])) ){ |
| 120 | /* Ignore files that have been shunned */ |
| 121 | return; |
| 122 | } |
| 123 | if( pXfer->nToken==4 ){ |
| 124 | Blob src, next; |
| 125 | srcid = rid_from_uuid(&pXfer->aToken[2], 1); |
| 126 | if( content_get(srcid, &src)==0 ){ |
| 127 | rid = content_put(&content, blob_str(&pXfer->aToken[1]), srcid); |
| 128 | pXfer->nDanglingFile++; |
| 129 | db_multi_exec("DELETE FROM phantom WHERE rid=%d", rid); |
| 130 | content_make_public(rid); |
| 131 | return; |
| 132 | } |
| 133 | pXfer->nDeltaRcvd++; |
| 134 | blob_delta_apply(&src, &content, &next); |
| 135 | blob_reset(&src); |
| 136 | blob_reset(&content); |
| 137 | content = next; |
| 138 | }else{ |
| 139 | pXfer->nFileRcvd++; |
| 140 | } |
| 141 | sha1sum_blob(&content, &hash); |
| 142 | if( !blob_eq_str(&pXfer->aToken[1], blob_str(&hash), -1) ){ |
| 143 |
+1
-1
| --- win/Makefile.PellesCGMake | ||
| +++ win/Makefile.PellesCGMake | ||
| @@ -60,11 +60,11 @@ | ||
| 60 | 60 | INCLUDE=/I $(PellesCDir)\Include\Win /I $(PellesCDir)\Include /I $(ZLIBSRCDIR) /I $(SRCDIR) |
| 61 | 61 | |
| 62 | 62 | UTILS=translate.exe mkindex.exe makeheaders.exe |
| 63 | 63 | UTILS_OBJ=$(UTILS:.exe=.obj) |
| 64 | 64 | |
| 65 | -SRC=add.c allrepo.c attach.c bag.c blob.c branch.c browse.c captcha.c cgi.c checkin.c checkout.c clearsign.c clone.c comformat.c configure.c content.c db.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 info.c login.c main.c manifest.c md5.c merge.c merge3.c name.c pivot.c popen.c pqueue.c printf.c rebuild.c report.c rss.c schema.c search.c setup.c sha1.c shun.c skins.c stat.c style.c sync.c tag.c th_main.c timeline.c tkt.c tktsetup.c undo.c update.c url.c user.c verify.c vfile.c wiki.c wikiformat.c winhttp.c xfer.c zip.c | |
| 65 | +SRC=add.c allrepo.c attach.c bag.c blob.c branch.c browse.c captcha.c cgi.c checkin.c checkout.c clearsign.c clone.c comformat.c configure.c content.c db.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 info.c login.c main.c manifest.c md5.c merge.c merge3.c name.c pivot.c popen.c pqueue.c printf.c rebuild.c report.c rss.c schema.c search.c setup.c sha1.c shun.c skins.c stat.c style.c sync.c tag.c th_main.c timeline.c tkt.c tktsetup.c undo.c update.c url.c user.c verify.c vfile.c wiki.c wikiformat.c winhttp.c xfer.c zip.c | |
| 66 | 66 | ORIGSRC=$(foreach sf,$(SRC),$(SRCDIR)$(sf)) |
| 67 | 67 | TRANSLATEDSRC=$(SRC:.c=_.c) |
| 68 | 68 | TRANSLATEDOBJ=$(TRANSLATEDSRC:.c=.obj) |
| 69 | 69 | |
| 70 | 70 | SQLITESRC=sqlite3.c |
| 71 | 71 |
| --- win/Makefile.PellesCGMake | |
| +++ win/Makefile.PellesCGMake | |
| @@ -60,11 +60,11 @@ | |
| 60 | INCLUDE=/I $(PellesCDir)\Include\Win /I $(PellesCDir)\Include /I $(ZLIBSRCDIR) /I $(SRCDIR) |
| 61 | |
| 62 | UTILS=translate.exe mkindex.exe makeheaders.exe |
| 63 | UTILS_OBJ=$(UTILS:.exe=.obj) |
| 64 | |
| 65 | SRC=add.c allrepo.c attach.c bag.c blob.c branch.c browse.c captcha.c cgi.c checkin.c checkout.c clearsign.c clone.c comformat.c configure.c content.c db.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 info.c login.c main.c manifest.c md5.c merge.c merge3.c name.c pivot.c popen.c pqueue.c printf.c rebuild.c report.c rss.c schema.c search.c setup.c sha1.c shun.c skins.c stat.c style.c sync.c tag.c th_main.c timeline.c tkt.c tktsetup.c undo.c update.c url.c user.c verify.c vfile.c wiki.c wikiformat.c winhttp.c xfer.c zip.c |
| 66 | ORIGSRC=$(foreach sf,$(SRC),$(SRCDIR)$(sf)) |
| 67 | TRANSLATEDSRC=$(SRC:.c=_.c) |
| 68 | TRANSLATEDOBJ=$(TRANSLATEDSRC:.c=.obj) |
| 69 | |
| 70 | SQLITESRC=sqlite3.c |
| 71 |
| --- win/Makefile.PellesCGMake | |
| +++ win/Makefile.PellesCGMake | |
| @@ -60,11 +60,11 @@ | |
| 60 | INCLUDE=/I $(PellesCDir)\Include\Win /I $(PellesCDir)\Include /I $(ZLIBSRCDIR) /I $(SRCDIR) |
| 61 | |
| 62 | UTILS=translate.exe mkindex.exe makeheaders.exe |
| 63 | UTILS_OBJ=$(UTILS:.exe=.obj) |
| 64 | |
| 65 | SRC=add.c allrepo.c attach.c bag.c blob.c branch.c browse.c captcha.c cgi.c checkin.c checkout.c clearsign.c clone.c comformat.c configure.c content.c db.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 info.c login.c main.c manifest.c md5.c merge.c merge3.c name.c pivot.c popen.c pqueue.c printf.c rebuild.c report.c rss.c schema.c search.c setup.c sha1.c shun.c skins.c stat.c style.c sync.c tag.c th_main.c timeline.c tkt.c tktsetup.c undo.c update.c url.c user.c verify.c vfile.c wiki.c wikiformat.c winhttp.c xfer.c zip.c |
| 66 | ORIGSRC=$(foreach sf,$(SRC),$(SRCDIR)$(sf)) |
| 67 | TRANSLATEDSRC=$(SRC:.c=_.c) |
| 68 | TRANSLATEDOBJ=$(TRANSLATEDSRC:.c=.obj) |
| 69 | |
| 70 | SQLITESRC=sqlite3.c |
| 71 |
+10
-4
| --- win/Makefile.dmc | ||
| +++ win/Makefile.dmc | ||
| @@ -24,13 +24,13 @@ | ||
| 24 | 24 | CFLAGS = -o |
| 25 | 25 | BCC = $(DMDIR)\bin\dmc $(CFLAGS) |
| 26 | 26 | TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(I18N) $(SSL) $(INCL) |
| 27 | 27 | LIBS = $(DMDIR)\extra\lib\ zlib wsock32 |
| 28 | 28 | |
| 29 | -SRC = add_.c allrepo_.c attach_.c bag_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.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 info_.c login_.c main_.c manifest_.c md5_.c merge_.c merge3_.c name_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c stat_.c style_.c sync_.c tag_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c update_.c url_.c user_.c verify_.c vfile_.c wiki_.c wikiformat_.c winhttp_.c xfer_.c zip_.c | |
| 29 | +SRC = add_.c allrepo_.c attach_.c bag_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.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 info_.c login_.c main_.c manifest_.c md5_.c merge_.c merge3_.c name_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c stat_.c style_.c sync_.c tag_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c update_.c url_.c user_.c verify_.c vfile_.c wiki_.c wikiformat_.c winhttp_.c xfer_.c zip_.c | |
| 30 | 30 | |
| 31 | -OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(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 $(OBJDIR)\info$O $(OBJDIR)\login$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\name$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\rebuild$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\skins$O $(OBJDIR)\stat$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winhttp$O $(OBJDIR)\xfer$O $(OBJDIR)\zip$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O | |
| 31 | +OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(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 $(OBJDIR)\info$O $(OBJDIR)\login$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\name$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\rebuild$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\skins$O $(OBJDIR)\stat$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winhttp$O $(OBJDIR)\xfer$O $(OBJDIR)\zip$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O | |
| 32 | 32 | |
| 33 | 33 | |
| 34 | 34 | APPNAME = $(OBJDIR)\fossil$(E) |
| 35 | 35 | |
| 36 | 36 | all: $(APPNAME) |
| @@ -38,11 +38,11 @@ | ||
| 38 | 38 | $(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OBJDIR)\link |
| 39 | 39 | cd $(OBJDIR) |
| 40 | 40 | $(DMDIR)\bin\link @link |
| 41 | 41 | |
| 42 | 42 | $(OBJDIR)\link: $B\win\Makefile.dmc |
| 43 | - +echo add allrepo attach bag blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode file finfo graph http http_socket http_ssl http_transport info login main manifest md5 merge merge3 name pivot popen pqueue printf rebuild report rss schema search setup sha1 shun skins stat style sync tag th_main timeline tkt tktsetup undo update url user verify vfile wiki wikiformat winhttp xfer zip sqlite3 th th_lang > $@ | |
| 43 | + +echo add allrepo attach bag blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event file finfo graph http http_socket http_ssl http_transport info login main manifest md5 merge merge3 name pivot popen pqueue printf rebuild report rss schema search setup sha1 shun skins stat style sync tag th_main timeline tkt tktsetup undo update url user verify vfile wiki wikiformat winhttp xfer zip sqlite3 th th_lang > $@ | |
| 44 | 44 | +echo fossil >> $@ |
| 45 | 45 | +echo fossil >> $@ |
| 46 | 46 | +echo $(LIBS) >> $@ |
| 47 | 47 | |
| 48 | 48 | |
| @@ -217,10 +217,16 @@ | ||
| 217 | 217 | $(OBJDIR)\doc$O : doc_.c doc.h |
| 218 | 218 | $(TCC) -o$@ -c doc_.c |
| 219 | 219 | |
| 220 | 220 | doc_.c : $(SRCDIR)\doc.c |
| 221 | 221 | +translate$E $** > $@ |
| 222 | + | |
| 223 | +$(OBJDIR)\event$O : event_.c event.h | |
| 224 | + $(TCC) -o$@ -c event_.c | |
| 225 | + | |
| 226 | +event_.c : $(SRCDIR)\event.c | |
| 227 | + +translate$E $** > $@ | |
| 222 | 228 | |
| 223 | 229 | $(OBJDIR)\encode$O : encode_.c encode.h |
| 224 | 230 | $(TCC) -o$@ -c encode_.c |
| 225 | 231 | |
| 226 | 232 | encode_.c : $(SRCDIR)\encode.c |
| @@ -507,7 +513,7 @@ | ||
| 507 | 513 | |
| 508 | 514 | zip_.c : $(SRCDIR)\zip.c |
| 509 | 515 | +translate$E $** > $@ |
| 510 | 516 | |
| 511 | 517 | headers: makeheaders$E page_index.h VERSION.h |
| 512 | - +makeheaders$E 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 | |
| 518 | + +makeheaders$E 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 | |
| 513 | 519 | @copy /Y nul: headers |
| 514 | 520 |
| --- win/Makefile.dmc | |
| +++ win/Makefile.dmc | |
| @@ -24,13 +24,13 @@ | |
| 24 | CFLAGS = -o |
| 25 | BCC = $(DMDIR)\bin\dmc $(CFLAGS) |
| 26 | TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(I18N) $(SSL) $(INCL) |
| 27 | LIBS = $(DMDIR)\extra\lib\ zlib wsock32 |
| 28 | |
| 29 | SRC = add_.c allrepo_.c attach_.c bag_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.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 info_.c login_.c main_.c manifest_.c md5_.c merge_.c merge3_.c name_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c stat_.c style_.c sync_.c tag_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c update_.c url_.c user_.c verify_.c vfile_.c wiki_.c wikiformat_.c winhttp_.c xfer_.c zip_.c |
| 30 | |
| 31 | OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(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 $(OBJDIR)\info$O $(OBJDIR)\login$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\name$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\rebuild$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\skins$O $(OBJDIR)\stat$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winhttp$O $(OBJDIR)\xfer$O $(OBJDIR)\zip$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O |
| 32 | |
| 33 | |
| 34 | APPNAME = $(OBJDIR)\fossil$(E) |
| 35 | |
| 36 | all: $(APPNAME) |
| @@ -38,11 +38,11 @@ | |
| 38 | $(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OBJDIR)\link |
| 39 | cd $(OBJDIR) |
| 40 | $(DMDIR)\bin\link @link |
| 41 | |
| 42 | $(OBJDIR)\link: $B\win\Makefile.dmc |
| 43 | +echo add allrepo attach bag blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode file finfo graph http http_socket http_ssl http_transport info login main manifest md5 merge merge3 name pivot popen pqueue printf rebuild report rss schema search setup sha1 shun skins stat style sync tag th_main timeline tkt tktsetup undo update url user verify vfile wiki wikiformat winhttp xfer zip sqlite3 th th_lang > $@ |
| 44 | +echo fossil >> $@ |
| 45 | +echo fossil >> $@ |
| 46 | +echo $(LIBS) >> $@ |
| 47 | |
| 48 | |
| @@ -217,10 +217,16 @@ | |
| 217 | $(OBJDIR)\doc$O : doc_.c doc.h |
| 218 | $(TCC) -o$@ -c doc_.c |
| 219 | |
| 220 | doc_.c : $(SRCDIR)\doc.c |
| 221 | +translate$E $** > $@ |
| 222 | |
| 223 | $(OBJDIR)\encode$O : encode_.c encode.h |
| 224 | $(TCC) -o$@ -c encode_.c |
| 225 | |
| 226 | encode_.c : $(SRCDIR)\encode.c |
| @@ -507,7 +513,7 @@ | |
| 507 | |
| 508 | zip_.c : $(SRCDIR)\zip.c |
| 509 | +translate$E $** > $@ |
| 510 | |
| 511 | headers: makeheaders$E page_index.h VERSION.h |
| 512 | +makeheaders$E 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 |
| 513 | @copy /Y nul: headers |
| 514 |
| --- win/Makefile.dmc | |
| +++ win/Makefile.dmc | |
| @@ -24,13 +24,13 @@ | |
| 24 | CFLAGS = -o |
| 25 | BCC = $(DMDIR)\bin\dmc $(CFLAGS) |
| 26 | TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(I18N) $(SSL) $(INCL) |
| 27 | LIBS = $(DMDIR)\extra\lib\ zlib wsock32 |
| 28 | |
| 29 | SRC = add_.c allrepo_.c attach_.c bag_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.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 info_.c login_.c main_.c manifest_.c md5_.c merge_.c merge3_.c name_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c stat_.c style_.c sync_.c tag_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c update_.c url_.c user_.c verify_.c vfile_.c wiki_.c wikiformat_.c winhttp_.c xfer_.c zip_.c |
| 30 | |
| 31 | OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(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 $(OBJDIR)\info$O $(OBJDIR)\login$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\name$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\rebuild$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\skins$O $(OBJDIR)\stat$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winhttp$O $(OBJDIR)\xfer$O $(OBJDIR)\zip$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O |
| 32 | |
| 33 | |
| 34 | APPNAME = $(OBJDIR)\fossil$(E) |
| 35 | |
| 36 | all: $(APPNAME) |
| @@ -38,11 +38,11 @@ | |
| 38 | $(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OBJDIR)\link |
| 39 | cd $(OBJDIR) |
| 40 | $(DMDIR)\bin\link @link |
| 41 | |
| 42 | $(OBJDIR)\link: $B\win\Makefile.dmc |
| 43 | +echo add allrepo attach bag blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event file finfo graph http http_socket http_ssl http_transport info login main manifest md5 merge merge3 name pivot popen pqueue printf rebuild report rss schema search setup sha1 shun skins stat style sync tag th_main timeline tkt tktsetup undo update url user verify vfile wiki wikiformat winhttp xfer zip sqlite3 th th_lang > $@ |
| 44 | +echo fossil >> $@ |
| 45 | +echo fossil >> $@ |
| 46 | +echo $(LIBS) >> $@ |
| 47 | |
| 48 | |
| @@ -217,10 +217,16 @@ | |
| 217 | $(OBJDIR)\doc$O : doc_.c doc.h |
| 218 | $(TCC) -o$@ -c doc_.c |
| 219 | |
| 220 | doc_.c : $(SRCDIR)\doc.c |
| 221 | +translate$E $** > $@ |
| 222 | |
| 223 | $(OBJDIR)\event$O : event_.c event.h |
| 224 | $(TCC) -o$@ -c event_.c |
| 225 | |
| 226 | event_.c : $(SRCDIR)\event.c |
| 227 | +translate$E $** > $@ |
| 228 | |
| 229 | $(OBJDIR)\encode$O : encode_.c encode.h |
| 230 | $(TCC) -o$@ -c encode_.c |
| 231 | |
| 232 | encode_.c : $(SRCDIR)\encode.c |
| @@ -507,7 +513,7 @@ | |
| 513 | |
| 514 | zip_.c : $(SRCDIR)\zip.c |
| 515 | +translate$E $** > $@ |
| 516 | |
| 517 | headers: makeheaders$E page_index.h VERSION.h |
| 518 | +makeheaders$E 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 |
| 519 | @copy /Y nul: headers |
| 520 |
+10
-4
| --- win/Makefile.dmc | ||
| +++ win/Makefile.dmc | ||
| @@ -24,13 +24,13 @@ | ||
| 24 | 24 | CFLAGS = -o |
| 25 | 25 | BCC = $(DMDIR)\bin\dmc $(CFLAGS) |
| 26 | 26 | TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(I18N) $(SSL) $(INCL) |
| 27 | 27 | LIBS = $(DMDIR)\extra\lib\ zlib wsock32 |
| 28 | 28 | |
| 29 | -SRC = add_.c allrepo_.c attach_.c bag_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.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 info_.c login_.c main_.c manifest_.c md5_.c merge_.c merge3_.c name_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c stat_.c style_.c sync_.c tag_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c update_.c url_.c user_.c verify_.c vfile_.c wiki_.c wikiformat_.c winhttp_.c xfer_.c zip_.c | |
| 29 | +SRC = add_.c allrepo_.c attach_.c bag_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.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 info_.c login_.c main_.c manifest_.c md5_.c merge_.c merge3_.c name_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c stat_.c style_.c sync_.c tag_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c update_.c url_.c user_.c verify_.c vfile_.c wiki_.c wikiformat_.c winhttp_.c xfer_.c zip_.c | |
| 30 | 30 | |
| 31 | -OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(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 $(OBJDIR)\info$O $(OBJDIR)\login$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\name$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\rebuild$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\skins$O $(OBJDIR)\stat$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winhttp$O $(OBJDIR)\xfer$O $(OBJDIR)\zip$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O | |
| 31 | +OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(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 $(OBJDIR)\info$O $(OBJDIR)\login$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\name$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\rebuild$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\skins$O $(OBJDIR)\stat$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winhttp$O $(OBJDIR)\xfer$O $(OBJDIR)\zip$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O | |
| 32 | 32 | |
| 33 | 33 | |
| 34 | 34 | APPNAME = $(OBJDIR)\fossil$(E) |
| 35 | 35 | |
| 36 | 36 | all: $(APPNAME) |
| @@ -38,11 +38,11 @@ | ||
| 38 | 38 | $(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OBJDIR)\link |
| 39 | 39 | cd $(OBJDIR) |
| 40 | 40 | $(DMDIR)\bin\link @link |
| 41 | 41 | |
| 42 | 42 | $(OBJDIR)\link: $B\win\Makefile.dmc |
| 43 | - +echo add allrepo attach bag blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode file finfo graph http http_socket http_ssl http_transport info login main manifest md5 merge merge3 name pivot popen pqueue printf rebuild report rss schema search setup sha1 shun skins stat style sync tag th_main timeline tkt tktsetup undo update url user verify vfile wiki wikiformat winhttp xfer zip sqlite3 th th_lang > $@ | |
| 43 | + +echo add allrepo attach bag blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event file finfo graph http http_socket http_ssl http_transport info login main manifest md5 merge merge3 name pivot popen pqueue printf rebuild report rss schema search setup sha1 shun skins stat style sync tag th_main timeline tkt tktsetup undo update url user verify vfile wiki wikiformat winhttp xfer zip sqlite3 th th_lang > $@ | |
| 44 | 44 | +echo fossil >> $@ |
| 45 | 45 | +echo fossil >> $@ |
| 46 | 46 | +echo $(LIBS) >> $@ |
| 47 | 47 | |
| 48 | 48 | |
| @@ -217,10 +217,16 @@ | ||
| 217 | 217 | $(OBJDIR)\doc$O : doc_.c doc.h |
| 218 | 218 | $(TCC) -o$@ -c doc_.c |
| 219 | 219 | |
| 220 | 220 | doc_.c : $(SRCDIR)\doc.c |
| 221 | 221 | +translate$E $** > $@ |
| 222 | + | |
| 223 | +$(OBJDIR)\event$O : event_.c event.h | |
| 224 | + $(TCC) -o$@ -c event_.c | |
| 225 | + | |
| 226 | +event_.c : $(SRCDIR)\event.c | |
| 227 | + +translate$E $** > $@ | |
| 222 | 228 | |
| 223 | 229 | $(OBJDIR)\encode$O : encode_.c encode.h |
| 224 | 230 | $(TCC) -o$@ -c encode_.c |
| 225 | 231 | |
| 226 | 232 | encode_.c : $(SRCDIR)\encode.c |
| @@ -507,7 +513,7 @@ | ||
| 507 | 513 | |
| 508 | 514 | zip_.c : $(SRCDIR)\zip.c |
| 509 | 515 | +translate$E $** > $@ |
| 510 | 516 | |
| 511 | 517 | headers: makeheaders$E page_index.h VERSION.h |
| 512 | - +makeheaders$E 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 | |
| 518 | + +makeheaders$E 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 | |
| 513 | 519 | @copy /Y nul: headers |
| 514 | 520 |
| --- win/Makefile.dmc | |
| +++ win/Makefile.dmc | |
| @@ -24,13 +24,13 @@ | |
| 24 | CFLAGS = -o |
| 25 | BCC = $(DMDIR)\bin\dmc $(CFLAGS) |
| 26 | TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(I18N) $(SSL) $(INCL) |
| 27 | LIBS = $(DMDIR)\extra\lib\ zlib wsock32 |
| 28 | |
| 29 | SRC = add_.c allrepo_.c attach_.c bag_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.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 info_.c login_.c main_.c manifest_.c md5_.c merge_.c merge3_.c name_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c stat_.c style_.c sync_.c tag_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c update_.c url_.c user_.c verify_.c vfile_.c wiki_.c wikiformat_.c winhttp_.c xfer_.c zip_.c |
| 30 | |
| 31 | OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(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 $(OBJDIR)\info$O $(OBJDIR)\login$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\name$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\rebuild$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\skins$O $(OBJDIR)\stat$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winhttp$O $(OBJDIR)\xfer$O $(OBJDIR)\zip$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O |
| 32 | |
| 33 | |
| 34 | APPNAME = $(OBJDIR)\fossil$(E) |
| 35 | |
| 36 | all: $(APPNAME) |
| @@ -38,11 +38,11 @@ | |
| 38 | $(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OBJDIR)\link |
| 39 | cd $(OBJDIR) |
| 40 | $(DMDIR)\bin\link @link |
| 41 | |
| 42 | $(OBJDIR)\link: $B\win\Makefile.dmc |
| 43 | +echo add allrepo attach bag blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode file finfo graph http http_socket http_ssl http_transport info login main manifest md5 merge merge3 name pivot popen pqueue printf rebuild report rss schema search setup sha1 shun skins stat style sync tag th_main timeline tkt tktsetup undo update url user verify vfile wiki wikiformat winhttp xfer zip sqlite3 th th_lang > $@ |
| 44 | +echo fossil >> $@ |
| 45 | +echo fossil >> $@ |
| 46 | +echo $(LIBS) >> $@ |
| 47 | |
| 48 | |
| @@ -217,10 +217,16 @@ | |
| 217 | $(OBJDIR)\doc$O : doc_.c doc.h |
| 218 | $(TCC) -o$@ -c doc_.c |
| 219 | |
| 220 | doc_.c : $(SRCDIR)\doc.c |
| 221 | +translate$E $** > $@ |
| 222 | |
| 223 | $(OBJDIR)\encode$O : encode_.c encode.h |
| 224 | $(TCC) -o$@ -c encode_.c |
| 225 | |
| 226 | encode_.c : $(SRCDIR)\encode.c |
| @@ -507,7 +513,7 @@ | |
| 507 | |
| 508 | zip_.c : $(SRCDIR)\zip.c |
| 509 | +translate$E $** > $@ |
| 510 | |
| 511 | headers: makeheaders$E page_index.h VERSION.h |
| 512 | +makeheaders$E 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 |
| 513 | @copy /Y nul: headers |
| 514 |
| --- win/Makefile.dmc | |
| +++ win/Makefile.dmc | |
| @@ -24,13 +24,13 @@ | |
| 24 | CFLAGS = -o |
| 25 | BCC = $(DMDIR)\bin\dmc $(CFLAGS) |
| 26 | TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(I18N) $(SSL) $(INCL) |
| 27 | LIBS = $(DMDIR)\extra\lib\ zlib wsock32 |
| 28 | |
| 29 | SRC = add_.c allrepo_.c attach_.c bag_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.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 info_.c login_.c main_.c manifest_.c md5_.c merge_.c merge3_.c name_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c stat_.c style_.c sync_.c tag_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c update_.c url_.c user_.c verify_.c vfile_.c wiki_.c wikiformat_.c winhttp_.c xfer_.c zip_.c |
| 30 | |
| 31 | OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(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 $(OBJDIR)\info$O $(OBJDIR)\login$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\name$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\rebuild$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\skins$O $(OBJDIR)\stat$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winhttp$O $(OBJDIR)\xfer$O $(OBJDIR)\zip$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O |
| 32 | |
| 33 | |
| 34 | APPNAME = $(OBJDIR)\fossil$(E) |
| 35 | |
| 36 | all: $(APPNAME) |
| @@ -38,11 +38,11 @@ | |
| 38 | $(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OBJDIR)\link |
| 39 | cd $(OBJDIR) |
| 40 | $(DMDIR)\bin\link @link |
| 41 | |
| 42 | $(OBJDIR)\link: $B\win\Makefile.dmc |
| 43 | +echo add allrepo attach bag blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event file finfo graph http http_socket http_ssl http_transport info login main manifest md5 merge merge3 name pivot popen pqueue printf rebuild report rss schema search setup sha1 shun skins stat style sync tag th_main timeline tkt tktsetup undo update url user verify vfile wiki wikiformat winhttp xfer zip sqlite3 th th_lang > $@ |
| 44 | +echo fossil >> $@ |
| 45 | +echo fossil >> $@ |
| 46 | +echo $(LIBS) >> $@ |
| 47 | |
| 48 | |
| @@ -217,10 +217,16 @@ | |
| 217 | $(OBJDIR)\doc$O : doc_.c doc.h |
| 218 | $(TCC) -o$@ -c doc_.c |
| 219 | |
| 220 | doc_.c : $(SRCDIR)\doc.c |
| 221 | +translate$E $** > $@ |
| 222 | |
| 223 | $(OBJDIR)\event$O : event_.c event.h |
| 224 | $(TCC) -o$@ -c event_.c |
| 225 | |
| 226 | event_.c : $(SRCDIR)\event.c |
| 227 | +translate$E $** > $@ |
| 228 | |
| 229 | $(OBJDIR)\encode$O : encode_.c encode.h |
| 230 | $(TCC) -o$@ -c encode_.c |
| 231 | |
| 232 | encode_.c : $(SRCDIR)\encode.c |
| @@ -507,7 +513,7 @@ | |
| 513 | |
| 514 | zip_.c : $(SRCDIR)\zip.c |
| 515 | +translate$E $** > $@ |
| 516 | |
| 517 | headers: makeheaders$E page_index.h VERSION.h |
| 518 | +makeheaders$E 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 |
| 519 | @copy /Y nul: headers |
| 520 |
+1
| --- www/branching.wiki | ||
| +++ www/branching.wiki | ||
| @@ -155,10 +155,11 @@ | ||
| 155 | 155 | accident that stems from concurrent development. In figure 4, giving |
| 156 | 156 | check-in 2 multiple children is a deliberate act. So, to a good |
| 157 | 157 | approximation, we define forking to be by accident and branching to |
| 158 | 158 | be by intent. Apart from that, they are the same. |
| 159 | 159 | |
| 160 | +<a name="tags"></a> | |
| 160 | 161 | <h2>Tags And Properties</h2> |
| 161 | 162 | |
| 162 | 163 | Tags and properties are used in fossil to help express the intent, and |
| 163 | 164 | thus to distinguish between forks and branches. Figure 5 shows the |
| 164 | 165 | same scenario as figure 4 but with tags and properties added: |
| 165 | 166 | |
| 166 | 167 | ADDED www/event.wiki |
| --- www/branching.wiki | |
| +++ www/branching.wiki | |
| @@ -155,10 +155,11 @@ | |
| 155 | accident that stems from concurrent development. In figure 4, giving |
| 156 | check-in 2 multiple children is a deliberate act. So, to a good |
| 157 | approximation, we define forking to be by accident and branching to |
| 158 | be by intent. Apart from that, they are the same. |
| 159 | |
| 160 | <h2>Tags And Properties</h2> |
| 161 | |
| 162 | Tags and properties are used in fossil to help express the intent, and |
| 163 | thus to distinguish between forks and branches. Figure 5 shows the |
| 164 | same scenario as figure 4 but with tags and properties added: |
| 165 | |
| 166 | DDED www/event.wiki |
| --- www/branching.wiki | |
| +++ www/branching.wiki | |
| @@ -155,10 +155,11 @@ | |
| 155 | accident that stems from concurrent development. In figure 4, giving |
| 156 | check-in 2 multiple children is a deliberate act. So, to a good |
| 157 | approximation, we define forking to be by accident and branching to |
| 158 | be by intent. Apart from that, they are the same. |
| 159 | |
| 160 | <a name="tags"></a> |
| 161 | <h2>Tags And Properties</h2> |
| 162 | |
| 163 | Tags and properties are used in fossil to help express the intent, and |
| 164 | thus to distinguish between forks and branches. Figure 5 shows the |
| 165 | same scenario as figure 4 but with tags and properties added: |
| 166 | |
| 167 | DDED www/event.wiki |
+35
| --- a/www/event.wiki | ||
| +++ b/www/event.wiki | ||
| @@ -0,0 +1,35 @@ | ||
| 1 | +<title>Eventes</title> | |
| 2 | + | |
| 3 | +<h2>What Is A "Event"?</h2>e?y=<titl | |
| 4 | +Possible uses for technotes include: | |
| 5 | + | |
| 6 | + * <b>Milestones</b>. Project milestones, such as releases or beta-test | |
| 7 | + cycles, can be recorded as technotes. The timeline entry for the technote | |
| 8 | + can be something simple like "Version 1.2.3" perhaps with a bright | |
| 9 | + color background to draw attention to the entry and the wiki content | |
| 10 | + can contain release notes, for example. | |
| 11 | + | |
| 12 | + * <b>Blog Entries</b>. Blog entries from developers describing the current | |
| 13 | + state of a project, or rational for v arious design decisions, or | |
| 14 | + roadmaps for future development, can be entered as technotes. | |
| 15 | + | |
| 16 | + * <b>Process Checkpoints</b>. For projects that have a formal process, | |
| 17 | + technotes can be used to record the completion or the initiation of | |
| 18 | + various process steps. For example, a technote can be used to record | |
| 19 | + the successful completion of a long-running test, perhaps w[./wikitheory.wiki | wiki page] | |
| 20 | +that is associated with a point in time rather thaevent causes a si [/timelinhyperlink ofTimeline Page]entry cause a jump to the wiThe wiki content, the timeline entry text, the | |
| 21 | +time of the eventTechnical Notes</title> | |
| 22 | + | |
| 23 | +<h2>What Is A "Technote"?</h2> | |
| 24 | + | |
| 25 | +In Fossil, a "technical note" or "technoteventerly called an "event") | |
| 26 | +is a speeventiki page] | |
| 27 | +that is associated with a point in time rather than having a page name. | |
| 28 | +eventaving a page name. | |
| 29 | +Each technote causes a single entry to appear on the | |
| 30 | +[/timeline?y=<titl | |
| 31 | +Possible uses for technotes include: | |
| 32 | + | |
| 33 | + * <b>Milestones</b>. Project milestones, such as releases or beta-test | |
| 34 | + cycles, can be recorded as technotes. The timeline entry for the technote | |
| 35 | + can be something simple like "V |
| --- a/www/event.wiki | |
| +++ b/www/event.wiki | |
| @@ -0,0 +1,35 @@ | |
| --- a/www/event.wiki | |
| +++ b/www/event.wiki | |
| @@ -0,0 +1,35 @@ | |
| 1 | <title>Eventes</title> |
| 2 | |
| 3 | <h2>What Is A "Event"?</h2>e?y=<titl |
| 4 | Possible uses for technotes include: |
| 5 | |
| 6 | * <b>Milestones</b>. Project milestones, such as releases or beta-test |
| 7 | cycles, can be recorded as technotes. The timeline entry for the technote |
| 8 | can be something simple like "Version 1.2.3" perhaps with a bright |
| 9 | color background to draw attention to the entry and the wiki content |
| 10 | can contain release notes, for example. |
| 11 | |
| 12 | * <b>Blog Entries</b>. Blog entries from developers describing the current |
| 13 | state of a project, or rational for v arious design decisions, or |
| 14 | roadmaps for future development, can be entered as technotes. |
| 15 | |
| 16 | * <b>Process Checkpoints</b>. For projects that have a formal process, |
| 17 | technotes can be used to record the completion or the initiation of |
| 18 | various process steps. For example, a technote can be used to record |
| 19 | the successful completion of a long-running test, perhaps w[./wikitheory.wiki | wiki page] |
| 20 | that is associated with a point in time rather thaevent causes a si [/timelinhyperlink ofTimeline Page]entry cause a jump to the wiThe wiki content, the timeline entry text, the |
| 21 | time of the eventTechnical Notes</title> |
| 22 | |
| 23 | <h2>What Is A "Technote"?</h2> |
| 24 | |
| 25 | In Fossil, a "technical note" or "technoteventerly called an "event") |
| 26 | is a speeventiki page] |
| 27 | that is associated with a point in time rather than having a page name. |
| 28 | eventaving a page name. |
| 29 | Each technote causes a single entry to appear on the |
| 30 | [/timeline?y=<titl |
| 31 | Possible uses for technotes include: |
| 32 | |
| 33 | * <b>Milestones</b>. Project milestones, such as releases or beta-test |
| 34 | cycles, can be recorded as technotes. The timeline entry for the technote |
| 35 | can be something simple like "V |
+106
-13
| --- www/fileformat.wiki | ||
| +++ www/fileformat.wiki | ||
| @@ -43,13 +43,14 @@ | ||
| 43 | 43 | <li> [#cluster | Clusters] </li> |
| 44 | 44 | <li> [#ctrl | Control Artifacts] </li> |
| 45 | 45 | <li> [#wikichng | Wiki Pages] </li> |
| 46 | 46 | <li> [#tktchng | Ticket Changes] </li> |
| 47 | 47 | <li> [#attachment | Attachments] </li> |
| 48 | +<li> [#event | Events] </li> | |
| 48 | 49 | </ul> |
| 49 | 50 | |
| 50 | -These five artifact types are described in the sequel. | |
| 51 | +These seven artifact types are described in the sequel. | |
| 51 | 52 | |
| 52 | 53 | In the current implementation (as of 2009-01-25) the artifacts that |
| 53 | 54 | make up a fossil repository are stored in in as delta- and zlib-compressed |
| 54 | 55 | blobs in an <a href="http://www.sqlite.org/">SQLite</a> database. This |
| 55 | 56 | is an implementation detail and might change in a future release. For |
| @@ -56,10 +57,13 @@ | ||
| 56 | 57 | the purpose of this article "file format" means the format of the artifacts, |
| 57 | 58 | not how the artifacts are stored on disk. It is the artifact format that |
| 58 | 59 | is intended to be enduring. The specifics of how artifacts are stored on |
| 59 | 60 | disk, though stable, is not intended to live as long as the |
| 60 | 61 | artifact format. |
| 62 | + | |
| 63 | +All of the artifacts can be extracted from a Fossil repository using | |
| 64 | +the "fossil deconstruct" command. | |
| 61 | 65 | |
| 62 | 66 | <a name="manifest"></a> |
| 63 | 67 | <h2>1.0 The Manifest</h2> |
| 64 | 68 | |
| 65 | 69 | A manifest defines a check-in or version of the project |
| @@ -165,12 +169,13 @@ | ||
| 165 | 169 | repository, append a single space (ASCII 0x20), the |
| 166 | 170 | size of the file in ASCII decimal, a single newline |
| 167 | 171 | character (ASCII 0x0A), and the complete text of the file. |
| 168 | 172 | Compute the MD5 checksum of the result. |
| 169 | 173 | |
| 170 | -A manifest might contain one or more T-cards used to set tags or | |
| 171 | -properties on the check-in. The format of the T-card is the same as | |
| 174 | +A manifest might contain one or more T-cards used to set | |
| 175 | +[./branching.wiki#tags | tags or properties] | |
| 176 | +on the check-in. The format of the T-card is the same as | |
| 172 | 177 | described in <i>Control Artifacts</i> section below, except that the |
| 173 | 178 | second argument is the single characcter "<b>*</b>" instead of an |
| 174 | 179 | artifact ID. The <b>*</b> in place of the artifact ID indicates that |
| 175 | 180 | the tag or property applies to the current artifact. It is not |
| 176 | 181 | possible to encode the current artifact ID as part of an artifact, |
| @@ -182,11 +187,11 @@ | ||
| 182 | 187 | Each manifest has a single U-card. The argument to the U-card is |
| 183 | 188 | the login of the user who created the manifest. The login name |
| 184 | 189 | is encoded using the same character escapes as is used for the |
| 185 | 190 | check-in comment argument to the C-card. |
| 186 | 191 | |
| 187 | -A manifest has an option Z-card as its last line. The argument | |
| 192 | +A manifest has an optional Z-card as its last line. The argument | |
| 188 | 193 | to the Z-card is a 32-character lowercase hexadecimal MD5 hash |
| 189 | 194 | of all prior lines of the manifest up to and including the newline |
| 190 | 195 | character that immediately precedes the "Z". The Z-card is just |
| 191 | 196 | a sanity check to prove that the manifest is well-formed and |
| 192 | 197 | consistent. |
| @@ -262,11 +267,12 @@ | ||
| 262 | 267 | clearsigned. |
| 263 | 268 | |
| 264 | 269 | The D card and the Z card of a control artifact are the same |
| 265 | 270 | as in a manifest. |
| 266 | 271 | |
| 267 | -The T card represents a "tag" or property that is applied to | |
| 272 | +The T card represents a [./branching.wiki#tags | tag or property] | |
| 273 | +that is applied to | |
| 268 | 274 | some other artifact. The T card has two or three values. The |
| 269 | 275 | second argument is the 40 character lowercase artifact ID of the artifact |
| 270 | 276 | to which the tag is to be applied. The |
| 271 | 277 | first value is the tag name. The first character of the tag |
| 272 | 278 | is either "+", "-", or "*". A "+" means the tag should be added |
| @@ -324,11 +330,11 @@ | ||
| 324 | 330 | of text in the wiki page. That text follows the newline character |
| 325 | 331 | that terminates the W card. The wiki text is always followed by one |
| 326 | 332 | extra newline. |
| 327 | 333 | |
| 328 | 334 | An example wiki artifact can be seen |
| 329 | -[/artifact/7b2f5fd0e0 | here]. | |
| 335 | +[/artifact?name=7b2f5fd0e0&txt=1 | here]. | |
| 330 | 336 | |
| 331 | 337 | <a name="tktchng"></a> |
| 332 | 338 | <h2>5.0 Ticket Changes</h2> |
| 333 | 339 | |
| 334 | 340 | A ticket-change artifact represents a change to a trouble ticket. |
| @@ -375,25 +381,25 @@ | ||
| 375 | 381 | |
| 376 | 382 | <a name="attachment"></a> |
| 377 | 383 | <h2>6.0 Attachments</h2> |
| 378 | 384 | |
| 379 | 385 | An attachment artifact associates some other artifact that is the |
| 380 | -attachment (the source artifact) with a ticket or wiki page to which | |
| 386 | +attachment (the source artifact) with a ticket or wiki page or event to which | |
| 381 | 387 | the attachment is connected (the target artifact). |
| 382 | 388 | The following cards are allowed on an attachment artifact: |
| 383 | 389 | |
| 384 | 390 | <blockquote> |
| 385 | -<b>A</b> <i>filename target</i> ?<i>source</i>? | |
| 386 | -<b>C</b> <i>comment</i><br> | |
| 391 | +<b>A</b> <i>filename target</i> ?<i>source</i>?<br /> | |
| 392 | +<b>C</b> <i>comment</i><br /> | |
| 387 | 393 | <b>D</b> <i>time-and-date-stamp</i><br /> |
| 388 | 394 | <b>U</b> <i>user-name</i><br /> |
| 389 | 395 | <b>Z</b> <i>checksum</i> |
| 390 | 396 | </blockquote> |
| 391 | 397 | |
| 392 | 398 | The A card specifies a filename for the attachment in its first argument. |
| 393 | 399 | The second argument to the A card is the name |
| 394 | -of the wiki page or ticket to which the attachment is connected. The | |
| 400 | +of the wiki page or ticket or event to which the attachment is connected. The | |
| 395 | 401 | third argument is either missing or else it is the 40-character artifact |
| 396 | 402 | ID of the attachment itself. A missing third argument means that the |
| 397 | 403 | attachment should be deleted. |
| 398 | 404 | |
| 399 | 405 | The C card is an optional comment describing what the attachment is about. |
| @@ -405,46 +411,111 @@ | ||
| 405 | 411 | A single U card gives the name of the user to added the attachment. |
| 406 | 412 | If an attachment is added anonymously, then the U card may be omitted. |
| 407 | 413 | |
| 408 | 414 | The Z card is the usual checksum over the rest of the attachment artifact. |
| 409 | 415 | |
| 416 | + | |
| 417 | +<a name="event"></a> | |
| 418 | +<h2>7.0 Events</h2> | |
| 419 | + | |
| 420 | +An event artifact associates a timeline comment and a page of text | |
| 421 | +(similar to a wiki page) with a point in time. Events can be used | |
| 422 | +to record project milestones, release notes, blog entries, process | |
| 423 | +checkpoints, or news articles. | |
| 424 | +The following cards are allowed on an event artifact: | |
| 425 | + | |
| 426 | +<blockquote> | |
| 427 | +<b>C</b> <i>comment</i><br> | |
| 428 | +<b>D</b> <i>time-and-date-stamp</i><br /> | |
| 429 | +<b>E</b> <i>event-time</i> <i>event-id</i><br /> | |
| 430 | +<b>P</b> <i>parent-artifact-id</i>+<br /> | |
| 431 | +<b>T</b> <b>+</b><i>tag-name</i> <b>*</b> <i>value</i><br /> | |
| 432 | +<b>U</b> <i>user-name</i><br /> | |
| 433 | +<b>W</b> <i>size</i> <b>\n</b> <i>text</i> <b>\n</b><br /> | |
| 434 | +<b>Z</b> <i>checksum</i> | |
| 435 | +</blockquote> | |
| 436 | + | |
| 437 | +The C card contains text that is displayed on the timeline for the | |
| 438 | +event. Exactly one C card is required on an event artifact. | |
| 439 | + | |
| 440 | +A single D card is required to give the date and time when the | |
| 441 | +event artifact was created. This is different from the time at which | |
| 442 | +the event occurs. | |
| 443 | + | |
| 444 | +A single E card gives the time of the event (the point on the timeline | |
| 445 | +where the event is displayed) and a unique identifier for the event. | |
| 446 | +When there are multiple artifacts with the same event-id, the one with | |
| 447 | +the most recent D card is the only one used. The event-id must be a | |
| 448 | +40-character lower-case hexadecimal string. | |
| 449 | + | |
| 450 | +The option P card specifies a prior event with the same event-id from | |
| 451 | +which the current event is an edit. The P card is a hint to the system | |
| 452 | +that it might be space efficient to store one event as a delta of the | |
| 453 | +other. | |
| 454 | + | |
| 455 | +An event might contain one or more T-cards used to set | |
| 456 | +[./branching.wiki#tags | tags or properties] | |
| 457 | +on the event. The format of the T-card is the same as | |
| 458 | +described in [#ctrl | Control Artifacts] section above, except that the | |
| 459 | +second argument is the single characcter "<b>*</b>" instead of an | |
| 460 | +artifact ID and the name is always prefaced by "<b>+</b>". | |
| 461 | +The <b>*</b> in place of the artifact ID indicates that | |
| 462 | +the tag or property applies to the current artifact. It is not | |
| 463 | +possible to encode the current artifact ID as part of an artifact, | |
| 464 | +since the act of inserting the artifact ID would change the artifact ID, | |
| 465 | +hence a <b>*</b> is used to represent "self". The "<b>+</b>" on the | |
| 466 | +name means that tags can only be add and they can only be non-propagating | |
| 467 | +tags. A an event, T cards are normally used to set the background | |
| 468 | +display color for timelines. | |
| 469 | + | |
| 470 | +The optional U card gives name of the user who entered the event. | |
| 471 | + | |
| 472 | +A single W card provides wiki text for the document associated with the | |
| 473 | +event. The format of the W card is exactly the same as for a | |
| 474 | +[#wikichng | wiki artifact]. | |
| 475 | + | |
| 476 | +The Z card is the usual checksum over the rest of the attachment artifact. | |
| 477 | + | |
| 410 | 478 | |
| 411 | 479 | <a name="summary"></a> |
| 412 | -<h2>7.0 Card Summary</h2> | |
| 480 | +<h2>8.0 Card Summary</h2> | |
| 413 | 481 | |
| 414 | 482 | The following table summaries the various kinds of cards that |
| 415 | 483 | appear on Fossil artifacts: |
| 416 | 484 | |
| 417 | 485 | <table border=1 width="100%"> |
| 418 | 486 | <tr> |
| 419 | 487 | <th rowspan=2 valign=bottom>Card Format</th> |
| 420 | -<th colspan=6>Used By</th> | |
| 488 | +<th colspan=7>Used By</th> | |
| 421 | 489 | </tr> |
| 422 | 490 | <tr> |
| 423 | 491 | <th>Manifest</th> |
| 424 | 492 | <th>Cluster</th> |
| 425 | 493 | <th>Control</th> |
| 426 | 494 | <th>Wiki</th> |
| 427 | 495 | <th>Ticket</th> |
| 428 | 496 | <th>Attachment</th> |
| 497 | +<th>Event</th> | |
| 429 | 498 | </tr> |
| 430 | 499 | <tr> |
| 431 | 500 | <td><b>A</b> <i>filename target source</i></td> |
| 432 | 501 | <td> </td> |
| 433 | 502 | <td> </td> |
| 434 | 503 | <td> </td> |
| 435 | 504 | <td> </td> |
| 436 | 505 | <td> </td> |
| 437 | 506 | <td align=center><b>X</b></td> |
| 507 | +<td> </td> | |
| 438 | 508 | </tr> |
| 439 | 509 | <tr> |
| 440 | -<td><b>C</b> <i>coment-text</i></td> | |
| 510 | +<td><b>C</b> <i>comment-text</i></td> | |
| 441 | 511 | <td align=center><b>X</b></td> |
| 442 | 512 | <td> </td> |
| 443 | 513 | <td> </td> |
| 444 | 514 | <td> </td> |
| 445 | 515 | <td> </td> |
| 516 | +<td align=center><b>X</b></td> | |
| 446 | 517 | <td align=center><b>X</b></td> |
| 447 | 518 | </tr> |
| 448 | 519 | <tr> |
| 449 | 520 | <td><b>D</b> <i>date-time-stamp</i></td> |
| 450 | 521 | <td align=center><b>X</b></td> |
| @@ -451,14 +522,26 @@ | ||
| 451 | 522 | <td align=center> </td> |
| 452 | 523 | <td align=center><b>X</b></td> |
| 453 | 524 | <td align=center><b>X</b></td> |
| 454 | 525 | <td align=center><b>X</b></td> |
| 455 | 526 | <td align=center><b>X</b></td> |
| 527 | +<td align=center><b>X</b></td> | |
| 528 | +</tr> | |
| 529 | +<tr> | |
| 530 | +<td><b>E</b> <i>event-time event-id</i></td> | |
| 531 | +<td align=center> </td> | |
| 532 | +<td align=center> </td> | |
| 533 | +<td align=center> </td> | |
| 534 | +<td align=center> </td> | |
| 535 | +<td align=center> </td> | |
| 536 | +<td align=center> </td> | |
| 537 | +<td align=center><b>X</b></td> | |
| 456 | 538 | </tr> |
| 457 | 539 | <tr> |
| 458 | 540 | <td><b>F</b> <i>filename uuid permissions oldname</i></td> |
| 459 | 541 | <td align=center><b>X</b></td> |
| 542 | +<td align=center> </td> | |
| 460 | 543 | <td align=center> </td> |
| 461 | 544 | <td align=center> </td> |
| 462 | 545 | <td align=center> </td> |
| 463 | 546 | <td align=center> </td> |
| 464 | 547 | <td align=center> </td> |
| @@ -469,18 +552,20 @@ | ||
| 469 | 552 | <td align=center> </td> |
| 470 | 553 | <td align=center> </td> |
| 471 | 554 | <td align=center> </td> |
| 472 | 555 | <td align=center><b>X</b></td> |
| 473 | 556 | <td align=center> </td> |
| 557 | +<td align=center> </td> | |
| 474 | 558 | </tr> |
| 475 | 559 | <tr> |
| 476 | 560 | <td><b>K</b> <i>ticket-uuid</i></td> |
| 477 | 561 | <td align=center> </td> |
| 478 | 562 | <td align=center> </td> |
| 479 | 563 | <td align=center> </td> |
| 480 | 564 | <td align=center> </td> |
| 481 | 565 | <td align=center><b>X</b></td> |
| 566 | +<td align=center> </td> | |
| 482 | 567 | <td align=center> </td> |
| 483 | 568 | </tr> |
| 484 | 569 | <tr> |
| 485 | 570 | <td><b>L</b> <i>wiki-title</i></td> |
| 486 | 571 | <td align=center> </td> |
| @@ -487,15 +572,17 @@ | ||
| 487 | 572 | <td align=center> </td> |
| 488 | 573 | <td align=center> </td> |
| 489 | 574 | <td align=center><b>X</b></td> |
| 490 | 575 | <td align=center> </td> |
| 491 | 576 | <td align=center> </td> |
| 577 | +<td align=center> </td> | |
| 492 | 578 | </tr> |
| 493 | 579 | <tr> |
| 494 | 580 | <td><b>M</b> <i>uuid</i></td> |
| 495 | 581 | <td align=center> </td> |
| 496 | 582 | <td align=center><b>X</b></td> |
| 583 | +<td align=center> </td> | |
| 497 | 584 | <td align=center> </td> |
| 498 | 585 | <td align=center> </td> |
| 499 | 586 | <td align=center> </td> |
| 500 | 587 | <td align=center> </td> |
| 501 | 588 | </tr> |
| @@ -505,14 +592,16 @@ | ||
| 505 | 592 | <td align=center> </td> |
| 506 | 593 | <td align=center> </td> |
| 507 | 594 | <td align=center><b>X</b></td> |
| 508 | 595 | <td align=center> </td> |
| 509 | 596 | <td align=center> </td> |
| 597 | +<td align=center> </td> | |
| 510 | 598 | </tr> |
| 511 | 599 | <tr> |
| 512 | 600 | <td><b>R</b> <i>md5sum</i></td> |
| 513 | 601 | <td align=center><b>X</b></td> |
| 602 | +<td align=center> </td> | |
| 514 | 603 | <td align=center> </td> |
| 515 | 604 | <td align=center> </td> |
| 516 | 605 | <td align=center> </td> |
| 517 | 606 | <td align=center> </td> |
| 518 | 607 | <td align=center> </td> |
| @@ -522,15 +611,17 @@ | ||
| 522 | 611 | <td align=center> </td> |
| 523 | 612 | <td align=center><b>X</b></td> |
| 524 | 613 | <td align=center> </td> |
| 525 | 614 | <td align=center> </td> |
| 526 | 615 | <td align=center> </td> |
| 616 | +<td align=center><b>X</b></td> | |
| 527 | 617 | </tr> |
| 528 | 618 | <tr> |
| 529 | 619 | <td><b>U</b> <i>username</i></td> |
| 530 | 620 | <td align=center><b>X</b></td> |
| 531 | 621 | <td align=center> </td> |
| 622 | +<td align=center><b>X</b></td> | |
| 532 | 623 | <td align=center><b>X</b></td> |
| 533 | 624 | <td align=center><b>X</b></td> |
| 534 | 625 | <td align=center><b>X</b></td> |
| 535 | 626 | <td align=center><b>X</b></td> |
| 536 | 627 | </tr> |
| @@ -540,16 +631,18 @@ | ||
| 540 | 631 | <td align=center> </td> |
| 541 | 632 | <td align=center> </td> |
| 542 | 633 | <td align=center><b>X</b></td> |
| 543 | 634 | <td align=center> </td> |
| 544 | 635 | <td align=center> </td> |
| 636 | +<td align=center><b>X</b></td> | |
| 545 | 637 | </tr> |
| 546 | 638 | <tr> |
| 547 | 639 | <td><b>Z</b> <i>md5sum</i></td> |
| 640 | +<td align=center><b>X</b></td> | |
| 548 | 641 | <td align=center><b>X</b></td> |
| 549 | 642 | <td align=center><b>X</b></td> |
| 550 | 643 | <td align=center><b>X</b></td> |
| 551 | 644 | <td align=center><b>X</b></td> |
| 552 | 645 | <td align=center><b>X</b></td> |
| 553 | 646 | <td align=center><b>X</b></td> |
| 554 | 647 | </tr> |
| 555 | 648 | </table> |
| 556 | 649 |
| --- www/fileformat.wiki | |
| +++ www/fileformat.wiki | |
| @@ -43,13 +43,14 @@ | |
| 43 | <li> [#cluster | Clusters] </li> |
| 44 | <li> [#ctrl | Control Artifacts] </li> |
| 45 | <li> [#wikichng | Wiki Pages] </li> |
| 46 | <li> [#tktchng | Ticket Changes] </li> |
| 47 | <li> [#attachment | Attachments] </li> |
| 48 | </ul> |
| 49 | |
| 50 | These five artifact types are described in the sequel. |
| 51 | |
| 52 | In the current implementation (as of 2009-01-25) the artifacts that |
| 53 | make up a fossil repository are stored in in as delta- and zlib-compressed |
| 54 | blobs in an <a href="http://www.sqlite.org/">SQLite</a> database. This |
| 55 | is an implementation detail and might change in a future release. For |
| @@ -56,10 +57,13 @@ | |
| 56 | the purpose of this article "file format" means the format of the artifacts, |
| 57 | not how the artifacts are stored on disk. It is the artifact format that |
| 58 | is intended to be enduring. The specifics of how artifacts are stored on |
| 59 | disk, though stable, is not intended to live as long as the |
| 60 | artifact format. |
| 61 | |
| 62 | <a name="manifest"></a> |
| 63 | <h2>1.0 The Manifest</h2> |
| 64 | |
| 65 | A manifest defines a check-in or version of the project |
| @@ -165,12 +169,13 @@ | |
| 165 | repository, append a single space (ASCII 0x20), the |
| 166 | size of the file in ASCII decimal, a single newline |
| 167 | character (ASCII 0x0A), and the complete text of the file. |
| 168 | Compute the MD5 checksum of the result. |
| 169 | |
| 170 | A manifest might contain one or more T-cards used to set tags or |
| 171 | properties on the check-in. The format of the T-card is the same as |
| 172 | described in <i>Control Artifacts</i> section below, except that the |
| 173 | second argument is the single characcter "<b>*</b>" instead of an |
| 174 | artifact ID. The <b>*</b> in place of the artifact ID indicates that |
| 175 | the tag or property applies to the current artifact. It is not |
| 176 | possible to encode the current artifact ID as part of an artifact, |
| @@ -182,11 +187,11 @@ | |
| 182 | Each manifest has a single U-card. The argument to the U-card is |
| 183 | the login of the user who created the manifest. The login name |
| 184 | is encoded using the same character escapes as is used for the |
| 185 | check-in comment argument to the C-card. |
| 186 | |
| 187 | A manifest has an option Z-card as its last line. The argument |
| 188 | to the Z-card is a 32-character lowercase hexadecimal MD5 hash |
| 189 | of all prior lines of the manifest up to and including the newline |
| 190 | character that immediately precedes the "Z". The Z-card is just |
| 191 | a sanity check to prove that the manifest is well-formed and |
| 192 | consistent. |
| @@ -262,11 +267,12 @@ | |
| 262 | clearsigned. |
| 263 | |
| 264 | The D card and the Z card of a control artifact are the same |
| 265 | as in a manifest. |
| 266 | |
| 267 | The T card represents a "tag" or property that is applied to |
| 268 | some other artifact. The T card has two or three values. The |
| 269 | second argument is the 40 character lowercase artifact ID of the artifact |
| 270 | to which the tag is to be applied. The |
| 271 | first value is the tag name. The first character of the tag |
| 272 | is either "+", "-", or "*". A "+" means the tag should be added |
| @@ -324,11 +330,11 @@ | |
| 324 | of text in the wiki page. That text follows the newline character |
| 325 | that terminates the W card. The wiki text is always followed by one |
| 326 | extra newline. |
| 327 | |
| 328 | An example wiki artifact can be seen |
| 329 | [/artifact/7b2f5fd0e0 | here]. |
| 330 | |
| 331 | <a name="tktchng"></a> |
| 332 | <h2>5.0 Ticket Changes</h2> |
| 333 | |
| 334 | A ticket-change artifact represents a change to a trouble ticket. |
| @@ -375,25 +381,25 @@ | |
| 375 | |
| 376 | <a name="attachment"></a> |
| 377 | <h2>6.0 Attachments</h2> |
| 378 | |
| 379 | An attachment artifact associates some other artifact that is the |
| 380 | attachment (the source artifact) with a ticket or wiki page to which |
| 381 | the attachment is connected (the target artifact). |
| 382 | The following cards are allowed on an attachment artifact: |
| 383 | |
| 384 | <blockquote> |
| 385 | <b>A</b> <i>filename target</i> ?<i>source</i>? |
| 386 | <b>C</b> <i>comment</i><br> |
| 387 | <b>D</b> <i>time-and-date-stamp</i><br /> |
| 388 | <b>U</b> <i>user-name</i><br /> |
| 389 | <b>Z</b> <i>checksum</i> |
| 390 | </blockquote> |
| 391 | |
| 392 | The A card specifies a filename for the attachment in its first argument. |
| 393 | The second argument to the A card is the name |
| 394 | of the wiki page or ticket to which the attachment is connected. The |
| 395 | third argument is either missing or else it is the 40-character artifact |
| 396 | ID of the attachment itself. A missing third argument means that the |
| 397 | attachment should be deleted. |
| 398 | |
| 399 | The C card is an optional comment describing what the attachment is about. |
| @@ -405,46 +411,111 @@ | |
| 405 | A single U card gives the name of the user to added the attachment. |
| 406 | If an attachment is added anonymously, then the U card may be omitted. |
| 407 | |
| 408 | The Z card is the usual checksum over the rest of the attachment artifact. |
| 409 | |
| 410 | |
| 411 | <a name="summary"></a> |
| 412 | <h2>7.0 Card Summary</h2> |
| 413 | |
| 414 | The following table summaries the various kinds of cards that |
| 415 | appear on Fossil artifacts: |
| 416 | |
| 417 | <table border=1 width="100%"> |
| 418 | <tr> |
| 419 | <th rowspan=2 valign=bottom>Card Format</th> |
| 420 | <th colspan=6>Used By</th> |
| 421 | </tr> |
| 422 | <tr> |
| 423 | <th>Manifest</th> |
| 424 | <th>Cluster</th> |
| 425 | <th>Control</th> |
| 426 | <th>Wiki</th> |
| 427 | <th>Ticket</th> |
| 428 | <th>Attachment</th> |
| 429 | </tr> |
| 430 | <tr> |
| 431 | <td><b>A</b> <i>filename target source</i></td> |
| 432 | <td> </td> |
| 433 | <td> </td> |
| 434 | <td> </td> |
| 435 | <td> </td> |
| 436 | <td> </td> |
| 437 | <td align=center><b>X</b></td> |
| 438 | </tr> |
| 439 | <tr> |
| 440 | <td><b>C</b> <i>coment-text</i></td> |
| 441 | <td align=center><b>X</b></td> |
| 442 | <td> </td> |
| 443 | <td> </td> |
| 444 | <td> </td> |
| 445 | <td> </td> |
| 446 | <td align=center><b>X</b></td> |
| 447 | </tr> |
| 448 | <tr> |
| 449 | <td><b>D</b> <i>date-time-stamp</i></td> |
| 450 | <td align=center><b>X</b></td> |
| @@ -451,14 +522,26 @@ | |
| 451 | <td align=center> </td> |
| 452 | <td align=center><b>X</b></td> |
| 453 | <td align=center><b>X</b></td> |
| 454 | <td align=center><b>X</b></td> |
| 455 | <td align=center><b>X</b></td> |
| 456 | </tr> |
| 457 | <tr> |
| 458 | <td><b>F</b> <i>filename uuid permissions oldname</i></td> |
| 459 | <td align=center><b>X</b></td> |
| 460 | <td align=center> </td> |
| 461 | <td align=center> </td> |
| 462 | <td align=center> </td> |
| 463 | <td align=center> </td> |
| 464 | <td align=center> </td> |
| @@ -469,18 +552,20 @@ | |
| 469 | <td align=center> </td> |
| 470 | <td align=center> </td> |
| 471 | <td align=center> </td> |
| 472 | <td align=center><b>X</b></td> |
| 473 | <td align=center> </td> |
| 474 | </tr> |
| 475 | <tr> |
| 476 | <td><b>K</b> <i>ticket-uuid</i></td> |
| 477 | <td align=center> </td> |
| 478 | <td align=center> </td> |
| 479 | <td align=center> </td> |
| 480 | <td align=center> </td> |
| 481 | <td align=center><b>X</b></td> |
| 482 | <td align=center> </td> |
| 483 | </tr> |
| 484 | <tr> |
| 485 | <td><b>L</b> <i>wiki-title</i></td> |
| 486 | <td align=center> </td> |
| @@ -487,15 +572,17 @@ | |
| 487 | <td align=center> </td> |
| 488 | <td align=center> </td> |
| 489 | <td align=center><b>X</b></td> |
| 490 | <td align=center> </td> |
| 491 | <td align=center> </td> |
| 492 | </tr> |
| 493 | <tr> |
| 494 | <td><b>M</b> <i>uuid</i></td> |
| 495 | <td align=center> </td> |
| 496 | <td align=center><b>X</b></td> |
| 497 | <td align=center> </td> |
| 498 | <td align=center> </td> |
| 499 | <td align=center> </td> |
| 500 | <td align=center> </td> |
| 501 | </tr> |
| @@ -505,14 +592,16 @@ | |
| 505 | <td align=center> </td> |
| 506 | <td align=center> </td> |
| 507 | <td align=center><b>X</b></td> |
| 508 | <td align=center> </td> |
| 509 | <td align=center> </td> |
| 510 | </tr> |
| 511 | <tr> |
| 512 | <td><b>R</b> <i>md5sum</i></td> |
| 513 | <td align=center><b>X</b></td> |
| 514 | <td align=center> </td> |
| 515 | <td align=center> </td> |
| 516 | <td align=center> </td> |
| 517 | <td align=center> </td> |
| 518 | <td align=center> </td> |
| @@ -522,15 +611,17 @@ | |
| 522 | <td align=center> </td> |
| 523 | <td align=center><b>X</b></td> |
| 524 | <td align=center> </td> |
| 525 | <td align=center> </td> |
| 526 | <td align=center> </td> |
| 527 | </tr> |
| 528 | <tr> |
| 529 | <td><b>U</b> <i>username</i></td> |
| 530 | <td align=center><b>X</b></td> |
| 531 | <td align=center> </td> |
| 532 | <td align=center><b>X</b></td> |
| 533 | <td align=center><b>X</b></td> |
| 534 | <td align=center><b>X</b></td> |
| 535 | <td align=center><b>X</b></td> |
| 536 | </tr> |
| @@ -540,16 +631,18 @@ | |
| 540 | <td align=center> </td> |
| 541 | <td align=center> </td> |
| 542 | <td align=center><b>X</b></td> |
| 543 | <td align=center> </td> |
| 544 | <td align=center> </td> |
| 545 | </tr> |
| 546 | <tr> |
| 547 | <td><b>Z</b> <i>md5sum</i></td> |
| 548 | <td align=center><b>X</b></td> |
| 549 | <td align=center><b>X</b></td> |
| 550 | <td align=center><b>X</b></td> |
| 551 | <td align=center><b>X</b></td> |
| 552 | <td align=center><b>X</b></td> |
| 553 | <td align=center><b>X</b></td> |
| 554 | </tr> |
| 555 | </table> |
| 556 |
| --- www/fileformat.wiki | |
| +++ www/fileformat.wiki | |
| @@ -43,13 +43,14 @@ | |
| 43 | <li> [#cluster | Clusters] </li> |
| 44 | <li> [#ctrl | Control Artifacts] </li> |
| 45 | <li> [#wikichng | Wiki Pages] </li> |
| 46 | <li> [#tktchng | Ticket Changes] </li> |
| 47 | <li> [#attachment | Attachments] </li> |
| 48 | <li> [#event | Events] </li> |
| 49 | </ul> |
| 50 | |
| 51 | These seven artifact types are described in the sequel. |
| 52 | |
| 53 | In the current implementation (as of 2009-01-25) the artifacts that |
| 54 | make up a fossil repository are stored in in as delta- and zlib-compressed |
| 55 | blobs in an <a href="http://www.sqlite.org/">SQLite</a> database. This |
| 56 | is an implementation detail and might change in a future release. For |
| @@ -56,10 +57,13 @@ | |
| 57 | the purpose of this article "file format" means the format of the artifacts, |
| 58 | not how the artifacts are stored on disk. It is the artifact format that |
| 59 | is intended to be enduring. The specifics of how artifacts are stored on |
| 60 | disk, though stable, is not intended to live as long as the |
| 61 | artifact format. |
| 62 | |
| 63 | All of the artifacts can be extracted from a Fossil repository using |
| 64 | the "fossil deconstruct" command. |
| 65 | |
| 66 | <a name="manifest"></a> |
| 67 | <h2>1.0 The Manifest</h2> |
| 68 | |
| 69 | A manifest defines a check-in or version of the project |
| @@ -165,12 +169,13 @@ | |
| 169 | repository, append a single space (ASCII 0x20), the |
| 170 | size of the file in ASCII decimal, a single newline |
| 171 | character (ASCII 0x0A), and the complete text of the file. |
| 172 | Compute the MD5 checksum of the result. |
| 173 | |
| 174 | A manifest might contain one or more T-cards used to set |
| 175 | [./branching.wiki#tags | tags or properties] |
| 176 | on the check-in. The format of the T-card is the same as |
| 177 | described in <i>Control Artifacts</i> section below, except that the |
| 178 | second argument is the single characcter "<b>*</b>" instead of an |
| 179 | artifact ID. The <b>*</b> in place of the artifact ID indicates that |
| 180 | the tag or property applies to the current artifact. It is not |
| 181 | possible to encode the current artifact ID as part of an artifact, |
| @@ -182,11 +187,11 @@ | |
| 187 | Each manifest has a single U-card. The argument to the U-card is |
| 188 | the login of the user who created the manifest. The login name |
| 189 | is encoded using the same character escapes as is used for the |
| 190 | check-in comment argument to the C-card. |
| 191 | |
| 192 | A manifest has an optional Z-card as its last line. The argument |
| 193 | to the Z-card is a 32-character lowercase hexadecimal MD5 hash |
| 194 | of all prior lines of the manifest up to and including the newline |
| 195 | character that immediately precedes the "Z". The Z-card is just |
| 196 | a sanity check to prove that the manifest is well-formed and |
| 197 | consistent. |
| @@ -262,11 +267,12 @@ | |
| 267 | clearsigned. |
| 268 | |
| 269 | The D card and the Z card of a control artifact are the same |
| 270 | as in a manifest. |
| 271 | |
| 272 | The T card represents a [./branching.wiki#tags | tag or property] |
| 273 | that is applied to |
| 274 | some other artifact. The T card has two or three values. The |
| 275 | second argument is the 40 character lowercase artifact ID of the artifact |
| 276 | to which the tag is to be applied. The |
| 277 | first value is the tag name. The first character of the tag |
| 278 | is either "+", "-", or "*". A "+" means the tag should be added |
| @@ -324,11 +330,11 @@ | |
| 330 | of text in the wiki page. That text follows the newline character |
| 331 | that terminates the W card. The wiki text is always followed by one |
| 332 | extra newline. |
| 333 | |
| 334 | An example wiki artifact can be seen |
| 335 | [/artifact?name=7b2f5fd0e0&txt=1 | here]. |
| 336 | |
| 337 | <a name="tktchng"></a> |
| 338 | <h2>5.0 Ticket Changes</h2> |
| 339 | |
| 340 | A ticket-change artifact represents a change to a trouble ticket. |
| @@ -375,25 +381,25 @@ | |
| 381 | |
| 382 | <a name="attachment"></a> |
| 383 | <h2>6.0 Attachments</h2> |
| 384 | |
| 385 | An attachment artifact associates some other artifact that is the |
| 386 | attachment (the source artifact) with a ticket or wiki page or event to which |
| 387 | the attachment is connected (the target artifact). |
| 388 | The following cards are allowed on an attachment artifact: |
| 389 | |
| 390 | <blockquote> |
| 391 | <b>A</b> <i>filename target</i> ?<i>source</i>?<br /> |
| 392 | <b>C</b> <i>comment</i><br /> |
| 393 | <b>D</b> <i>time-and-date-stamp</i><br /> |
| 394 | <b>U</b> <i>user-name</i><br /> |
| 395 | <b>Z</b> <i>checksum</i> |
| 396 | </blockquote> |
| 397 | |
| 398 | The A card specifies a filename for the attachment in its first argument. |
| 399 | The second argument to the A card is the name |
| 400 | of the wiki page or ticket or event to which the attachment is connected. The |
| 401 | third argument is either missing or else it is the 40-character artifact |
| 402 | ID of the attachment itself. A missing third argument means that the |
| 403 | attachment should be deleted. |
| 404 | |
| 405 | The C card is an optional comment describing what the attachment is about. |
| @@ -405,46 +411,111 @@ | |
| 411 | A single U card gives the name of the user to added the attachment. |
| 412 | If an attachment is added anonymously, then the U card may be omitted. |
| 413 | |
| 414 | The Z card is the usual checksum over the rest of the attachment artifact. |
| 415 | |
| 416 | |
| 417 | <a name="event"></a> |
| 418 | <h2>7.0 Events</h2> |
| 419 | |
| 420 | An event artifact associates a timeline comment and a page of text |
| 421 | (similar to a wiki page) with a point in time. Events can be used |
| 422 | to record project milestones, release notes, blog entries, process |
| 423 | checkpoints, or news articles. |
| 424 | The following cards are allowed on an event artifact: |
| 425 | |
| 426 | <blockquote> |
| 427 | <b>C</b> <i>comment</i><br> |
| 428 | <b>D</b> <i>time-and-date-stamp</i><br /> |
| 429 | <b>E</b> <i>event-time</i> <i>event-id</i><br /> |
| 430 | <b>P</b> <i>parent-artifact-id</i>+<br /> |
| 431 | <b>T</b> <b>+</b><i>tag-name</i> <b>*</b> <i>value</i><br /> |
| 432 | <b>U</b> <i>user-name</i><br /> |
| 433 | <b>W</b> <i>size</i> <b>\n</b> <i>text</i> <b>\n</b><br /> |
| 434 | <b>Z</b> <i>checksum</i> |
| 435 | </blockquote> |
| 436 | |
| 437 | The C card contains text that is displayed on the timeline for the |
| 438 | event. Exactly one C card is required on an event artifact. |
| 439 | |
| 440 | A single D card is required to give the date and time when the |
| 441 | event artifact was created. This is different from the time at which |
| 442 | the event occurs. |
| 443 | |
| 444 | A single E card gives the time of the event (the point on the timeline |
| 445 | where the event is displayed) and a unique identifier for the event. |
| 446 | When there are multiple artifacts with the same event-id, the one with |
| 447 | the most recent D card is the only one used. The event-id must be a |
| 448 | 40-character lower-case hexadecimal string. |
| 449 | |
| 450 | The option P card specifies a prior event with the same event-id from |
| 451 | which the current event is an edit. The P card is a hint to the system |
| 452 | that it might be space efficient to store one event as a delta of the |
| 453 | other. |
| 454 | |
| 455 | An event might contain one or more T-cards used to set |
| 456 | [./branching.wiki#tags | tags or properties] |
| 457 | on the event. The format of the T-card is the same as |
| 458 | described in [#ctrl | Control Artifacts] section above, except that the |
| 459 | second argument is the single characcter "<b>*</b>" instead of an |
| 460 | artifact ID and the name is always prefaced by "<b>+</b>". |
| 461 | The <b>*</b> in place of the artifact ID indicates that |
| 462 | the tag or property applies to the current artifact. It is not |
| 463 | possible to encode the current artifact ID as part of an artifact, |
| 464 | since the act of inserting the artifact ID would change the artifact ID, |
| 465 | hence a <b>*</b> is used to represent "self". The "<b>+</b>" on the |
| 466 | name means that tags can only be add and they can only be non-propagating |
| 467 | tags. A an event, T cards are normally used to set the background |
| 468 | display color for timelines. |
| 469 | |
| 470 | The optional U card gives name of the user who entered the event. |
| 471 | |
| 472 | A single W card provides wiki text for the document associated with the |
| 473 | event. The format of the W card is exactly the same as for a |
| 474 | [#wikichng | wiki artifact]. |
| 475 | |
| 476 | The Z card is the usual checksum over the rest of the attachment artifact. |
| 477 | |
| 478 | |
| 479 | <a name="summary"></a> |
| 480 | <h2>8.0 Card Summary</h2> |
| 481 | |
| 482 | The following table summaries the various kinds of cards that |
| 483 | appear on Fossil artifacts: |
| 484 | |
| 485 | <table border=1 width="100%"> |
| 486 | <tr> |
| 487 | <th rowspan=2 valign=bottom>Card Format</th> |
| 488 | <th colspan=7>Used By</th> |
| 489 | </tr> |
| 490 | <tr> |
| 491 | <th>Manifest</th> |
| 492 | <th>Cluster</th> |
| 493 | <th>Control</th> |
| 494 | <th>Wiki</th> |
| 495 | <th>Ticket</th> |
| 496 | <th>Attachment</th> |
| 497 | <th>Event</th> |
| 498 | </tr> |
| 499 | <tr> |
| 500 | <td><b>A</b> <i>filename target source</i></td> |
| 501 | <td> </td> |
| 502 | <td> </td> |
| 503 | <td> </td> |
| 504 | <td> </td> |
| 505 | <td> </td> |
| 506 | <td align=center><b>X</b></td> |
| 507 | <td> </td> |
| 508 | </tr> |
| 509 | <tr> |
| 510 | <td><b>C</b> <i>comment-text</i></td> |
| 511 | <td align=center><b>X</b></td> |
| 512 | <td> </td> |
| 513 | <td> </td> |
| 514 | <td> </td> |
| 515 | <td> </td> |
| 516 | <td align=center><b>X</b></td> |
| 517 | <td align=center><b>X</b></td> |
| 518 | </tr> |
| 519 | <tr> |
| 520 | <td><b>D</b> <i>date-time-stamp</i></td> |
| 521 | <td align=center><b>X</b></td> |
| @@ -451,14 +522,26 @@ | |
| 522 | <td align=center> </td> |
| 523 | <td align=center><b>X</b></td> |
| 524 | <td align=center><b>X</b></td> |
| 525 | <td align=center><b>X</b></td> |
| 526 | <td align=center><b>X</b></td> |
| 527 | <td align=center><b>X</b></td> |
| 528 | </tr> |
| 529 | <tr> |
| 530 | <td><b>E</b> <i>event-time event-id</i></td> |
| 531 | <td align=center> </td> |
| 532 | <td align=center> </td> |
| 533 | <td align=center> </td> |
| 534 | <td align=center> </td> |
| 535 | <td align=center> </td> |
| 536 | <td align=center> </td> |
| 537 | <td align=center><b>X</b></td> |
| 538 | </tr> |
| 539 | <tr> |
| 540 | <td><b>F</b> <i>filename uuid permissions oldname</i></td> |
| 541 | <td align=center><b>X</b></td> |
| 542 | <td align=center> </td> |
| 543 | <td align=center> </td> |
| 544 | <td align=center> </td> |
| 545 | <td align=center> </td> |
| 546 | <td align=center> </td> |
| 547 | <td align=center> </td> |
| @@ -469,18 +552,20 @@ | |
| 552 | <td align=center> </td> |
| 553 | <td align=center> </td> |
| 554 | <td align=center> </td> |
| 555 | <td align=center><b>X</b></td> |
| 556 | <td align=center> </td> |
| 557 | <td align=center> </td> |
| 558 | </tr> |
| 559 | <tr> |
| 560 | <td><b>K</b> <i>ticket-uuid</i></td> |
| 561 | <td align=center> </td> |
| 562 | <td align=center> </td> |
| 563 | <td align=center> </td> |
| 564 | <td align=center> </td> |
| 565 | <td align=center><b>X</b></td> |
| 566 | <td align=center> </td> |
| 567 | <td align=center> </td> |
| 568 | </tr> |
| 569 | <tr> |
| 570 | <td><b>L</b> <i>wiki-title</i></td> |
| 571 | <td align=center> </td> |
| @@ -487,15 +572,17 @@ | |
| 572 | <td align=center> </td> |
| 573 | <td align=center> </td> |
| 574 | <td align=center><b>X</b></td> |
| 575 | <td align=center> </td> |
| 576 | <td align=center> </td> |
| 577 | <td align=center> </td> |
| 578 | </tr> |
| 579 | <tr> |
| 580 | <td><b>M</b> <i>uuid</i></td> |
| 581 | <td align=center> </td> |
| 582 | <td align=center><b>X</b></td> |
| 583 | <td align=center> </td> |
| 584 | <td align=center> </td> |
| 585 | <td align=center> </td> |
| 586 | <td align=center> </td> |
| 587 | <td align=center> </td> |
| 588 | </tr> |
| @@ -505,14 +592,16 @@ | |
| 592 | <td align=center> </td> |
| 593 | <td align=center> </td> |
| 594 | <td align=center><b>X</b></td> |
| 595 | <td align=center> </td> |
| 596 | <td align=center> </td> |
| 597 | <td align=center> </td> |
| 598 | </tr> |
| 599 | <tr> |
| 600 | <td><b>R</b> <i>md5sum</i></td> |
| 601 | <td align=center><b>X</b></td> |
| 602 | <td align=center> </td> |
| 603 | <td align=center> </td> |
| 604 | <td align=center> </td> |
| 605 | <td align=center> </td> |
| 606 | <td align=center> </td> |
| 607 | <td align=center> </td> |
| @@ -522,15 +611,17 @@ | |
| 611 | <td align=center> </td> |
| 612 | <td align=center><b>X</b></td> |
| 613 | <td align=center> </td> |
| 614 | <td align=center> </td> |
| 615 | <td align=center> </td> |
| 616 | <td align=center><b>X</b></td> |
| 617 | </tr> |
| 618 | <tr> |
| 619 | <td><b>U</b> <i>username</i></td> |
| 620 | <td align=center><b>X</b></td> |
| 621 | <td align=center> </td> |
| 622 | <td align=center><b>X</b></td> |
| 623 | <td align=center><b>X</b></td> |
| 624 | <td align=center><b>X</b></td> |
| 625 | <td align=center><b>X</b></td> |
| 626 | <td align=center><b>X</b></td> |
| 627 | </tr> |
| @@ -540,16 +631,18 @@ | |
| 631 | <td align=center> </td> |
| 632 | <td align=center> </td> |
| 633 | <td align=center><b>X</b></td> |
| 634 | <td align=center> </td> |
| 635 | <td align=center> </td> |
| 636 | <td align=center><b>X</b></td> |
| 637 | </tr> |
| 638 | <tr> |
| 639 | <td><b>Z</b> <i>md5sum</i></td> |
| 640 | <td align=center><b>X</b></td> |
| 641 | <td align=center><b>X</b></td> |
| 642 | <td align=center><b>X</b></td> |
| 643 | <td align=center><b>X</b></td> |
| 644 | <td align=center><b>X</b></td> |
| 645 | <td align=center><b>X</b></td> |
| 646 | <td align=center><b>X</b></td> |
| 647 | </tr> |
| 648 | </table> |
| 649 |
+5
-2
| --- www/index.wiki | ||
| +++ www/index.wiki | ||
| @@ -40,12 +40,13 @@ | ||
| 40 | 40 | internet these days. What makes Fossil worthy of attention? |
| 41 | 41 | |
| 42 | 42 | 1. <b>Bug Tracking And Wiki</b> - |
| 43 | 43 | In addition to doing [./concepts.wiki | distributed version control] |
| 44 | 44 | like Git and Mercurial, |
| 45 | - Fossil also supports [./bugtheory.wiki | distributed bug tracking] and | |
| 46 | - [./wikitheory.wiki | distributed wiki] all in a single | |
| 45 | + Fossil also supports [./bugtheory.wiki | distributed bug tracking], | |
| 46 | + [./wikitheory.wiki | distributed wiki], and a | |
| 47 | + [./event.wiki | distributed blog] mechanism all in a single | |
| 47 | 48 | integrated package. |
| 48 | 49 | |
| 49 | 50 | 2. <b>Web Interface</b> - |
| 50 | 51 | Fossil has a built-in and easy-to-use [./webui.wiki | web interface] |
| 51 | 52 | that simplifies project tracking and promotes situational awareness. |
| @@ -111,10 +112,12 @@ | ||
| 111 | 112 | * A tutorial on [./branching.wiki | branching], what it means and how |
| 112 | 113 | to do it using fossil. |
| 113 | 114 | * The [./selfcheck.wiki | automatic self-check] mechanism |
| 114 | 115 | helps insure project integrity. |
| 115 | 116 | * Fossil contains a [./wikitheory.wiki | built-in wiki]. |
| 117 | + * An [./event.wiki | Event] is a special kind of wiki page associated | |
| 118 | + with a point in time rather than a name. | |
| 116 | 119 | * There is a |
| 117 | 120 | [http://lists.fossil-scm.org:8080/cgi-bin/mailman/listinfo/fossil-users | mailing list] (with publicly readable |
| 118 | 121 | [http://www.mail-archive.com/[email protected] | archives] |
| 119 | 122 | available for discussing fossil issues. |
| 120 | 123 | * [./stats.wiki | Performance statistics] taken from real-world projects |
| 121 | 124 |
| --- www/index.wiki | |
| +++ www/index.wiki | |
| @@ -40,12 +40,13 @@ | |
| 40 | internet these days. What makes Fossil worthy of attention? |
| 41 | |
| 42 | 1. <b>Bug Tracking And Wiki</b> - |
| 43 | In addition to doing [./concepts.wiki | distributed version control] |
| 44 | like Git and Mercurial, |
| 45 | Fossil also supports [./bugtheory.wiki | distributed bug tracking] and |
| 46 | [./wikitheory.wiki | distributed wiki] all in a single |
| 47 | integrated package. |
| 48 | |
| 49 | 2. <b>Web Interface</b> - |
| 50 | Fossil has a built-in and easy-to-use [./webui.wiki | web interface] |
| 51 | that simplifies project tracking and promotes situational awareness. |
| @@ -111,10 +112,12 @@ | |
| 111 | * A tutorial on [./branching.wiki | branching], what it means and how |
| 112 | to do it using fossil. |
| 113 | * The [./selfcheck.wiki | automatic self-check] mechanism |
| 114 | helps insure project integrity. |
| 115 | * Fossil contains a [./wikitheory.wiki | built-in wiki]. |
| 116 | * There is a |
| 117 | [http://lists.fossil-scm.org:8080/cgi-bin/mailman/listinfo/fossil-users | mailing list] (with publicly readable |
| 118 | [http://www.mail-archive.com/[email protected] | archives] |
| 119 | available for discussing fossil issues. |
| 120 | * [./stats.wiki | Performance statistics] taken from real-world projects |
| 121 |
| --- www/index.wiki | |
| +++ www/index.wiki | |
| @@ -40,12 +40,13 @@ | |
| 40 | internet these days. What makes Fossil worthy of attention? |
| 41 | |
| 42 | 1. <b>Bug Tracking And Wiki</b> - |
| 43 | In addition to doing [./concepts.wiki | distributed version control] |
| 44 | like Git and Mercurial, |
| 45 | Fossil also supports [./bugtheory.wiki | distributed bug tracking], |
| 46 | [./wikitheory.wiki | distributed wiki], and a |
| 47 | [./event.wiki | distributed blog] mechanism all in a single |
| 48 | integrated package. |
| 49 | |
| 50 | 2. <b>Web Interface</b> - |
| 51 | Fossil has a built-in and easy-to-use [./webui.wiki | web interface] |
| 52 | that simplifies project tracking and promotes situational awareness. |
| @@ -111,10 +112,12 @@ | |
| 112 | * A tutorial on [./branching.wiki | branching], what it means and how |
| 113 | to do it using fossil. |
| 114 | * The [./selfcheck.wiki | automatic self-check] mechanism |
| 115 | helps insure project integrity. |
| 116 | * Fossil contains a [./wikitheory.wiki | built-in wiki]. |
| 117 | * An [./event.wiki | Event] is a special kind of wiki page associated |
| 118 | with a point in time rather than a name. |
| 119 | * There is a |
| 120 | [http://lists.fossil-scm.org:8080/cgi-bin/mailman/listinfo/fossil-users | mailing list] (with publicly readable |
| 121 | [http://www.mail-archive.com/[email protected] | archives] |
| 122 | available for discussing fossil issues. |
| 123 | * [./stats.wiki | Performance statistics] taken from real-world projects |
| 124 |
+1
-1
| --- www/qandc.wiki | ||
| +++ www/qandc.wiki | ||
| @@ -63,11 +63,11 @@ | ||
| 63 | 63 | Other projects are also adopting fossil. But fossil does not yet have |
| 64 | 64 | the massive user base of git or mercurial. |
| 65 | 65 | </blockquote> |
| 66 | 66 | |
| 67 | 67 | <b>Fossil looks like the bug tracker that would be in your |
| 68 | -Linksys Router's administration screen.</p> | |
| 68 | +Linksys Router's administration screen.</b> | |
| 69 | 69 | |
| 70 | 70 | <blockquote> |
| 71 | 71 | <p>I take a pragmatic approach to software: form follows function. |
| 72 | 72 | To me, it is more important to have a reliable, fast, efficient, |
| 73 | 73 | enduring, and simple DVCS than one that looks pretty.</p> |
| 74 | 74 |
| --- www/qandc.wiki | |
| +++ www/qandc.wiki | |
| @@ -63,11 +63,11 @@ | |
| 63 | Other projects are also adopting fossil. But fossil does not yet have |
| 64 | the massive user base of git or mercurial. |
| 65 | </blockquote> |
| 66 | |
| 67 | <b>Fossil looks like the bug tracker that would be in your |
| 68 | Linksys Router's administration screen.</p> |
| 69 | |
| 70 | <blockquote> |
| 71 | <p>I take a pragmatic approach to software: form follows function. |
| 72 | To me, it is more important to have a reliable, fast, efficient, |
| 73 | enduring, and simple DVCS than one that looks pretty.</p> |
| 74 |
| --- www/qandc.wiki | |
| +++ www/qandc.wiki | |
| @@ -63,11 +63,11 @@ | |
| 63 | Other projects are also adopting fossil. But fossil does not yet have |
| 64 | the massive user base of git or mercurial. |
| 65 | </blockquote> |
| 66 | |
| 67 | <b>Fossil looks like the bug tracker that would be in your |
| 68 | Linksys Router's administration screen.</b> |
| 69 | |
| 70 | <blockquote> |
| 71 | <p>I take a pragmatic approach to software: form follows function. |
| 72 | To me, it is more important to have a reliable, fast, efficient, |
| 73 | enduring, and simple DVCS than one that looks pretty.</p> |
| 74 |
+1
| --- www/wikitheory.wiki | ||
| +++ www/wikitheory.wiki | ||
| @@ -5,10 +5,11 @@ | ||
| 5 | 5 | * Stand-alone wiki pages. |
| 6 | 6 | * Description and comments in [./bugtheory.wiki | bug reports]. |
| 7 | 7 | * Check-in comments. |
| 8 | 8 | * [./embeddeddoc.wiki | Embedded documentation] files whose |
| 9 | 9 | name ends in "wiki". |
| 10 | + * [./event.wiki | Event descriptions]. | |
| 10 | 11 | |
| 11 | 12 | The [/wiki_rules | formatting rules] for fossil wiki |
| 12 | 13 | are designed to be simple and intuitive. The idea is that wiki provides |
| 13 | 14 | paragraph breaks, numbered and bulleted lists, and hyperlinking for |
| 14 | 15 | simple documents together with a safe subset of HTML for more complex |
| 15 | 16 |
| --- www/wikitheory.wiki | |
| +++ www/wikitheory.wiki | |
| @@ -5,10 +5,11 @@ | |
| 5 | * Stand-alone wiki pages. |
| 6 | * Description and comments in [./bugtheory.wiki | bug reports]. |
| 7 | * Check-in comments. |
| 8 | * [./embeddeddoc.wiki | Embedded documentation] files whose |
| 9 | name ends in "wiki". |
| 10 | |
| 11 | The [/wiki_rules | formatting rules] for fossil wiki |
| 12 | are designed to be simple and intuitive. The idea is that wiki provides |
| 13 | paragraph breaks, numbered and bulleted lists, and hyperlinking for |
| 14 | simple documents together with a safe subset of HTML for more complex |
| 15 |
| --- www/wikitheory.wiki | |
| +++ www/wikitheory.wiki | |
| @@ -5,10 +5,11 @@ | |
| 5 | * Stand-alone wiki pages. |
| 6 | * Description and comments in [./bugtheory.wiki | bug reports]. |
| 7 | * Check-in comments. |
| 8 | * [./embeddeddoc.wiki | Embedded documentation] files whose |
| 9 | name ends in "wiki". |
| 10 | * [./event.wiki | Event descriptions]. |
| 11 | |
| 12 | The [/wiki_rules | formatting rules] for fossil wiki |
| 13 | are designed to be simple and intuitive. The idea is that wiki provides |
| 14 | paragraph breaks, numbered and bulleted lists, and hyperlinking for |
| 15 | simple documents together with a safe subset of HTML for more complex |
| 16 |