Fossil SCM

merge trunk

jan.nijtmans 2012-10-13 18:38 use-utf8-in-win-external-editor merge
Commit 011142060139dff95dcd10c7e12d3b8a79cfdf69
+5 -4
--- src/add.c
+++ src/add.c
@@ -216,13 +216,14 @@
216216
int vid; /* Currently checked out version */
217217
int nRoot; /* Full path characters in g.zLocalRoot */
218218
const char *zIgnoreFlag; /* The --ignore option or ignore-glob setting */
219219
Glob *pIgnore; /* Ignore everything matching this glob pattern */
220220
int caseSensitive; /* True if filenames are case sensitive */
221
+ unsigned scanFlags = 0; /* Flags passed to vfile_scan() */
221222
222223
zIgnoreFlag = find_option("ignore",0,1);
223
- includeDotFiles = find_option("dotfiles",0,0)!=0;
224
+ if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL;
224225
capture_case_sensitive_option();
225226
db_must_be_within_tree();
226227
caseSensitive = filenames_are_case_sensitive();
227228
if( zIgnoreFlag==0 ){
228229
zIgnoreFlag = db_get("ignore-glob", 0);
@@ -250,11 +251,11 @@
250251
251252
file_canonical_name(g.argv[i], &fullName, 0);
252253
zName = blob_str(&fullName);
253254
isDir = file_wd_isdir(zName);
254255
if( isDir==1 ){
255
- vfile_scan(&fullName, nRoot-1, includeDotFiles, pIgnore);
256
+ vfile_scan(&fullName, nRoot-1, scanFlags, pIgnore);
256257
}else if( isDir==0 ){
257258
fossil_warning("not found: %s", zName);
258259
}else if( file_access(zName, R_OK) ){
259260
fossil_fatal("cannot open %s", zName);
260261
}else{
@@ -433,11 +434,11 @@
433434
** See also: add, rm
434435
*/
435436
void addremove_cmd(void){
436437
Blob path;
437438
const char *zIgnoreFlag = find_option("ignore",0,1);
438
- int allFlag = find_option("dotfiles",0,0)!=0;
439
+ unsigned scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0;
439440
int isTest = find_option("test",0,0)!=0;
440441
int caseSensitive;
441442
int n;
442443
Stmt q;
443444
int vid;
@@ -466,11 +467,11 @@
466467
db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)");
467468
n = strlen(g.zLocalRoot);
468469
blob_init(&path, g.zLocalRoot, n-1);
469470
/* now we read the complete file structure into a temp table */
470471
pIgnore = glob_create(zIgnoreFlag);
471
- vfile_scan(&path, blob_size(&path), allFlag, pIgnore);
472
+ vfile_scan(&path, blob_size(&path), scanFlags, pIgnore);
472473
glob_free(pIgnore);
473474
nAdd = add_files_in_sfile(vid, caseSensitive);
474475
475476
/* step 2: search for missing files */
476477
db_prepare(&q,
477478
--- src/add.c
+++ src/add.c
@@ -216,13 +216,14 @@
216 int vid; /* Currently checked out version */
217 int nRoot; /* Full path characters in g.zLocalRoot */
218 const char *zIgnoreFlag; /* The --ignore option or ignore-glob setting */
219 Glob *pIgnore; /* Ignore everything matching this glob pattern */
220 int caseSensitive; /* True if filenames are case sensitive */
 
221
222 zIgnoreFlag = find_option("ignore",0,1);
223 includeDotFiles = find_option("dotfiles",0,0)!=0;
224 capture_case_sensitive_option();
225 db_must_be_within_tree();
226 caseSensitive = filenames_are_case_sensitive();
227 if( zIgnoreFlag==0 ){
228 zIgnoreFlag = db_get("ignore-glob", 0);
@@ -250,11 +251,11 @@
250
251 file_canonical_name(g.argv[i], &fullName, 0);
252 zName = blob_str(&fullName);
253 isDir = file_wd_isdir(zName);
254 if( isDir==1 ){
255 vfile_scan(&fullName, nRoot-1, includeDotFiles, pIgnore);
256 }else if( isDir==0 ){
257 fossil_warning("not found: %s", zName);
258 }else if( file_access(zName, R_OK) ){
259 fossil_fatal("cannot open %s", zName);
260 }else{
@@ -433,11 +434,11 @@
433 ** See also: add, rm
434 */
435 void addremove_cmd(void){
436 Blob path;
437 const char *zIgnoreFlag = find_option("ignore",0,1);
438 int allFlag = find_option("dotfiles",0,0)!=0;
439 int isTest = find_option("test",0,0)!=0;
440 int caseSensitive;
441 int n;
442 Stmt q;
443 int vid;
@@ -466,11 +467,11 @@
466 db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)");
467 n = strlen(g.zLocalRoot);
468 blob_init(&path, g.zLocalRoot, n-1);
469 /* now we read the complete file structure into a temp table */
470 pIgnore = glob_create(zIgnoreFlag);
471 vfile_scan(&path, blob_size(&path), allFlag, pIgnore);
472 glob_free(pIgnore);
473 nAdd = add_files_in_sfile(vid, caseSensitive);
474
475 /* step 2: search for missing files */
476 db_prepare(&q,
477
--- src/add.c
+++ src/add.c
@@ -216,13 +216,14 @@
216 int vid; /* Currently checked out version */
217 int nRoot; /* Full path characters in g.zLocalRoot */
218 const char *zIgnoreFlag; /* The --ignore option or ignore-glob setting */
219 Glob *pIgnore; /* Ignore everything matching this glob pattern */
220 int caseSensitive; /* True if filenames are case sensitive */
221 unsigned scanFlags = 0; /* Flags passed to vfile_scan() */
222
223 zIgnoreFlag = find_option("ignore",0,1);
224 if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL;
225 capture_case_sensitive_option();
226 db_must_be_within_tree();
227 caseSensitive = filenames_are_case_sensitive();
228 if( zIgnoreFlag==0 ){
229 zIgnoreFlag = db_get("ignore-glob", 0);
@@ -250,11 +251,11 @@
251
252 file_canonical_name(g.argv[i], &fullName, 0);
253 zName = blob_str(&fullName);
254 isDir = file_wd_isdir(zName);
255 if( isDir==1 ){
256 vfile_scan(&fullName, nRoot-1, scanFlags, pIgnore);
257 }else if( isDir==0 ){
258 fossil_warning("not found: %s", zName);
259 }else if( file_access(zName, R_OK) ){
260 fossil_fatal("cannot open %s", zName);
261 }else{
@@ -433,11 +434,11 @@
434 ** See also: add, rm
435 */
436 void addremove_cmd(void){
437 Blob path;
438 const char *zIgnoreFlag = find_option("ignore",0,1);
439 unsigned scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0;
440 int isTest = find_option("test",0,0)!=0;
441 int caseSensitive;
442 int n;
443 Stmt q;
444 int vid;
@@ -466,11 +467,11 @@
467 db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)");
468 n = strlen(g.zLocalRoot);
469 blob_init(&path, g.zLocalRoot, n-1);
470 /* now we read the complete file structure into a temp table */
471 pIgnore = glob_create(zIgnoreFlag);
472 vfile_scan(&path, blob_size(&path), scanFlags, pIgnore);
473 glob_free(pIgnore);
474 nAdd = add_files_in_sfile(vid, caseSensitive);
475
476 /* step 2: search for missing files */
477 db_prepare(&q,
478
+152
--- src/browse.c
+++ src/browse.c
@@ -165,10 +165,12 @@
165165
if( zD ){
166166
style_submenu_element("Top", "Top", "%R/dir?ci=%S", zUuid);
167167
style_submenu_element("All", "All", "%R/dir?name=%t", zD);
168168
}else{
169169
style_submenu_element("All", "All", "%R/dir");
170
+ style_submenu_element("File Ages", "File Ages", "%R/fileage?name=%S",
171
+ zUuid);
170172
}
171173
}else{
172174
int hasTrunk;
173175
@ <h2>The union of all files from all check-ins
174176
@ %s(blob_str(&dirname))</h2>
@@ -293,5 +295,155 @@
293295
db_finalize(&q);
294296
manifest_destroy(pM);
295297
@ </ul></td></tr></table>
296298
style_footer();
297299
}
300
+
301
+/*
302
+** Look at all file containing in the version "vid". Construct a
303
+** temporary table named "fileage" that contains the file-id for each
304
+** files, the pathname, the check-in where the file was added, and the
305
+** mtime on that checkin.
306
+*/
307
+int compute_fileage(int vid){
308
+ Manifest *pManifest;
309
+ ManifestFile *pFile;
310
+ int nFile = 0;
311
+ double vmtime;
312
+ Stmt ins;
313
+ Stmt q1, q2, q3;
314
+ Stmt upd;
315
+ db_multi_exec(
316
+ /*"DROP TABLE IF EXISTS temp.fileage;"*/
317
+ "CREATE TEMP TABLE fileage("
318
+ " fid INTEGER,"
319
+ " mid INTEGER,"
320
+ " mtime DATETIME,"
321
+ " pathname TEXT"
322
+ ");"
323
+ "CREATE INDEX fileage_fid ON fileage(fid);"
324
+ );
325
+ pManifest = manifest_get(vid, CFTYPE_MANIFEST);
326
+ if( pManifest==0 ) return 1;
327
+ manifest_file_rewind(pManifest);
328
+ db_prepare(&ins,
329
+ "INSERT INTO temp.fileage(fid, pathname)"
330
+ " SELECT rid, :path FROM blob WHERE uuid=:uuid"
331
+ );
332
+ while( (pFile = manifest_file_next(pManifest, 0))!=0 ){
333
+ db_bind_text(&ins, ":uuid", pFile->zUuid);
334
+ db_bind_text(&ins, ":path", pFile->zName);
335
+ db_step(&ins);
336
+ db_reset(&ins);
337
+ nFile++;
338
+ }
339
+ db_finalize(&ins);
340
+ manifest_destroy(pManifest);
341
+ db_prepare(&q1,"SELECT fid FROM mlink WHERE mid=:mid");
342
+ db_prepare(&upd, "UPDATE fileage SET mid=:mid, mtime=:vmtime"
343
+ " WHERE fid=:fid AND mid IS NULL");
344
+ db_prepare(&q2,"SELECT pid FROM plink WHERE cid=:vid AND isprim");
345
+ db_prepare(&q3,"SELECT mtime FROM event WHERE objid=:vid");
346
+ while( nFile>0 && vid>0 ){
347
+ db_bind_int(&q3, ":vid", vid);
348
+ if( db_step(&q3)==SQLITE_ROW ){
349
+ vmtime = db_column_double(&q3, 0);
350
+ }else{
351
+ break;
352
+ }
353
+ db_reset(&q3);
354
+ db_bind_int(&q1, ":mid", vid);
355
+ db_bind_int(&upd, ":mid", vid);
356
+ db_bind_double(&upd, ":vmtime", vmtime);
357
+ while( db_step(&q1)==SQLITE_ROW ){
358
+ db_bind_int(&upd, ":fid", db_column_int(&q1, 0));
359
+ db_step(&upd);
360
+ nFile -= db_changes();
361
+ db_reset(&upd);
362
+ }
363
+ db_reset(&q1);
364
+ db_bind_int(&q2, ":vid", vid);
365
+ if( db_step(&q2)!=SQLITE_ROW ) break;
366
+ vid = db_column_int(&q2, 0);
367
+ db_reset(&q2);
368
+ }
369
+ db_finalize(&q1);
370
+ db_finalize(&upd);
371
+ db_finalize(&q2);
372
+ db_finalize(&q3);
373
+ return 0;
374
+}
375
+
376
+/*
377
+** WEBPAGE: fileage
378
+**
379
+** Parameters:
380
+** name=VERSION
381
+*/
382
+void fileage_page(void){
383
+ int rid;
384
+ const char *zName;
385
+ char *zBaseTime;
386
+ Stmt q;
387
+ double baseTime;
388
+ int lastMid = -1;
389
+
390
+ login_check_credentials();
391
+ if( !g.perm.Read ){ login_needed(); return; }
392
+ zName = P("name");
393
+ if( zName==0 ) zName = "tip";
394
+ rid = symbolic_name_to_rid(zName, "ci");
395
+ if( rid==0 ){
396
+ fossil_fatal("not a valid check-in: %s", zName);
397
+ }
398
+ style_header("File Ages", zName);
399
+ compute_fileage(rid);
400
+ baseTime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid);
401
+ zBaseTime = db_text("","SELECT datetime(%.20g,'localtime')", baseTime);
402
+ @ <h2>File Ages For Check-in
403
+ @ %z(href("%R/info?name=%T",zName))%h(zName)</a></h2>
404
+ @
405
+ @ <p>The times given are relative
406
+ @ %z(href("%R/timeline?c=%T",zBaseTime))%s(zBaseTime)</a>, which is the
407
+ @ check-in time for
408
+ @ %z(href("%R/info?name=%T",zName))%h(zName)</a></p>
409
+ @
410
+ @ <table border=0 cellspacing=0 cellpadding=0>
411
+ db_prepare(&q,
412
+ "SELECT mtime, (SELECT uuid FROM blob WHERE rid=fid), mid, pathname"
413
+ " FROM fileage"
414
+ " ORDER BY mtime DESC, mid, pathname"
415
+ );
416
+ while( db_step(&q)==SQLITE_ROW ){
417
+ double age = baseTime - db_column_double(&q, 0);
418
+ int mid = db_column_int(&q, 2);
419
+ const char *zFUuid = db_column_text(&q, 1);
420
+ char zAge[200];
421
+ if( lastMid!=mid ){
422
+ @ <tr><td colspan=3><hr></tr>
423
+ lastMid = mid;
424
+ if( age*86400.0<120 ){
425
+ sqlite3_snprintf(sizeof(zAge), zAge, "%d seconds", (int)(age*86400.0));
426
+ }else if( age*1440.0<90 ){
427
+ sqlite3_snprintf(sizeof(zAge), zAge, "%.1f minutes", age*1440.0);
428
+ }else if( age*24.0<36 ){
429
+ sqlite3_snprintf(sizeof(zAge), zAge, "%.1f hours", age*24.0);
430
+ }else if( age<365.0 ){
431
+ sqlite3_snprintf(sizeof(zAge), zAge, "%.1f days", age);
432
+ }else{
433
+ sqlite3_snprintf(sizeof(zAge), zAge, "%.2f years", age/365.0);
434
+ }
435
+ }else{
436
+ zAge[0] = 0;
437
+ }
438
+ @ <tr>
439
+ @ <td>%s(zAge)
440
+ @ <td width="25">
441
+ @ <td>%z(href("%R/artifact/%S?ln", zFUuid))%h(db_column_text(&q, 3))</a>
442
+ @ </tr>
443
+ @
444
+ }
445
+ @ <tr><td colspan=3><hr></tr>
446
+ @ </table>
447
+ db_finalize(&q);
448
+ style_footer();
449
+}
298450
--- src/browse.c
+++ src/browse.c
@@ -165,10 +165,12 @@
165 if( zD ){
166 style_submenu_element("Top", "Top", "%R/dir?ci=%S", zUuid);
167 style_submenu_element("All", "All", "%R/dir?name=%t", zD);
168 }else{
169 style_submenu_element("All", "All", "%R/dir");
 
 
170 }
171 }else{
172 int hasTrunk;
173 @ <h2>The union of all files from all check-ins
174 @ %s(blob_str(&dirname))</h2>
@@ -293,5 +295,155 @@
293 db_finalize(&q);
294 manifest_destroy(pM);
295 @ </ul></td></tr></table>
296 style_footer();
297 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
298
--- src/browse.c
+++ src/browse.c
@@ -165,10 +165,12 @@
165 if( zD ){
166 style_submenu_element("Top", "Top", "%R/dir?ci=%S", zUuid);
167 style_submenu_element("All", "All", "%R/dir?name=%t", zD);
168 }else{
169 style_submenu_element("All", "All", "%R/dir");
170 style_submenu_element("File Ages", "File Ages", "%R/fileage?name=%S",
171 zUuid);
172 }
173 }else{
174 int hasTrunk;
175 @ <h2>The union of all files from all check-ins
176 @ %s(blob_str(&dirname))</h2>
@@ -293,5 +295,155 @@
295 db_finalize(&q);
296 manifest_destroy(pM);
297 @ </ul></td></tr></table>
298 style_footer();
299 }
300
301 /*
302 ** Look at all file containing in the version "vid". Construct a
303 ** temporary table named "fileage" that contains the file-id for each
304 ** files, the pathname, the check-in where the file was added, and the
305 ** mtime on that checkin.
306 */
307 int compute_fileage(int vid){
308 Manifest *pManifest;
309 ManifestFile *pFile;
310 int nFile = 0;
311 double vmtime;
312 Stmt ins;
313 Stmt q1, q2, q3;
314 Stmt upd;
315 db_multi_exec(
316 /*"DROP TABLE IF EXISTS temp.fileage;"*/
317 "CREATE TEMP TABLE fileage("
318 " fid INTEGER,"
319 " mid INTEGER,"
320 " mtime DATETIME,"
321 " pathname TEXT"
322 ");"
323 "CREATE INDEX fileage_fid ON fileage(fid);"
324 );
325 pManifest = manifest_get(vid, CFTYPE_MANIFEST);
326 if( pManifest==0 ) return 1;
327 manifest_file_rewind(pManifest);
328 db_prepare(&ins,
329 "INSERT INTO temp.fileage(fid, pathname)"
330 " SELECT rid, :path FROM blob WHERE uuid=:uuid"
331 );
332 while( (pFile = manifest_file_next(pManifest, 0))!=0 ){
333 db_bind_text(&ins, ":uuid", pFile->zUuid);
334 db_bind_text(&ins, ":path", pFile->zName);
335 db_step(&ins);
336 db_reset(&ins);
337 nFile++;
338 }
339 db_finalize(&ins);
340 manifest_destroy(pManifest);
341 db_prepare(&q1,"SELECT fid FROM mlink WHERE mid=:mid");
342 db_prepare(&upd, "UPDATE fileage SET mid=:mid, mtime=:vmtime"
343 " WHERE fid=:fid AND mid IS NULL");
344 db_prepare(&q2,"SELECT pid FROM plink WHERE cid=:vid AND isprim");
345 db_prepare(&q3,"SELECT mtime FROM event WHERE objid=:vid");
346 while( nFile>0 && vid>0 ){
347 db_bind_int(&q3, ":vid", vid);
348 if( db_step(&q3)==SQLITE_ROW ){
349 vmtime = db_column_double(&q3, 0);
350 }else{
351 break;
352 }
353 db_reset(&q3);
354 db_bind_int(&q1, ":mid", vid);
355 db_bind_int(&upd, ":mid", vid);
356 db_bind_double(&upd, ":vmtime", vmtime);
357 while( db_step(&q1)==SQLITE_ROW ){
358 db_bind_int(&upd, ":fid", db_column_int(&q1, 0));
359 db_step(&upd);
360 nFile -= db_changes();
361 db_reset(&upd);
362 }
363 db_reset(&q1);
364 db_bind_int(&q2, ":vid", vid);
365 if( db_step(&q2)!=SQLITE_ROW ) break;
366 vid = db_column_int(&q2, 0);
367 db_reset(&q2);
368 }
369 db_finalize(&q1);
370 db_finalize(&upd);
371 db_finalize(&q2);
372 db_finalize(&q3);
373 return 0;
374 }
375
376 /*
377 ** WEBPAGE: fileage
378 **
379 ** Parameters:
380 ** name=VERSION
381 */
382 void fileage_page(void){
383 int rid;
384 const char *zName;
385 char *zBaseTime;
386 Stmt q;
387 double baseTime;
388 int lastMid = -1;
389
390 login_check_credentials();
391 if( !g.perm.Read ){ login_needed(); return; }
392 zName = P("name");
393 if( zName==0 ) zName = "tip";
394 rid = symbolic_name_to_rid(zName, "ci");
395 if( rid==0 ){
396 fossil_fatal("not a valid check-in: %s", zName);
397 }
398 style_header("File Ages", zName);
399 compute_fileage(rid);
400 baseTime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid);
401 zBaseTime = db_text("","SELECT datetime(%.20g,'localtime')", baseTime);
402 @ <h2>File Ages For Check-in
403 @ %z(href("%R/info?name=%T",zName))%h(zName)</a></h2>
404 @
405 @ <p>The times given are relative
406 @ %z(href("%R/timeline?c=%T",zBaseTime))%s(zBaseTime)</a>, which is the
407 @ check-in time for
408 @ %z(href("%R/info?name=%T",zName))%h(zName)</a></p>
409 @
410 @ <table border=0 cellspacing=0 cellpadding=0>
411 db_prepare(&q,
412 "SELECT mtime, (SELECT uuid FROM blob WHERE rid=fid), mid, pathname"
413 " FROM fileage"
414 " ORDER BY mtime DESC, mid, pathname"
415 );
416 while( db_step(&q)==SQLITE_ROW ){
417 double age = baseTime - db_column_double(&q, 0);
418 int mid = db_column_int(&q, 2);
419 const char *zFUuid = db_column_text(&q, 1);
420 char zAge[200];
421 if( lastMid!=mid ){
422 @ <tr><td colspan=3><hr></tr>
423 lastMid = mid;
424 if( age*86400.0<120 ){
425 sqlite3_snprintf(sizeof(zAge), zAge, "%d seconds", (int)(age*86400.0));
426 }else if( age*1440.0<90 ){
427 sqlite3_snprintf(sizeof(zAge), zAge, "%.1f minutes", age*1440.0);
428 }else if( age*24.0<36 ){
429 sqlite3_snprintf(sizeof(zAge), zAge, "%.1f hours", age*24.0);
430 }else if( age<365.0 ){
431 sqlite3_snprintf(sizeof(zAge), zAge, "%.1f days", age);
432 }else{
433 sqlite3_snprintf(sizeof(zAge), zAge, "%.2f years", age/365.0);
434 }
435 }else{
436 zAge[0] = 0;
437 }
438 @ <tr>
439 @ <td>%s(zAge)
440 @ <td width="25">
441 @ <td>%z(href("%R/artifact/%S?ln", zFUuid))%h(db_column_text(&q, 3))</a>
442 @ </tr>
443 @
444 }
445 @ <tr><td colspan=3><hr></tr>
446 @ </table>
447 db_finalize(&q);
448 style_footer();
449 }
450
+46 -19
--- src/checkin.c
+++ src/checkin.c
@@ -160,11 +160,11 @@
160160
int cwdRelative = 0;
161161
db_must_be_within_tree();
162162
cwdRelative = determine_cwd_relative_option();
163163
blob_zero(&report);
164164
vid = db_lget_int("checkout", 0);
165
- vfile_check_signature(vid, 0, useSha1sum);
165
+ vfile_check_signature(vid, useSha1sum ? CKSIG_SHA1 : 0);
166166
status_report(&report, "", 0, cwdRelative);
167167
if( verbose && blob_size(&report)==0 ){
168168
blob_append(&report, " (none)\n", -1);
169169
}
170170
if( showHdr && blob_size(&report)>0 ){
@@ -205,46 +205,74 @@
205205
show_common_info(vid, "checkout:", 1, 1);
206206
}
207207
db_record_repository_filename(0);
208208
changes_cmd();
209209
}
210
+
211
+/*
212
+** Implementation of the checkin_mtime SQL function
213
+*/
214
+
210215
211216
/*
212217
** COMMAND: ls
213218
**
214
-** Usage: %fossil ls ?OPTIONS?
219
+** Usage: %fossil ls ?OPTIONS? ?VERSION?
215220
**
216221
** Show the names of all files in the current checkout. The -l provides
217222
** extra information about each file.
218223
**
219224
** Options:
220
-** -l Provide extra information about each file.
225
+** -l Provide extra information about each file.
226
+** --age Show when each file was committed
221227
**
222228
** See also: changes, extra, status
223229
*/
224230
void ls_cmd(void){
225231
int vid;
226232
Stmt q;
227233
int isBrief;
234
+ int showAge;
235
+ char *zOrderBy = "pathname";
228236
229237
isBrief = find_option("l","l", 0)==0;
238
+ showAge = find_option("age",0,0)!=0;
230239
db_must_be_within_tree();
231240
vid = db_lget_int("checkout", 0);
232
- vfile_check_signature(vid, 0, 0);
233
- db_prepare(&q,
234
- "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)"
235
- " FROM vfile"
236
- " ORDER BY 1"
237
- );
241
+ if( find_option("t","t",0)!=0 ){
242
+ if( showAge ){
243
+ zOrderBy = mprintf("checkin_mtime(%d,rid) DESC", vid);
244
+ }else{
245
+ zOrderBy = "mtime DESC";
246
+ }
247
+ }
248
+ verify_all_options();
249
+ vfile_check_signature(vid, 0);
250
+ if( showAge ){
251
+ db_prepare(&q,
252
+ "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0),"
253
+ " datetime(checkin_mtime(%d,rid),'unixepoch','localtime')"
254
+ " FROM vfile"
255
+ " ORDER BY %s", vid, zOrderBy
256
+ );
257
+ }else{
258
+ db_prepare(&q,
259
+ "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)"
260
+ " FROM vfile"
261
+ " ORDER BY %s", zOrderBy
262
+ );
263
+ }
238264
while( db_step(&q)==SQLITE_ROW ){
239265
const char *zPathname = db_column_text(&q,0);
240266
int isDeleted = db_column_int(&q, 1);
241267
int isNew = db_column_int(&q,2)==0;
242268
int chnged = db_column_int(&q,3);
243269
int renamed = db_column_int(&q,4);
244270
char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
245
- if( isBrief ){
271
+ if( showAge ){
272
+ fossil_print("%s %s\n", db_column_text(&q, 5), zPathname);
273
+ }else if( isBrief ){
246274
fossil_print("%s\n", zPathname);
247275
}else if( isNew ){
248276
fossil_print("ADDED %s\n", zPathname);
249277
}else if( isDeleted ){
250278
fossil_print("DELETED %s\n", zPathname);
@@ -296,16 +324,17 @@
296324
Blob path;
297325
Blob repo;
298326
Stmt q;
299327
int n;
300328
const char *zIgnoreFlag = find_option("ignore",0,1);
301
- int allFlag = find_option("dotfiles",0,0)!=0;
329
+ unsigned scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0;
302330
int cwdRelative = 0;
303331
Glob *pIgnore;
304332
Blob rewrittenPathname;
305333
const char *zPathname, *zDisplayName;
306334
335
+ if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP;
307336
db_must_be_within_tree();
308337
cwdRelative = determine_cwd_relative_option();
309338
db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
310339
filename_collation());
311340
n = strlen(g.zLocalRoot);
@@ -312,11 +341,11 @@
312341
blob_init(&path, g.zLocalRoot, n-1);
313342
if( zIgnoreFlag==0 ){
314343
zIgnoreFlag = db_get("ignore-glob", 0);
315344
}
316345
pIgnore = glob_create(zIgnoreFlag);
317
- vfile_scan(&path, blob_size(&path), allFlag, pIgnore);
346
+ vfile_scan(&path, blob_size(&path), scanFlags, pIgnore);
318347
glob_free(pIgnore);
319348
db_prepare(&q,
320349
"SELECT x FROM sfile"
321350
" WHERE x NOT IN (%s)"
322351
" ORDER BY 1",
@@ -367,34 +396,36 @@
367396
** Options:
368397
** --dotfiles include files beginning with a dot (".")
369398
** --force Remove files without prompting
370399
** --ignore <CSG> ignore files matching patterns from the
371400
** comma separated list of glob patterns.
401
+** --temp Remove only Fossil-generated temporary files
372402
**
373403
** See also: addremove, extra, status
374404
*/
375405
void clean_cmd(void){
376406
int allFlag;
377
- int dotfilesFlag;
407
+ unsigned scanFlags = 0;
378408
const char *zIgnoreFlag;
379409
Blob path, repo;
380410
Stmt q;
381411
int n;
382412
Glob *pIgnore;
383413
384414
allFlag = find_option("force","f",0)!=0;
385
- dotfilesFlag = find_option("dotfiles",0,0)!=0;
415
+ if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL;
416
+ if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP;
386417
zIgnoreFlag = find_option("ignore",0,1);
387418
db_must_be_within_tree();
388419
if( zIgnoreFlag==0 ){
389420
zIgnoreFlag = db_get("ignore-glob", 0);
390421
}
391422
db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)");
392423
n = strlen(g.zLocalRoot);
393424
blob_init(&path, g.zLocalRoot, n-1);
394425
pIgnore = glob_create(zIgnoreFlag);
395
- vfile_scan(&path, blob_size(&path), dotfilesFlag, pIgnore);
426
+ vfile_scan(&path, blob_size(&path), scanFlags, pIgnore);
396427
glob_free(pIgnore);
397428
db_prepare(&q,
398429
"SELECT %Q || x FROM sfile"
399430
" WHERE x NOT IN (%s)"
400431
" ORDER BY 1",
@@ -813,14 +844,10 @@
813844
}
814845
if( zColor && zColor[0] ){
815846
/* One-time background color */
816847
blob_appendf(pOut, "T +bgcolor * %F\n", zColor);
817848
}
818
- if( g.markPrivate ){
819
- /* If this manifest is private, mark it as such */
820
- blob_appendf(pOut, "T +private *\n");
821
- }
822849
if( azTag ){
823850
for(i=0; azTag[i]; i++){
824851
/* Add a symbolic tag to this check-in. The tag names have already
825852
** been sorted and converted using the %F format */
826853
blob_appendf(pOut, "T +sym-%s *\n", azTag[i]);
827854
--- src/checkin.c
+++ src/checkin.c
@@ -160,11 +160,11 @@
160 int cwdRelative = 0;
161 db_must_be_within_tree();
162 cwdRelative = determine_cwd_relative_option();
163 blob_zero(&report);
164 vid = db_lget_int("checkout", 0);
165 vfile_check_signature(vid, 0, useSha1sum);
166 status_report(&report, "", 0, cwdRelative);
167 if( verbose && blob_size(&report)==0 ){
168 blob_append(&report, " (none)\n", -1);
169 }
170 if( showHdr && blob_size(&report)>0 ){
@@ -205,46 +205,74 @@
205 show_common_info(vid, "checkout:", 1, 1);
206 }
207 db_record_repository_filename(0);
208 changes_cmd();
209 }
 
 
 
 
 
210
211 /*
212 ** COMMAND: ls
213 **
214 ** Usage: %fossil ls ?OPTIONS?
215 **
216 ** Show the names of all files in the current checkout. The -l provides
217 ** extra information about each file.
218 **
219 ** Options:
220 ** -l Provide extra information about each file.
 
221 **
222 ** See also: changes, extra, status
223 */
224 void ls_cmd(void){
225 int vid;
226 Stmt q;
227 int isBrief;
 
 
228
229 isBrief = find_option("l","l", 0)==0;
 
230 db_must_be_within_tree();
231 vid = db_lget_int("checkout", 0);
232 vfile_check_signature(vid, 0, 0);
233 db_prepare(&q,
234 "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)"
235 " FROM vfile"
236 " ORDER BY 1"
237 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
238 while( db_step(&q)==SQLITE_ROW ){
239 const char *zPathname = db_column_text(&q,0);
240 int isDeleted = db_column_int(&q, 1);
241 int isNew = db_column_int(&q,2)==0;
242 int chnged = db_column_int(&q,3);
243 int renamed = db_column_int(&q,4);
244 char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
245 if( isBrief ){
 
 
246 fossil_print("%s\n", zPathname);
247 }else if( isNew ){
248 fossil_print("ADDED %s\n", zPathname);
249 }else if( isDeleted ){
250 fossil_print("DELETED %s\n", zPathname);
@@ -296,16 +324,17 @@
296 Blob path;
297 Blob repo;
298 Stmt q;
299 int n;
300 const char *zIgnoreFlag = find_option("ignore",0,1);
301 int allFlag = find_option("dotfiles",0,0)!=0;
302 int cwdRelative = 0;
303 Glob *pIgnore;
304 Blob rewrittenPathname;
305 const char *zPathname, *zDisplayName;
306
 
307 db_must_be_within_tree();
308 cwdRelative = determine_cwd_relative_option();
309 db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
310 filename_collation());
311 n = strlen(g.zLocalRoot);
@@ -312,11 +341,11 @@
312 blob_init(&path, g.zLocalRoot, n-1);
313 if( zIgnoreFlag==0 ){
314 zIgnoreFlag = db_get("ignore-glob", 0);
315 }
316 pIgnore = glob_create(zIgnoreFlag);
317 vfile_scan(&path, blob_size(&path), allFlag, pIgnore);
318 glob_free(pIgnore);
319 db_prepare(&q,
320 "SELECT x FROM sfile"
321 " WHERE x NOT IN (%s)"
322 " ORDER BY 1",
@@ -367,34 +396,36 @@
367 ** Options:
368 ** --dotfiles include files beginning with a dot (".")
369 ** --force Remove files without prompting
370 ** --ignore <CSG> ignore files matching patterns from the
371 ** comma separated list of glob patterns.
 
372 **
373 ** See also: addremove, extra, status
374 */
375 void clean_cmd(void){
376 int allFlag;
377 int dotfilesFlag;
378 const char *zIgnoreFlag;
379 Blob path, repo;
380 Stmt q;
381 int n;
382 Glob *pIgnore;
383
384 allFlag = find_option("force","f",0)!=0;
385 dotfilesFlag = find_option("dotfiles",0,0)!=0;
 
386 zIgnoreFlag = find_option("ignore",0,1);
387 db_must_be_within_tree();
388 if( zIgnoreFlag==0 ){
389 zIgnoreFlag = db_get("ignore-glob", 0);
390 }
391 db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)");
392 n = strlen(g.zLocalRoot);
393 blob_init(&path, g.zLocalRoot, n-1);
394 pIgnore = glob_create(zIgnoreFlag);
395 vfile_scan(&path, blob_size(&path), dotfilesFlag, pIgnore);
396 glob_free(pIgnore);
397 db_prepare(&q,
398 "SELECT %Q || x FROM sfile"
399 " WHERE x NOT IN (%s)"
400 " ORDER BY 1",
@@ -813,14 +844,10 @@
813 }
814 if( zColor && zColor[0] ){
815 /* One-time background color */
816 blob_appendf(pOut, "T +bgcolor * %F\n", zColor);
817 }
818 if( g.markPrivate ){
819 /* If this manifest is private, mark it as such */
820 blob_appendf(pOut, "T +private *\n");
821 }
822 if( azTag ){
823 for(i=0; azTag[i]; i++){
824 /* Add a symbolic tag to this check-in. The tag names have already
825 ** been sorted and converted using the %F format */
826 blob_appendf(pOut, "T +sym-%s *\n", azTag[i]);
827
--- src/checkin.c
+++ src/checkin.c
@@ -160,11 +160,11 @@
160 int cwdRelative = 0;
161 db_must_be_within_tree();
162 cwdRelative = determine_cwd_relative_option();
163 blob_zero(&report);
164 vid = db_lget_int("checkout", 0);
165 vfile_check_signature(vid, useSha1sum ? CKSIG_SHA1 : 0);
166 status_report(&report, "", 0, cwdRelative);
167 if( verbose && blob_size(&report)==0 ){
168 blob_append(&report, " (none)\n", -1);
169 }
170 if( showHdr && blob_size(&report)>0 ){
@@ -205,46 +205,74 @@
205 show_common_info(vid, "checkout:", 1, 1);
206 }
207 db_record_repository_filename(0);
208 changes_cmd();
209 }
210
211 /*
212 ** Implementation of the checkin_mtime SQL function
213 */
214
215
216 /*
217 ** COMMAND: ls
218 **
219 ** Usage: %fossil ls ?OPTIONS? ?VERSION?
220 **
221 ** Show the names of all files in the current checkout. The -l provides
222 ** extra information about each file.
223 **
224 ** Options:
225 ** -l Provide extra information about each file.
226 ** --age Show when each file was committed
227 **
228 ** See also: changes, extra, status
229 */
230 void ls_cmd(void){
231 int vid;
232 Stmt q;
233 int isBrief;
234 int showAge;
235 char *zOrderBy = "pathname";
236
237 isBrief = find_option("l","l", 0)==0;
238 showAge = find_option("age",0,0)!=0;
239 db_must_be_within_tree();
240 vid = db_lget_int("checkout", 0);
241 if( find_option("t","t",0)!=0 ){
242 if( showAge ){
243 zOrderBy = mprintf("checkin_mtime(%d,rid) DESC", vid);
244 }else{
245 zOrderBy = "mtime DESC";
246 }
247 }
248 verify_all_options();
249 vfile_check_signature(vid, 0);
250 if( showAge ){
251 db_prepare(&q,
252 "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0),"
253 " datetime(checkin_mtime(%d,rid),'unixepoch','localtime')"
254 " FROM vfile"
255 " ORDER BY %s", vid, zOrderBy
256 );
257 }else{
258 db_prepare(&q,
259 "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)"
260 " FROM vfile"
261 " ORDER BY %s", zOrderBy
262 );
263 }
264 while( db_step(&q)==SQLITE_ROW ){
265 const char *zPathname = db_column_text(&q,0);
266 int isDeleted = db_column_int(&q, 1);
267 int isNew = db_column_int(&q,2)==0;
268 int chnged = db_column_int(&q,3);
269 int renamed = db_column_int(&q,4);
270 char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
271 if( showAge ){
272 fossil_print("%s %s\n", db_column_text(&q, 5), zPathname);
273 }else if( isBrief ){
274 fossil_print("%s\n", zPathname);
275 }else if( isNew ){
276 fossil_print("ADDED %s\n", zPathname);
277 }else if( isDeleted ){
278 fossil_print("DELETED %s\n", zPathname);
@@ -296,16 +324,17 @@
324 Blob path;
325 Blob repo;
326 Stmt q;
327 int n;
328 const char *zIgnoreFlag = find_option("ignore",0,1);
329 unsigned scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0;
330 int cwdRelative = 0;
331 Glob *pIgnore;
332 Blob rewrittenPathname;
333 const char *zPathname, *zDisplayName;
334
335 if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP;
336 db_must_be_within_tree();
337 cwdRelative = determine_cwd_relative_option();
338 db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
339 filename_collation());
340 n = strlen(g.zLocalRoot);
@@ -312,11 +341,11 @@
341 blob_init(&path, g.zLocalRoot, n-1);
342 if( zIgnoreFlag==0 ){
343 zIgnoreFlag = db_get("ignore-glob", 0);
344 }
345 pIgnore = glob_create(zIgnoreFlag);
346 vfile_scan(&path, blob_size(&path), scanFlags, pIgnore);
347 glob_free(pIgnore);
348 db_prepare(&q,
349 "SELECT x FROM sfile"
350 " WHERE x NOT IN (%s)"
351 " ORDER BY 1",
@@ -367,34 +396,36 @@
396 ** Options:
397 ** --dotfiles include files beginning with a dot (".")
398 ** --force Remove files without prompting
399 ** --ignore <CSG> ignore files matching patterns from the
400 ** comma separated list of glob patterns.
401 ** --temp Remove only Fossil-generated temporary files
402 **
403 ** See also: addremove, extra, status
404 */
405 void clean_cmd(void){
406 int allFlag;
407 unsigned scanFlags = 0;
408 const char *zIgnoreFlag;
409 Blob path, repo;
410 Stmt q;
411 int n;
412 Glob *pIgnore;
413
414 allFlag = find_option("force","f",0)!=0;
415 if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL;
416 if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP;
417 zIgnoreFlag = find_option("ignore",0,1);
418 db_must_be_within_tree();
419 if( zIgnoreFlag==0 ){
420 zIgnoreFlag = db_get("ignore-glob", 0);
421 }
422 db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)");
423 n = strlen(g.zLocalRoot);
424 blob_init(&path, g.zLocalRoot, n-1);
425 pIgnore = glob_create(zIgnoreFlag);
426 vfile_scan(&path, blob_size(&path), scanFlags, pIgnore);
427 glob_free(pIgnore);
428 db_prepare(&q,
429 "SELECT %Q || x FROM sfile"
430 " WHERE x NOT IN (%s)"
431 " ORDER BY 1",
@@ -813,14 +844,10 @@
844 }
845 if( zColor && zColor[0] ){
846 /* One-time background color */
847 blob_appendf(pOut, "T +bgcolor * %F\n", zColor);
848 }
 
 
 
 
849 if( azTag ){
850 for(i=0; azTag[i]; i++){
851 /* Add a symbolic tag to this check-in. The tag names have already
852 ** been sorted and converted using the %F format */
853 blob_appendf(pOut, "T +sym-%s *\n", azTag[i]);
854
+46 -19
--- src/checkin.c
+++ src/checkin.c
@@ -160,11 +160,11 @@
160160
int cwdRelative = 0;
161161
db_must_be_within_tree();
162162
cwdRelative = determine_cwd_relative_option();
163163
blob_zero(&report);
164164
vid = db_lget_int("checkout", 0);
165
- vfile_check_signature(vid, 0, useSha1sum);
165
+ vfile_check_signature(vid, useSha1sum ? CKSIG_SHA1 : 0);
166166
status_report(&report, "", 0, cwdRelative);
167167
if( verbose && blob_size(&report)==0 ){
168168
blob_append(&report, " (none)\n", -1);
169169
}
170170
if( showHdr && blob_size(&report)>0 ){
@@ -205,46 +205,74 @@
205205
show_common_info(vid, "checkout:", 1, 1);
206206
}
207207
db_record_repository_filename(0);
208208
changes_cmd();
209209
}
210
+
211
+/*
212
+** Implementation of the checkin_mtime SQL function
213
+*/
214
+
210215
211216
/*
212217
** COMMAND: ls
213218
**
214
-** Usage: %fossil ls ?OPTIONS?
219
+** Usage: %fossil ls ?OPTIONS? ?VERSION?
215220
**
216221
** Show the names of all files in the current checkout. The -l provides
217222
** extra information about each file.
218223
**
219224
** Options:
220
-** -l Provide extra information about each file.
225
+** -l Provide extra information about each file.
226
+** --age Show when each file was committed
221227
**
222228
** See also: changes, extra, status
223229
*/
224230
void ls_cmd(void){
225231
int vid;
226232
Stmt q;
227233
int isBrief;
234
+ int showAge;
235
+ char *zOrderBy = "pathname";
228236
229237
isBrief = find_option("l","l", 0)==0;
238
+ showAge = find_option("age",0,0)!=0;
230239
db_must_be_within_tree();
231240
vid = db_lget_int("checkout", 0);
232
- vfile_check_signature(vid, 0, 0);
233
- db_prepare(&q,
234
- "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)"
235
- " FROM vfile"
236
- " ORDER BY 1"
237
- );
241
+ if( find_option("t","t",0)!=0 ){
242
+ if( showAge ){
243
+ zOrderBy = mprintf("checkin_mtime(%d,rid) DESC", vid);
244
+ }else{
245
+ zOrderBy = "mtime DESC";
246
+ }
247
+ }
248
+ verify_all_options();
249
+ vfile_check_signature(vid, 0);
250
+ if( showAge ){
251
+ db_prepare(&q,
252
+ "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0),"
253
+ " datetime(checkin_mtime(%d,rid),'unixepoch','localtime')"
254
+ " FROM vfile"
255
+ " ORDER BY %s", vid, zOrderBy
256
+ );
257
+ }else{
258
+ db_prepare(&q,
259
+ "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)"
260
+ " FROM vfile"
261
+ " ORDER BY %s", zOrderBy
262
+ );
263
+ }
238264
while( db_step(&q)==SQLITE_ROW ){
239265
const char *zPathname = db_column_text(&q,0);
240266
int isDeleted = db_column_int(&q, 1);
241267
int isNew = db_column_int(&q,2)==0;
242268
int chnged = db_column_int(&q,3);
243269
int renamed = db_column_int(&q,4);
244270
char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
245
- if( isBrief ){
271
+ if( showAge ){
272
+ fossil_print("%s %s\n", db_column_text(&q, 5), zPathname);
273
+ }else if( isBrief ){
246274
fossil_print("%s\n", zPathname);
247275
}else if( isNew ){
248276
fossil_print("ADDED %s\n", zPathname);
249277
}else if( isDeleted ){
250278
fossil_print("DELETED %s\n", zPathname);
@@ -296,16 +324,17 @@
296324
Blob path;
297325
Blob repo;
298326
Stmt q;
299327
int n;
300328
const char *zIgnoreFlag = find_option("ignore",0,1);
301
- int allFlag = find_option("dotfiles",0,0)!=0;
329
+ unsigned scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0;
302330
int cwdRelative = 0;
303331
Glob *pIgnore;
304332
Blob rewrittenPathname;
305333
const char *zPathname, *zDisplayName;
306334
335
+ if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP;
307336
db_must_be_within_tree();
308337
cwdRelative = determine_cwd_relative_option();
309338
db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
310339
filename_collation());
311340
n = strlen(g.zLocalRoot);
@@ -312,11 +341,11 @@
312341
blob_init(&path, g.zLocalRoot, n-1);
313342
if( zIgnoreFlag==0 ){
314343
zIgnoreFlag = db_get("ignore-glob", 0);
315344
}
316345
pIgnore = glob_create(zIgnoreFlag);
317
- vfile_scan(&path, blob_size(&path), allFlag, pIgnore);
346
+ vfile_scan(&path, blob_size(&path), scanFlags, pIgnore);
318347
glob_free(pIgnore);
319348
db_prepare(&q,
320349
"SELECT x FROM sfile"
321350
" WHERE x NOT IN (%s)"
322351
" ORDER BY 1",
@@ -367,34 +396,36 @@
367396
** Options:
368397
** --dotfiles include files beginning with a dot (".")
369398
** --force Remove files without prompting
370399
** --ignore <CSG> ignore files matching patterns from the
371400
** comma separated list of glob patterns.
401
+** --temp Remove only Fossil-generated temporary files
372402
**
373403
** See also: addremove, extra, status
374404
*/
375405
void clean_cmd(void){
376406
int allFlag;
377
- int dotfilesFlag;
407
+ unsigned scanFlags = 0;
378408
const char *zIgnoreFlag;
379409
Blob path, repo;
380410
Stmt q;
381411
int n;
382412
Glob *pIgnore;
383413
384414
allFlag = find_option("force","f",0)!=0;
385
- dotfilesFlag = find_option("dotfiles",0,0)!=0;
415
+ if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL;
416
+ if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP;
386417
zIgnoreFlag = find_option("ignore",0,1);
387418
db_must_be_within_tree();
388419
if( zIgnoreFlag==0 ){
389420
zIgnoreFlag = db_get("ignore-glob", 0);
390421
}
391422
db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)");
392423
n = strlen(g.zLocalRoot);
393424
blob_init(&path, g.zLocalRoot, n-1);
394425
pIgnore = glob_create(zIgnoreFlag);
395
- vfile_scan(&path, blob_size(&path), dotfilesFlag, pIgnore);
426
+ vfile_scan(&path, blob_size(&path), scanFlags, pIgnore);
396427
glob_free(pIgnore);
397428
db_prepare(&q,
398429
"SELECT %Q || x FROM sfile"
399430
" WHERE x NOT IN (%s)"
400431
" ORDER BY 1",
@@ -813,14 +844,10 @@
813844
}
814845
if( zColor && zColor[0] ){
815846
/* One-time background color */
816847
blob_appendf(pOut, "T +bgcolor * %F\n", zColor);
817848
}
818
- if( g.markPrivate ){
819
- /* If this manifest is private, mark it as such */
820
- blob_appendf(pOut, "T +private *\n");
821
- }
822849
if( azTag ){
823850
for(i=0; azTag[i]; i++){
824851
/* Add a symbolic tag to this check-in. The tag names have already
825852
** been sorted and converted using the %F format */
826853
blob_appendf(pOut, "T +sym-%s *\n", azTag[i]);
827854
--- src/checkin.c
+++ src/checkin.c
@@ -160,11 +160,11 @@
160 int cwdRelative = 0;
161 db_must_be_within_tree();
162 cwdRelative = determine_cwd_relative_option();
163 blob_zero(&report);
164 vid = db_lget_int("checkout", 0);
165 vfile_check_signature(vid, 0, useSha1sum);
166 status_report(&report, "", 0, cwdRelative);
167 if( verbose && blob_size(&report)==0 ){
168 blob_append(&report, " (none)\n", -1);
169 }
170 if( showHdr && blob_size(&report)>0 ){
@@ -205,46 +205,74 @@
205 show_common_info(vid, "checkout:", 1, 1);
206 }
207 db_record_repository_filename(0);
208 changes_cmd();
209 }
 
 
 
 
 
210
211 /*
212 ** COMMAND: ls
213 **
214 ** Usage: %fossil ls ?OPTIONS?
215 **
216 ** Show the names of all files in the current checkout. The -l provides
217 ** extra information about each file.
218 **
219 ** Options:
220 ** -l Provide extra information about each file.
 
221 **
222 ** See also: changes, extra, status
223 */
224 void ls_cmd(void){
225 int vid;
226 Stmt q;
227 int isBrief;
 
 
228
229 isBrief = find_option("l","l", 0)==0;
 
230 db_must_be_within_tree();
231 vid = db_lget_int("checkout", 0);
232 vfile_check_signature(vid, 0, 0);
233 db_prepare(&q,
234 "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)"
235 " FROM vfile"
236 " ORDER BY 1"
237 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
238 while( db_step(&q)==SQLITE_ROW ){
239 const char *zPathname = db_column_text(&q,0);
240 int isDeleted = db_column_int(&q, 1);
241 int isNew = db_column_int(&q,2)==0;
242 int chnged = db_column_int(&q,3);
243 int renamed = db_column_int(&q,4);
244 char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
245 if( isBrief ){
 
 
246 fossil_print("%s\n", zPathname);
247 }else if( isNew ){
248 fossil_print("ADDED %s\n", zPathname);
249 }else if( isDeleted ){
250 fossil_print("DELETED %s\n", zPathname);
@@ -296,16 +324,17 @@
296 Blob path;
297 Blob repo;
298 Stmt q;
299 int n;
300 const char *zIgnoreFlag = find_option("ignore",0,1);
301 int allFlag = find_option("dotfiles",0,0)!=0;
302 int cwdRelative = 0;
303 Glob *pIgnore;
304 Blob rewrittenPathname;
305 const char *zPathname, *zDisplayName;
306
 
307 db_must_be_within_tree();
308 cwdRelative = determine_cwd_relative_option();
309 db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
310 filename_collation());
311 n = strlen(g.zLocalRoot);
@@ -312,11 +341,11 @@
312 blob_init(&path, g.zLocalRoot, n-1);
313 if( zIgnoreFlag==0 ){
314 zIgnoreFlag = db_get("ignore-glob", 0);
315 }
316 pIgnore = glob_create(zIgnoreFlag);
317 vfile_scan(&path, blob_size(&path), allFlag, pIgnore);
318 glob_free(pIgnore);
319 db_prepare(&q,
320 "SELECT x FROM sfile"
321 " WHERE x NOT IN (%s)"
322 " ORDER BY 1",
@@ -367,34 +396,36 @@
367 ** Options:
368 ** --dotfiles include files beginning with a dot (".")
369 ** --force Remove files without prompting
370 ** --ignore <CSG> ignore files matching patterns from the
371 ** comma separated list of glob patterns.
 
372 **
373 ** See also: addremove, extra, status
374 */
375 void clean_cmd(void){
376 int allFlag;
377 int dotfilesFlag;
378 const char *zIgnoreFlag;
379 Blob path, repo;
380 Stmt q;
381 int n;
382 Glob *pIgnore;
383
384 allFlag = find_option("force","f",0)!=0;
385 dotfilesFlag = find_option("dotfiles",0,0)!=0;
 
386 zIgnoreFlag = find_option("ignore",0,1);
387 db_must_be_within_tree();
388 if( zIgnoreFlag==0 ){
389 zIgnoreFlag = db_get("ignore-glob", 0);
390 }
391 db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)");
392 n = strlen(g.zLocalRoot);
393 blob_init(&path, g.zLocalRoot, n-1);
394 pIgnore = glob_create(zIgnoreFlag);
395 vfile_scan(&path, blob_size(&path), dotfilesFlag, pIgnore);
396 glob_free(pIgnore);
397 db_prepare(&q,
398 "SELECT %Q || x FROM sfile"
399 " WHERE x NOT IN (%s)"
400 " ORDER BY 1",
@@ -813,14 +844,10 @@
813 }
814 if( zColor && zColor[0] ){
815 /* One-time background color */
816 blob_appendf(pOut, "T +bgcolor * %F\n", zColor);
817 }
818 if( g.markPrivate ){
819 /* If this manifest is private, mark it as such */
820 blob_appendf(pOut, "T +private *\n");
821 }
822 if( azTag ){
823 for(i=0; azTag[i]; i++){
824 /* Add a symbolic tag to this check-in. The tag names have already
825 ** been sorted and converted using the %F format */
826 blob_appendf(pOut, "T +sym-%s *\n", azTag[i]);
827
--- src/checkin.c
+++ src/checkin.c
@@ -160,11 +160,11 @@
160 int cwdRelative = 0;
161 db_must_be_within_tree();
162 cwdRelative = determine_cwd_relative_option();
163 blob_zero(&report);
164 vid = db_lget_int("checkout", 0);
165 vfile_check_signature(vid, useSha1sum ? CKSIG_SHA1 : 0);
166 status_report(&report, "", 0, cwdRelative);
167 if( verbose && blob_size(&report)==0 ){
168 blob_append(&report, " (none)\n", -1);
169 }
170 if( showHdr && blob_size(&report)>0 ){
@@ -205,46 +205,74 @@
205 show_common_info(vid, "checkout:", 1, 1);
206 }
207 db_record_repository_filename(0);
208 changes_cmd();
209 }
210
211 /*
212 ** Implementation of the checkin_mtime SQL function
213 */
214
215
216 /*
217 ** COMMAND: ls
218 **
219 ** Usage: %fossil ls ?OPTIONS? ?VERSION?
220 **
221 ** Show the names of all files in the current checkout. The -l provides
222 ** extra information about each file.
223 **
224 ** Options:
225 ** -l Provide extra information about each file.
226 ** --age Show when each file was committed
227 **
228 ** See also: changes, extra, status
229 */
230 void ls_cmd(void){
231 int vid;
232 Stmt q;
233 int isBrief;
234 int showAge;
235 char *zOrderBy = "pathname";
236
237 isBrief = find_option("l","l", 0)==0;
238 showAge = find_option("age",0,0)!=0;
239 db_must_be_within_tree();
240 vid = db_lget_int("checkout", 0);
241 if( find_option("t","t",0)!=0 ){
242 if( showAge ){
243 zOrderBy = mprintf("checkin_mtime(%d,rid) DESC", vid);
244 }else{
245 zOrderBy = "mtime DESC";
246 }
247 }
248 verify_all_options();
249 vfile_check_signature(vid, 0);
250 if( showAge ){
251 db_prepare(&q,
252 "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0),"
253 " datetime(checkin_mtime(%d,rid),'unixepoch','localtime')"
254 " FROM vfile"
255 " ORDER BY %s", vid, zOrderBy
256 );
257 }else{
258 db_prepare(&q,
259 "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)"
260 " FROM vfile"
261 " ORDER BY %s", zOrderBy
262 );
263 }
264 while( db_step(&q)==SQLITE_ROW ){
265 const char *zPathname = db_column_text(&q,0);
266 int isDeleted = db_column_int(&q, 1);
267 int isNew = db_column_int(&q,2)==0;
268 int chnged = db_column_int(&q,3);
269 int renamed = db_column_int(&q,4);
270 char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
271 if( showAge ){
272 fossil_print("%s %s\n", db_column_text(&q, 5), zPathname);
273 }else if( isBrief ){
274 fossil_print("%s\n", zPathname);
275 }else if( isNew ){
276 fossil_print("ADDED %s\n", zPathname);
277 }else if( isDeleted ){
278 fossil_print("DELETED %s\n", zPathname);
@@ -296,16 +324,17 @@
324 Blob path;
325 Blob repo;
326 Stmt q;
327 int n;
328 const char *zIgnoreFlag = find_option("ignore",0,1);
329 unsigned scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0;
330 int cwdRelative = 0;
331 Glob *pIgnore;
332 Blob rewrittenPathname;
333 const char *zPathname, *zDisplayName;
334
335 if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP;
336 db_must_be_within_tree();
337 cwdRelative = determine_cwd_relative_option();
338 db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
339 filename_collation());
340 n = strlen(g.zLocalRoot);
@@ -312,11 +341,11 @@
341 blob_init(&path, g.zLocalRoot, n-1);
342 if( zIgnoreFlag==0 ){
343 zIgnoreFlag = db_get("ignore-glob", 0);
344 }
345 pIgnore = glob_create(zIgnoreFlag);
346 vfile_scan(&path, blob_size(&path), scanFlags, pIgnore);
347 glob_free(pIgnore);
348 db_prepare(&q,
349 "SELECT x FROM sfile"
350 " WHERE x NOT IN (%s)"
351 " ORDER BY 1",
@@ -367,34 +396,36 @@
396 ** Options:
397 ** --dotfiles include files beginning with a dot (".")
398 ** --force Remove files without prompting
399 ** --ignore <CSG> ignore files matching patterns from the
400 ** comma separated list of glob patterns.
401 ** --temp Remove only Fossil-generated temporary files
402 **
403 ** See also: addremove, extra, status
404 */
405 void clean_cmd(void){
406 int allFlag;
407 unsigned scanFlags = 0;
408 const char *zIgnoreFlag;
409 Blob path, repo;
410 Stmt q;
411 int n;
412 Glob *pIgnore;
413
414 allFlag = find_option("force","f",0)!=0;
415 if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL;
416 if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP;
417 zIgnoreFlag = find_option("ignore",0,1);
418 db_must_be_within_tree();
419 if( zIgnoreFlag==0 ){
420 zIgnoreFlag = db_get("ignore-glob", 0);
421 }
422 db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)");
423 n = strlen(g.zLocalRoot);
424 blob_init(&path, g.zLocalRoot, n-1);
425 pIgnore = glob_create(zIgnoreFlag);
426 vfile_scan(&path, blob_size(&path), scanFlags, pIgnore);
427 glob_free(pIgnore);
428 db_prepare(&q,
429 "SELECT %Q || x FROM sfile"
430 " WHERE x NOT IN (%s)"
431 " ORDER BY 1",
@@ -813,14 +844,10 @@
844 }
845 if( zColor && zColor[0] ){
846 /* One-time background color */
847 blob_appendf(pOut, "T +bgcolor * %F\n", zColor);
848 }
 
 
 
 
849 if( azTag ){
850 for(i=0; azTag[i]; i++){
851 /* Add a symbolic tag to this check-in. The tag names have already
852 ** been sorted and converted using the %F format */
853 blob_appendf(pOut, "T +sym-%s *\n", azTag[i]);
854
+1 -1
--- src/checkout.c
+++ src/checkout.c
@@ -33,11 +33,11 @@
3333
int unsaved_changes(void){
3434
int vid;
3535
db_must_be_within_tree();
3636
vid = db_lget_int("checkout",0);
3737
if( vid==0 ) return 2;
38
- vfile_check_signature(vid, 1, 0);
38
+ vfile_check_signature(vid, CKSIG_ENOTFILE);
3939
return db_exists("SELECT 1 FROM vfile WHERE chnged"
4040
" OR coalesce(origname!=pathname,0)");
4141
}
4242
4343
/*
4444
--- src/checkout.c
+++ src/checkout.c
@@ -33,11 +33,11 @@
33 int unsaved_changes(void){
34 int vid;
35 db_must_be_within_tree();
36 vid = db_lget_int("checkout",0);
37 if( vid==0 ) return 2;
38 vfile_check_signature(vid, 1, 0);
39 return db_exists("SELECT 1 FROM vfile WHERE chnged"
40 " OR coalesce(origname!=pathname,0)");
41 }
42
43 /*
44
--- src/checkout.c
+++ src/checkout.c
@@ -33,11 +33,11 @@
33 int unsaved_changes(void){
34 int vid;
35 db_must_be_within_tree();
36 vid = db_lget_int("checkout",0);
37 if( vid==0 ) return 2;
38 vfile_check_signature(vid, CKSIG_ENOTFILE);
39 return db_exists("SELECT 1 FROM vfile WHERE chnged"
40 " OR coalesce(origname!=pathname,0)");
41 }
42
43 /*
44
+19 -1
--- src/db.c
+++ src/db.c
@@ -676,10 +676,26 @@
676676
sqlite3_value **argv
677677
){
678678
sqlite3_result_int64(context, time(0));
679679
}
680680
681
+/*
682
+** Function to return the check-in time for a file.
683
+*/
684
+void db_checkin_mtime_function(
685
+ sqlite3_context *context,
686
+ int argc,
687
+ sqlite3_value **argv
688
+){
689
+ i64 mtime;
690
+ int rc = mtime_of_manifest_file(sqlite3_value_int(argv[0]),
691
+ sqlite3_value_int(argv[1]), &mtime);
692
+ if( rc==0 ){
693
+ sqlite3_result_int64(context, mtime);
694
+ }
695
+}
696
+
681697
682698
/*
683699
** Open a database file. Return a pointer to the new database
684700
** connection. An error results in process abort.
685701
*/
@@ -698,10 +714,12 @@
698714
db_err(sqlite3_errmsg(db));
699715
}
700716
sqlite3_busy_timeout(db, 5000);
701717
sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */
702718
sqlite3_create_function(db, "now", 0, SQLITE_ANY, 0, db_now_function, 0, 0);
719
+ sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_ANY, 0,
720
+ db_checkin_mtime_function, 0, 0);
703721
return db;
704722
}
705723
706724
707725
/*
@@ -722,11 +740,11 @@
722740
/*
723741
** zDbName is the name of a database file. If no other database
724742
** file is open, then open this one. If another database file is
725743
** already open, then attach zDbName using the name zLabel.
726744
*/
727
-static void db_open_or_attach(const char *zDbName, const char *zLabel){
745
+void db_open_or_attach(const char *zDbName, const char *zLabel){
728746
if( !g.db ){
729747
g.db = openDatabase(zDbName);
730748
g.zMainDbType = zLabel;
731749
db_connection_init();
732750
}else{
733751
--- src/db.c
+++ src/db.c
@@ -676,10 +676,26 @@
676 sqlite3_value **argv
677 ){
678 sqlite3_result_int64(context, time(0));
679 }
680
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
681
682 /*
683 ** Open a database file. Return a pointer to the new database
684 ** connection. An error results in process abort.
685 */
@@ -698,10 +714,12 @@
698 db_err(sqlite3_errmsg(db));
699 }
700 sqlite3_busy_timeout(db, 5000);
701 sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */
702 sqlite3_create_function(db, "now", 0, SQLITE_ANY, 0, db_now_function, 0, 0);
 
 
703 return db;
704 }
705
706
707 /*
@@ -722,11 +740,11 @@
722 /*
723 ** zDbName is the name of a database file. If no other database
724 ** file is open, then open this one. If another database file is
725 ** already open, then attach zDbName using the name zLabel.
726 */
727 static void db_open_or_attach(const char *zDbName, const char *zLabel){
728 if( !g.db ){
729 g.db = openDatabase(zDbName);
730 g.zMainDbType = zLabel;
731 db_connection_init();
732 }else{
733
--- src/db.c
+++ src/db.c
@@ -676,10 +676,26 @@
676 sqlite3_value **argv
677 ){
678 sqlite3_result_int64(context, time(0));
679 }
680
681 /*
682 ** Function to return the check-in time for a file.
683 */
684 void db_checkin_mtime_function(
685 sqlite3_context *context,
686 int argc,
687 sqlite3_value **argv
688 ){
689 i64 mtime;
690 int rc = mtime_of_manifest_file(sqlite3_value_int(argv[0]),
691 sqlite3_value_int(argv[1]), &mtime);
692 if( rc==0 ){
693 sqlite3_result_int64(context, mtime);
694 }
695 }
696
697
698 /*
699 ** Open a database file. Return a pointer to the new database
700 ** connection. An error results in process abort.
701 */
@@ -698,10 +714,12 @@
714 db_err(sqlite3_errmsg(db));
715 }
716 sqlite3_busy_timeout(db, 5000);
717 sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */
718 sqlite3_create_function(db, "now", 0, SQLITE_ANY, 0, db_now_function, 0, 0);
719 sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_ANY, 0,
720 db_checkin_mtime_function, 0, 0);
721 return db;
722 }
723
724
725 /*
@@ -722,11 +740,11 @@
740 /*
741 ** zDbName is the name of a database file. If no other database
742 ** file is open, then open this one. If another database file is
743 ** already open, then attach zDbName using the name zLabel.
744 */
745 void db_open_or_attach(const char *zDbName, const char *zLabel){
746 if( !g.db ){
747 g.db = openDatabase(zDbName);
748 g.zMainDbType = zLabel;
749 db_connection_init();
750 }else{
751
--- src/descendants.c
+++ src/descendants.c
@@ -156,11 +156,11 @@
156156
157157
/*
158158
** Load the record ID rid and up to N-1 closest ancestors into
159159
** the "ok" table.
160160
*/
161
-void compute_ancestors(int rid, int N){
161
+void compute_ancestors(int rid, int N, int directOnly){
162162
Bag seen;
163163
PQueue queue;
164164
Stmt ins;
165165
Stmt q;
166166
bag_init(&seen);
@@ -168,11 +168,12 @@
168168
bag_insert(&seen, rid);
169169
pqueuex_insert(&queue, rid, 0.0, 0);
170170
db_prepare(&ins, "INSERT OR IGNORE INTO ok VALUES(:rid)");
171171
db_prepare(&q,
172172
"SELECT a.pid, b.mtime FROM plink a LEFT JOIN plink b ON b.cid=a.pid"
173
- " WHERE a.cid=:rid"
173
+ " WHERE a.cid=:rid %s",
174
+ directOnly ? " AND a.isprim" : ""
174175
);
175176
while( (N--)>0 && (rid = pqueuex_extract(&queue, 0))!=0 ){
176177
db_bind_int(&ins, ":rid", rid);
177178
db_step(&ins);
178179
db_reset(&ins);
@@ -202,11 +203,12 @@
202203
void compute_direct_ancestors(int rid, int N){
203204
Stmt ins;
204205
Stmt q;
205206
int gen = 0;
206207
db_multi_exec(
207
- "CREATE TEMP TABLE IF NOT EXISTS ancestor(rid INTEGER, generation INTEGER PRIMARY KEY);"
208
+ "CREATE TEMP TABLE IF NOT EXISTS ancestor(rid INTEGER,"
209
+ " generation INTEGER PRIMARY KEY);"
208210
"DELETE FROM ancestor;"
209211
"INSERT INTO ancestor VALUES(%d, 0);", rid
210212
);
211213
db_prepare(&ins, "INSERT INTO ancestor VALUES(:rid, :gen)");
212214
db_prepare(&q,
@@ -225,10 +227,44 @@
225227
db_reset(&ins);
226228
}
227229
db_finalize(&ins);
228230
db_finalize(&q);
229231
}
232
+
233
+/*
234
+** Compute the "mtime" of the file given whose blob.rid is "fid" that
235
+** is part of check-in "vid". The mtime will be the mtime on vid or
236
+** some ancestor of vid where fid first appears.
237
+*/
238
+int mtime_of_manifest_file(
239
+ int vid, /* The check-in that contains fid */
240
+ int fid, /* The id of the file whose check-in time is sought */
241
+ i64 *pMTime /* Write result here */
242
+){
243
+ static int prevVid = -1;
244
+ static Stmt q;
245
+
246
+ if( prevVid!=vid ){
247
+ prevVid = vid;
248
+ db_multi_exec("DROP TABLE IF EXISTS temp.ok;"
249
+ "CREATE TEMP TABLE ok(x INTEGER PRIMARY KEY);");
250
+ compute_ancestors(vid, 100000000, 1);
251
+ }
252
+ db_static_prepare(&q,
253
+ "SELECT (max(event.mtime)-2440587.5)*86400 FROM mlink, event"
254
+ " WHERE mlink.mid=event.objid"
255
+ " AND +mlink.mid IN ok"
256
+ " AND mlink.fid=:fid");
257
+ db_bind_int(&q, ":fid", fid);
258
+ if( db_step(&q)!=SQLITE_ROW ){
259
+ db_reset(&q);
260
+ return 1;
261
+ }
262
+ *pMTime = db_column_int64(&q, 0);
263
+ db_reset(&q);
264
+ return 0;
265
+}
230266
231267
/*
232268
** Load the record ID rid and up to N-1 closest descendants into
233269
** the "ok" table.
234270
*/
235271
--- src/descendants.c
+++ src/descendants.c
@@ -156,11 +156,11 @@
156
157 /*
158 ** Load the record ID rid and up to N-1 closest ancestors into
159 ** the "ok" table.
160 */
161 void compute_ancestors(int rid, int N){
162 Bag seen;
163 PQueue queue;
164 Stmt ins;
165 Stmt q;
166 bag_init(&seen);
@@ -168,11 +168,12 @@
168 bag_insert(&seen, rid);
169 pqueuex_insert(&queue, rid, 0.0, 0);
170 db_prepare(&ins, "INSERT OR IGNORE INTO ok VALUES(:rid)");
171 db_prepare(&q,
172 "SELECT a.pid, b.mtime FROM plink a LEFT JOIN plink b ON b.cid=a.pid"
173 " WHERE a.cid=:rid"
 
174 );
175 while( (N--)>0 && (rid = pqueuex_extract(&queue, 0))!=0 ){
176 db_bind_int(&ins, ":rid", rid);
177 db_step(&ins);
178 db_reset(&ins);
@@ -202,11 +203,12 @@
202 void compute_direct_ancestors(int rid, int N){
203 Stmt ins;
204 Stmt q;
205 int gen = 0;
206 db_multi_exec(
207 "CREATE TEMP TABLE IF NOT EXISTS ancestor(rid INTEGER, generation INTEGER PRIMARY KEY);"
 
208 "DELETE FROM ancestor;"
209 "INSERT INTO ancestor VALUES(%d, 0);", rid
210 );
211 db_prepare(&ins, "INSERT INTO ancestor VALUES(:rid, :gen)");
212 db_prepare(&q,
@@ -225,10 +227,44 @@
225 db_reset(&ins);
226 }
227 db_finalize(&ins);
228 db_finalize(&q);
229 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230
231 /*
232 ** Load the record ID rid and up to N-1 closest descendants into
233 ** the "ok" table.
234 */
235
--- src/descendants.c
+++ src/descendants.c
@@ -156,11 +156,11 @@
156
157 /*
158 ** Load the record ID rid and up to N-1 closest ancestors into
159 ** the "ok" table.
160 */
161 void compute_ancestors(int rid, int N, int directOnly){
162 Bag seen;
163 PQueue queue;
164 Stmt ins;
165 Stmt q;
166 bag_init(&seen);
@@ -168,11 +168,12 @@
168 bag_insert(&seen, rid);
169 pqueuex_insert(&queue, rid, 0.0, 0);
170 db_prepare(&ins, "INSERT OR IGNORE INTO ok VALUES(:rid)");
171 db_prepare(&q,
172 "SELECT a.pid, b.mtime FROM plink a LEFT JOIN plink b ON b.cid=a.pid"
173 " WHERE a.cid=:rid %s",
174 directOnly ? " AND a.isprim" : ""
175 );
176 while( (N--)>0 && (rid = pqueuex_extract(&queue, 0))!=0 ){
177 db_bind_int(&ins, ":rid", rid);
178 db_step(&ins);
179 db_reset(&ins);
@@ -202,11 +203,12 @@
203 void compute_direct_ancestors(int rid, int N){
204 Stmt ins;
205 Stmt q;
206 int gen = 0;
207 db_multi_exec(
208 "CREATE TEMP TABLE IF NOT EXISTS ancestor(rid INTEGER,"
209 " generation INTEGER PRIMARY KEY);"
210 "DELETE FROM ancestor;"
211 "INSERT INTO ancestor VALUES(%d, 0);", rid
212 );
213 db_prepare(&ins, "INSERT INTO ancestor VALUES(:rid, :gen)");
214 db_prepare(&q,
@@ -225,10 +227,44 @@
227 db_reset(&ins);
228 }
229 db_finalize(&ins);
230 db_finalize(&q);
231 }
232
233 /*
234 ** Compute the "mtime" of the file given whose blob.rid is "fid" that
235 ** is part of check-in "vid". The mtime will be the mtime on vid or
236 ** some ancestor of vid where fid first appears.
237 */
238 int mtime_of_manifest_file(
239 int vid, /* The check-in that contains fid */
240 int fid, /* The id of the file whose check-in time is sought */
241 i64 *pMTime /* Write result here */
242 ){
243 static int prevVid = -1;
244 static Stmt q;
245
246 if( prevVid!=vid ){
247 prevVid = vid;
248 db_multi_exec("DROP TABLE IF EXISTS temp.ok;"
249 "CREATE TEMP TABLE ok(x INTEGER PRIMARY KEY);");
250 compute_ancestors(vid, 100000000, 1);
251 }
252 db_static_prepare(&q,
253 "SELECT (max(event.mtime)-2440587.5)*86400 FROM mlink, event"
254 " WHERE mlink.mid=event.objid"
255 " AND +mlink.mid IN ok"
256 " AND mlink.fid=:fid");
257 db_bind_int(&q, ":fid", fid);
258 if( db_step(&q)!=SQLITE_ROW ){
259 db_reset(&q);
260 return 1;
261 }
262 *pMTime = db_column_int64(&q, 0);
263 db_reset(&q);
264 return 0;
265 }
266
267 /*
268 ** Load the record ID rid and up to N-1 closest descendants into
269 ** the "ok" table.
270 */
271
+1 -1
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -322,11 +322,11 @@
322322
Stmt q;
323323
int asNewFile; /* Treat non-existant files as empty files */
324324
325325
asNewFile = (diffFlags & DIFF_NEWFILE)!=0;
326326
vid = db_lget_int("checkout", 0);
327
- vfile_check_signature(vid, 1, 0);
327
+ vfile_check_signature(vid, CKSIG_ENOTFILE);
328328
blob_zero(&sql);
329329
db_begin_transaction();
330330
if( zFrom ){
331331
int rid = name_to_typed_rid(zFrom, "ci");
332332
if( !is_a_version(rid) ){
333333
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -322,11 +322,11 @@
322 Stmt q;
323 int asNewFile; /* Treat non-existant files as empty files */
324
325 asNewFile = (diffFlags & DIFF_NEWFILE)!=0;
326 vid = db_lget_int("checkout", 0);
327 vfile_check_signature(vid, 1, 0);
328 blob_zero(&sql);
329 db_begin_transaction();
330 if( zFrom ){
331 int rid = name_to_typed_rid(zFrom, "ci");
332 if( !is_a_version(rid) ){
333
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -322,11 +322,11 @@
322 Stmt q;
323 int asNewFile; /* Treat non-existant files as empty files */
324
325 asNewFile = (diffFlags & DIFF_NEWFILE)!=0;
326 vid = db_lget_int("checkout", 0);
327 vfile_check_signature(vid, CKSIG_ENOTFILE);
328 blob_zero(&sql);
329 db_begin_transaction();
330 if( zFrom ){
331 int rid = name_to_typed_rid(zFrom, "ci");
332 if( !is_a_version(rid) ){
333
+44
--- src/file.c
+++ src/file.c
@@ -34,10 +34,11 @@
3434
** On Windows, include the Platform SDK header file.
3535
*/
3636
#ifdef _WIN32
3737
# include <direct.h>
3838
# include <windows.h>
39
+# include <sys/utime.h>
3940
#endif
4041
4142
/*
4243
** The file status information from the most recent stat() call.
4344
**
@@ -389,10 +390,53 @@
389390
}
390391
}
391392
#endif /* _WIN32 */
392393
return rc;
393394
}
395
+
396
+/*
397
+** Set the mtime for a file.
398
+*/
399
+void file_set_mtime(const char *zFilename, i64 newMTime){
400
+#if !defined(_WIN32)
401
+ struct timeval tv[2];
402
+ memset(tv, 0, sizeof(tv[0])*2);
403
+ tv[0].tv_sec = newMTime;
404
+ tv[1].tv_sec = newMTime;
405
+ utimes(zFilename, tv);
406
+#else
407
+ struct utimbuf tb;
408
+ wchar_t *zMbcs = fossil_utf8_to_unicode(zFilename);
409
+ tb.actime = newMTime;
410
+ tb.modtime = newMTime;
411
+ _wutime(zMbcs, &tb);
412
+ fossil_mbcs_free(zMbcs);
413
+#endif
414
+}
415
+
416
+/*
417
+** COMMAND: test-set-mtime
418
+**
419
+** Usage: %fossil test-set-mtime FILENAME DATE/TIME
420
+**
421
+** Sets the mtime of the named file to the date/time shown.
422
+*/
423
+void test_set_mtime(void){
424
+ const char *zFile;
425
+ char *zDate;
426
+ i64 iMTime;
427
+ if( g.argc!=4 ){
428
+ usage("test-set-mtime FILENAME DATE/TIME");
429
+ }
430
+ db_open_or_attach(":memory:", "mem");
431
+ iMTime = db_int64(0, "SELECT strftime('%%s',%Q)", g.argv[3]);
432
+ zFile = g.argv[2];
433
+ file_set_mtime(zFile, iMTime);
434
+ iMTime = file_wd_mtime(zFile);
435
+ zDate = db_text(0, "SELECT datetime(%lld, 'unixepoch')", iMTime);
436
+ fossil_print("Set mtime of \"%s\" to %s (%lld)\n", zFile, zDate, iMTime);
437
+}
394438
395439
/*
396440
** Delete a file.
397441
*/
398442
void file_delete(const char *zFilename){
399443
--- src/file.c
+++ src/file.c
@@ -34,10 +34,11 @@
34 ** On Windows, include the Platform SDK header file.
35 */
36 #ifdef _WIN32
37 # include <direct.h>
38 # include <windows.h>
 
39 #endif
40
41 /*
42 ** The file status information from the most recent stat() call.
43 **
@@ -389,10 +390,53 @@
389 }
390 }
391 #endif /* _WIN32 */
392 return rc;
393 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
394
395 /*
396 ** Delete a file.
397 */
398 void file_delete(const char *zFilename){
399
--- src/file.c
+++ src/file.c
@@ -34,10 +34,11 @@
34 ** On Windows, include the Platform SDK header file.
35 */
36 #ifdef _WIN32
37 # include <direct.h>
38 # include <windows.h>
39 # include <sys/utime.h>
40 #endif
41
42 /*
43 ** The file status information from the most recent stat() call.
44 **
@@ -389,10 +390,53 @@
390 }
391 }
392 #endif /* _WIN32 */
393 return rc;
394 }
395
396 /*
397 ** Set the mtime for a file.
398 */
399 void file_set_mtime(const char *zFilename, i64 newMTime){
400 #if !defined(_WIN32)
401 struct timeval tv[2];
402 memset(tv, 0, sizeof(tv[0])*2);
403 tv[0].tv_sec = newMTime;
404 tv[1].tv_sec = newMTime;
405 utimes(zFilename, tv);
406 #else
407 struct utimbuf tb;
408 wchar_t *zMbcs = fossil_utf8_to_unicode(zFilename);
409 tb.actime = newMTime;
410 tb.modtime = newMTime;
411 _wutime(zMbcs, &tb);
412 fossil_mbcs_free(zMbcs);
413 #endif
414 }
415
416 /*
417 ** COMMAND: test-set-mtime
418 **
419 ** Usage: %fossil test-set-mtime FILENAME DATE/TIME
420 **
421 ** Sets the mtime of the named file to the date/time shown.
422 */
423 void test_set_mtime(void){
424 const char *zFile;
425 char *zDate;
426 i64 iMTime;
427 if( g.argc!=4 ){
428 usage("test-set-mtime FILENAME DATE/TIME");
429 }
430 db_open_or_attach(":memory:", "mem");
431 iMTime = db_int64(0, "SELECT strftime('%%s',%Q)", g.argv[3]);
432 zFile = g.argv[2];
433 file_set_mtime(zFile, iMTime);
434 iMTime = file_wd_mtime(zFile);
435 zDate = db_text(0, "SELECT datetime(%lld, 'unixepoch')", iMTime);
436 fossil_print("Set mtime of \"%s\" to %s (%lld)\n", zFile, zDate, iMTime);
437 }
438
439 /*
440 ** Delete a file.
441 */
442 void file_delete(const char *zFilename){
443
+1 -1
--- src/finfo.c
+++ src/finfo.c
@@ -66,11 +66,11 @@
6666
if( g.argc!=3 ) usage("-s|--status FILENAME");
6767
vid = db_lget_int("checkout", 0);
6868
if( vid==0 ){
6969
fossil_panic("no checkout to finfo files in");
7070
}
71
- vfile_check_signature(vid, 1, 0);
71
+ vfile_check_signature(vid, CKSIG_ENOTFILE);
7272
file_tree_name(g.argv[2], &fname, 1);
7373
db_prepare(&q,
7474
"SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)"
7575
" FROM vfile WHERE vfile.pathname=%B %s",
7676
&fname, filename_collation());
7777
--- src/finfo.c
+++ src/finfo.c
@@ -66,11 +66,11 @@
66 if( g.argc!=3 ) usage("-s|--status FILENAME");
67 vid = db_lget_int("checkout", 0);
68 if( vid==0 ){
69 fossil_panic("no checkout to finfo files in");
70 }
71 vfile_check_signature(vid, 1, 0);
72 file_tree_name(g.argv[2], &fname, 1);
73 db_prepare(&q,
74 "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)"
75 " FROM vfile WHERE vfile.pathname=%B %s",
76 &fname, filename_collation());
77
--- src/finfo.c
+++ src/finfo.c
@@ -66,11 +66,11 @@
66 if( g.argc!=3 ) usage("-s|--status FILENAME");
67 vid = db_lget_int("checkout", 0);
68 if( vid==0 ){
69 fossil_panic("no checkout to finfo files in");
70 }
71 vfile_check_signature(vid, CKSIG_ENOTFILE);
72 file_tree_name(g.argv[2], &fname, 1);
73 db_prepare(&q,
74 "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)"
75 " FROM vfile WHERE vfile.pathname=%B %s",
76 &fname, filename_collation());
77
+9 -2
--- src/info.c
+++ src/info.c
@@ -630,10 +630,11 @@
630630
}
631631
@ </td></tr>
632632
@ <tr><th>Other&nbsp;Links:</th>
633633
@ <td>
634634
@ %z(href("%R/dir?ci=%S",zUuid))files</a>
635
+ @ | %z(href("%R/fileage?name=%S",zUuid))file ages</a>
635636
@ | %z(href("%R/artifact/%S",zUuid))manifest</a>
636637
if( g.perm.Write ){
637638
@ | %z(href("%R/ci_edit?r=%S",zUuid))edit</a>
638639
}
639640
@ </td>
@@ -966,15 +967,15 @@
966967
}else{
967968
cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName);
968969
}
969970
if( cmp<0 ){
970971
append_file_change_line(pFileFrom->zName,
971
- pFileFrom->zUuid, 0, 0, 0, 0);
972
+ pFileFrom->zUuid, 0, 0, diffFlags, 0);
972973
pFileFrom = manifest_file_next(pFrom, 0);
973974
}else if( cmp>0 ){
974975
append_file_change_line(pFileTo->zName,
975
- 0, pFileTo->zUuid, 0, 0,
976
+ 0, pFileTo->zUuid, 0, diffFlags,
976977
manifest_file_mperm(pFileTo));
977978
pFileTo = manifest_file_next(pTo, 0);
978979
}else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){
979980
/* No changes */
980981
pFileFrom = manifest_file_next(pFrom, 0);
@@ -1304,10 +1305,16 @@
13041305
zMime = P("m");
13051306
if( zMime==0 ){
13061307
char *zFName = db_text(0, "SELECT filename.name FROM mlink, filename"
13071308
" WHERE mlink.fid=%d"
13081309
" AND filename.fnid=mlink.fnid", rid);
1310
+ if( !zFName ){
1311
+ /* Look also at the attachment table */
1312
+ zFName = db_text(0, "SELECT attachment.filename FROM attachment, blob"
1313
+ " WHERE blob.rid=%d"
1314
+ " AND attachment.src=blob.uuid", rid);
1315
+ }
13091316
if( zFName ) zMime = mimetype_from_name(zFName);
13101317
if( zMime==0 ) zMime = "application/x-fossil-artifact";
13111318
}
13121319
content_get(rid, &content);
13131320
cgi_set_content_type(zMime);
13141321
--- src/info.c
+++ src/info.c
@@ -630,10 +630,11 @@
630 }
631 @ </td></tr>
632 @ <tr><th>Other&nbsp;Links:</th>
633 @ <td>
634 @ %z(href("%R/dir?ci=%S",zUuid))files</a>
 
635 @ | %z(href("%R/artifact/%S",zUuid))manifest</a>
636 if( g.perm.Write ){
637 @ | %z(href("%R/ci_edit?r=%S",zUuid))edit</a>
638 }
639 @ </td>
@@ -966,15 +967,15 @@
966 }else{
967 cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName);
968 }
969 if( cmp<0 ){
970 append_file_change_line(pFileFrom->zName,
971 pFileFrom->zUuid, 0, 0, 0, 0);
972 pFileFrom = manifest_file_next(pFrom, 0);
973 }else if( cmp>0 ){
974 append_file_change_line(pFileTo->zName,
975 0, pFileTo->zUuid, 0, 0,
976 manifest_file_mperm(pFileTo));
977 pFileTo = manifest_file_next(pTo, 0);
978 }else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){
979 /* No changes */
980 pFileFrom = manifest_file_next(pFrom, 0);
@@ -1304,10 +1305,16 @@
1304 zMime = P("m");
1305 if( zMime==0 ){
1306 char *zFName = db_text(0, "SELECT filename.name FROM mlink, filename"
1307 " WHERE mlink.fid=%d"
1308 " AND filename.fnid=mlink.fnid", rid);
 
 
 
 
 
 
1309 if( zFName ) zMime = mimetype_from_name(zFName);
1310 if( zMime==0 ) zMime = "application/x-fossil-artifact";
1311 }
1312 content_get(rid, &content);
1313 cgi_set_content_type(zMime);
1314
--- src/info.c
+++ src/info.c
@@ -630,10 +630,11 @@
630 }
631 @ </td></tr>
632 @ <tr><th>Other&nbsp;Links:</th>
633 @ <td>
634 @ %z(href("%R/dir?ci=%S",zUuid))files</a>
635 @ | %z(href("%R/fileage?name=%S",zUuid))file ages</a>
636 @ | %z(href("%R/artifact/%S",zUuid))manifest</a>
637 if( g.perm.Write ){
638 @ | %z(href("%R/ci_edit?r=%S",zUuid))edit</a>
639 }
640 @ </td>
@@ -966,15 +967,15 @@
967 }else{
968 cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName);
969 }
970 if( cmp<0 ){
971 append_file_change_line(pFileFrom->zName,
972 pFileFrom->zUuid, 0, 0, diffFlags, 0);
973 pFileFrom = manifest_file_next(pFrom, 0);
974 }else if( cmp>0 ){
975 append_file_change_line(pFileTo->zName,
976 0, pFileTo->zUuid, 0, diffFlags,
977 manifest_file_mperm(pFileTo));
978 pFileTo = manifest_file_next(pTo, 0);
979 }else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){
980 /* No changes */
981 pFileFrom = manifest_file_next(pFrom, 0);
@@ -1304,10 +1305,16 @@
1305 zMime = P("m");
1306 if( zMime==0 ){
1307 char *zFName = db_text(0, "SELECT filename.name FROM mlink, filename"
1308 " WHERE mlink.fid=%d"
1309 " AND filename.fnid=mlink.fnid", rid);
1310 if( !zFName ){
1311 /* Look also at the attachment table */
1312 zFName = db_text(0, "SELECT attachment.filename FROM attachment, blob"
1313 " WHERE blob.rid=%d"
1314 " AND attachment.src=blob.uuid", rid);
1315 }
1316 if( zFName ) zMime = mimetype_from_name(zFName);
1317 if( zMime==0 ) zMime = "application/x-fossil-artifact";
1318 }
1319 content_get(rid, &content);
1320 cgi_set_content_type(zMime);
1321
+2
--- src/main.c
+++ src/main.c
@@ -555,10 +555,11 @@
555555
newArgv[j] = 0;
556556
g.argc = j;
557557
g.argv = newArgv;
558558
}
559559
560
+#ifdef FOSSIL_ENABLE_TCL
560561
/*
561562
** Make a deep copy of the provided argument array and return it.
562563
*/
563564
static char **copy_args(int argc, char **argv){
564565
char **zNewArgv;
@@ -568,10 +569,11 @@
568569
for(i=0; i<argc; i++){
569570
zNewArgv[i] = fossil_strdup(argv[i]);
570571
}
571572
return zNewArgv;
572573
}
574
+#endif
573575
574576
/*
575577
** This procedure runs first.
576578
*/
577579
int main(int argc, char **argv)
578580
--- src/main.c
+++ src/main.c
@@ -555,10 +555,11 @@
555 newArgv[j] = 0;
556 g.argc = j;
557 g.argv = newArgv;
558 }
559
 
560 /*
561 ** Make a deep copy of the provided argument array and return it.
562 */
563 static char **copy_args(int argc, char **argv){
564 char **zNewArgv;
@@ -568,10 +569,11 @@
568 for(i=0; i<argc; i++){
569 zNewArgv[i] = fossil_strdup(argv[i]);
570 }
571 return zNewArgv;
572 }
 
573
574 /*
575 ** This procedure runs first.
576 */
577 int main(int argc, char **argv)
578
--- src/main.c
+++ src/main.c
@@ -555,10 +555,11 @@
555 newArgv[j] = 0;
556 g.argc = j;
557 g.argv = newArgv;
558 }
559
560 #ifdef FOSSIL_ENABLE_TCL
561 /*
562 ** Make a deep copy of the provided argument array and return it.
563 */
564 static char **copy_args(int argc, char **argv){
565 char **zNewArgv;
@@ -568,10 +569,11 @@
569 for(i=0; i<argc; i++){
570 zNewArgv[i] = fossil_strdup(argv[i]);
571 }
572 return zNewArgv;
573 }
574 #endif
575
576 /*
577 ** This procedure runs first.
578 */
579 int main(int argc, char **argv)
580
+1 -1
--- src/merge.c
+++ src/merge.c
@@ -189,11 +189,11 @@
189189
}
190190
if( detailFlag ){
191191
print_checkin_description(mid, 12, "merge-from:");
192192
print_checkin_description(pid, 12, "baseline:");
193193
}
194
- vfile_check_signature(vid, 1, 0);
194
+ vfile_check_signature(vid, CKSIG_ENOTFILE);
195195
db_begin_transaction();
196196
if( !nochangeFlag ) undo_begin();
197197
load_vfile_from_rid(mid);
198198
load_vfile_from_rid(pid);
199199
if( debugFlag ){
200200
--- src/merge.c
+++ src/merge.c
@@ -189,11 +189,11 @@
189 }
190 if( detailFlag ){
191 print_checkin_description(mid, 12, "merge-from:");
192 print_checkin_description(pid, 12, "baseline:");
193 }
194 vfile_check_signature(vid, 1, 0);
195 db_begin_transaction();
196 if( !nochangeFlag ) undo_begin();
197 load_vfile_from_rid(mid);
198 load_vfile_from_rid(pid);
199 if( debugFlag ){
200
--- src/merge.c
+++ src/merge.c
@@ -189,11 +189,11 @@
189 }
190 if( detailFlag ){
191 print_checkin_description(mid, 12, "merge-from:");
192 print_checkin_description(pid, 12, "baseline:");
193 }
194 vfile_check_signature(vid, CKSIG_ENOTFILE);
195 db_begin_transaction();
196 if( !nochangeFlag ) undo_begin();
197 load_vfile_from_rid(mid);
198 load_vfile_from_rid(pid);
199 if( debugFlag ){
200
+21 -14
--- src/rebuild.c
+++ src/rebuild.c
@@ -925,27 +925,20 @@
925925
**
926926
** Options:
927927
** -R|--repository REPOSITORY deconstruct given REPOSITORY
928928
** -L|--prefixlength N set the length of the names of the DESTINATION
929929
** subdirectories to N
930
+** --private Include private artifacts.
930931
**
931932
** See also: rebuild, reconstruct
932933
*/
933934
void deconstruct_cmd(void){
934935
const char *zDestDir;
935936
const char *zPrefixOpt;
936937
Stmt s;
937
-
938
- /* check number of arguments */
939
- if( (g.argc != 3) && (g.argc != 5) && (g.argc != 7)){
940
- usage ("?-R|--repository REPOSITORY? ?-L|--prefixlength N? DESTINATION");
941
- }
942
- /* get and check argument destination directory */
943
- zDestDir = g.argv[g.argc-1];
944
- if( !*zDestDir || !file_isdir(zDestDir)) {
945
- fossil_panic("DESTINATION(%s) is not a directory!",zDestDir);
946
- }
938
+ int privateFlag;
939
+
947940
/* get and check prefix length argument and build format string */
948941
zPrefixOpt=find_option("prefixlength","L",1);
949942
if( !zPrefixOpt ){
950943
prefixLength = 2;
951944
}else{
@@ -953,10 +946,23 @@
953946
prefixLength = (int)(*zPrefixOpt-'0');
954947
}else{
955948
fossil_fatal("N(%s) is not a a valid prefix length!",zPrefixOpt);
956949
}
957950
}
951
+ /* open repository and open query for all artifacts */
952
+ db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
953
+ privateFlag = find_option("private",0,0)!=0;
954
+ verify_all_options();
955
+ /* check number of arguments */
956
+ if( g.argc!=3 ){
957
+ usage ("?OPTIONS? DESTINATION");
958
+ }
959
+ /* get and check argument destination directory */
960
+ zDestDir = g.argv[g.argc-1];
961
+ if( !*zDestDir || !file_isdir(zDestDir)) {
962
+ fossil_fatal("DESTINATION(%s) is not a directory!",zDestDir);
963
+ }
958964
#ifndef _WIN32
959965
if( file_access(zDestDir, W_OK) ){
960966
fossil_fatal("DESTINATION(%s) is not writeable!",zDestDir);
961967
}
962968
#else
@@ -967,12 +973,11 @@
967973
if( prefixLength ){
968974
zFNameFormat = mprintf("%s/%%.%ds/%%s",zDestDir,prefixLength);
969975
}else{
970976
zFNameFormat = mprintf("%s/%%s",zDestDir);
971977
}
972
- /* open repository and open query for all artifacts */
973
- db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
978
+
974979
bag_init(&bagDone);
975980
ttyOutput = 1;
976981
processCnt = 0;
977982
if (!g.fQuiet) {
978983
fossil_print("0 (0%%)...\r");
@@ -980,11 +985,12 @@
980985
}
981986
totalSize = db_int(0, "SELECT count(*) FROM blob");
982987
db_prepare(&s,
983988
"SELECT rid, size FROM blob /*scan*/"
984989
" WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)"
985
- " AND NOT EXISTS(SELECT 1 FROM delta WHERE rid=blob.rid)"
990
+ " AND NOT EXISTS(SELECT 1 FROM delta WHERE rid=blob.rid) %s",
991
+ privateFlag==0 ? "AND rid NOT IN private" : ""
986992
);
987993
while( db_step(&s)==SQLITE_ROW ){
988994
int rid = db_column_int(&s, 0);
989995
int size = db_column_int(&s, 1);
990996
if( size>=0 ){
@@ -994,11 +1000,12 @@
9941000
}
9951001
}
9961002
db_finalize(&s);
9971003
db_prepare(&s,
9981004
"SELECT rid, size FROM blob"
999
- " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)"
1005
+ " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid) %s",
1006
+ privateFlag==0 ? "AND rid NOT IN private" : ""
10001007
);
10011008
while( db_step(&s)==SQLITE_ROW ){
10021009
int rid = db_column_int(&s, 0);
10031010
int size = db_column_int(&s, 1);
10041011
if( size>=0 ){
10051012
--- src/rebuild.c
+++ src/rebuild.c
@@ -925,27 +925,20 @@
925 **
926 ** Options:
927 ** -R|--repository REPOSITORY deconstruct given REPOSITORY
928 ** -L|--prefixlength N set the length of the names of the DESTINATION
929 ** subdirectories to N
 
930 **
931 ** See also: rebuild, reconstruct
932 */
933 void deconstruct_cmd(void){
934 const char *zDestDir;
935 const char *zPrefixOpt;
936 Stmt s;
937
938 /* check number of arguments */
939 if( (g.argc != 3) && (g.argc != 5) && (g.argc != 7)){
940 usage ("?-R|--repository REPOSITORY? ?-L|--prefixlength N? DESTINATION");
941 }
942 /* get and check argument destination directory */
943 zDestDir = g.argv[g.argc-1];
944 if( !*zDestDir || !file_isdir(zDestDir)) {
945 fossil_panic("DESTINATION(%s) is not a directory!",zDestDir);
946 }
947 /* get and check prefix length argument and build format string */
948 zPrefixOpt=find_option("prefixlength","L",1);
949 if( !zPrefixOpt ){
950 prefixLength = 2;
951 }else{
@@ -953,10 +946,23 @@
953 prefixLength = (int)(*zPrefixOpt-'0');
954 }else{
955 fossil_fatal("N(%s) is not a a valid prefix length!",zPrefixOpt);
956 }
957 }
 
 
 
 
 
 
 
 
 
 
 
 
 
958 #ifndef _WIN32
959 if( file_access(zDestDir, W_OK) ){
960 fossil_fatal("DESTINATION(%s) is not writeable!",zDestDir);
961 }
962 #else
@@ -967,12 +973,11 @@
967 if( prefixLength ){
968 zFNameFormat = mprintf("%s/%%.%ds/%%s",zDestDir,prefixLength);
969 }else{
970 zFNameFormat = mprintf("%s/%%s",zDestDir);
971 }
972 /* open repository and open query for all artifacts */
973 db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
974 bag_init(&bagDone);
975 ttyOutput = 1;
976 processCnt = 0;
977 if (!g.fQuiet) {
978 fossil_print("0 (0%%)...\r");
@@ -980,11 +985,12 @@
980 }
981 totalSize = db_int(0, "SELECT count(*) FROM blob");
982 db_prepare(&s,
983 "SELECT rid, size FROM blob /*scan*/"
984 " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)"
985 " AND NOT EXISTS(SELECT 1 FROM delta WHERE rid=blob.rid)"
 
986 );
987 while( db_step(&s)==SQLITE_ROW ){
988 int rid = db_column_int(&s, 0);
989 int size = db_column_int(&s, 1);
990 if( size>=0 ){
@@ -994,11 +1000,12 @@
994 }
995 }
996 db_finalize(&s);
997 db_prepare(&s,
998 "SELECT rid, size FROM blob"
999 " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)"
 
1000 );
1001 while( db_step(&s)==SQLITE_ROW ){
1002 int rid = db_column_int(&s, 0);
1003 int size = db_column_int(&s, 1);
1004 if( size>=0 ){
1005
--- src/rebuild.c
+++ src/rebuild.c
@@ -925,27 +925,20 @@
925 **
926 ** Options:
927 ** -R|--repository REPOSITORY deconstruct given REPOSITORY
928 ** -L|--prefixlength N set the length of the names of the DESTINATION
929 ** subdirectories to N
930 ** --private Include private artifacts.
931 **
932 ** See also: rebuild, reconstruct
933 */
934 void deconstruct_cmd(void){
935 const char *zDestDir;
936 const char *zPrefixOpt;
937 Stmt s;
938 int privateFlag;
939
 
 
 
 
 
 
 
 
940 /* get and check prefix length argument and build format string */
941 zPrefixOpt=find_option("prefixlength","L",1);
942 if( !zPrefixOpt ){
943 prefixLength = 2;
944 }else{
@@ -953,10 +946,23 @@
946 prefixLength = (int)(*zPrefixOpt-'0');
947 }else{
948 fossil_fatal("N(%s) is not a a valid prefix length!",zPrefixOpt);
949 }
950 }
951 /* open repository and open query for all artifacts */
952 db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
953 privateFlag = find_option("private",0,0)!=0;
954 verify_all_options();
955 /* check number of arguments */
956 if( g.argc!=3 ){
957 usage ("?OPTIONS? DESTINATION");
958 }
959 /* get and check argument destination directory */
960 zDestDir = g.argv[g.argc-1];
961 if( !*zDestDir || !file_isdir(zDestDir)) {
962 fossil_fatal("DESTINATION(%s) is not a directory!",zDestDir);
963 }
964 #ifndef _WIN32
965 if( file_access(zDestDir, W_OK) ){
966 fossil_fatal("DESTINATION(%s) is not writeable!",zDestDir);
967 }
968 #else
@@ -967,12 +973,11 @@
973 if( prefixLength ){
974 zFNameFormat = mprintf("%s/%%.%ds/%%s",zDestDir,prefixLength);
975 }else{
976 zFNameFormat = mprintf("%s/%%s",zDestDir);
977 }
978
 
979 bag_init(&bagDone);
980 ttyOutput = 1;
981 processCnt = 0;
982 if (!g.fQuiet) {
983 fossil_print("0 (0%%)...\r");
@@ -980,11 +985,12 @@
985 }
986 totalSize = db_int(0, "SELECT count(*) FROM blob");
987 db_prepare(&s,
988 "SELECT rid, size FROM blob /*scan*/"
989 " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)"
990 " AND NOT EXISTS(SELECT 1 FROM delta WHERE rid=blob.rid) %s",
991 privateFlag==0 ? "AND rid NOT IN private" : ""
992 );
993 while( db_step(&s)==SQLITE_ROW ){
994 int rid = db_column_int(&s, 0);
995 int size = db_column_int(&s, 1);
996 if( size>=0 ){
@@ -994,11 +1000,12 @@
1000 }
1001 }
1002 db_finalize(&s);
1003 db_prepare(&s,
1004 "SELECT rid, size FROM blob"
1005 " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid) %s",
1006 privateFlag==0 ? "AND rid NOT IN private" : ""
1007 );
1008 while( db_step(&s)==SQLITE_ROW ){
1009 int rid = db_column_int(&s, 0);
1010 int size = db_column_int(&s, 1);
1011 if( size>=0 ){
1012
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -143,10 +143,11 @@
143143
extern int sqlite3_shell(int, char**);
144144
db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
145145
db_close(1);
146146
sqlite3_shutdown();
147147
sqlite3_shell(g.argc-1, g.argv+1);
148
+ g.db = 0;
148149
}
149150
150151
/*
151152
** This routine is called by the patched sqlite3 command-line shell in order
152153
** to load the name and database connection for the open Fossil database.
153154
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -143,10 +143,11 @@
143 extern int sqlite3_shell(int, char**);
144 db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
145 db_close(1);
146 sqlite3_shutdown();
147 sqlite3_shell(g.argc-1, g.argv+1);
 
148 }
149
150 /*
151 ** This routine is called by the patched sqlite3 command-line shell in order
152 ** to load the name and database connection for the open Fossil database.
153
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -143,10 +143,11 @@
143 extern int sqlite3_shell(int, char**);
144 db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
145 db_close(1);
146 sqlite3_shutdown();
147 sqlite3_shell(g.argc-1, g.argv+1);
148 g.db = 0;
149 }
150
151 /*
152 ** This routine is called by the patched sqlite3 command-line shell in order
153 ** to load the name and database connection for the open Fossil database.
154
+292 -205
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -673,11 +673,11 @@
673673
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
674674
** [sqlite_version()] and [sqlite_source_id()].
675675
*/
676676
#define SQLITE_VERSION "3.7.15"
677677
#define SQLITE_VERSION_NUMBER 3007015
678
-#define SQLITE_SOURCE_ID "2012-10-05 07:36:34 43155b1543bddbb84a8bc13a5b7344b228ddacb9"
678
+#define SQLITE_SOURCE_ID "2012-10-09 01:39:25 01dc032b5bbd9c9ebb1965f176ca5d732cda85ea"
679679
680680
/*
681681
** CAPI3REF: Run-Time Library Version Numbers
682682
** KEYWORDS: sqlite3_version, sqlite3_sourceid
683683
**
@@ -10905,10 +10905,11 @@
1090510905
*/
1090610906
struct SrcList {
1090710907
i16 nSrc; /* Number of tables or subqueries in the FROM clause */
1090810908
i16 nAlloc; /* Number of entries allocated in a[] below */
1090910909
struct SrcList_item {
10910
+ Schema *pSchema; /* Schema to which this item is fixed */
1091010911
char *zDatabase; /* Name of database holding this table */
1091110912
char *zName; /* Name of the table */
1091210913
char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */
1091310914
Table *pTab; /* An SQL table corresponding to zName */
1091410915
Select *pSelect; /* A SELECT statement used in place of a table name */
@@ -11473,10 +11474,11 @@
1147311474
** explicit.
1147411475
*/
1147511476
typedef struct DbFixer DbFixer;
1147611477
struct DbFixer {
1147711478
Parse *pParse; /* The parsing context. Error messages written here */
11479
+ Schema *pSchema; /* Fix items to this schema */
1147811480
const char *zDb; /* Make sure all objects are contained in this database */
1147911481
const char *zType; /* Type of the container - used for error messages */
1148011482
const Token *pName; /* Name of the container - used for error messages */
1148111483
};
1148211484
@@ -11883,10 +11885,11 @@
1188311885
SQLITE_PRIVATE int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int);
1188411886
SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse*, Expr*, int, int);
1188511887
SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse*, Expr*, int, int);
1188611888
SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3*,const char*, const char*);
1188711889
SQLITE_PRIVATE Table *sqlite3LocateTable(Parse*,int isView,const char*, const char*);
11890
+SQLITE_PRIVATE Table *sqlite3LocateTableItem(Parse*,int isView,struct SrcList_item *);
1188811891
SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3*,const char*, const char*);
1188911892
SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*);
1189011893
SQLITE_PRIVATE void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*);
1189111894
SQLITE_PRIVATE void sqlite3Vacuum(Parse*);
1189211895
SQLITE_PRIVATE int sqlite3RunVacuum(char**, sqlite3*);
@@ -12113,11 +12116,11 @@
1211312116
SQLITE_PRIVATE void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*);
1211412117
SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*);
1211512118
SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *, Table *, int, int);
1211612119
SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *, Token *);
1211712120
SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *, SrcList *);
12118
-SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(sqlite3*, u8, CollSeq *, const char*);
12121
+SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*);
1211912122
SQLITE_PRIVATE char sqlite3AffinityType(const char*);
1212012123
SQLITE_PRIVATE void sqlite3Analyze(Parse*, Token*, Token*);
1212112124
SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler*);
1212212125
SQLITE_PRIVATE int sqlite3FindDb(sqlite3*, Token*);
1212312126
SQLITE_PRIVATE int sqlite3FindDbName(sqlite3 *, const char *);
@@ -29968,10 +29971,61 @@
2996829971
#if !SQLITE_OS_WINNT && !defined(SQLITE_OMIT_WAL)
2996929972
# error "WAL mode requires support from the Windows NT kernel, compile\
2997029973
with SQLITE_OMIT_WAL."
2997129974
#endif
2997229975
29976
+/*
29977
+** Are most of the Win32 ANSI APIs available (i.e. with certain exceptions
29978
+** based on the sub-platform)?
29979
+*/
29980
+#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
29981
+# define SQLITE_WIN32_HAS_ANSI
29982
+#endif
29983
+
29984
+/*
29985
+** Are most of the Win32 Unicode APIs available (i.e. with certain exceptions
29986
+** based on the sub-platform)?
29987
+*/
29988
+#if SQLITE_OS_WINCE || SQLITE_OS_WINNT || SQLITE_OS_WINRT
29989
+# define SQLITE_WIN32_HAS_WIDE
29990
+#endif
29991
+
29992
+/*
29993
+** Do we need to manually define the Win32 file mapping APIs for use with WAL
29994
+** mode (e.g. these APIs are available in the Windows CE SDK; however, they
29995
+** are not present in the header file)?
29996
+*/
29997
+#if SQLITE_WIN32_FILEMAPPING_API && !defined(SQLITE_OMIT_WAL)
29998
+/*
29999
+** Two of the file mapping APIs are different under WinRT. Figure out which
30000
+** set we need.
30001
+*/
30002
+#if SQLITE_OS_WINRT
30003
+WINBASEAPI HANDLE WINAPI CreateFileMappingFromApp(HANDLE, \
30004
+ LPSECURITY_ATTRIBUTES, ULONG, ULONG64, LPCWSTR);
30005
+
30006
+WINBASEAPI LPVOID WINAPI MapViewOfFileFromApp(HANDLE, ULONG, ULONG64, SIZE_T);
30007
+#else
30008
+#if defined(SQLITE_WIN32_HAS_ANSI)
30009
+WINBASEAPI HANDLE WINAPI CreateFileMappingA(HANDLE, LPSECURITY_ATTRIBUTES, \
30010
+ DWORD, DWORD, DWORD, LPCSTR);
30011
+#endif /* defined(SQLITE_WIN32_HAS_ANSI) */
30012
+
30013
+#if defined(SQLITE_WIN32_HAS_WIDE)
30014
+WINBASEAPI HANDLE WINAPI CreateFileMappingW(HANDLE, LPSECURITY_ATTRIBUTES, \
30015
+ DWORD, DWORD, DWORD, LPCWSTR);
30016
+#endif /* defined(SQLITE_WIN32_HAS_WIDE) */
30017
+
30018
+WINBASEAPI LPVOID WINAPI MapViewOfFile(HANDLE, DWORD, DWORD, DWORD, SIZE_T);
30019
+#endif /* SQLITE_OS_WINRT */
30020
+
30021
+/*
30022
+** This file mapping API is common to both Win32 and WinRT.
30023
+*/
30024
+WINBASEAPI BOOL WINAPI UnmapViewOfFile(LPCVOID);
30025
+#endif /* SQLITE_WIN32_FILEMAPPING_API && !defined(SQLITE_OMIT_WAL) */
30026
+
2997330027
/*
2997430028
** Macro to find the minimum of two numeric values.
2997530029
*/
2997630030
#ifndef MIN
2997730031
# define MIN(x,y) ((x)<(y)?(x):(y))
@@ -30173,18 +30227,10 @@
3017330227
SQLITE_API int sqlite3_os_type = 0;
3017430228
#else
3017530229
static int sqlite3_os_type = 0;
3017630230
#endif
3017730231
30178
-#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
30179
-# define SQLITE_WIN32_HAS_ANSI
30180
-#endif
30181
-
30182
-#if SQLITE_OS_WINCE || SQLITE_OS_WINNT || SQLITE_OS_WINRT
30183
-# define SQLITE_WIN32_HAS_WIDE
30184
-#endif
30185
-
3018630232
#ifndef SYSCALL
3018730233
# define SYSCALL sqlite3_syscall_ptr
3018830234
#endif
3018930235
3019030236
/*
@@ -30337,11 +30383,15 @@
3033730383
#endif
3033830384
3033930385
#define osFormatMessageW ((DWORD(WINAPI*)(DWORD,LPCVOID,DWORD,DWORD,LPWSTR, \
3034030386
DWORD,va_list*))aSyscall[15].pCurrent)
3034130387
30388
+#if !defined(SQLITE_OMIT_LOAD_EXTENSION)
3034230389
{ "FreeLibrary", (SYSCALL)FreeLibrary, 0 },
30390
+#else
30391
+ { "FreeLibrary", (SYSCALL)0, 0 },
30392
+#endif
3034330393
3034430394
#define osFreeLibrary ((BOOL(WINAPI*)(HMODULE))aSyscall[16].pCurrent)
3034530395
3034630396
{ "GetCurrentProcessId", (SYSCALL)GetCurrentProcessId, 0 },
3034730397
@@ -30418,18 +30468,22 @@
3041830468
3041930469
{ "GetLastError", (SYSCALL)GetLastError, 0 },
3042030470
3042130471
#define osGetLastError ((DWORD(WINAPI*)(VOID))aSyscall[26].pCurrent)
3042230472
30473
+#if !defined(SQLITE_OMIT_LOAD_EXTENSION)
3042330474
#if SQLITE_OS_WINCE
3042430475
/* The GetProcAddressA() routine is only available on Windows CE. */
3042530476
{ "GetProcAddressA", (SYSCALL)GetProcAddressA, 0 },
3042630477
#else
3042730478
/* All other Windows platforms expect GetProcAddress() to take
3042830479
** an ANSI string regardless of the _UNICODE setting */
3042930480
{ "GetProcAddressA", (SYSCALL)GetProcAddress, 0 },
3043030481
#endif
30482
+#else
30483
+ { "GetProcAddressA", (SYSCALL)0, 0 },
30484
+#endif
3043130485
3043230486
#define osGetProcAddressA ((FARPROC(WINAPI*)(HMODULE, \
3043330487
LPCSTR))aSyscall[27].pCurrent)
3043430488
3043530489
#if !SQLITE_OS_WINRT
@@ -30529,19 +30583,20 @@
3052930583
#endif
3053030584
3053130585
#define osHeapValidate ((BOOL(WINAPI*)(HANDLE,DWORD, \
3053230586
LPCVOID))aSyscall[41].pCurrent)
3053330587
30534
-#if defined(SQLITE_WIN32_HAS_ANSI)
30588
+#if defined(SQLITE_WIN32_HAS_ANSI) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
3053530589
{ "LoadLibraryA", (SYSCALL)LoadLibraryA, 0 },
3053630590
#else
3053730591
{ "LoadLibraryA", (SYSCALL)0, 0 },
3053830592
#endif
3053930593
3054030594
#define osLoadLibraryA ((HMODULE(WINAPI*)(LPCSTR))aSyscall[42].pCurrent)
3054130595
30542
-#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
30596
+#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \
30597
+ !defined(SQLITE_OMIT_LOAD_EXTENSION)
3054330598
{ "LoadLibraryW", (SYSCALL)LoadLibraryW, 0 },
3054430599
#else
3054530600
{ "LoadLibraryW", (SYSCALL)0, 0 },
3054630601
#endif
3054730602
@@ -30726,11 +30781,11 @@
3072630781
#endif
3072730782
3072830783
#define osCreateFile2 ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD,DWORD, \
3072930784
LPCREATEFILE2_EXTENDED_PARAMETERS))aSyscall[66].pCurrent)
3073030785
30731
-#if SQLITE_OS_WINRT
30786
+#if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_LOAD_EXTENSION)
3073230787
{ "LoadPackagedLibrary", (SYSCALL)LoadPackagedLibrary, 0 },
3073330788
#else
3073430789
{ "LoadPackagedLibrary", (SYSCALL)0, 0 },
3073530790
#endif
3073630791
@@ -60050,11 +60105,13 @@
6005060105
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
6005160106
Btree *pBt = db->aDb[i].pBt;
6005260107
if( sqlite3BtreeIsInTrans(pBt) ){
6005360108
needXcommit = 1;
6005460109
if( i!=1 ) nTrans++;
60110
+ sqlite3BtreeEnter(pBt);
6005560111
rc = sqlite3PagerExclusiveLock(sqlite3BtreePager(pBt));
60112
+ sqlite3BtreeLeave(pBt);
6005660113
}
6005760114
}
6005860115
if( rc!=SQLITE_OK ){
6005960116
return rc;
6006060117
}
@@ -74362,10 +74419,11 @@
7436274419
pNew->nSrc = pNew->nAlloc = p->nSrc;
7436374420
for(i=0; i<p->nSrc; i++){
7436474421
struct SrcList_item *pNewItem = &pNew->a[i];
7436574422
struct SrcList_item *pOldItem = &p->a[i];
7436674423
Table *pTab;
74424
+ pNewItem->pSchema = pOldItem->pSchema;
7436774425
pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase);
7436874426
pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
7436974427
pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias);
7437074428
pNewItem->jointype = pOldItem->jointype;
7437174429
pNewItem->iCursor = pOldItem->iCursor;
@@ -77988,11 +78046,11 @@
7798878046
savedDbFlags = db->flags;
7798978047
if( NEVER(db->mallocFailed) ) goto exit_rename_table;
7799078048
assert( pSrc->nSrc==1 );
7799178049
assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
7799278050
77993
- pTab = sqlite3LocateTable(pParse, 0, pSrc->a[0].zName, pSrc->a[0].zDatabase);
78051
+ pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]);
7799478052
if( !pTab ) goto exit_rename_table;
7799578053
iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
7799678054
zDb = db->aDb[iDb].zName;
7799778055
db->flags |= SQLITE_PreferBuiltin;
7799878056
@@ -78331,11 +78389,11 @@
7833178389
7833278390
/* Look up the table being altered. */
7833378391
assert( pParse->pNewTable==0 );
7833478392
assert( sqlite3BtreeHoldsAllMutexes(db) );
7833578393
if( db->mallocFailed ) goto exit_begin_add_column;
78336
- pTab = sqlite3LocateTable(pParse, 0, pSrc->a[0].zName, pSrc->a[0].zDatabase);
78394
+ pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]);
7833778395
if( !pTab ) goto exit_begin_add_column;
7833878396
7833978397
#ifndef SQLITE_OMIT_VIRTUALTABLE
7834078398
if( IsVirtual(pTab) ){
7834178399
sqlite3ErrorMsg(pParse, "virtual tables may not be altered");
@@ -79962,10 +80020,11 @@
7996280020
if( NEVER(iDb<0) || iDb==1 ) return 0;
7996380021
db = pParse->db;
7996480022
assert( db->nDb>iDb );
7996580023
pFix->pParse = pParse;
7996680024
pFix->zDb = db->aDb[iDb].zName;
80025
+ pFix->pSchema = db->aDb[iDb].pSchema;
7996780026
pFix->zType = zType;
7996880027
pFix->pName = pName;
7996980028
return 1;
7997080029
}
7997180030
@@ -79992,18 +80051,19 @@
7999280051
struct SrcList_item *pItem;
7999380052
7999480053
if( NEVER(pList==0) ) return 0;
7999580054
zDb = pFix->zDb;
7999680055
for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
79997
- if( pItem->zDatabase==0 ){
79998
- pItem->zDatabase = sqlite3DbStrDup(pFix->pParse->db, zDb);
79999
- }else if( sqlite3StrICmp(pItem->zDatabase,zDb)!=0 ){
80056
+ if( pItem->zDatabase && sqlite3StrICmp(pItem->zDatabase, zDb) ){
8000080057
sqlite3ErrorMsg(pFix->pParse,
8000180058
"%s %T cannot reference objects in database %s",
8000280059
pFix->zType, pFix->pName, pItem->zDatabase);
8000380060
return 1;
8000480061
}
80062
+ sqlite3_free(pItem->zDatabase);
80063
+ pItem->zDatabase = 0;
80064
+ pItem->pSchema = pFix->pSchema;
8000580065
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
8000680066
if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1;
8000780067
if( sqlite3FixExpr(pFix, pItem->pOn) ) return 1;
8000880068
#endif
8000980069
}
@@ -80656,10 +80716,35 @@
8065680716
}
8065780717
pParse->checkSchema = 1;
8065880718
}
8065980719
return p;
8066080720
}
80721
+
80722
+/*
80723
+** Locate the table identified by *p.
80724
+**
80725
+** This is a wrapper around sqlite3LocateTable(). The difference between
80726
+** sqlite3LocateTable() and this function is that this function restricts
80727
+** the search to schema (p->pSchema) if it is not NULL. p->pSchema may be
80728
+** non-NULL if it is part of a view or trigger program definition. See
80729
+** sqlite3FixSrcList() for details.
80730
+*/
80731
+SQLITE_PRIVATE Table *sqlite3LocateTableItem(
80732
+ Parse *pParse,
80733
+ int isView,
80734
+ struct SrcList_item *p
80735
+){
80736
+ const char *zDb;
80737
+ assert( p->pSchema==0 || p->zDatabase==0 );
80738
+ if( p->pSchema ){
80739
+ int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema);
80740
+ zDb = pParse->db->aDb[iDb].zName;
80741
+ }else{
80742
+ zDb = p->zDatabase;
80743
+ }
80744
+ return sqlite3LocateTable(pParse, isView, p->zName, zDb);
80745
+}
8066180746
8066280747
/*
8066380748
** Locate the in-memory structure that describes
8066480749
** a particular index given the name of that index
8066580750
** and the name of the database that contains the index.
@@ -81633,14 +81718,11 @@
8163381718
u8 initbusy = db->init.busy;
8163481719
CollSeq *pColl;
8163581720
8163681721
pColl = sqlite3FindCollSeq(db, enc, zName, initbusy);
8163781722
if( !initbusy && (!pColl || !pColl->xCmp) ){
81638
- pColl = sqlite3GetCollSeq(db, enc, pColl, zName);
81639
- if( !pColl ){
81640
- sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName);
81641
- }
81723
+ pColl = sqlite3GetCollSeq(pParse, enc, pColl, zName);
8164281724
}
8164381725
8164481726
return pColl;
8164581727
}
8164681728
@@ -82452,12 +82534,11 @@
8245282534
goto exit_drop_table;
8245382535
}
8245482536
assert( pParse->nErr==0 );
8245582537
assert( pName->nSrc==1 );
8245682538
if( noErr ) db->suppressErr++;
82457
- pTab = sqlite3LocateTable(pParse, isView,
82458
- pName->a[0].zName, pName->a[0].zDatabase);
82539
+ pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]);
8245982540
if( noErr ) db->suppressErr--;
8246082541
8246182542
if( pTab==0 ){
8246282543
if( noErr ) sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase);
8246382544
goto exit_drop_table;
@@ -82893,13 +82974,13 @@
8289382974
){
8289482975
/* Because the parser constructs pTblName from a single identifier,
8289582976
** sqlite3FixSrcList can never fail. */
8289682977
assert(0);
8289782978
}
82898
- pTab = sqlite3LocateTable(pParse, 0, pTblName->a[0].zName,
82899
- pTblName->a[0].zDatabase);
82900
- if( !pTab || db->mallocFailed ) goto exit_create_index;
82979
+ pTab = sqlite3LocateTableItem(pParse, 0, &pTblName->a[0]);
82980
+ assert( db->mallocFailed==0 || pTab==0 );
82981
+ if( pTab==0 ) goto exit_create_index;
8290182982
assert( db->aDb[iDb].pSchema==pTab->pSchema );
8290282983
}else{
8290382984
assert( pName==0 );
8290482985
assert( pStart==0 );
8290582986
pTab = pParse->pNewTable;
@@ -84254,21 +84335,22 @@
8425484335
** If it is not NULL, then pColl must point to the database native encoding
8425584336
** collation sequence with name zName, length nName.
8425684337
**
8425784338
** The return value is either the collation sequence to be used in database
8425884339
** db for collation type name zName, length nName, or NULL, if no collation
84259
-** sequence can be found.
84340
+** sequence can be found. If no collation is found, leave an error message.
8426084341
**
8426184342
** See also: sqlite3LocateCollSeq(), sqlite3FindCollSeq()
8426284343
*/
8426384344
SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(
84264
- sqlite3* db, /* The database connection */
84345
+ Parse *pParse, /* Parsing context */
8426584346
u8 enc, /* The desired encoding for the collating sequence */
8426684347
CollSeq *pColl, /* Collating sequence with native encoding, or NULL */
8426784348
const char *zName /* Collating sequence name */
8426884349
){
8426984350
CollSeq *p;
84351
+ sqlite3 *db = pParse->db;
8427084352
8427184353
p = pColl;
8427284354
if( !p ){
8427384355
p = sqlite3FindCollSeq(db, enc, zName, 0);
8427484356
}
@@ -84281,10 +84363,13 @@
8428184363
}
8428284364
if( p && !p->xCmp && synthCollSeq(db, p) ){
8428384365
p = 0;
8428484366
}
8428584367
assert( !p || p->xCmp );
84368
+ if( p==0 ){
84369
+ sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName);
84370
+ }
8428684371
return p;
8428784372
}
8428884373
8428984374
/*
8429084375
** This routine is called on a collation sequence before it is used to
@@ -84299,14 +84384,12 @@
8429984384
*/
8430084385
SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){
8430184386
if( pColl ){
8430284387
const char *zName = pColl->zName;
8430384388
sqlite3 *db = pParse->db;
84304
- CollSeq *p = sqlite3GetCollSeq(db, ENC(db), pColl, zName);
84389
+ CollSeq *p = sqlite3GetCollSeq(pParse, ENC(db), pColl, zName);
8430584390
if( !p ){
84306
- sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName);
84307
- pParse->nErr++;
8430884391
return SQLITE_ERROR;
8430984392
}
8431084393
assert( p==pColl );
8431184394
}
8431284395
return SQLITE_OK;
@@ -84689,11 +84772,11 @@
8468984772
*/
8469084773
SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
8469184774
struct SrcList_item *pItem = pSrc->a;
8469284775
Table *pTab;
8469384776
assert( pItem && pSrc->nSrc==1 );
84694
- pTab = sqlite3LocateTable(pParse, 0, pItem->zName, pItem->zDatabase);
84777
+ pTab = sqlite3LocateTableItem(pParse, 0, pItem);
8469584778
sqlite3DeleteTable(pParse->db, pItem->pTab);
8469684779
pItem->pTab = pTab;
8469784780
if( pTab ){
8469884781
pTab->nRef++;
8469984782
}
@@ -89415,24 +89498,29 @@
8941589498
ExprList *pCheck = pTab->pCheck;
8941689499
pParse->ckBase = regData;
8941789500
onError = overrideError!=OE_Default ? overrideError : OE_Abort;
8941889501
for(i=0; i<pCheck->nExpr; i++){
8941989502
int allOk = sqlite3VdbeMakeLabel(v);
89420
- sqlite3ExprIfTrue(pParse, pCheck->a[i].pExpr, allOk, SQLITE_JUMPIFNULL);
89421
- if( onError==OE_Ignore ){
89422
- sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
89423
- }else{
89424
- char *zConsName = pCheck->a[i].zName;
89425
- if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-15569-63625 */
89426
- if( zConsName ){
89427
- zConsName = sqlite3MPrintf(db, "constraint %s failed", zConsName);
89428
- }else{
89429
- zConsName = 0;
89430
- }
89431
- sqlite3HaltConstraint(pParse, onError, zConsName, P4_DYNAMIC);
89432
- }
89433
- sqlite3VdbeResolveLabel(v, allOk);
89503
+ Expr *pDup = sqlite3ExprDup(db, pCheck->a[i].pExpr, 0);
89504
+ if( !db->mallocFailed ){
89505
+ assert( pDup!=0 );
89506
+ sqlite3ExprIfTrue(pParse, pDup, allOk, SQLITE_JUMPIFNULL);
89507
+ if( onError==OE_Ignore ){
89508
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
89509
+ }else{
89510
+ char *zConsName = pCheck->a[i].zName;
89511
+ if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-15569-63625 */
89512
+ if( zConsName ){
89513
+ zConsName = sqlite3MPrintf(db, "constraint %s failed", zConsName);
89514
+ }else{
89515
+ zConsName = 0;
89516
+ }
89517
+ sqlite3HaltConstraint(pParse, onError, zConsName, P4_DYNAMIC);
89518
+ }
89519
+ sqlite3VdbeResolveLabel(v, allOk);
89520
+ }
89521
+ sqlite3ExprDelete(db, pDup);
8943489522
}
8943589523
}
8943689524
#endif /* !defined(SQLITE_OMIT_CHECK) */
8943789525
8943889526
/* If we have an INTEGER PRIMARY KEY, make sure the primary key
@@ -89884,11 +89972,11 @@
8988489972
/* At this point we have established that the statement is of the
8988589973
** correct syntactic form to participate in this optimization. Now
8988689974
** we have to check the semantics.
8988789975
*/
8988889976
pItem = pSelect->pSrc->a;
89889
- pSrc = sqlite3LocateTable(pParse, 0, pItem->zName, pItem->zDatabase);
89977
+ pSrc = sqlite3LocateTableItem(pParse, 0, pItem);
8989089978
if( pSrc==0 ){
8989189979
return 0; /* FROM clause does not contain a real table */
8989289980
}
8989389981
if( pSrc==pDest ){
8989489982
return 0; /* tab1 and tab2 may not be the same table */
@@ -97153,12 +97241,11 @@
9715397241
pTab->tabFlags |= TF_Ephemeral;
9715497242
#endif
9715597243
}else{
9715697244
/* An ordinary table or view name in the FROM clause */
9715797245
assert( pFrom->pTab==0 );
97158
- pFrom->pTab = pTab =
97159
- sqlite3LocateTable(pParse,0,pFrom->zName,pFrom->zDatabase);
97246
+ pFrom->pTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom);
9716097247
if( pTab==0 ) return WRC_Abort;
9716197248
pTab->nRef++;
9716297249
#if !defined(SQLITE_OMIT_VIEW) || !defined (SQLITE_OMIT_VIRTUALTABLE)
9716397250
if( pTab->pSelect || IsVirtual(pTab) ){
9716497251
/* We reach here if the named table is a really a view */
@@ -101095,10 +101182,11 @@
101095101182
*/
101096101183
SQLITE_PRIVATE void sqlite3VtabClear(sqlite3 *db, Table *p){
101097101184
if( !db || db->pnBytesFreed==0 ) vtabDisconnectAll(0, p);
101098101185
if( p->azModuleArg ){
101099101186
int i;
101187
+ assert( p->nModuleArg<2 || p->azModuleArg[1]==0 );
101100101188
for(i=0; i<p->nModuleArg; i++){
101101101189
sqlite3DbFree(db, p->azModuleArg[i]);
101102101190
}
101103101191
sqlite3DbFree(db, p->azModuleArg);
101104101192
}
@@ -101156,11 +101244,11 @@
101156101244
assert( iDb>=0 );
101157101245
101158101246
pTable->tabFlags |= TF_Virtual;
101159101247
pTable->nModuleArg = 0;
101160101248
addModuleArgument(db, pTable, sqlite3NameFromToken(db, pModuleName));
101161
- addModuleArgument(db, pTable, sqlite3DbStrDup(db, db->aDb[iDb].zName));
101249
+ addModuleArgument(db, pTable, 0);
101162101250
addModuleArgument(db, pTable, sqlite3DbStrDup(db, pTable->zName));
101163101251
pParse->sNameToken.n = (int)(&pModuleName->z[pModuleName->n] - pName1->z);
101164101252
101165101253
#ifndef SQLITE_OMIT_AUTHORIZATION
101166101254
/* Creating a virtual table invokes the authorization callback twice.
@@ -101313,10 +101401,11 @@
101313101401
int rc;
101314101402
const char *const*azArg = (const char *const*)pTab->azModuleArg;
101315101403
int nArg = pTab->nModuleArg;
101316101404
char *zErr = 0;
101317101405
char *zModuleName = sqlite3MPrintf(db, "%s", pTab->zName);
101406
+ int iDb;
101318101407
101319101408
if( !zModuleName ){
101320101409
return SQLITE_NOMEM;
101321101410
}
101322101411
@@ -101326,10 +101415,14 @@
101326101415
return SQLITE_NOMEM;
101327101416
}
101328101417
pVTable->db = db;
101329101418
pVTable->pMod = pMod;
101330101419
101420
+ assert( pTab->azModuleArg[1]==0 );
101421
+ iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
101422
+ pTab->azModuleArg[1] = db->aDb[iDb].zName;
101423
+
101331101424
/* Invoke the virtual table constructor */
101332101425
assert( &db->pVtabCtx );
101333101426
assert( xConstruct );
101334101427
sCtx.pTab = pTab;
101335101428
sCtx.pVTable = pVTable;
@@ -101336,10 +101429,11 @@
101336101429
pPriorCtx = db->pVtabCtx;
101337101430
db->pVtabCtx = &sCtx;
101338101431
rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr);
101339101432
db->pVtabCtx = pPriorCtx;
101340101433
if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
101434
+ pTab->azModuleArg[1] = 0;
101341101435
101342101436
if( SQLITE_OK!=rc ){
101343101437
if( zErr==0 ){
101344101438
*pzErr = sqlite3MPrintf(db, "vtable constructor failed: %s", zModuleName);
101345101439
}else {
@@ -103371,26 +103465,10 @@
103371103465
** an index for tables to the left of the join.
103372103466
*/
103373103467
pTerm->prereqRight |= extraRight;
103374103468
}
103375103469
103376
-/*
103377
-** Return TRUE if the given index is UNIQUE and all columns past the
103378
-** first nSkip columns are NOT NULL.
103379
-*/
103380
-static int indexIsUniqueNotNull(Index *pIdx, int nSkip){
103381
- Table *pTab = pIdx->pTable;
103382
- int i;
103383
- if( pIdx->onError==OE_None ) return 0;
103384
- for(i=nSkip; i<pIdx->nColumn; i++){
103385
- int j = pIdx->aiColumn[i];
103386
- assert( j>=0 && j<pTab->nCol );
103387
- if( pTab->aCol[j].notNull==0 ) return 0;
103388
- }
103389
- return 1;
103390
-}
103391
-
103392103470
/*
103393103471
** This function searches the expression list passed as the second argument
103394103472
** for an expression of type TK_COLUMN that refers to the same column and
103395103473
** uses the same collation sequence as the iCol'th column of index pIdx.
103396103474
** Argument iBase is the cursor number used for the table that pIdx refers
@@ -104344,14 +104422,12 @@
104344104422
if( eType==SQLITE_BLOB ){
104345104423
z = (const u8 *)sqlite3_value_blob(pVal);
104346104424
pColl = db->pDfltColl;
104347104425
assert( pColl->enc==SQLITE_UTF8 );
104348104426
}else{
104349
- pColl = sqlite3GetCollSeq(db, SQLITE_UTF8, 0, *pIdx->azColl);
104427
+ pColl = sqlite3GetCollSeq(pParse, SQLITE_UTF8, 0, *pIdx->azColl);
104350104428
if( pColl==0 ){
104351
- sqlite3ErrorMsg(pParse, "no such collation sequence: %s",
104352
- *pIdx->azColl);
104353104429
return SQLITE_ERROR;
104354104430
}
104355104431
z = (const u8 *)sqlite3ValueText(pVal, pColl->enc);
104356104432
if( !z ){
104357104433
return SQLITE_NOMEM;
@@ -104657,30 +104733,34 @@
104657104733
}
104658104734
#endif /* defined(SQLITE_ENABLE_STAT3) */
104659104735
104660104736
/*
104661104737
** Check to see if column iCol of the table with cursor iTab will appear
104662
-** in sorted order according to the current query plan. Return true if
104663
-** it will and false if not.
104738
+** in sorted order according to the current query plan.
104664104739
**
104665
-** If *pbRev is initially 2 (meaning "unknown") then set *pbRev to the
104666
-** sort order of iTab.iCol. If *pbRev is 0 or 1 but does not match
104667
-** the sort order of iTab.iCol, then consider the column to be unordered.
104740
+** Return values:
104741
+**
104742
+** 0 iCol is not ordered
104743
+** 1 iCol has only a single value
104744
+** 2 iCol is in ASC order
104745
+** 3 iCol is in DESC order
104668104746
*/
104669
-static int isOrderedColumn(WhereBestIdx *p, int iTab, int iCol, int *pbRev){
104747
+static int isOrderedColumn(
104748
+ WhereBestIdx *p,
104749
+ int iTab,
104750
+ int iCol
104751
+){
104670104752
int i, j;
104671104753
WhereLevel *pLevel = &p->aLevel[p->i-1];
104672104754
Index *pIdx;
104673104755
u8 sortOrder;
104674104756
for(i=p->i-1; i>=0; i--, pLevel--){
104675104757
if( pLevel->iTabCur!=iTab ) continue;
104676104758
if( (pLevel->plan.wsFlags & WHERE_ALL_UNIQUE)!=0 ){
104677104759
return 1;
104678104760
}
104679
- if( (pLevel->plan.wsFlags & WHERE_ORDERED)==0 ){
104680
- return 0;
104681
- }
104761
+ assert( (pLevel->plan.wsFlags & WHERE_ORDERED)!=0 );
104682104762
if( (pIdx = pLevel->plan.u.pIdx)!=0 ){
104683104763
if( iCol<0 ){
104684104764
sortOrder = 0;
104685104765
testcase( (pLevel->plan.wsFlags & WHERE_REVERSE)!=0 );
104686104766
}else{
@@ -104700,39 +104780,12 @@
104700104780
if( (pLevel->plan.wsFlags & WHERE_REVERSE)!=0 ){
104701104781
assert( sortOrder==0 || sortOrder==1 );
104702104782
testcase( sortOrder==1 );
104703104783
sortOrder = 1 - sortOrder;
104704104784
}
104705
- if( *pbRev==2 ){
104706
- *pbRev = sortOrder;
104707
- return 1;
104708
- }
104709
- return (*pbRev==sortOrder);
104710
- }
104711
- return 0;
104712
-}
104713
-
104714
-/*
104715
-** pTerm is an == constraint. Check to see if the other side of
104716
-** the == is a constant or a value that is guaranteed to be ordered
104717
-** by outer loops. Return 1 if pTerm is ordered, and 0 if not.
104718
-*/
104719
-static int isOrderedTerm(WhereBestIdx *p, WhereTerm *pTerm, int *pbRev){
104720
- Expr *pExpr = pTerm->pExpr;
104721
- assert( pExpr->op==TK_EQ );
104722
- assert( pExpr->pLeft!=0 && pExpr->pLeft->op==TK_COLUMN );
104723
- assert( pExpr->pRight!=0 );
104724
- if( pTerm->prereqRight==0 ){
104725
- return 1; /* RHS of the == is a constant */
104726
- }
104727
- if( pExpr->pRight->op==TK_COLUMN
104728
- && isOrderedColumn(p, pExpr->pRight->iTable, pExpr->pRight->iColumn, pbRev)
104729
- ){
104730
- return 1;
104731
- }
104732
-
104733
- /* If we cannot prove that the constraint is ordered, assume it is not */
104785
+ return sortOrder+2;
104786
+ }
104734104787
return 0;
104735104788
}
104736104789
104737104790
/*
104738104791
** This routine decides if pIdx can be used to satisfy the ORDER BY
@@ -104756,49 +104809,49 @@
104756104809
*/
104757104810
static int isSortingIndex(
104758104811
WhereBestIdx *p, /* Best index search context */
104759104812
Index *pIdx, /* The index we are testing */
104760104813
int base, /* Cursor number for the table to be sorted */
104761
- int nEqCol, /* Number of index columns with ordered == constraints */
104762
- int wsFlags, /* Index usages flags */
104763
- int bOuterRev, /* True if outer loops scan in reverse order */
104764104814
int *pbRev /* Set to 1 for reverse-order scan of pIdx */
104765104815
){
104766104816
int i; /* Number of pIdx terms used */
104767104817
int j; /* Number of ORDER BY terms satisfied */
104768
- int sortOrder = 0; /* XOR of index and ORDER BY sort direction */
104818
+ int sortOrder = 2; /* 0: forward. 1: backward. 2: unknown */
104769104819
int nTerm; /* Number of ORDER BY terms */
104770
- struct ExprList_item *pTerm; /* A term of the ORDER BY clause */
104820
+ struct ExprList_item *pOBItem;/* A term of the ORDER BY clause */
104821
+ Table *pTab = pIdx->pTable; /* Table that owns index pIdx */
104771104822
ExprList *pOrderBy; /* The ORDER BY clause */
104772104823
Parse *pParse = p->pParse; /* Parser context */
104773104824
sqlite3 *db = pParse->db; /* Database connection */
104774104825
int nPriorSat; /* ORDER BY terms satisfied by outer loops */
104775104826
int seenRowid = 0; /* True if an ORDER BY rowid term is seen */
104776
- int nEqOneRow; /* Idx columns that ref unique values */
104827
+ int uniqueNotNull; /* pIdx is UNIQUE with all terms are NOT NULL */
104777104828
104778104829
if( p->i==0 ){
104779104830
nPriorSat = 0;
104780104831
}else{
104781104832
nPriorSat = p->aLevel[p->i-1].plan.nOBSat;
104782
- if( OptimizationDisabled(db, SQLITE_OrderByIdxJoin) ) return nPriorSat;
104783
- }
104784
- if( nEqCol==0 ){
104785
- if( p->i && (p->aLevel[p->i-1].plan.wsFlags & WHERE_ORDERED)==0 ){
104833
+ if( (p->aLevel[p->i-1].plan.wsFlags & WHERE_ORDERED)==0 ){
104834
+ /* This loop cannot be ordered unless the next outer loop is
104835
+ ** also ordered */
104836
+ return nPriorSat;
104837
+ }
104838
+ if( OptimizationDisabled(db, SQLITE_OrderByIdxJoin) ){
104839
+ /* Only look at the outer-most loop if the OrderByIdxJoin
104840
+ ** optimization is disabled */
104786104841
return nPriorSat;
104787104842
}
104788
- nEqOneRow = 0;
104789
- }else if( p->i==0 || (p->aLevel[p->i-1].plan.wsFlags & WHERE_ALL_UNIQUE)!=0 ){
104790
- nEqOneRow = nEqCol;
104791
- }else{
104792
- sortOrder = bOuterRev;
104793
- nEqOneRow = -1;
104794104843
}
104795104844
pOrderBy = p->pOrderBy;
104796104845
assert( pOrderBy!=0 );
104797
- if( wsFlags & WHERE_COLUMN_IN ) return nPriorSat;
104798
- if( pIdx->bUnordered ) return nPriorSat;
104846
+ if( pIdx->bUnordered ){
104847
+ /* Hash indices (indicated by the "unordered" tag on sqlite_stat1) cannot
104848
+ ** be used for sorting */
104849
+ return nPriorSat;
104850
+ }
104799104851
nTerm = pOrderBy->nExpr;
104852
+ uniqueNotNull = pIdx->onError!=OE_None;
104800104853
assert( nTerm>0 );
104801104854
104802104855
/* Argument pIdx must either point to a 'real' named index structure,
104803104856
** or an index structure allocated on the stack by bestBtreeIndex() to
104804104857
** represent the rowid index that is part of every table. */
@@ -104810,90 +104863,130 @@
104810104863
** Note that indices have pIdx->nColumn regular columns plus
104811104864
** one additional column containing the rowid. The rowid column
104812104865
** of the index is also allowed to match against the ORDER BY
104813104866
** clause.
104814104867
*/
104815
- for(i=0,j=nPriorSat,pTerm=&pOrderBy->a[j]; j<nTerm; i++){
104816
- Expr *pExpr; /* The expression of the ORDER BY pTerm */
104817
- CollSeq *pColl; /* The collating sequence of pExpr */
104818
- int termSortOrder; /* Sort order for this term */
104819
- int iColumn; /* The i-th column of the index. -1 for rowid */
104820
- int iSortOrder; /* 1 for DESC, 0 for ASC on the i-th index term */
104821
- const char *zColl; /* Name of the collating sequence for i-th index term */
104822
-
104823
- assert( i<=pIdx->nColumn );
104824
- pExpr = pTerm->pExpr;
104825
- if( pExpr->op!=TK_COLUMN || pExpr->iTable!=base ){
104826
- /* Can not use an index sort on anything that is not a column in the
104827
- ** left-most table of the FROM clause */
104868
+ j = nPriorSat;
104869
+ for(i=0,pOBItem=&pOrderBy->a[j]; j<nTerm && i<=pIdx->nColumn; i++){
104870
+ Expr *pOBExpr; /* The expression of the ORDER BY pOBItem */
104871
+ CollSeq *pColl; /* The collating sequence of pOBExpr */
104872
+ int termSortOrder; /* Sort order for this term */
104873
+ int iColumn; /* The i-th column of the index. -1 for rowid */
104874
+ int iSortOrder; /* 1 for DESC, 0 for ASC on the i-th index term */
104875
+ int isEq; /* Subject to an == or IS NULL constraint */
104876
+ int isMatch; /* ORDER BY term matches the index term */
104877
+ const char *zColl; /* Name of collating sequence for i-th index term */
104878
+ WhereTerm *pConstraint; /* A constraint in the WHERE clause */
104879
+
104880
+ /* If the next term of the ORDER BY clause refers to anything other than
104881
+ ** a column in the "base" table, then this index will not be of any
104882
+ ** further use in handling the ORDER BY. */
104883
+ pOBExpr = pOBItem->pExpr;
104884
+ if( pOBExpr->op!=TK_COLUMN || pOBExpr->iTable!=base ){
104828104885
break;
104829104886
}
104830
- pColl = sqlite3ExprCollSeq(pParse, pExpr);
104831
- if( !pColl ){
104832
- pColl = db->pDfltColl;
104833
- }
104887
+
104888
+ /* Find column number and collating sequence for the next entry
104889
+ ** in the index */
104834104890
if( pIdx->zName && i<pIdx->nColumn ){
104835104891
iColumn = pIdx->aiColumn[i];
104836104892
if( iColumn==pIdx->pTable->iPKey ){
104837104893
iColumn = -1;
104838104894
}
104839104895
iSortOrder = pIdx->aSortOrder[i];
104840104896
zColl = pIdx->azColl[i];
104897
+ assert( zColl!=0 );
104841104898
}else{
104842104899
iColumn = -1;
104843104900
iSortOrder = 0;
104844
- zColl = pColl->zName;
104845
- }
104846
- if( pExpr->iColumn!=iColumn || sqlite3StrICmp(pColl->zName, zColl) ){
104847
- /* Term j of the ORDER BY clause does not match column i of the index */
104848
- if( i<nEqCol ){
104849
- /* If an index column that is constrained by == fails to match an
104850
- ** ORDER BY term, that is OK. Just ignore that column of the index
104851
- */
104852
- continue;
104853
- }else if( i==pIdx->nColumn ){
104854
- /* Index column i is the rowid. All other terms match. */
104855
- break;
104901
+ zColl = 0;
104902
+ }
104903
+
104904
+ /* Check to see if the column number and collating sequence of the
104905
+ ** index match the column number and collating sequence of the ORDER BY
104906
+ ** clause entry. Set isMatch to 1 if they both match. */
104907
+ if( pOBExpr->iColumn==iColumn ){
104908
+ if( zColl ){
104909
+ pColl = sqlite3ExprCollSeq(pParse, pOBExpr);
104910
+ if( !pColl ) pColl = db->pDfltColl;
104911
+ isMatch = sqlite3StrICmp(pColl->zName, zColl)==0;
104912
+ }else{
104913
+ isMatch = 1;
104914
+ }
104915
+ }else{
104916
+ isMatch = 0;
104917
+ }
104918
+
104919
+ /* termSortOrder is 0 or 1 for whether or not the access loop should
104920
+ ** run forward or backwards (respectively) in order to satisfy this
104921
+ ** term of the ORDER BY clause. */
104922
+ termSortOrder = iSortOrder ^ pOBItem->sortOrder;
104923
+
104924
+ /* If X is the column in the index and ORDER BY clause, check to see
104925
+ ** if there are any X= or X IS NULL constraints in the WHERE clause. */
104926
+ pConstraint = findTerm(p->pWC, base, iColumn, p->notReady,
104927
+ WO_EQ|WO_ISNULL|WO_IN, pIdx);
104928
+ if( pConstraint==0 ){
104929
+ isEq = 0;
104930
+ }else if( pConstraint->eOperator==WO_IN ){
104931
+ break;
104932
+ }else if( pConstraint->eOperator==WO_ISNULL ){
104933
+ uniqueNotNull = 0;
104934
+ isEq = 1;
104935
+ }else if( pConstraint->prereqRight==0 ){
104936
+ isEq = 1;
104937
+ }else{
104938
+ Expr *pRight = pConstraint->pExpr->pRight;
104939
+ if( pRight->op==TK_COLUMN ){
104940
+ WHERETRACE((" .. isOrderedColumn(tab=%d,col=%d)",
104941
+ pRight->iTable, pRight->iColumn));
104942
+ isEq = isOrderedColumn(p, pRight->iTable, pRight->iColumn);
104943
+ WHERETRACE((" -> isEq=%d\n", isEq));
104944
+ if( isMatch && isEq>=2 && isEq!=pOBItem->sortOrder+2 ){
104945
+ break;
104946
+ }
104856104947
}else{
104857
- /* If an index column fails to match and is not constrained by ==
104858
- ** then the index cannot satisfy the ORDER BY constraint.
104859
- */
104860
- return nPriorSat;
104948
+ isEq = 0;
104861104949
}
104862104950
}
104863
- assert( pIdx->aSortOrder!=0 || iColumn==-1 );
104864
- assert( pTerm->sortOrder==0 || pTerm->sortOrder==1 );
104951
+ assert( pOBItem->sortOrder==0 || pOBItem->sortOrder==1 );
104865104952
assert( iSortOrder==0 || iSortOrder==1 );
104866
- termSortOrder = iSortOrder ^ pTerm->sortOrder;
104867
- if( i>nEqOneRow ){
104868
- if( termSortOrder!=sortOrder ){
104869
- /* Indices can only be used if all ORDER BY terms past the
104870
- ** equality constraints have the correct DESC or ASC. */
104953
+ if( !isMatch ){
104954
+ if( isEq==0 ){
104955
+ break;
104956
+ }else{
104957
+ continue;
104958
+ }
104959
+ }else if( isEq!=1 ){
104960
+ if( sortOrder==2 ){
104961
+ sortOrder = termSortOrder;
104962
+ }else if( termSortOrder!=sortOrder ){
104871104963
break;
104872104964
}
104873
- }else{
104874
- sortOrder = termSortOrder;
104875104965
}
104876104966
j++;
104877
- pTerm++;
104967
+ pOBItem++;
104878104968
if( iColumn<0 ){
104879104969
seenRowid = 1;
104880104970
break;
104971
+ }else if( pTab->aCol[iColumn].notNull==0 && isEq==0 ){
104972
+ uniqueNotNull = 0;
104881104973
}
104882104974
}
104883
- *pbRev = sortOrder;
104975
+
104976
+ /* If we have not found at least one ORDER BY term that matches the
104977
+ ** index, then show no progress. */
104978
+ if( pOBItem==&pOrderBy->a[nPriorSat] ) return nPriorSat;
104979
+
104980
+ /* Return the necessary scan order back to the caller */
104981
+ *pbRev = sortOrder & 1;
104884104982
104885104983
/* If there was an "ORDER BY rowid" term that matched, or it is only
104886104984
** possible for a single row from this table to match, then skip over
104887104985
** any additional ORDER BY terms dealing with this table.
104888104986
*/
104889
- if( seenRowid ||
104890
- ( (wsFlags & WHERE_COLUMN_NULL)==0
104891
- && i>=pIdx->nColumn
104892
- && indexIsUniqueNotNull(pIdx, nEqCol)
104893
- )
104894
- ){
104987
+ if( seenRowid || (uniqueNotNull && i>=pIdx->nColumn) ){
104895104988
/* Advance j over additional ORDER BY terms associated with base */
104896104989
WhereMaskSet *pMS = p->pWC->pMaskSet;
104897104990
Bitmask m = ~getMask(pMS, base);
104898104991
while( j<nTerm && (exprTableUsage(pMS, pOrderBy->a[j].pExpr)&m)==0 ){
104899104992
j++;
@@ -104995,11 +105088,10 @@
104995105088
*/
104996105089
for(; pProbe; pIdx=pProbe=pProbe->pNext){
104997105090
const tRowcnt * const aiRowEst = pProbe->aiRowEst;
104998105091
WhereCost pc; /* Cost of using pProbe */
104999105092
double log10N = (double)1; /* base-10 logarithm of nRow (inexact) */
105000
- int bRev = 2; /* 0=forward scan. 1=reverse. 2=undecided */
105001105093
105002105094
/* The following variables are populated based on the properties of
105003105095
** index being evaluated. They are then used to determine the expected
105004105096
** cost and number of rows returned.
105005105097
**
@@ -105026,14 +105118,10 @@
105026105118
**
105027105119
** If there exists a WHERE term of the form "x IN (SELECT ...)", then
105028105120
** the sub-select is assumed to return 25 rows for the purposes of
105029105121
** determining nInMul.
105030105122
**
105031
- ** nOrdered:
105032
- ** The number of equality terms that are constrainted by outer loop
105033
- ** variables that are well-ordered.
105034
- **
105035105123
** bInEst:
105036105124
** Set to true if there was at least one "x IN (SELECT ...)" term used
105037105125
** in determining the value of nInMul. Note that the RHS of the
105038105126
** IN operator must be a SELECT, not a value list, for this variable
105039105127
** to be true.
@@ -105067,11 +105155,10 @@
105067105155
** both available in the index.
105068105156
**
105069105157
** SELECT a, b FROM tbl WHERE a = 1;
105070105158
** SELECT a, b, c FROM tbl WHERE a = 1;
105071105159
*/
105072
- int nOrdered; /* Number of ordered terms matching index */
105073105160
int bInEst = 0; /* True if "x IN (SELECT...)" seen */
105074105161
int nInMul = 1; /* Number of distinct equalities to lookup */
105075105162
double rangeDiv = (double)1; /* Estimated reduction in search space */
105076105163
int nBound = 0; /* Number of range constraints seen */
105077105164
int bSort; /* True if external sort required */
@@ -105082,10 +105169,14 @@
105082105169
WhereTerm *pTerm; /* A single term of the WHERE clause */
105083105170
#ifdef SQLITE_ENABLE_STAT3
105084105171
WhereTerm *pFirstTerm = 0; /* First term matching the index */
105085105172
#endif
105086105173
105174
+ WHERETRACE((
105175
+ " %s(%s):\n",
105176
+ pSrc->pTab->zName, (pIdx ? pIdx->zName : "ipk")
105177
+ ));
105087105178
memset(&pc, 0, sizeof(pc));
105088105179
nOrderBy = p->pOrderBy ? p->pOrderBy->nExpr : 0;
105089105180
if( p->i ){
105090105181
nPriorSat = pc.plan.nOBSat = p->aLevel[p->i-1].plan.nOBSat;
105091105182
bSort = nPriorSat<nOrderBy;
@@ -105095,11 +105186,11 @@
105095105186
bSort = nOrderBy>0;
105096105187
bDist = p->pDistinct!=0;
105097105188
}
105098105189
105099105190
/* Determine the values of pc.plan.nEq and nInMul */
105100
- for(pc.plan.nEq=nOrdered=0; pc.plan.nEq<pProbe->nColumn; pc.plan.nEq++){
105191
+ for(pc.plan.nEq=0; pc.plan.nEq<pProbe->nColumn; pc.plan.nEq++){
105101105192
int j = pProbe->aiColumn[pc.plan.nEq];
105102105193
pTerm = findTerm(pWC, iCur, j, p->notReady, eqTermMask, pIdx);
105103105194
if( pTerm==0 ) break;
105104105195
pc.plan.wsFlags |= (WHERE_COLUMN_EQ|WHERE_ROWID_EQ);
105105105196
testcase( pTerm->pWC!=pWC );
@@ -105114,14 +105205,10 @@
105114105205
/* "x IN (value, value, ...)" */
105115105206
nInMul *= pExpr->x.pList->nExpr;
105116105207
}
105117105208
}else if( pTerm->eOperator & WO_ISNULL ){
105118105209
pc.plan.wsFlags |= WHERE_COLUMN_NULL;
105119
- if( pc.plan.nEq==nOrdered ) nOrdered++;
105120
- }else if( bSort && pc.plan.nEq==nOrdered
105121
- && isOrderedTerm(p,pTerm,&bRev) ){
105122
- nOrdered++;
105123105210
}
105124105211
#ifdef SQLITE_ENABLE_STAT3
105125105212
if( pc.plan.nEq==0 && pProbe->aSample ) pFirstTerm = pTerm;
105126105213
#endif
105127105214
pc.used |= pTerm->prereqRight;
@@ -105172,17 +105259,16 @@
105172105259
/* If there is an ORDER BY clause and the index being considered will
105173105260
** naturally scan rows in the required order, set the appropriate flags
105174105261
** in pc.plan.wsFlags. Otherwise, if there is an ORDER BY clause but
105175105262
** the index will scan rows in a different order, set the bSort
105176105263
** variable. */
105177
- assert( bRev>=0 && bRev<=2 );
105178
- if( bSort ){
105179
- testcase( bRev==0 );
105180
- testcase( bRev==1 );
105181
- testcase( bRev==2 );
105182
- pc.plan.nOBSat = isSortingIndex(p, pProbe, iCur, nOrdered,
105183
- pc.plan.wsFlags, bRev&1, &bRev);
105264
+ if( bSort && (pSrc->jointype & JT_LEFT)==0 ){
105265
+ int bRev = 2;
105266
+ WHERETRACE((" --> before isSortingIndex: nPriorSat=%d\n",nPriorSat));
105267
+ pc.plan.nOBSat = isSortingIndex(p, pProbe, iCur, &bRev);
105268
+ WHERETRACE((" --> after isSortingIndex: bRev=%d nOBSat=%d\n",
105269
+ bRev, pc.plan.nOBSat));
105184105270
if( nPriorSat<pc.plan.nOBSat || (pc.plan.wsFlags & WHERE_UNIQUE)!=0 ){
105185105271
pc.plan.wsFlags |= WHERE_ORDERED;
105186105272
}
105187105273
if( nOrderBy==pc.plan.nOBSat ){
105188105274
bSort = 0;
@@ -105296,11 +105382,14 @@
105296105382
** decision and one which we expect to revisit in the future. But
105297105383
** it seems to be working well enough at the moment.
105298105384
*/
105299105385
pc.rCost = aiRowEst[0]*4;
105300105386
pc.plan.wsFlags &= ~WHERE_IDX_ONLY;
105301
- if( pIdx ) pc.plan.wsFlags &= ~WHERE_ORDERED;
105387
+ if( pIdx ){
105388
+ pc.plan.wsFlags &= ~WHERE_ORDERED;
105389
+ pc.plan.nOBSat = nPriorSat;
105390
+ }
105302105391
}else{
105303105392
log10N = estLog(aiRowEst[0]);
105304105393
pc.rCost = pc.plan.nRow;
105305105394
if( pIdx ){
105306105395
if( bLookup ){
@@ -105401,17 +105490,15 @@
105401105490
if( pc.plan.nRow<2 ) pc.plan.nRow = 2;
105402105491
}
105403105492
105404105493
105405105494
WHERETRACE((
105406
- "%s(%s):\n"
105407
- " nEq=%d nInMul=%d rangeDiv=%d bSort=%d bLookup=%d wsFlags=0x%08x\n"
105408
- " notReady=0x%llx log10N=%.1f nRow=%.1f cost=%.1f\n"
105409
- " used=0x%llx nOrdered=%d nOBSat=%d\n",
105410
- pSrc->pTab->zName, (pIdx ? pIdx->zName : "ipk"),
105495
+ " nEq=%d nInMul=%d rangeDiv=%d bSort=%d bLookup=%d wsFlags=0x%08x\n"
105496
+ " notReady=0x%llx log10N=%.1f nRow=%.1f cost=%.1f\n"
105497
+ " used=0x%llx nOBSat=%d\n",
105411105498
pc.plan.nEq, nInMul, (int)rangeDiv, bSort, bLookup, pc.plan.wsFlags,
105412
- p->notReady, log10N, pc.plan.nRow, pc.rCost, pc.used, nOrdered,
105499
+ p->notReady, log10N, pc.plan.nRow, pc.rCost, pc.used,
105413105500
pc.plan.nOBSat
105414105501
));
105415105502
105416105503
/* If this index is the best we have seen so far, then record this
105417105504
** index and its cost in the p->cost structure.
@@ -105445,11 +105532,11 @@
105445105532
assert( pSrc->pIndex==0
105446105533
|| p->cost.plan.u.pIdx==0
105447105534
|| p->cost.plan.u.pIdx==pSrc->pIndex
105448105535
);
105449105536
105450
- WHERETRACE(("best index is: %s\n",
105537
+ WHERETRACE((" best index is: %s\n",
105451105538
p->cost.plan.u.pIdx ? p->cost.plan.u.pIdx->zName : "ipk"));
105452105539
105453105540
bestOrClauseIndex(p);
105454105541
bestAutomaticIndex(p);
105455105542
p->cost.plan.wsFlags |= eqTermMask;
@@ -106995,11 +107082,11 @@
106995107082
continue;
106996107083
}
106997107084
sWBI.notReady = (isOptimal ? m : sWBI.notValid);
106998107085
if( sWBI.pSrc->pIndex==0 ) nUnconstrained++;
106999107086
107000
- WHERETRACE(("=== trying table %d (%s) with isOptimal=%d ===\n",
107087
+ WHERETRACE((" === trying table %d (%s) with isOptimal=%d ===\n",
107001107088
j, sWBI.pSrc->pTab->zName, isOptimal));
107002107089
assert( sWBI.pSrc->pTab );
107003107090
#ifndef SQLITE_OMIT_VIRTUALTABLE
107004107091
if( IsVirtual(sWBI.pSrc->pTab) ){
107005107092
sWBI.ppIdxInfo = &pWInfo->a[j].pIdxInfo;
@@ -107048,12 +107135,12 @@
107048107135
|| (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0)
107049107136
&& (nUnconstrained==0 || sWBI.pSrc->pIndex==0 /* (3) */
107050107137
|| NEVER((sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0))
107051107138
&& (bestJ<0 || compareCost(&sWBI.cost, &bestPlan)) /* (4) */
107052107139
){
107053
- WHERETRACE(("=== table %d (%s) is best so far\n"
107054
- " cost=%.1f, nRow=%.1f, nOBSat=%d, wsFlags=%08x\n",
107140
+ WHERETRACE((" === table %d (%s) is best so far\n"
107141
+ " cost=%.1f, nRow=%.1f, nOBSat=%d, wsFlags=%08x\n",
107055107142
j, sWBI.pSrc->pTab->zName,
107056107143
sWBI.cost.rCost, sWBI.cost.plan.nRow,
107057107144
sWBI.cost.plan.nOBSat, sWBI.cost.plan.wsFlags));
107058107145
bestPlan = sWBI.cost;
107059107146
bestJ = j;
107060107147
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -673,11 +673,11 @@
673 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
674 ** [sqlite_version()] and [sqlite_source_id()].
675 */
676 #define SQLITE_VERSION "3.7.15"
677 #define SQLITE_VERSION_NUMBER 3007015
678 #define SQLITE_SOURCE_ID "2012-10-05 07:36:34 43155b1543bddbb84a8bc13a5b7344b228ddacb9"
679
680 /*
681 ** CAPI3REF: Run-Time Library Version Numbers
682 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
683 **
@@ -10905,10 +10905,11 @@
10905 */
10906 struct SrcList {
10907 i16 nSrc; /* Number of tables or subqueries in the FROM clause */
10908 i16 nAlloc; /* Number of entries allocated in a[] below */
10909 struct SrcList_item {
 
10910 char *zDatabase; /* Name of database holding this table */
10911 char *zName; /* Name of the table */
10912 char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */
10913 Table *pTab; /* An SQL table corresponding to zName */
10914 Select *pSelect; /* A SELECT statement used in place of a table name */
@@ -11473,10 +11474,11 @@
11473 ** explicit.
11474 */
11475 typedef struct DbFixer DbFixer;
11476 struct DbFixer {
11477 Parse *pParse; /* The parsing context. Error messages written here */
 
11478 const char *zDb; /* Make sure all objects are contained in this database */
11479 const char *zType; /* Type of the container - used for error messages */
11480 const Token *pName; /* Name of the container - used for error messages */
11481 };
11482
@@ -11883,10 +11885,11 @@
11883 SQLITE_PRIVATE int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int);
11884 SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse*, Expr*, int, int);
11885 SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse*, Expr*, int, int);
11886 SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3*,const char*, const char*);
11887 SQLITE_PRIVATE Table *sqlite3LocateTable(Parse*,int isView,const char*, const char*);
 
11888 SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3*,const char*, const char*);
11889 SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*);
11890 SQLITE_PRIVATE void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*);
11891 SQLITE_PRIVATE void sqlite3Vacuum(Parse*);
11892 SQLITE_PRIVATE int sqlite3RunVacuum(char**, sqlite3*);
@@ -12113,11 +12116,11 @@
12113 SQLITE_PRIVATE void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*);
12114 SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*);
12115 SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *, Table *, int, int);
12116 SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *, Token *);
12117 SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *, SrcList *);
12118 SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(sqlite3*, u8, CollSeq *, const char*);
12119 SQLITE_PRIVATE char sqlite3AffinityType(const char*);
12120 SQLITE_PRIVATE void sqlite3Analyze(Parse*, Token*, Token*);
12121 SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler*);
12122 SQLITE_PRIVATE int sqlite3FindDb(sqlite3*, Token*);
12123 SQLITE_PRIVATE int sqlite3FindDbName(sqlite3 *, const char *);
@@ -29968,10 +29971,61 @@
29968 #if !SQLITE_OS_WINNT && !defined(SQLITE_OMIT_WAL)
29969 # error "WAL mode requires support from the Windows NT kernel, compile\
29970 with SQLITE_OMIT_WAL."
29971 #endif
29972
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29973 /*
29974 ** Macro to find the minimum of two numeric values.
29975 */
29976 #ifndef MIN
29977 # define MIN(x,y) ((x)<(y)?(x):(y))
@@ -30173,18 +30227,10 @@
30173 SQLITE_API int sqlite3_os_type = 0;
30174 #else
30175 static int sqlite3_os_type = 0;
30176 #endif
30177
30178 #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
30179 # define SQLITE_WIN32_HAS_ANSI
30180 #endif
30181
30182 #if SQLITE_OS_WINCE || SQLITE_OS_WINNT || SQLITE_OS_WINRT
30183 # define SQLITE_WIN32_HAS_WIDE
30184 #endif
30185
30186 #ifndef SYSCALL
30187 # define SYSCALL sqlite3_syscall_ptr
30188 #endif
30189
30190 /*
@@ -30337,11 +30383,15 @@
30337 #endif
30338
30339 #define osFormatMessageW ((DWORD(WINAPI*)(DWORD,LPCVOID,DWORD,DWORD,LPWSTR, \
30340 DWORD,va_list*))aSyscall[15].pCurrent)
30341
 
30342 { "FreeLibrary", (SYSCALL)FreeLibrary, 0 },
 
 
 
30343
30344 #define osFreeLibrary ((BOOL(WINAPI*)(HMODULE))aSyscall[16].pCurrent)
30345
30346 { "GetCurrentProcessId", (SYSCALL)GetCurrentProcessId, 0 },
30347
@@ -30418,18 +30468,22 @@
30418
30419 { "GetLastError", (SYSCALL)GetLastError, 0 },
30420
30421 #define osGetLastError ((DWORD(WINAPI*)(VOID))aSyscall[26].pCurrent)
30422
 
30423 #if SQLITE_OS_WINCE
30424 /* The GetProcAddressA() routine is only available on Windows CE. */
30425 { "GetProcAddressA", (SYSCALL)GetProcAddressA, 0 },
30426 #else
30427 /* All other Windows platforms expect GetProcAddress() to take
30428 ** an ANSI string regardless of the _UNICODE setting */
30429 { "GetProcAddressA", (SYSCALL)GetProcAddress, 0 },
30430 #endif
 
 
 
30431
30432 #define osGetProcAddressA ((FARPROC(WINAPI*)(HMODULE, \
30433 LPCSTR))aSyscall[27].pCurrent)
30434
30435 #if !SQLITE_OS_WINRT
@@ -30529,19 +30583,20 @@
30529 #endif
30530
30531 #define osHeapValidate ((BOOL(WINAPI*)(HANDLE,DWORD, \
30532 LPCVOID))aSyscall[41].pCurrent)
30533
30534 #if defined(SQLITE_WIN32_HAS_ANSI)
30535 { "LoadLibraryA", (SYSCALL)LoadLibraryA, 0 },
30536 #else
30537 { "LoadLibraryA", (SYSCALL)0, 0 },
30538 #endif
30539
30540 #define osLoadLibraryA ((HMODULE(WINAPI*)(LPCSTR))aSyscall[42].pCurrent)
30541
30542 #if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE)
 
30543 { "LoadLibraryW", (SYSCALL)LoadLibraryW, 0 },
30544 #else
30545 { "LoadLibraryW", (SYSCALL)0, 0 },
30546 #endif
30547
@@ -30726,11 +30781,11 @@
30726 #endif
30727
30728 #define osCreateFile2 ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD,DWORD, \
30729 LPCREATEFILE2_EXTENDED_PARAMETERS))aSyscall[66].pCurrent)
30730
30731 #if SQLITE_OS_WINRT
30732 { "LoadPackagedLibrary", (SYSCALL)LoadPackagedLibrary, 0 },
30733 #else
30734 { "LoadPackagedLibrary", (SYSCALL)0, 0 },
30735 #endif
30736
@@ -60050,11 +60105,13 @@
60050 for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
60051 Btree *pBt = db->aDb[i].pBt;
60052 if( sqlite3BtreeIsInTrans(pBt) ){
60053 needXcommit = 1;
60054 if( i!=1 ) nTrans++;
 
60055 rc = sqlite3PagerExclusiveLock(sqlite3BtreePager(pBt));
 
60056 }
60057 }
60058 if( rc!=SQLITE_OK ){
60059 return rc;
60060 }
@@ -74362,10 +74419,11 @@
74362 pNew->nSrc = pNew->nAlloc = p->nSrc;
74363 for(i=0; i<p->nSrc; i++){
74364 struct SrcList_item *pNewItem = &pNew->a[i];
74365 struct SrcList_item *pOldItem = &p->a[i];
74366 Table *pTab;
 
74367 pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase);
74368 pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
74369 pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias);
74370 pNewItem->jointype = pOldItem->jointype;
74371 pNewItem->iCursor = pOldItem->iCursor;
@@ -77988,11 +78046,11 @@
77988 savedDbFlags = db->flags;
77989 if( NEVER(db->mallocFailed) ) goto exit_rename_table;
77990 assert( pSrc->nSrc==1 );
77991 assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
77992
77993 pTab = sqlite3LocateTable(pParse, 0, pSrc->a[0].zName, pSrc->a[0].zDatabase);
77994 if( !pTab ) goto exit_rename_table;
77995 iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
77996 zDb = db->aDb[iDb].zName;
77997 db->flags |= SQLITE_PreferBuiltin;
77998
@@ -78331,11 +78389,11 @@
78331
78332 /* Look up the table being altered. */
78333 assert( pParse->pNewTable==0 );
78334 assert( sqlite3BtreeHoldsAllMutexes(db) );
78335 if( db->mallocFailed ) goto exit_begin_add_column;
78336 pTab = sqlite3LocateTable(pParse, 0, pSrc->a[0].zName, pSrc->a[0].zDatabase);
78337 if( !pTab ) goto exit_begin_add_column;
78338
78339 #ifndef SQLITE_OMIT_VIRTUALTABLE
78340 if( IsVirtual(pTab) ){
78341 sqlite3ErrorMsg(pParse, "virtual tables may not be altered");
@@ -79962,10 +80020,11 @@
79962 if( NEVER(iDb<0) || iDb==1 ) return 0;
79963 db = pParse->db;
79964 assert( db->nDb>iDb );
79965 pFix->pParse = pParse;
79966 pFix->zDb = db->aDb[iDb].zName;
 
79967 pFix->zType = zType;
79968 pFix->pName = pName;
79969 return 1;
79970 }
79971
@@ -79992,18 +80051,19 @@
79992 struct SrcList_item *pItem;
79993
79994 if( NEVER(pList==0) ) return 0;
79995 zDb = pFix->zDb;
79996 for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
79997 if( pItem->zDatabase==0 ){
79998 pItem->zDatabase = sqlite3DbStrDup(pFix->pParse->db, zDb);
79999 }else if( sqlite3StrICmp(pItem->zDatabase,zDb)!=0 ){
80000 sqlite3ErrorMsg(pFix->pParse,
80001 "%s %T cannot reference objects in database %s",
80002 pFix->zType, pFix->pName, pItem->zDatabase);
80003 return 1;
80004 }
 
 
 
80005 #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
80006 if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1;
80007 if( sqlite3FixExpr(pFix, pItem->pOn) ) return 1;
80008 #endif
80009 }
@@ -80656,10 +80716,35 @@
80656 }
80657 pParse->checkSchema = 1;
80658 }
80659 return p;
80660 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80661
80662 /*
80663 ** Locate the in-memory structure that describes
80664 ** a particular index given the name of that index
80665 ** and the name of the database that contains the index.
@@ -81633,14 +81718,11 @@
81633 u8 initbusy = db->init.busy;
81634 CollSeq *pColl;
81635
81636 pColl = sqlite3FindCollSeq(db, enc, zName, initbusy);
81637 if( !initbusy && (!pColl || !pColl->xCmp) ){
81638 pColl = sqlite3GetCollSeq(db, enc, pColl, zName);
81639 if( !pColl ){
81640 sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName);
81641 }
81642 }
81643
81644 return pColl;
81645 }
81646
@@ -82452,12 +82534,11 @@
82452 goto exit_drop_table;
82453 }
82454 assert( pParse->nErr==0 );
82455 assert( pName->nSrc==1 );
82456 if( noErr ) db->suppressErr++;
82457 pTab = sqlite3LocateTable(pParse, isView,
82458 pName->a[0].zName, pName->a[0].zDatabase);
82459 if( noErr ) db->suppressErr--;
82460
82461 if( pTab==0 ){
82462 if( noErr ) sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase);
82463 goto exit_drop_table;
@@ -82893,13 +82974,13 @@
82893 ){
82894 /* Because the parser constructs pTblName from a single identifier,
82895 ** sqlite3FixSrcList can never fail. */
82896 assert(0);
82897 }
82898 pTab = sqlite3LocateTable(pParse, 0, pTblName->a[0].zName,
82899 pTblName->a[0].zDatabase);
82900 if( !pTab || db->mallocFailed ) goto exit_create_index;
82901 assert( db->aDb[iDb].pSchema==pTab->pSchema );
82902 }else{
82903 assert( pName==0 );
82904 assert( pStart==0 );
82905 pTab = pParse->pNewTable;
@@ -84254,21 +84335,22 @@
84254 ** If it is not NULL, then pColl must point to the database native encoding
84255 ** collation sequence with name zName, length nName.
84256 **
84257 ** The return value is either the collation sequence to be used in database
84258 ** db for collation type name zName, length nName, or NULL, if no collation
84259 ** sequence can be found.
84260 **
84261 ** See also: sqlite3LocateCollSeq(), sqlite3FindCollSeq()
84262 */
84263 SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(
84264 sqlite3* db, /* The database connection */
84265 u8 enc, /* The desired encoding for the collating sequence */
84266 CollSeq *pColl, /* Collating sequence with native encoding, or NULL */
84267 const char *zName /* Collating sequence name */
84268 ){
84269 CollSeq *p;
 
84270
84271 p = pColl;
84272 if( !p ){
84273 p = sqlite3FindCollSeq(db, enc, zName, 0);
84274 }
@@ -84281,10 +84363,13 @@
84281 }
84282 if( p && !p->xCmp && synthCollSeq(db, p) ){
84283 p = 0;
84284 }
84285 assert( !p || p->xCmp );
 
 
 
84286 return p;
84287 }
84288
84289 /*
84290 ** This routine is called on a collation sequence before it is used to
@@ -84299,14 +84384,12 @@
84299 */
84300 SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){
84301 if( pColl ){
84302 const char *zName = pColl->zName;
84303 sqlite3 *db = pParse->db;
84304 CollSeq *p = sqlite3GetCollSeq(db, ENC(db), pColl, zName);
84305 if( !p ){
84306 sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName);
84307 pParse->nErr++;
84308 return SQLITE_ERROR;
84309 }
84310 assert( p==pColl );
84311 }
84312 return SQLITE_OK;
@@ -84689,11 +84772,11 @@
84689 */
84690 SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
84691 struct SrcList_item *pItem = pSrc->a;
84692 Table *pTab;
84693 assert( pItem && pSrc->nSrc==1 );
84694 pTab = sqlite3LocateTable(pParse, 0, pItem->zName, pItem->zDatabase);
84695 sqlite3DeleteTable(pParse->db, pItem->pTab);
84696 pItem->pTab = pTab;
84697 if( pTab ){
84698 pTab->nRef++;
84699 }
@@ -89415,24 +89498,29 @@
89415 ExprList *pCheck = pTab->pCheck;
89416 pParse->ckBase = regData;
89417 onError = overrideError!=OE_Default ? overrideError : OE_Abort;
89418 for(i=0; i<pCheck->nExpr; i++){
89419 int allOk = sqlite3VdbeMakeLabel(v);
89420 sqlite3ExprIfTrue(pParse, pCheck->a[i].pExpr, allOk, SQLITE_JUMPIFNULL);
89421 if( onError==OE_Ignore ){
89422 sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
89423 }else{
89424 char *zConsName = pCheck->a[i].zName;
89425 if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-15569-63625 */
89426 if( zConsName ){
89427 zConsName = sqlite3MPrintf(db, "constraint %s failed", zConsName);
89428 }else{
89429 zConsName = 0;
89430 }
89431 sqlite3HaltConstraint(pParse, onError, zConsName, P4_DYNAMIC);
89432 }
89433 sqlite3VdbeResolveLabel(v, allOk);
 
 
 
 
 
89434 }
89435 }
89436 #endif /* !defined(SQLITE_OMIT_CHECK) */
89437
89438 /* If we have an INTEGER PRIMARY KEY, make sure the primary key
@@ -89884,11 +89972,11 @@
89884 /* At this point we have established that the statement is of the
89885 ** correct syntactic form to participate in this optimization. Now
89886 ** we have to check the semantics.
89887 */
89888 pItem = pSelect->pSrc->a;
89889 pSrc = sqlite3LocateTable(pParse, 0, pItem->zName, pItem->zDatabase);
89890 if( pSrc==0 ){
89891 return 0; /* FROM clause does not contain a real table */
89892 }
89893 if( pSrc==pDest ){
89894 return 0; /* tab1 and tab2 may not be the same table */
@@ -97153,12 +97241,11 @@
97153 pTab->tabFlags |= TF_Ephemeral;
97154 #endif
97155 }else{
97156 /* An ordinary table or view name in the FROM clause */
97157 assert( pFrom->pTab==0 );
97158 pFrom->pTab = pTab =
97159 sqlite3LocateTable(pParse,0,pFrom->zName,pFrom->zDatabase);
97160 if( pTab==0 ) return WRC_Abort;
97161 pTab->nRef++;
97162 #if !defined(SQLITE_OMIT_VIEW) || !defined (SQLITE_OMIT_VIRTUALTABLE)
97163 if( pTab->pSelect || IsVirtual(pTab) ){
97164 /* We reach here if the named table is a really a view */
@@ -101095,10 +101182,11 @@
101095 */
101096 SQLITE_PRIVATE void sqlite3VtabClear(sqlite3 *db, Table *p){
101097 if( !db || db->pnBytesFreed==0 ) vtabDisconnectAll(0, p);
101098 if( p->azModuleArg ){
101099 int i;
 
101100 for(i=0; i<p->nModuleArg; i++){
101101 sqlite3DbFree(db, p->azModuleArg[i]);
101102 }
101103 sqlite3DbFree(db, p->azModuleArg);
101104 }
@@ -101156,11 +101244,11 @@
101156 assert( iDb>=0 );
101157
101158 pTable->tabFlags |= TF_Virtual;
101159 pTable->nModuleArg = 0;
101160 addModuleArgument(db, pTable, sqlite3NameFromToken(db, pModuleName));
101161 addModuleArgument(db, pTable, sqlite3DbStrDup(db, db->aDb[iDb].zName));
101162 addModuleArgument(db, pTable, sqlite3DbStrDup(db, pTable->zName));
101163 pParse->sNameToken.n = (int)(&pModuleName->z[pModuleName->n] - pName1->z);
101164
101165 #ifndef SQLITE_OMIT_AUTHORIZATION
101166 /* Creating a virtual table invokes the authorization callback twice.
@@ -101313,10 +101401,11 @@
101313 int rc;
101314 const char *const*azArg = (const char *const*)pTab->azModuleArg;
101315 int nArg = pTab->nModuleArg;
101316 char *zErr = 0;
101317 char *zModuleName = sqlite3MPrintf(db, "%s", pTab->zName);
 
101318
101319 if( !zModuleName ){
101320 return SQLITE_NOMEM;
101321 }
101322
@@ -101326,10 +101415,14 @@
101326 return SQLITE_NOMEM;
101327 }
101328 pVTable->db = db;
101329 pVTable->pMod = pMod;
101330
 
 
 
 
101331 /* Invoke the virtual table constructor */
101332 assert( &db->pVtabCtx );
101333 assert( xConstruct );
101334 sCtx.pTab = pTab;
101335 sCtx.pVTable = pVTable;
@@ -101336,10 +101429,11 @@
101336 pPriorCtx = db->pVtabCtx;
101337 db->pVtabCtx = &sCtx;
101338 rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr);
101339 db->pVtabCtx = pPriorCtx;
101340 if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
 
101341
101342 if( SQLITE_OK!=rc ){
101343 if( zErr==0 ){
101344 *pzErr = sqlite3MPrintf(db, "vtable constructor failed: %s", zModuleName);
101345 }else {
@@ -103371,26 +103465,10 @@
103371 ** an index for tables to the left of the join.
103372 */
103373 pTerm->prereqRight |= extraRight;
103374 }
103375
103376 /*
103377 ** Return TRUE if the given index is UNIQUE and all columns past the
103378 ** first nSkip columns are NOT NULL.
103379 */
103380 static int indexIsUniqueNotNull(Index *pIdx, int nSkip){
103381 Table *pTab = pIdx->pTable;
103382 int i;
103383 if( pIdx->onError==OE_None ) return 0;
103384 for(i=nSkip; i<pIdx->nColumn; i++){
103385 int j = pIdx->aiColumn[i];
103386 assert( j>=0 && j<pTab->nCol );
103387 if( pTab->aCol[j].notNull==0 ) return 0;
103388 }
103389 return 1;
103390 }
103391
103392 /*
103393 ** This function searches the expression list passed as the second argument
103394 ** for an expression of type TK_COLUMN that refers to the same column and
103395 ** uses the same collation sequence as the iCol'th column of index pIdx.
103396 ** Argument iBase is the cursor number used for the table that pIdx refers
@@ -104344,14 +104422,12 @@
104344 if( eType==SQLITE_BLOB ){
104345 z = (const u8 *)sqlite3_value_blob(pVal);
104346 pColl = db->pDfltColl;
104347 assert( pColl->enc==SQLITE_UTF8 );
104348 }else{
104349 pColl = sqlite3GetCollSeq(db, SQLITE_UTF8, 0, *pIdx->azColl);
104350 if( pColl==0 ){
104351 sqlite3ErrorMsg(pParse, "no such collation sequence: %s",
104352 *pIdx->azColl);
104353 return SQLITE_ERROR;
104354 }
104355 z = (const u8 *)sqlite3ValueText(pVal, pColl->enc);
104356 if( !z ){
104357 return SQLITE_NOMEM;
@@ -104657,30 +104733,34 @@
104657 }
104658 #endif /* defined(SQLITE_ENABLE_STAT3) */
104659
104660 /*
104661 ** Check to see if column iCol of the table with cursor iTab will appear
104662 ** in sorted order according to the current query plan. Return true if
104663 ** it will and false if not.
104664 **
104665 ** If *pbRev is initially 2 (meaning "unknown") then set *pbRev to the
104666 ** sort order of iTab.iCol. If *pbRev is 0 or 1 but does not match
104667 ** the sort order of iTab.iCol, then consider the column to be unordered.
 
 
 
104668 */
104669 static int isOrderedColumn(WhereBestIdx *p, int iTab, int iCol, int *pbRev){
 
 
 
 
104670 int i, j;
104671 WhereLevel *pLevel = &p->aLevel[p->i-1];
104672 Index *pIdx;
104673 u8 sortOrder;
104674 for(i=p->i-1; i>=0; i--, pLevel--){
104675 if( pLevel->iTabCur!=iTab ) continue;
104676 if( (pLevel->plan.wsFlags & WHERE_ALL_UNIQUE)!=0 ){
104677 return 1;
104678 }
104679 if( (pLevel->plan.wsFlags & WHERE_ORDERED)==0 ){
104680 return 0;
104681 }
104682 if( (pIdx = pLevel->plan.u.pIdx)!=0 ){
104683 if( iCol<0 ){
104684 sortOrder = 0;
104685 testcase( (pLevel->plan.wsFlags & WHERE_REVERSE)!=0 );
104686 }else{
@@ -104700,39 +104780,12 @@
104700 if( (pLevel->plan.wsFlags & WHERE_REVERSE)!=0 ){
104701 assert( sortOrder==0 || sortOrder==1 );
104702 testcase( sortOrder==1 );
104703 sortOrder = 1 - sortOrder;
104704 }
104705 if( *pbRev==2 ){
104706 *pbRev = sortOrder;
104707 return 1;
104708 }
104709 return (*pbRev==sortOrder);
104710 }
104711 return 0;
104712 }
104713
104714 /*
104715 ** pTerm is an == constraint. Check to see if the other side of
104716 ** the == is a constant or a value that is guaranteed to be ordered
104717 ** by outer loops. Return 1 if pTerm is ordered, and 0 if not.
104718 */
104719 static int isOrderedTerm(WhereBestIdx *p, WhereTerm *pTerm, int *pbRev){
104720 Expr *pExpr = pTerm->pExpr;
104721 assert( pExpr->op==TK_EQ );
104722 assert( pExpr->pLeft!=0 && pExpr->pLeft->op==TK_COLUMN );
104723 assert( pExpr->pRight!=0 );
104724 if( pTerm->prereqRight==0 ){
104725 return 1; /* RHS of the == is a constant */
104726 }
104727 if( pExpr->pRight->op==TK_COLUMN
104728 && isOrderedColumn(p, pExpr->pRight->iTable, pExpr->pRight->iColumn, pbRev)
104729 ){
104730 return 1;
104731 }
104732
104733 /* If we cannot prove that the constraint is ordered, assume it is not */
104734 return 0;
104735 }
104736
104737 /*
104738 ** This routine decides if pIdx can be used to satisfy the ORDER BY
@@ -104756,49 +104809,49 @@
104756 */
104757 static int isSortingIndex(
104758 WhereBestIdx *p, /* Best index search context */
104759 Index *pIdx, /* The index we are testing */
104760 int base, /* Cursor number for the table to be sorted */
104761 int nEqCol, /* Number of index columns with ordered == constraints */
104762 int wsFlags, /* Index usages flags */
104763 int bOuterRev, /* True if outer loops scan in reverse order */
104764 int *pbRev /* Set to 1 for reverse-order scan of pIdx */
104765 ){
104766 int i; /* Number of pIdx terms used */
104767 int j; /* Number of ORDER BY terms satisfied */
104768 int sortOrder = 0; /* XOR of index and ORDER BY sort direction */
104769 int nTerm; /* Number of ORDER BY terms */
104770 struct ExprList_item *pTerm; /* A term of the ORDER BY clause */
 
104771 ExprList *pOrderBy; /* The ORDER BY clause */
104772 Parse *pParse = p->pParse; /* Parser context */
104773 sqlite3 *db = pParse->db; /* Database connection */
104774 int nPriorSat; /* ORDER BY terms satisfied by outer loops */
104775 int seenRowid = 0; /* True if an ORDER BY rowid term is seen */
104776 int nEqOneRow; /* Idx columns that ref unique values */
104777
104778 if( p->i==0 ){
104779 nPriorSat = 0;
104780 }else{
104781 nPriorSat = p->aLevel[p->i-1].plan.nOBSat;
104782 if( OptimizationDisabled(db, SQLITE_OrderByIdxJoin) ) return nPriorSat;
104783 }
104784 if( nEqCol==0 ){
104785 if( p->i && (p->aLevel[p->i-1].plan.wsFlags & WHERE_ORDERED)==0 ){
 
 
 
 
104786 return nPriorSat;
104787 }
104788 nEqOneRow = 0;
104789 }else if( p->i==0 || (p->aLevel[p->i-1].plan.wsFlags & WHERE_ALL_UNIQUE)!=0 ){
104790 nEqOneRow = nEqCol;
104791 }else{
104792 sortOrder = bOuterRev;
104793 nEqOneRow = -1;
104794 }
104795 pOrderBy = p->pOrderBy;
104796 assert( pOrderBy!=0 );
104797 if( wsFlags & WHERE_COLUMN_IN ) return nPriorSat;
104798 if( pIdx->bUnordered ) return nPriorSat;
 
 
 
104799 nTerm = pOrderBy->nExpr;
 
104800 assert( nTerm>0 );
104801
104802 /* Argument pIdx must either point to a 'real' named index structure,
104803 ** or an index structure allocated on the stack by bestBtreeIndex() to
104804 ** represent the rowid index that is part of every table. */
@@ -104810,90 +104863,130 @@
104810 ** Note that indices have pIdx->nColumn regular columns plus
104811 ** one additional column containing the rowid. The rowid column
104812 ** of the index is also allowed to match against the ORDER BY
104813 ** clause.
104814 */
104815 for(i=0,j=nPriorSat,pTerm=&pOrderBy->a[j]; j<nTerm; i++){
104816 Expr *pExpr; /* The expression of the ORDER BY pTerm */
104817 CollSeq *pColl; /* The collating sequence of pExpr */
104818 int termSortOrder; /* Sort order for this term */
104819 int iColumn; /* The i-th column of the index. -1 for rowid */
104820 int iSortOrder; /* 1 for DESC, 0 for ASC on the i-th index term */
104821 const char *zColl; /* Name of the collating sequence for i-th index term */
104822
104823 assert( i<=pIdx->nColumn );
104824 pExpr = pTerm->pExpr;
104825 if( pExpr->op!=TK_COLUMN || pExpr->iTable!=base ){
104826 /* Can not use an index sort on anything that is not a column in the
104827 ** left-most table of the FROM clause */
 
 
 
 
104828 break;
104829 }
104830 pColl = sqlite3ExprCollSeq(pParse, pExpr);
104831 if( !pColl ){
104832 pColl = db->pDfltColl;
104833 }
104834 if( pIdx->zName && i<pIdx->nColumn ){
104835 iColumn = pIdx->aiColumn[i];
104836 if( iColumn==pIdx->pTable->iPKey ){
104837 iColumn = -1;
104838 }
104839 iSortOrder = pIdx->aSortOrder[i];
104840 zColl = pIdx->azColl[i];
 
104841 }else{
104842 iColumn = -1;
104843 iSortOrder = 0;
104844 zColl = pColl->zName;
104845 }
104846 if( pExpr->iColumn!=iColumn || sqlite3StrICmp(pColl->zName, zColl) ){
104847 /* Term j of the ORDER BY clause does not match column i of the index */
104848 if( i<nEqCol ){
104849 /* If an index column that is constrained by == fails to match an
104850 ** ORDER BY term, that is OK. Just ignore that column of the index
104851 */
104852 continue;
104853 }else if( i==pIdx->nColumn ){
104854 /* Index column i is the rowid. All other terms match. */
104855 break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104856 }else{
104857 /* If an index column fails to match and is not constrained by ==
104858 ** then the index cannot satisfy the ORDER BY constraint.
104859 */
104860 return nPriorSat;
104861 }
104862 }
104863 assert( pIdx->aSortOrder!=0 || iColumn==-1 );
104864 assert( pTerm->sortOrder==0 || pTerm->sortOrder==1 );
104865 assert( iSortOrder==0 || iSortOrder==1 );
104866 termSortOrder = iSortOrder ^ pTerm->sortOrder;
104867 if( i>nEqOneRow ){
104868 if( termSortOrder!=sortOrder ){
104869 /* Indices can only be used if all ORDER BY terms past the
104870 ** equality constraints have the correct DESC or ASC. */
 
 
 
 
 
104871 break;
104872 }
104873 }else{
104874 sortOrder = termSortOrder;
104875 }
104876 j++;
104877 pTerm++;
104878 if( iColumn<0 ){
104879 seenRowid = 1;
104880 break;
 
 
104881 }
104882 }
104883 *pbRev = sortOrder;
 
 
 
 
 
 
104884
104885 /* If there was an "ORDER BY rowid" term that matched, or it is only
104886 ** possible for a single row from this table to match, then skip over
104887 ** any additional ORDER BY terms dealing with this table.
104888 */
104889 if( seenRowid ||
104890 ( (wsFlags & WHERE_COLUMN_NULL)==0
104891 && i>=pIdx->nColumn
104892 && indexIsUniqueNotNull(pIdx, nEqCol)
104893 )
104894 ){
104895 /* Advance j over additional ORDER BY terms associated with base */
104896 WhereMaskSet *pMS = p->pWC->pMaskSet;
104897 Bitmask m = ~getMask(pMS, base);
104898 while( j<nTerm && (exprTableUsage(pMS, pOrderBy->a[j].pExpr)&m)==0 ){
104899 j++;
@@ -104995,11 +105088,10 @@
104995 */
104996 for(; pProbe; pIdx=pProbe=pProbe->pNext){
104997 const tRowcnt * const aiRowEst = pProbe->aiRowEst;
104998 WhereCost pc; /* Cost of using pProbe */
104999 double log10N = (double)1; /* base-10 logarithm of nRow (inexact) */
105000 int bRev = 2; /* 0=forward scan. 1=reverse. 2=undecided */
105001
105002 /* The following variables are populated based on the properties of
105003 ** index being evaluated. They are then used to determine the expected
105004 ** cost and number of rows returned.
105005 **
@@ -105026,14 +105118,10 @@
105026 **
105027 ** If there exists a WHERE term of the form "x IN (SELECT ...)", then
105028 ** the sub-select is assumed to return 25 rows for the purposes of
105029 ** determining nInMul.
105030 **
105031 ** nOrdered:
105032 ** The number of equality terms that are constrainted by outer loop
105033 ** variables that are well-ordered.
105034 **
105035 ** bInEst:
105036 ** Set to true if there was at least one "x IN (SELECT ...)" term used
105037 ** in determining the value of nInMul. Note that the RHS of the
105038 ** IN operator must be a SELECT, not a value list, for this variable
105039 ** to be true.
@@ -105067,11 +105155,10 @@
105067 ** both available in the index.
105068 **
105069 ** SELECT a, b FROM tbl WHERE a = 1;
105070 ** SELECT a, b, c FROM tbl WHERE a = 1;
105071 */
105072 int nOrdered; /* Number of ordered terms matching index */
105073 int bInEst = 0; /* True if "x IN (SELECT...)" seen */
105074 int nInMul = 1; /* Number of distinct equalities to lookup */
105075 double rangeDiv = (double)1; /* Estimated reduction in search space */
105076 int nBound = 0; /* Number of range constraints seen */
105077 int bSort; /* True if external sort required */
@@ -105082,10 +105169,14 @@
105082 WhereTerm *pTerm; /* A single term of the WHERE clause */
105083 #ifdef SQLITE_ENABLE_STAT3
105084 WhereTerm *pFirstTerm = 0; /* First term matching the index */
105085 #endif
105086
 
 
 
 
105087 memset(&pc, 0, sizeof(pc));
105088 nOrderBy = p->pOrderBy ? p->pOrderBy->nExpr : 0;
105089 if( p->i ){
105090 nPriorSat = pc.plan.nOBSat = p->aLevel[p->i-1].plan.nOBSat;
105091 bSort = nPriorSat<nOrderBy;
@@ -105095,11 +105186,11 @@
105095 bSort = nOrderBy>0;
105096 bDist = p->pDistinct!=0;
105097 }
105098
105099 /* Determine the values of pc.plan.nEq and nInMul */
105100 for(pc.plan.nEq=nOrdered=0; pc.plan.nEq<pProbe->nColumn; pc.plan.nEq++){
105101 int j = pProbe->aiColumn[pc.plan.nEq];
105102 pTerm = findTerm(pWC, iCur, j, p->notReady, eqTermMask, pIdx);
105103 if( pTerm==0 ) break;
105104 pc.plan.wsFlags |= (WHERE_COLUMN_EQ|WHERE_ROWID_EQ);
105105 testcase( pTerm->pWC!=pWC );
@@ -105114,14 +105205,10 @@
105114 /* "x IN (value, value, ...)" */
105115 nInMul *= pExpr->x.pList->nExpr;
105116 }
105117 }else if( pTerm->eOperator & WO_ISNULL ){
105118 pc.plan.wsFlags |= WHERE_COLUMN_NULL;
105119 if( pc.plan.nEq==nOrdered ) nOrdered++;
105120 }else if( bSort && pc.plan.nEq==nOrdered
105121 && isOrderedTerm(p,pTerm,&bRev) ){
105122 nOrdered++;
105123 }
105124 #ifdef SQLITE_ENABLE_STAT3
105125 if( pc.plan.nEq==0 && pProbe->aSample ) pFirstTerm = pTerm;
105126 #endif
105127 pc.used |= pTerm->prereqRight;
@@ -105172,17 +105259,16 @@
105172 /* If there is an ORDER BY clause and the index being considered will
105173 ** naturally scan rows in the required order, set the appropriate flags
105174 ** in pc.plan.wsFlags. Otherwise, if there is an ORDER BY clause but
105175 ** the index will scan rows in a different order, set the bSort
105176 ** variable. */
105177 assert( bRev>=0 && bRev<=2 );
105178 if( bSort ){
105179 testcase( bRev==0 );
105180 testcase( bRev==1 );
105181 testcase( bRev==2 );
105182 pc.plan.nOBSat = isSortingIndex(p, pProbe, iCur, nOrdered,
105183 pc.plan.wsFlags, bRev&1, &bRev);
105184 if( nPriorSat<pc.plan.nOBSat || (pc.plan.wsFlags & WHERE_UNIQUE)!=0 ){
105185 pc.plan.wsFlags |= WHERE_ORDERED;
105186 }
105187 if( nOrderBy==pc.plan.nOBSat ){
105188 bSort = 0;
@@ -105296,11 +105382,14 @@
105296 ** decision and one which we expect to revisit in the future. But
105297 ** it seems to be working well enough at the moment.
105298 */
105299 pc.rCost = aiRowEst[0]*4;
105300 pc.plan.wsFlags &= ~WHERE_IDX_ONLY;
105301 if( pIdx ) pc.plan.wsFlags &= ~WHERE_ORDERED;
 
 
 
105302 }else{
105303 log10N = estLog(aiRowEst[0]);
105304 pc.rCost = pc.plan.nRow;
105305 if( pIdx ){
105306 if( bLookup ){
@@ -105401,17 +105490,15 @@
105401 if( pc.plan.nRow<2 ) pc.plan.nRow = 2;
105402 }
105403
105404
105405 WHERETRACE((
105406 "%s(%s):\n"
105407 " nEq=%d nInMul=%d rangeDiv=%d bSort=%d bLookup=%d wsFlags=0x%08x\n"
105408 " notReady=0x%llx log10N=%.1f nRow=%.1f cost=%.1f\n"
105409 " used=0x%llx nOrdered=%d nOBSat=%d\n",
105410 pSrc->pTab->zName, (pIdx ? pIdx->zName : "ipk"),
105411 pc.plan.nEq, nInMul, (int)rangeDiv, bSort, bLookup, pc.plan.wsFlags,
105412 p->notReady, log10N, pc.plan.nRow, pc.rCost, pc.used, nOrdered,
105413 pc.plan.nOBSat
105414 ));
105415
105416 /* If this index is the best we have seen so far, then record this
105417 ** index and its cost in the p->cost structure.
@@ -105445,11 +105532,11 @@
105445 assert( pSrc->pIndex==0
105446 || p->cost.plan.u.pIdx==0
105447 || p->cost.plan.u.pIdx==pSrc->pIndex
105448 );
105449
105450 WHERETRACE(("best index is: %s\n",
105451 p->cost.plan.u.pIdx ? p->cost.plan.u.pIdx->zName : "ipk"));
105452
105453 bestOrClauseIndex(p);
105454 bestAutomaticIndex(p);
105455 p->cost.plan.wsFlags |= eqTermMask;
@@ -106995,11 +107082,11 @@
106995 continue;
106996 }
106997 sWBI.notReady = (isOptimal ? m : sWBI.notValid);
106998 if( sWBI.pSrc->pIndex==0 ) nUnconstrained++;
106999
107000 WHERETRACE(("=== trying table %d (%s) with isOptimal=%d ===\n",
107001 j, sWBI.pSrc->pTab->zName, isOptimal));
107002 assert( sWBI.pSrc->pTab );
107003 #ifndef SQLITE_OMIT_VIRTUALTABLE
107004 if( IsVirtual(sWBI.pSrc->pTab) ){
107005 sWBI.ppIdxInfo = &pWInfo->a[j].pIdxInfo;
@@ -107048,12 +107135,12 @@
107048 || (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0)
107049 && (nUnconstrained==0 || sWBI.pSrc->pIndex==0 /* (3) */
107050 || NEVER((sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0))
107051 && (bestJ<0 || compareCost(&sWBI.cost, &bestPlan)) /* (4) */
107052 ){
107053 WHERETRACE(("=== table %d (%s) is best so far\n"
107054 " cost=%.1f, nRow=%.1f, nOBSat=%d, wsFlags=%08x\n",
107055 j, sWBI.pSrc->pTab->zName,
107056 sWBI.cost.rCost, sWBI.cost.plan.nRow,
107057 sWBI.cost.plan.nOBSat, sWBI.cost.plan.wsFlags));
107058 bestPlan = sWBI.cost;
107059 bestJ = j;
107060
--- src/sqlite3.c
+++ src/sqlite3.c
@@ -673,11 +673,11 @@
673 ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
674 ** [sqlite_version()] and [sqlite_source_id()].
675 */
676 #define SQLITE_VERSION "3.7.15"
677 #define SQLITE_VERSION_NUMBER 3007015
678 #define SQLITE_SOURCE_ID "2012-10-09 01:39:25 01dc032b5bbd9c9ebb1965f176ca5d732cda85ea"
679
680 /*
681 ** CAPI3REF: Run-Time Library Version Numbers
682 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
683 **
@@ -10905,10 +10905,11 @@
10905 */
10906 struct SrcList {
10907 i16 nSrc; /* Number of tables or subqueries in the FROM clause */
10908 i16 nAlloc; /* Number of entries allocated in a[] below */
10909 struct SrcList_item {
10910 Schema *pSchema; /* Schema to which this item is fixed */
10911 char *zDatabase; /* Name of database holding this table */
10912 char *zName; /* Name of the table */
10913 char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */
10914 Table *pTab; /* An SQL table corresponding to zName */
10915 Select *pSelect; /* A SELECT statement used in place of a table name */
@@ -11473,10 +11474,11 @@
11474 ** explicit.
11475 */
11476 typedef struct DbFixer DbFixer;
11477 struct DbFixer {
11478 Parse *pParse; /* The parsing context. Error messages written here */
11479 Schema *pSchema; /* Fix items to this schema */
11480 const char *zDb; /* Make sure all objects are contained in this database */
11481 const char *zType; /* Type of the container - used for error messages */
11482 const Token *pName; /* Name of the container - used for error messages */
11483 };
11484
@@ -11883,10 +11885,11 @@
11885 SQLITE_PRIVATE int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int);
11886 SQLITE_PRIVATE void sqlite3ExprIfTrue(Parse*, Expr*, int, int);
11887 SQLITE_PRIVATE void sqlite3ExprIfFalse(Parse*, Expr*, int, int);
11888 SQLITE_PRIVATE Table *sqlite3FindTable(sqlite3*,const char*, const char*);
11889 SQLITE_PRIVATE Table *sqlite3LocateTable(Parse*,int isView,const char*, const char*);
11890 SQLITE_PRIVATE Table *sqlite3LocateTableItem(Parse*,int isView,struct SrcList_item *);
11891 SQLITE_PRIVATE Index *sqlite3FindIndex(sqlite3*,const char*, const char*);
11892 SQLITE_PRIVATE void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*);
11893 SQLITE_PRIVATE void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*);
11894 SQLITE_PRIVATE void sqlite3Vacuum(Parse*);
11895 SQLITE_PRIVATE int sqlite3RunVacuum(char**, sqlite3*);
@@ -12113,11 +12116,11 @@
12116 SQLITE_PRIVATE void sqlite3ResolveSelectNames(Parse*, Select*, NameContext*);
12117 SQLITE_PRIVATE int sqlite3ResolveOrderGroupBy(Parse*, Select*, ExprList*, const char*);
12118 SQLITE_PRIVATE void sqlite3ColumnDefault(Vdbe *, Table *, int, int);
12119 SQLITE_PRIVATE void sqlite3AlterFinishAddColumn(Parse *, Token *);
12120 SQLITE_PRIVATE void sqlite3AlterBeginAddColumn(Parse *, SrcList *);
12121 SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*);
12122 SQLITE_PRIVATE char sqlite3AffinityType(const char*);
12123 SQLITE_PRIVATE void sqlite3Analyze(Parse*, Token*, Token*);
12124 SQLITE_PRIVATE int sqlite3InvokeBusyHandler(BusyHandler*);
12125 SQLITE_PRIVATE int sqlite3FindDb(sqlite3*, Token*);
12126 SQLITE_PRIVATE int sqlite3FindDbName(sqlite3 *, const char *);
@@ -29968,10 +29971,61 @@
29971 #if !SQLITE_OS_WINNT && !defined(SQLITE_OMIT_WAL)
29972 # error "WAL mode requires support from the Windows NT kernel, compile\
29973 with SQLITE_OMIT_WAL."
29974 #endif
29975
29976 /*
29977 ** Are most of the Win32 ANSI APIs available (i.e. with certain exceptions
29978 ** based on the sub-platform)?
29979 */
29980 #if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
29981 # define SQLITE_WIN32_HAS_ANSI
29982 #endif
29983
29984 /*
29985 ** Are most of the Win32 Unicode APIs available (i.e. with certain exceptions
29986 ** based on the sub-platform)?
29987 */
29988 #if SQLITE_OS_WINCE || SQLITE_OS_WINNT || SQLITE_OS_WINRT
29989 # define SQLITE_WIN32_HAS_WIDE
29990 #endif
29991
29992 /*
29993 ** Do we need to manually define the Win32 file mapping APIs for use with WAL
29994 ** mode (e.g. these APIs are available in the Windows CE SDK; however, they
29995 ** are not present in the header file)?
29996 */
29997 #if SQLITE_WIN32_FILEMAPPING_API && !defined(SQLITE_OMIT_WAL)
29998 /*
29999 ** Two of the file mapping APIs are different under WinRT. Figure out which
30000 ** set we need.
30001 */
30002 #if SQLITE_OS_WINRT
30003 WINBASEAPI HANDLE WINAPI CreateFileMappingFromApp(HANDLE, \
30004 LPSECURITY_ATTRIBUTES, ULONG, ULONG64, LPCWSTR);
30005
30006 WINBASEAPI LPVOID WINAPI MapViewOfFileFromApp(HANDLE, ULONG, ULONG64, SIZE_T);
30007 #else
30008 #if defined(SQLITE_WIN32_HAS_ANSI)
30009 WINBASEAPI HANDLE WINAPI CreateFileMappingA(HANDLE, LPSECURITY_ATTRIBUTES, \
30010 DWORD, DWORD, DWORD, LPCSTR);
30011 #endif /* defined(SQLITE_WIN32_HAS_ANSI) */
30012
30013 #if defined(SQLITE_WIN32_HAS_WIDE)
30014 WINBASEAPI HANDLE WINAPI CreateFileMappingW(HANDLE, LPSECURITY_ATTRIBUTES, \
30015 DWORD, DWORD, DWORD, LPCWSTR);
30016 #endif /* defined(SQLITE_WIN32_HAS_WIDE) */
30017
30018 WINBASEAPI LPVOID WINAPI MapViewOfFile(HANDLE, DWORD, DWORD, DWORD, SIZE_T);
30019 #endif /* SQLITE_OS_WINRT */
30020
30021 /*
30022 ** This file mapping API is common to both Win32 and WinRT.
30023 */
30024 WINBASEAPI BOOL WINAPI UnmapViewOfFile(LPCVOID);
30025 #endif /* SQLITE_WIN32_FILEMAPPING_API && !defined(SQLITE_OMIT_WAL) */
30026
30027 /*
30028 ** Macro to find the minimum of two numeric values.
30029 */
30030 #ifndef MIN
30031 # define MIN(x,y) ((x)<(y)?(x):(y))
@@ -30173,18 +30227,10 @@
30227 SQLITE_API int sqlite3_os_type = 0;
30228 #else
30229 static int sqlite3_os_type = 0;
30230 #endif
30231
 
 
 
 
 
 
 
 
30232 #ifndef SYSCALL
30233 # define SYSCALL sqlite3_syscall_ptr
30234 #endif
30235
30236 /*
@@ -30337,11 +30383,15 @@
30383 #endif
30384
30385 #define osFormatMessageW ((DWORD(WINAPI*)(DWORD,LPCVOID,DWORD,DWORD,LPWSTR, \
30386 DWORD,va_list*))aSyscall[15].pCurrent)
30387
30388 #if !defined(SQLITE_OMIT_LOAD_EXTENSION)
30389 { "FreeLibrary", (SYSCALL)FreeLibrary, 0 },
30390 #else
30391 { "FreeLibrary", (SYSCALL)0, 0 },
30392 #endif
30393
30394 #define osFreeLibrary ((BOOL(WINAPI*)(HMODULE))aSyscall[16].pCurrent)
30395
30396 { "GetCurrentProcessId", (SYSCALL)GetCurrentProcessId, 0 },
30397
@@ -30418,18 +30468,22 @@
30468
30469 { "GetLastError", (SYSCALL)GetLastError, 0 },
30470
30471 #define osGetLastError ((DWORD(WINAPI*)(VOID))aSyscall[26].pCurrent)
30472
30473 #if !defined(SQLITE_OMIT_LOAD_EXTENSION)
30474 #if SQLITE_OS_WINCE
30475 /* The GetProcAddressA() routine is only available on Windows CE. */
30476 { "GetProcAddressA", (SYSCALL)GetProcAddressA, 0 },
30477 #else
30478 /* All other Windows platforms expect GetProcAddress() to take
30479 ** an ANSI string regardless of the _UNICODE setting */
30480 { "GetProcAddressA", (SYSCALL)GetProcAddress, 0 },
30481 #endif
30482 #else
30483 { "GetProcAddressA", (SYSCALL)0, 0 },
30484 #endif
30485
30486 #define osGetProcAddressA ((FARPROC(WINAPI*)(HMODULE, \
30487 LPCSTR))aSyscall[27].pCurrent)
30488
30489 #if !SQLITE_OS_WINRT
@@ -30529,19 +30583,20 @@
30583 #endif
30584
30585 #define osHeapValidate ((BOOL(WINAPI*)(HANDLE,DWORD, \
30586 LPCVOID))aSyscall[41].pCurrent)
30587
30588 #if defined(SQLITE_WIN32_HAS_ANSI) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
30589 { "LoadLibraryA", (SYSCALL)LoadLibraryA, 0 },
30590 #else
30591 { "LoadLibraryA", (SYSCALL)0, 0 },
30592 #endif
30593
30594 #define osLoadLibraryA ((HMODULE(WINAPI*)(LPCSTR))aSyscall[42].pCurrent)
30595
30596 #if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_HAS_WIDE) && \
30597 !defined(SQLITE_OMIT_LOAD_EXTENSION)
30598 { "LoadLibraryW", (SYSCALL)LoadLibraryW, 0 },
30599 #else
30600 { "LoadLibraryW", (SYSCALL)0, 0 },
30601 #endif
30602
@@ -30726,11 +30781,11 @@
30781 #endif
30782
30783 #define osCreateFile2 ((HANDLE(WINAPI*)(LPCWSTR,DWORD,DWORD,DWORD, \
30784 LPCREATEFILE2_EXTENDED_PARAMETERS))aSyscall[66].pCurrent)
30785
30786 #if SQLITE_OS_WINRT && !defined(SQLITE_OMIT_LOAD_EXTENSION)
30787 { "LoadPackagedLibrary", (SYSCALL)LoadPackagedLibrary, 0 },
30788 #else
30789 { "LoadPackagedLibrary", (SYSCALL)0, 0 },
30790 #endif
30791
@@ -60050,11 +60105,13 @@
60105 for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
60106 Btree *pBt = db->aDb[i].pBt;
60107 if( sqlite3BtreeIsInTrans(pBt) ){
60108 needXcommit = 1;
60109 if( i!=1 ) nTrans++;
60110 sqlite3BtreeEnter(pBt);
60111 rc = sqlite3PagerExclusiveLock(sqlite3BtreePager(pBt));
60112 sqlite3BtreeLeave(pBt);
60113 }
60114 }
60115 if( rc!=SQLITE_OK ){
60116 return rc;
60117 }
@@ -74362,10 +74419,11 @@
74419 pNew->nSrc = pNew->nAlloc = p->nSrc;
74420 for(i=0; i<p->nSrc; i++){
74421 struct SrcList_item *pNewItem = &pNew->a[i];
74422 struct SrcList_item *pOldItem = &p->a[i];
74423 Table *pTab;
74424 pNewItem->pSchema = pOldItem->pSchema;
74425 pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase);
74426 pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName);
74427 pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias);
74428 pNewItem->jointype = pOldItem->jointype;
74429 pNewItem->iCursor = pOldItem->iCursor;
@@ -77988,11 +78046,11 @@
78046 savedDbFlags = db->flags;
78047 if( NEVER(db->mallocFailed) ) goto exit_rename_table;
78048 assert( pSrc->nSrc==1 );
78049 assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
78050
78051 pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]);
78052 if( !pTab ) goto exit_rename_table;
78053 iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
78054 zDb = db->aDb[iDb].zName;
78055 db->flags |= SQLITE_PreferBuiltin;
78056
@@ -78331,11 +78389,11 @@
78389
78390 /* Look up the table being altered. */
78391 assert( pParse->pNewTable==0 );
78392 assert( sqlite3BtreeHoldsAllMutexes(db) );
78393 if( db->mallocFailed ) goto exit_begin_add_column;
78394 pTab = sqlite3LocateTableItem(pParse, 0, &pSrc->a[0]);
78395 if( !pTab ) goto exit_begin_add_column;
78396
78397 #ifndef SQLITE_OMIT_VIRTUALTABLE
78398 if( IsVirtual(pTab) ){
78399 sqlite3ErrorMsg(pParse, "virtual tables may not be altered");
@@ -79962,10 +80020,11 @@
80020 if( NEVER(iDb<0) || iDb==1 ) return 0;
80021 db = pParse->db;
80022 assert( db->nDb>iDb );
80023 pFix->pParse = pParse;
80024 pFix->zDb = db->aDb[iDb].zName;
80025 pFix->pSchema = db->aDb[iDb].pSchema;
80026 pFix->zType = zType;
80027 pFix->pName = pName;
80028 return 1;
80029 }
80030
@@ -79992,18 +80051,19 @@
80051 struct SrcList_item *pItem;
80052
80053 if( NEVER(pList==0) ) return 0;
80054 zDb = pFix->zDb;
80055 for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){
80056 if( pItem->zDatabase && sqlite3StrICmp(pItem->zDatabase, zDb) ){
 
 
80057 sqlite3ErrorMsg(pFix->pParse,
80058 "%s %T cannot reference objects in database %s",
80059 pFix->zType, pFix->pName, pItem->zDatabase);
80060 return 1;
80061 }
80062 sqlite3_free(pItem->zDatabase);
80063 pItem->zDatabase = 0;
80064 pItem->pSchema = pFix->pSchema;
80065 #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
80066 if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1;
80067 if( sqlite3FixExpr(pFix, pItem->pOn) ) return 1;
80068 #endif
80069 }
@@ -80656,10 +80716,35 @@
80716 }
80717 pParse->checkSchema = 1;
80718 }
80719 return p;
80720 }
80721
80722 /*
80723 ** Locate the table identified by *p.
80724 **
80725 ** This is a wrapper around sqlite3LocateTable(). The difference between
80726 ** sqlite3LocateTable() and this function is that this function restricts
80727 ** the search to schema (p->pSchema) if it is not NULL. p->pSchema may be
80728 ** non-NULL if it is part of a view or trigger program definition. See
80729 ** sqlite3FixSrcList() for details.
80730 */
80731 SQLITE_PRIVATE Table *sqlite3LocateTableItem(
80732 Parse *pParse,
80733 int isView,
80734 struct SrcList_item *p
80735 ){
80736 const char *zDb;
80737 assert( p->pSchema==0 || p->zDatabase==0 );
80738 if( p->pSchema ){
80739 int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema);
80740 zDb = pParse->db->aDb[iDb].zName;
80741 }else{
80742 zDb = p->zDatabase;
80743 }
80744 return sqlite3LocateTable(pParse, isView, p->zName, zDb);
80745 }
80746
80747 /*
80748 ** Locate the in-memory structure that describes
80749 ** a particular index given the name of that index
80750 ** and the name of the database that contains the index.
@@ -81633,14 +81718,11 @@
81718 u8 initbusy = db->init.busy;
81719 CollSeq *pColl;
81720
81721 pColl = sqlite3FindCollSeq(db, enc, zName, initbusy);
81722 if( !initbusy && (!pColl || !pColl->xCmp) ){
81723 pColl = sqlite3GetCollSeq(pParse, enc, pColl, zName);
 
 
 
81724 }
81725
81726 return pColl;
81727 }
81728
@@ -82452,12 +82534,11 @@
82534 goto exit_drop_table;
82535 }
82536 assert( pParse->nErr==0 );
82537 assert( pName->nSrc==1 );
82538 if( noErr ) db->suppressErr++;
82539 pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]);
 
82540 if( noErr ) db->suppressErr--;
82541
82542 if( pTab==0 ){
82543 if( noErr ) sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase);
82544 goto exit_drop_table;
@@ -82893,13 +82974,13 @@
82974 ){
82975 /* Because the parser constructs pTblName from a single identifier,
82976 ** sqlite3FixSrcList can never fail. */
82977 assert(0);
82978 }
82979 pTab = sqlite3LocateTableItem(pParse, 0, &pTblName->a[0]);
82980 assert( db->mallocFailed==0 || pTab==0 );
82981 if( pTab==0 ) goto exit_create_index;
82982 assert( db->aDb[iDb].pSchema==pTab->pSchema );
82983 }else{
82984 assert( pName==0 );
82985 assert( pStart==0 );
82986 pTab = pParse->pNewTable;
@@ -84254,21 +84335,22 @@
84335 ** If it is not NULL, then pColl must point to the database native encoding
84336 ** collation sequence with name zName, length nName.
84337 **
84338 ** The return value is either the collation sequence to be used in database
84339 ** db for collation type name zName, length nName, or NULL, if no collation
84340 ** sequence can be found. If no collation is found, leave an error message.
84341 **
84342 ** See also: sqlite3LocateCollSeq(), sqlite3FindCollSeq()
84343 */
84344 SQLITE_PRIVATE CollSeq *sqlite3GetCollSeq(
84345 Parse *pParse, /* Parsing context */
84346 u8 enc, /* The desired encoding for the collating sequence */
84347 CollSeq *pColl, /* Collating sequence with native encoding, or NULL */
84348 const char *zName /* Collating sequence name */
84349 ){
84350 CollSeq *p;
84351 sqlite3 *db = pParse->db;
84352
84353 p = pColl;
84354 if( !p ){
84355 p = sqlite3FindCollSeq(db, enc, zName, 0);
84356 }
@@ -84281,10 +84363,13 @@
84363 }
84364 if( p && !p->xCmp && synthCollSeq(db, p) ){
84365 p = 0;
84366 }
84367 assert( !p || p->xCmp );
84368 if( p==0 ){
84369 sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName);
84370 }
84371 return p;
84372 }
84373
84374 /*
84375 ** This routine is called on a collation sequence before it is used to
@@ -84299,14 +84384,12 @@
84384 */
84385 SQLITE_PRIVATE int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){
84386 if( pColl ){
84387 const char *zName = pColl->zName;
84388 sqlite3 *db = pParse->db;
84389 CollSeq *p = sqlite3GetCollSeq(pParse, ENC(db), pColl, zName);
84390 if( !p ){
 
 
84391 return SQLITE_ERROR;
84392 }
84393 assert( p==pColl );
84394 }
84395 return SQLITE_OK;
@@ -84689,11 +84772,11 @@
84772 */
84773 SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
84774 struct SrcList_item *pItem = pSrc->a;
84775 Table *pTab;
84776 assert( pItem && pSrc->nSrc==1 );
84777 pTab = sqlite3LocateTableItem(pParse, 0, pItem);
84778 sqlite3DeleteTable(pParse->db, pItem->pTab);
84779 pItem->pTab = pTab;
84780 if( pTab ){
84781 pTab->nRef++;
84782 }
@@ -89415,24 +89498,29 @@
89498 ExprList *pCheck = pTab->pCheck;
89499 pParse->ckBase = regData;
89500 onError = overrideError!=OE_Default ? overrideError : OE_Abort;
89501 for(i=0; i<pCheck->nExpr; i++){
89502 int allOk = sqlite3VdbeMakeLabel(v);
89503 Expr *pDup = sqlite3ExprDup(db, pCheck->a[i].pExpr, 0);
89504 if( !db->mallocFailed ){
89505 assert( pDup!=0 );
89506 sqlite3ExprIfTrue(pParse, pDup, allOk, SQLITE_JUMPIFNULL);
89507 if( onError==OE_Ignore ){
89508 sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
89509 }else{
89510 char *zConsName = pCheck->a[i].zName;
89511 if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-15569-63625 */
89512 if( zConsName ){
89513 zConsName = sqlite3MPrintf(db, "constraint %s failed", zConsName);
89514 }else{
89515 zConsName = 0;
89516 }
89517 sqlite3HaltConstraint(pParse, onError, zConsName, P4_DYNAMIC);
89518 }
89519 sqlite3VdbeResolveLabel(v, allOk);
89520 }
89521 sqlite3ExprDelete(db, pDup);
89522 }
89523 }
89524 #endif /* !defined(SQLITE_OMIT_CHECK) */
89525
89526 /* If we have an INTEGER PRIMARY KEY, make sure the primary key
@@ -89884,11 +89972,11 @@
89972 /* At this point we have established that the statement is of the
89973 ** correct syntactic form to participate in this optimization. Now
89974 ** we have to check the semantics.
89975 */
89976 pItem = pSelect->pSrc->a;
89977 pSrc = sqlite3LocateTableItem(pParse, 0, pItem);
89978 if( pSrc==0 ){
89979 return 0; /* FROM clause does not contain a real table */
89980 }
89981 if( pSrc==pDest ){
89982 return 0; /* tab1 and tab2 may not be the same table */
@@ -97153,12 +97241,11 @@
97241 pTab->tabFlags |= TF_Ephemeral;
97242 #endif
97243 }else{
97244 /* An ordinary table or view name in the FROM clause */
97245 assert( pFrom->pTab==0 );
97246 pFrom->pTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom);
 
97247 if( pTab==0 ) return WRC_Abort;
97248 pTab->nRef++;
97249 #if !defined(SQLITE_OMIT_VIEW) || !defined (SQLITE_OMIT_VIRTUALTABLE)
97250 if( pTab->pSelect || IsVirtual(pTab) ){
97251 /* We reach here if the named table is a really a view */
@@ -101095,10 +101182,11 @@
101182 */
101183 SQLITE_PRIVATE void sqlite3VtabClear(sqlite3 *db, Table *p){
101184 if( !db || db->pnBytesFreed==0 ) vtabDisconnectAll(0, p);
101185 if( p->azModuleArg ){
101186 int i;
101187 assert( p->nModuleArg<2 || p->azModuleArg[1]==0 );
101188 for(i=0; i<p->nModuleArg; i++){
101189 sqlite3DbFree(db, p->azModuleArg[i]);
101190 }
101191 sqlite3DbFree(db, p->azModuleArg);
101192 }
@@ -101156,11 +101244,11 @@
101244 assert( iDb>=0 );
101245
101246 pTable->tabFlags |= TF_Virtual;
101247 pTable->nModuleArg = 0;
101248 addModuleArgument(db, pTable, sqlite3NameFromToken(db, pModuleName));
101249 addModuleArgument(db, pTable, 0);
101250 addModuleArgument(db, pTable, sqlite3DbStrDup(db, pTable->zName));
101251 pParse->sNameToken.n = (int)(&pModuleName->z[pModuleName->n] - pName1->z);
101252
101253 #ifndef SQLITE_OMIT_AUTHORIZATION
101254 /* Creating a virtual table invokes the authorization callback twice.
@@ -101313,10 +101401,11 @@
101401 int rc;
101402 const char *const*azArg = (const char *const*)pTab->azModuleArg;
101403 int nArg = pTab->nModuleArg;
101404 char *zErr = 0;
101405 char *zModuleName = sqlite3MPrintf(db, "%s", pTab->zName);
101406 int iDb;
101407
101408 if( !zModuleName ){
101409 return SQLITE_NOMEM;
101410 }
101411
@@ -101326,10 +101415,14 @@
101415 return SQLITE_NOMEM;
101416 }
101417 pVTable->db = db;
101418 pVTable->pMod = pMod;
101419
101420 assert( pTab->azModuleArg[1]==0 );
101421 iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
101422 pTab->azModuleArg[1] = db->aDb[iDb].zName;
101423
101424 /* Invoke the virtual table constructor */
101425 assert( &db->pVtabCtx );
101426 assert( xConstruct );
101427 sCtx.pTab = pTab;
101428 sCtx.pVTable = pVTable;
@@ -101336,10 +101429,11 @@
101429 pPriorCtx = db->pVtabCtx;
101430 db->pVtabCtx = &sCtx;
101431 rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr);
101432 db->pVtabCtx = pPriorCtx;
101433 if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
101434 pTab->azModuleArg[1] = 0;
101435
101436 if( SQLITE_OK!=rc ){
101437 if( zErr==0 ){
101438 *pzErr = sqlite3MPrintf(db, "vtable constructor failed: %s", zModuleName);
101439 }else {
@@ -103371,26 +103465,10 @@
103465 ** an index for tables to the left of the join.
103466 */
103467 pTerm->prereqRight |= extraRight;
103468 }
103469
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103470 /*
103471 ** This function searches the expression list passed as the second argument
103472 ** for an expression of type TK_COLUMN that refers to the same column and
103473 ** uses the same collation sequence as the iCol'th column of index pIdx.
103474 ** Argument iBase is the cursor number used for the table that pIdx refers
@@ -104344,14 +104422,12 @@
104422 if( eType==SQLITE_BLOB ){
104423 z = (const u8 *)sqlite3_value_blob(pVal);
104424 pColl = db->pDfltColl;
104425 assert( pColl->enc==SQLITE_UTF8 );
104426 }else{
104427 pColl = sqlite3GetCollSeq(pParse, SQLITE_UTF8, 0, *pIdx->azColl);
104428 if( pColl==0 ){
 
 
104429 return SQLITE_ERROR;
104430 }
104431 z = (const u8 *)sqlite3ValueText(pVal, pColl->enc);
104432 if( !z ){
104433 return SQLITE_NOMEM;
@@ -104657,30 +104733,34 @@
104733 }
104734 #endif /* defined(SQLITE_ENABLE_STAT3) */
104735
104736 /*
104737 ** Check to see if column iCol of the table with cursor iTab will appear
104738 ** in sorted order according to the current query plan.
 
104739 **
104740 ** Return values:
104741 **
104742 ** 0 iCol is not ordered
104743 ** 1 iCol has only a single value
104744 ** 2 iCol is in ASC order
104745 ** 3 iCol is in DESC order
104746 */
104747 static int isOrderedColumn(
104748 WhereBestIdx *p,
104749 int iTab,
104750 int iCol
104751 ){
104752 int i, j;
104753 WhereLevel *pLevel = &p->aLevel[p->i-1];
104754 Index *pIdx;
104755 u8 sortOrder;
104756 for(i=p->i-1; i>=0; i--, pLevel--){
104757 if( pLevel->iTabCur!=iTab ) continue;
104758 if( (pLevel->plan.wsFlags & WHERE_ALL_UNIQUE)!=0 ){
104759 return 1;
104760 }
104761 assert( (pLevel->plan.wsFlags & WHERE_ORDERED)!=0 );
 
 
104762 if( (pIdx = pLevel->plan.u.pIdx)!=0 ){
104763 if( iCol<0 ){
104764 sortOrder = 0;
104765 testcase( (pLevel->plan.wsFlags & WHERE_REVERSE)!=0 );
104766 }else{
@@ -104700,39 +104780,12 @@
104780 if( (pLevel->plan.wsFlags & WHERE_REVERSE)!=0 ){
104781 assert( sortOrder==0 || sortOrder==1 );
104782 testcase( sortOrder==1 );
104783 sortOrder = 1 - sortOrder;
104784 }
104785 return sortOrder+2;
104786 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104787 return 0;
104788 }
104789
104790 /*
104791 ** This routine decides if pIdx can be used to satisfy the ORDER BY
@@ -104756,49 +104809,49 @@
104809 */
104810 static int isSortingIndex(
104811 WhereBestIdx *p, /* Best index search context */
104812 Index *pIdx, /* The index we are testing */
104813 int base, /* Cursor number for the table to be sorted */
 
 
 
104814 int *pbRev /* Set to 1 for reverse-order scan of pIdx */
104815 ){
104816 int i; /* Number of pIdx terms used */
104817 int j; /* Number of ORDER BY terms satisfied */
104818 int sortOrder = 2; /* 0: forward. 1: backward. 2: unknown */
104819 int nTerm; /* Number of ORDER BY terms */
104820 struct ExprList_item *pOBItem;/* A term of the ORDER BY clause */
104821 Table *pTab = pIdx->pTable; /* Table that owns index pIdx */
104822 ExprList *pOrderBy; /* The ORDER BY clause */
104823 Parse *pParse = p->pParse; /* Parser context */
104824 sqlite3 *db = pParse->db; /* Database connection */
104825 int nPriorSat; /* ORDER BY terms satisfied by outer loops */
104826 int seenRowid = 0; /* True if an ORDER BY rowid term is seen */
104827 int uniqueNotNull; /* pIdx is UNIQUE with all terms are NOT NULL */
104828
104829 if( p->i==0 ){
104830 nPriorSat = 0;
104831 }else{
104832 nPriorSat = p->aLevel[p->i-1].plan.nOBSat;
104833 if( (p->aLevel[p->i-1].plan.wsFlags & WHERE_ORDERED)==0 ){
104834 /* This loop cannot be ordered unless the next outer loop is
104835 ** also ordered */
104836 return nPriorSat;
104837 }
104838 if( OptimizationDisabled(db, SQLITE_OrderByIdxJoin) ){
104839 /* Only look at the outer-most loop if the OrderByIdxJoin
104840 ** optimization is disabled */
104841 return nPriorSat;
104842 }
 
 
 
 
 
 
104843 }
104844 pOrderBy = p->pOrderBy;
104845 assert( pOrderBy!=0 );
104846 if( pIdx->bUnordered ){
104847 /* Hash indices (indicated by the "unordered" tag on sqlite_stat1) cannot
104848 ** be used for sorting */
104849 return nPriorSat;
104850 }
104851 nTerm = pOrderBy->nExpr;
104852 uniqueNotNull = pIdx->onError!=OE_None;
104853 assert( nTerm>0 );
104854
104855 /* Argument pIdx must either point to a 'real' named index structure,
104856 ** or an index structure allocated on the stack by bestBtreeIndex() to
104857 ** represent the rowid index that is part of every table. */
@@ -104810,90 +104863,130 @@
104863 ** Note that indices have pIdx->nColumn regular columns plus
104864 ** one additional column containing the rowid. The rowid column
104865 ** of the index is also allowed to match against the ORDER BY
104866 ** clause.
104867 */
104868 j = nPriorSat;
104869 for(i=0,pOBItem=&pOrderBy->a[j]; j<nTerm && i<=pIdx->nColumn; i++){
104870 Expr *pOBExpr; /* The expression of the ORDER BY pOBItem */
104871 CollSeq *pColl; /* The collating sequence of pOBExpr */
104872 int termSortOrder; /* Sort order for this term */
104873 int iColumn; /* The i-th column of the index. -1 for rowid */
104874 int iSortOrder; /* 1 for DESC, 0 for ASC on the i-th index term */
104875 int isEq; /* Subject to an == or IS NULL constraint */
104876 int isMatch; /* ORDER BY term matches the index term */
104877 const char *zColl; /* Name of collating sequence for i-th index term */
104878 WhereTerm *pConstraint; /* A constraint in the WHERE clause */
104879
104880 /* If the next term of the ORDER BY clause refers to anything other than
104881 ** a column in the "base" table, then this index will not be of any
104882 ** further use in handling the ORDER BY. */
104883 pOBExpr = pOBItem->pExpr;
104884 if( pOBExpr->op!=TK_COLUMN || pOBExpr->iTable!=base ){
104885 break;
104886 }
104887
104888 /* Find column number and collating sequence for the next entry
104889 ** in the index */
 
104890 if( pIdx->zName && i<pIdx->nColumn ){
104891 iColumn = pIdx->aiColumn[i];
104892 if( iColumn==pIdx->pTable->iPKey ){
104893 iColumn = -1;
104894 }
104895 iSortOrder = pIdx->aSortOrder[i];
104896 zColl = pIdx->azColl[i];
104897 assert( zColl!=0 );
104898 }else{
104899 iColumn = -1;
104900 iSortOrder = 0;
104901 zColl = 0;
104902 }
104903
104904 /* Check to see if the column number and collating sequence of the
104905 ** index match the column number and collating sequence of the ORDER BY
104906 ** clause entry. Set isMatch to 1 if they both match. */
104907 if( pOBExpr->iColumn==iColumn ){
104908 if( zColl ){
104909 pColl = sqlite3ExprCollSeq(pParse, pOBExpr);
104910 if( !pColl ) pColl = db->pDfltColl;
104911 isMatch = sqlite3StrICmp(pColl->zName, zColl)==0;
104912 }else{
104913 isMatch = 1;
104914 }
104915 }else{
104916 isMatch = 0;
104917 }
104918
104919 /* termSortOrder is 0 or 1 for whether or not the access loop should
104920 ** run forward or backwards (respectively) in order to satisfy this
104921 ** term of the ORDER BY clause. */
104922 termSortOrder = iSortOrder ^ pOBItem->sortOrder;
104923
104924 /* If X is the column in the index and ORDER BY clause, check to see
104925 ** if there are any X= or X IS NULL constraints in the WHERE clause. */
104926 pConstraint = findTerm(p->pWC, base, iColumn, p->notReady,
104927 WO_EQ|WO_ISNULL|WO_IN, pIdx);
104928 if( pConstraint==0 ){
104929 isEq = 0;
104930 }else if( pConstraint->eOperator==WO_IN ){
104931 break;
104932 }else if( pConstraint->eOperator==WO_ISNULL ){
104933 uniqueNotNull = 0;
104934 isEq = 1;
104935 }else if( pConstraint->prereqRight==0 ){
104936 isEq = 1;
104937 }else{
104938 Expr *pRight = pConstraint->pExpr->pRight;
104939 if( pRight->op==TK_COLUMN ){
104940 WHERETRACE((" .. isOrderedColumn(tab=%d,col=%d)",
104941 pRight->iTable, pRight->iColumn));
104942 isEq = isOrderedColumn(p, pRight->iTable, pRight->iColumn);
104943 WHERETRACE((" -> isEq=%d\n", isEq));
104944 if( isMatch && isEq>=2 && isEq!=pOBItem->sortOrder+2 ){
104945 break;
104946 }
104947 }else{
104948 isEq = 0;
 
 
 
104949 }
104950 }
104951 assert( pOBItem->sortOrder==0 || pOBItem->sortOrder==1 );
 
104952 assert( iSortOrder==0 || iSortOrder==1 );
104953 if( !isMatch ){
104954 if( isEq==0 ){
104955 break;
104956 }else{
104957 continue;
104958 }
104959 }else if( isEq!=1 ){
104960 if( sortOrder==2 ){
104961 sortOrder = termSortOrder;
104962 }else if( termSortOrder!=sortOrder ){
104963 break;
104964 }
 
 
104965 }
104966 j++;
104967 pOBItem++;
104968 if( iColumn<0 ){
104969 seenRowid = 1;
104970 break;
104971 }else if( pTab->aCol[iColumn].notNull==0 && isEq==0 ){
104972 uniqueNotNull = 0;
104973 }
104974 }
104975
104976 /* If we have not found at least one ORDER BY term that matches the
104977 ** index, then show no progress. */
104978 if( pOBItem==&pOrderBy->a[nPriorSat] ) return nPriorSat;
104979
104980 /* Return the necessary scan order back to the caller */
104981 *pbRev = sortOrder & 1;
104982
104983 /* If there was an "ORDER BY rowid" term that matched, or it is only
104984 ** possible for a single row from this table to match, then skip over
104985 ** any additional ORDER BY terms dealing with this table.
104986 */
104987 if( seenRowid || (uniqueNotNull && i>=pIdx->nColumn) ){
 
 
 
 
 
104988 /* Advance j over additional ORDER BY terms associated with base */
104989 WhereMaskSet *pMS = p->pWC->pMaskSet;
104990 Bitmask m = ~getMask(pMS, base);
104991 while( j<nTerm && (exprTableUsage(pMS, pOrderBy->a[j].pExpr)&m)==0 ){
104992 j++;
@@ -104995,11 +105088,10 @@
105088 */
105089 for(; pProbe; pIdx=pProbe=pProbe->pNext){
105090 const tRowcnt * const aiRowEst = pProbe->aiRowEst;
105091 WhereCost pc; /* Cost of using pProbe */
105092 double log10N = (double)1; /* base-10 logarithm of nRow (inexact) */
 
105093
105094 /* The following variables are populated based on the properties of
105095 ** index being evaluated. They are then used to determine the expected
105096 ** cost and number of rows returned.
105097 **
@@ -105026,14 +105118,10 @@
105118 **
105119 ** If there exists a WHERE term of the form "x IN (SELECT ...)", then
105120 ** the sub-select is assumed to return 25 rows for the purposes of
105121 ** determining nInMul.
105122 **
 
 
 
 
105123 ** bInEst:
105124 ** Set to true if there was at least one "x IN (SELECT ...)" term used
105125 ** in determining the value of nInMul. Note that the RHS of the
105126 ** IN operator must be a SELECT, not a value list, for this variable
105127 ** to be true.
@@ -105067,11 +105155,10 @@
105155 ** both available in the index.
105156 **
105157 ** SELECT a, b FROM tbl WHERE a = 1;
105158 ** SELECT a, b, c FROM tbl WHERE a = 1;
105159 */
 
105160 int bInEst = 0; /* True if "x IN (SELECT...)" seen */
105161 int nInMul = 1; /* Number of distinct equalities to lookup */
105162 double rangeDiv = (double)1; /* Estimated reduction in search space */
105163 int nBound = 0; /* Number of range constraints seen */
105164 int bSort; /* True if external sort required */
@@ -105082,10 +105169,14 @@
105169 WhereTerm *pTerm; /* A single term of the WHERE clause */
105170 #ifdef SQLITE_ENABLE_STAT3
105171 WhereTerm *pFirstTerm = 0; /* First term matching the index */
105172 #endif
105173
105174 WHERETRACE((
105175 " %s(%s):\n",
105176 pSrc->pTab->zName, (pIdx ? pIdx->zName : "ipk")
105177 ));
105178 memset(&pc, 0, sizeof(pc));
105179 nOrderBy = p->pOrderBy ? p->pOrderBy->nExpr : 0;
105180 if( p->i ){
105181 nPriorSat = pc.plan.nOBSat = p->aLevel[p->i-1].plan.nOBSat;
105182 bSort = nPriorSat<nOrderBy;
@@ -105095,11 +105186,11 @@
105186 bSort = nOrderBy>0;
105187 bDist = p->pDistinct!=0;
105188 }
105189
105190 /* Determine the values of pc.plan.nEq and nInMul */
105191 for(pc.plan.nEq=0; pc.plan.nEq<pProbe->nColumn; pc.plan.nEq++){
105192 int j = pProbe->aiColumn[pc.plan.nEq];
105193 pTerm = findTerm(pWC, iCur, j, p->notReady, eqTermMask, pIdx);
105194 if( pTerm==0 ) break;
105195 pc.plan.wsFlags |= (WHERE_COLUMN_EQ|WHERE_ROWID_EQ);
105196 testcase( pTerm->pWC!=pWC );
@@ -105114,14 +105205,10 @@
105205 /* "x IN (value, value, ...)" */
105206 nInMul *= pExpr->x.pList->nExpr;
105207 }
105208 }else if( pTerm->eOperator & WO_ISNULL ){
105209 pc.plan.wsFlags |= WHERE_COLUMN_NULL;
 
 
 
 
105210 }
105211 #ifdef SQLITE_ENABLE_STAT3
105212 if( pc.plan.nEq==0 && pProbe->aSample ) pFirstTerm = pTerm;
105213 #endif
105214 pc.used |= pTerm->prereqRight;
@@ -105172,17 +105259,16 @@
105259 /* If there is an ORDER BY clause and the index being considered will
105260 ** naturally scan rows in the required order, set the appropriate flags
105261 ** in pc.plan.wsFlags. Otherwise, if there is an ORDER BY clause but
105262 ** the index will scan rows in a different order, set the bSort
105263 ** variable. */
105264 if( bSort && (pSrc->jointype & JT_LEFT)==0 ){
105265 int bRev = 2;
105266 WHERETRACE((" --> before isSortingIndex: nPriorSat=%d\n",nPriorSat));
105267 pc.plan.nOBSat = isSortingIndex(p, pProbe, iCur, &bRev);
105268 WHERETRACE((" --> after isSortingIndex: bRev=%d nOBSat=%d\n",
105269 bRev, pc.plan.nOBSat));
 
105270 if( nPriorSat<pc.plan.nOBSat || (pc.plan.wsFlags & WHERE_UNIQUE)!=0 ){
105271 pc.plan.wsFlags |= WHERE_ORDERED;
105272 }
105273 if( nOrderBy==pc.plan.nOBSat ){
105274 bSort = 0;
@@ -105296,11 +105382,14 @@
105382 ** decision and one which we expect to revisit in the future. But
105383 ** it seems to be working well enough at the moment.
105384 */
105385 pc.rCost = aiRowEst[0]*4;
105386 pc.plan.wsFlags &= ~WHERE_IDX_ONLY;
105387 if( pIdx ){
105388 pc.plan.wsFlags &= ~WHERE_ORDERED;
105389 pc.plan.nOBSat = nPriorSat;
105390 }
105391 }else{
105392 log10N = estLog(aiRowEst[0]);
105393 pc.rCost = pc.plan.nRow;
105394 if( pIdx ){
105395 if( bLookup ){
@@ -105401,17 +105490,15 @@
105490 if( pc.plan.nRow<2 ) pc.plan.nRow = 2;
105491 }
105492
105493
105494 WHERETRACE((
105495 " nEq=%d nInMul=%d rangeDiv=%d bSort=%d bLookup=%d wsFlags=0x%08x\n"
105496 " notReady=0x%llx log10N=%.1f nRow=%.1f cost=%.1f\n"
105497 " used=0x%llx nOBSat=%d\n",
 
 
105498 pc.plan.nEq, nInMul, (int)rangeDiv, bSort, bLookup, pc.plan.wsFlags,
105499 p->notReady, log10N, pc.plan.nRow, pc.rCost, pc.used,
105500 pc.plan.nOBSat
105501 ));
105502
105503 /* If this index is the best we have seen so far, then record this
105504 ** index and its cost in the p->cost structure.
@@ -105445,11 +105532,11 @@
105532 assert( pSrc->pIndex==0
105533 || p->cost.plan.u.pIdx==0
105534 || p->cost.plan.u.pIdx==pSrc->pIndex
105535 );
105536
105537 WHERETRACE((" best index is: %s\n",
105538 p->cost.plan.u.pIdx ? p->cost.plan.u.pIdx->zName : "ipk"));
105539
105540 bestOrClauseIndex(p);
105541 bestAutomaticIndex(p);
105542 p->cost.plan.wsFlags |= eqTermMask;
@@ -106995,11 +107082,11 @@
107082 continue;
107083 }
107084 sWBI.notReady = (isOptimal ? m : sWBI.notValid);
107085 if( sWBI.pSrc->pIndex==0 ) nUnconstrained++;
107086
107087 WHERETRACE((" === trying table %d (%s) with isOptimal=%d ===\n",
107088 j, sWBI.pSrc->pTab->zName, isOptimal));
107089 assert( sWBI.pSrc->pTab );
107090 #ifndef SQLITE_OMIT_VIRTUALTABLE
107091 if( IsVirtual(sWBI.pSrc->pTab) ){
107092 sWBI.ppIdxInfo = &pWInfo->a[j].pIdxInfo;
@@ -107048,12 +107135,12 @@
107135 || (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0)
107136 && (nUnconstrained==0 || sWBI.pSrc->pIndex==0 /* (3) */
107137 || NEVER((sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0))
107138 && (bestJ<0 || compareCost(&sWBI.cost, &bestPlan)) /* (4) */
107139 ){
107140 WHERETRACE((" === table %d (%s) is best so far\n"
107141 " cost=%.1f, nRow=%.1f, nOBSat=%d, wsFlags=%08x\n",
107142 j, sWBI.pSrc->pTab->zName,
107143 sWBI.cost.rCost, sWBI.cost.plan.nRow,
107144 sWBI.cost.plan.nOBSat, sWBI.cost.plan.wsFlags));
107145 bestPlan = sWBI.cost;
107146 bestJ = j;
107147
+1 -1
--- src/sqlite3.h
+++ src/sqlite3.h
@@ -107,11 +107,11 @@
107107
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
108108
** [sqlite_version()] and [sqlite_source_id()].
109109
*/
110110
#define SQLITE_VERSION "3.7.15"
111111
#define SQLITE_VERSION_NUMBER 3007015
112
-#define SQLITE_SOURCE_ID "2012-10-05 07:36:34 43155b1543bddbb84a8bc13a5b7344b228ddacb9"
112
+#define SQLITE_SOURCE_ID "2012-10-09 01:39:25 01dc032b5bbd9c9ebb1965f176ca5d732cda85ea"
113113
114114
/*
115115
** CAPI3REF: Run-Time Library Version Numbers
116116
** KEYWORDS: sqlite3_version, sqlite3_sourceid
117117
**
118118
--- 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.15"
111 #define SQLITE_VERSION_NUMBER 3007015
112 #define SQLITE_SOURCE_ID "2012-10-05 07:36:34 43155b1543bddbb84a8bc13a5b7344b228ddacb9"
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.15"
111 #define SQLITE_VERSION_NUMBER 3007015
112 #define SQLITE_SOURCE_ID "2012-10-09 01:39:25 01dc032b5bbd9c9ebb1965f176ca5d732cda85ea"
113
114 /*
115 ** CAPI3REF: Run-Time Library Version Numbers
116 ** KEYWORDS: sqlite3_version, sqlite3_sourceid
117 **
118
+1 -1
--- src/stash.c
+++ src/stash.c
@@ -172,11 +172,11 @@
172172
zComment = blob_str(&comment);
173173
}
174174
stashid = db_lget_int("stash-next", 1);
175175
db_lset_int("stash-next", stashid+1);
176176
vid = db_lget_int("checkout", 0);
177
- vfile_check_signature(vid, 0, 0);
177
+ vfile_check_signature(vid, 0);
178178
db_multi_exec(
179179
"INSERT INTO stash(stashid,vid,comment,ctime)"
180180
"VALUES(%d,%d,%Q,julianday('now'))",
181181
stashid, vid, zComment
182182
);
183183
--- src/stash.c
+++ src/stash.c
@@ -172,11 +172,11 @@
172 zComment = blob_str(&comment);
173 }
174 stashid = db_lget_int("stash-next", 1);
175 db_lset_int("stash-next", stashid+1);
176 vid = db_lget_int("checkout", 0);
177 vfile_check_signature(vid, 0, 0);
178 db_multi_exec(
179 "INSERT INTO stash(stashid,vid,comment,ctime)"
180 "VALUES(%d,%d,%Q,julianday('now'))",
181 stashid, vid, zComment
182 );
183
--- src/stash.c
+++ src/stash.c
@@ -172,11 +172,11 @@
172 zComment = blob_str(&comment);
173 }
174 stashid = db_lget_int("stash-next", 1);
175 db_lset_int("stash-next", stashid+1);
176 vid = db_lget_int("checkout", 0);
177 vfile_check_signature(vid, 0);
178 db_multi_exec(
179 "INSERT INTO stash(stashid,vid,comment,ctime)"
180 "VALUES(%d,%d,%Q,julianday('now'))",
181 stashid, vid, zComment
182 );
183
+2 -2
--- src/timeline.c
+++ src/timeline.c
@@ -1023,11 +1023,11 @@
10231023
if( nd>0 ) blob_appendf(&desc, "%d descendant%s", nd,(1==nd)?"":"s");
10241024
if( useDividers ) timeline_add_dividers(0, d_rid);
10251025
db_multi_exec("DELETE FROM ok");
10261026
}
10271027
if( p_rid ){
1028
- compute_ancestors(p_rid, nEntry+1);
1028
+ compute_ancestors(p_rid, nEntry+1, 0);
10291029
np = db_int(0, "SELECT count(*)-1 FROM ok");
10301030
if( np>0 ){
10311031
if( nd>0 ) blob_appendf(&desc, " and ");
10321032
blob_appendf(&desc, "%d ancestors", np);
10331033
db_multi_exec("%s", blob_str(&sql));
@@ -1538,11 +1538,11 @@
15381538
if( mode==3 || mode==4 ){
15391539
db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)");
15401540
if( mode==3 ){
15411541
compute_descendants(objid, n);
15421542
}else{
1543
- compute_ancestors(objid, n);
1543
+ compute_ancestors(objid, n, 0);
15441544
}
15451545
blob_appendf(&sql, " AND blob.rid IN ok");
15461546
}
15471547
if( zType && (zType[0]!='a') ){
15481548
blob_appendf(&sql, " AND event.type=%Q ", zType);
15491549
--- src/timeline.c
+++ src/timeline.c
@@ -1023,11 +1023,11 @@
1023 if( nd>0 ) blob_appendf(&desc, "%d descendant%s", nd,(1==nd)?"":"s");
1024 if( useDividers ) timeline_add_dividers(0, d_rid);
1025 db_multi_exec("DELETE FROM ok");
1026 }
1027 if( p_rid ){
1028 compute_ancestors(p_rid, nEntry+1);
1029 np = db_int(0, "SELECT count(*)-1 FROM ok");
1030 if( np>0 ){
1031 if( nd>0 ) blob_appendf(&desc, " and ");
1032 blob_appendf(&desc, "%d ancestors", np);
1033 db_multi_exec("%s", blob_str(&sql));
@@ -1538,11 +1538,11 @@
1538 if( mode==3 || mode==4 ){
1539 db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)");
1540 if( mode==3 ){
1541 compute_descendants(objid, n);
1542 }else{
1543 compute_ancestors(objid, n);
1544 }
1545 blob_appendf(&sql, " AND blob.rid IN ok");
1546 }
1547 if( zType && (zType[0]!='a') ){
1548 blob_appendf(&sql, " AND event.type=%Q ", zType);
1549
--- src/timeline.c
+++ src/timeline.c
@@ -1023,11 +1023,11 @@
1023 if( nd>0 ) blob_appendf(&desc, "%d descendant%s", nd,(1==nd)?"":"s");
1024 if( useDividers ) timeline_add_dividers(0, d_rid);
1025 db_multi_exec("DELETE FROM ok");
1026 }
1027 if( p_rid ){
1028 compute_ancestors(p_rid, nEntry+1, 0);
1029 np = db_int(0, "SELECT count(*)-1 FROM ok");
1030 if( np>0 ){
1031 if( nd>0 ) blob_appendf(&desc, " and ");
1032 blob_appendf(&desc, "%d ancestors", np);
1033 db_multi_exec("%s", blob_str(&sql));
@@ -1538,11 +1538,11 @@
1538 if( mode==3 || mode==4 ){
1539 db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)");
1540 if( mode==3 ){
1541 compute_descendants(objid, n);
1542 }else{
1543 compute_ancestors(objid, n, 0);
1544 }
1545 blob_appendf(&sql, " AND blob.rid IN ok");
1546 }
1547 if( zType && (zType[0]!='a') ){
1548 blob_appendf(&sql, " AND event.type=%Q ", zType);
1549
+5 -2
--- src/update.c
+++ src/update.c
@@ -100,10 +100,11 @@
100100
Stmt q;
101101
int latestFlag; /* --latest. Pick the latest version if true */
102102
int nochangeFlag; /* -n or --nochange. Do a dry run */
103103
int verboseFlag; /* -v or --verbose. Output extra information */
104104
int debugFlag; /* --debug option */
105
+ int setmtimeFlag; /* --setmtime. Set mtimes on files */
105106
int nChng; /* Number of file renames */
106107
int *aChng; /* Array of file renames */
107108
int i; /* Loop counter */
108109
int nConflict = 0; /* Number of merge conflicts */
109110
int nOverwrite = 0; /* Number of unmanaged files overwritten */
@@ -116,10 +117,11 @@
116117
}
117118
latestFlag = find_option("latest",0, 0)!=0;
118119
nochangeFlag = find_option("nochange","n",0)!=0;
119120
verboseFlag = find_option("verbose","v",0)!=0;
120121
debugFlag = find_option("debug",0,0)!=0;
122
+ setmtimeFlag = find_option("setmtime",0,0)!=0;
121123
db_must_be_within_tree();
122124
vid = db_lget_int("checkout", 0);
123125
if( vid==0 ){
124126
fossil_fatal("cannot find current version");
125127
}
@@ -194,11 +196,11 @@
194196
if( tid==0 ){
195197
fossil_panic("Internal Error: unable to find a version to update to.");
196198
}
197199
198200
db_begin_transaction();
199
- vfile_check_signature(vid, 1, 0);
201
+ vfile_check_signature(vid, CKSIG_ENOTFILE);
200202
if( !nochangeFlag && !internalUpdate ) undo_begin();
201203
load_vfile_from_rid(tid);
202204
203205
/*
204206
** The record.fn field is used to match files against each other. The
@@ -529,10 +531,11 @@
529531
/* A subset of files have been checked out. Keep the current
530532
** checkout unchanged. */
531533
db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid);
532534
}
533535
if( !internalUpdate ) undo_finish();
536
+ if( setmtimeFlag ) vfile_check_signature(vid, CKSIG_SETMTIME);
534537
db_end_transaction(0);
535538
}
536539
}
537540
538541
/*
@@ -696,11 +699,11 @@
696699
blob_reset(&fname);
697700
}
698701
}else{
699702
int vid;
700703
vid = db_lget_int("checkout", 0);
701
- vfile_check_signature(vid, 0, 0);
704
+ vfile_check_signature(vid, 0);
702705
db_multi_exec(
703706
"DELETE FROM vmerge;"
704707
"INSERT INTO torevert "
705708
"SELECT pathname"
706709
" FROM vfile "
707710
--- src/update.c
+++ src/update.c
@@ -100,10 +100,11 @@
100 Stmt q;
101 int latestFlag; /* --latest. Pick the latest version if true */
102 int nochangeFlag; /* -n or --nochange. Do a dry run */
103 int verboseFlag; /* -v or --verbose. Output extra information */
104 int debugFlag; /* --debug option */
 
105 int nChng; /* Number of file renames */
106 int *aChng; /* Array of file renames */
107 int i; /* Loop counter */
108 int nConflict = 0; /* Number of merge conflicts */
109 int nOverwrite = 0; /* Number of unmanaged files overwritten */
@@ -116,10 +117,11 @@
116 }
117 latestFlag = find_option("latest",0, 0)!=0;
118 nochangeFlag = find_option("nochange","n",0)!=0;
119 verboseFlag = find_option("verbose","v",0)!=0;
120 debugFlag = find_option("debug",0,0)!=0;
 
121 db_must_be_within_tree();
122 vid = db_lget_int("checkout", 0);
123 if( vid==0 ){
124 fossil_fatal("cannot find current version");
125 }
@@ -194,11 +196,11 @@
194 if( tid==0 ){
195 fossil_panic("Internal Error: unable to find a version to update to.");
196 }
197
198 db_begin_transaction();
199 vfile_check_signature(vid, 1, 0);
200 if( !nochangeFlag && !internalUpdate ) undo_begin();
201 load_vfile_from_rid(tid);
202
203 /*
204 ** The record.fn field is used to match files against each other. The
@@ -529,10 +531,11 @@
529 /* A subset of files have been checked out. Keep the current
530 ** checkout unchanged. */
531 db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid);
532 }
533 if( !internalUpdate ) undo_finish();
 
534 db_end_transaction(0);
535 }
536 }
537
538 /*
@@ -696,11 +699,11 @@
696 blob_reset(&fname);
697 }
698 }else{
699 int vid;
700 vid = db_lget_int("checkout", 0);
701 vfile_check_signature(vid, 0, 0);
702 db_multi_exec(
703 "DELETE FROM vmerge;"
704 "INSERT INTO torevert "
705 "SELECT pathname"
706 " FROM vfile "
707
--- src/update.c
+++ src/update.c
@@ -100,10 +100,11 @@
100 Stmt q;
101 int latestFlag; /* --latest. Pick the latest version if true */
102 int nochangeFlag; /* -n or --nochange. Do a dry run */
103 int verboseFlag; /* -v or --verbose. Output extra information */
104 int debugFlag; /* --debug option */
105 int setmtimeFlag; /* --setmtime. Set mtimes on files */
106 int nChng; /* Number of file renames */
107 int *aChng; /* Array of file renames */
108 int i; /* Loop counter */
109 int nConflict = 0; /* Number of merge conflicts */
110 int nOverwrite = 0; /* Number of unmanaged files overwritten */
@@ -116,10 +117,11 @@
117 }
118 latestFlag = find_option("latest",0, 0)!=0;
119 nochangeFlag = find_option("nochange","n",0)!=0;
120 verboseFlag = find_option("verbose","v",0)!=0;
121 debugFlag = find_option("debug",0,0)!=0;
122 setmtimeFlag = find_option("setmtime",0,0)!=0;
123 db_must_be_within_tree();
124 vid = db_lget_int("checkout", 0);
125 if( vid==0 ){
126 fossil_fatal("cannot find current version");
127 }
@@ -194,11 +196,11 @@
196 if( tid==0 ){
197 fossil_panic("Internal Error: unable to find a version to update to.");
198 }
199
200 db_begin_transaction();
201 vfile_check_signature(vid, CKSIG_ENOTFILE);
202 if( !nochangeFlag && !internalUpdate ) undo_begin();
203 load_vfile_from_rid(tid);
204
205 /*
206 ** The record.fn field is used to match files against each other. The
@@ -529,10 +531,11 @@
531 /* A subset of files have been checked out. Keep the current
532 ** checkout unchanged. */
533 db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid);
534 }
535 if( !internalUpdate ) undo_finish();
536 if( setmtimeFlag ) vfile_check_signature(vid, CKSIG_SETMTIME);
537 db_end_transaction(0);
538 }
539 }
540
541 /*
@@ -696,11 +699,11 @@
699 blob_reset(&fname);
700 }
701 }else{
702 int vid;
703 vid = db_lget_int("checkout", 0);
704 vfile_check_signature(vid, 0);
705 db_multi_exec(
706 "DELETE FROM vmerge;"
707 "INSERT INTO torevert "
708 "SELECT pathname"
709 " FROM vfile "
710
+75 -14
--- src/vfile.c
+++ src/vfile.c
@@ -118,19 +118,30 @@
118118
db_finalize(&ins);
119119
manifest_destroy(p);
120120
db_end_transaction(0);
121121
}
122122
123
+#if INTERFACE
124
+/*
125
+** The cksigFlags parameter to vfile_check_signature() is an OR-ed
126
+** combination of the following bits:
127
+*/
128
+#define CKSIG_ENOTFILE 0x001 /* non-file FS objects throw an error */
129
+#define CKSIG_SHA1 0x002 /* Verify file content using sha1sum */
130
+#define CKSIG_SETMTIME 0x004 /* Set mtime to last check-out time */
131
+
132
+#endif /* INTERFACE */
133
+
123134
/*
124
-** Look at every VFILE entry with the given vid and set update
125
-** VFILE.CHNGED field on every file according to whether or not
126
-** the file has changes. 0 means no change. 1 means edited. 2 means
135
+** Look at every VFILE entry with the given vid and update
136
+** VFILE.CHNGED field according to whether or not
137
+** the file has changed. 0 means no change. 1 means edited. 2 means
127138
** the file has changed due to a merge. 3 means the file was added
128139
** by a merge.
129140
**
130
-** If VFILE.DELETED is true or if VFILE.RID is zero, then the file was
131
-** either removed from managemented via "fossil rm" or added via
141
+** If VFILE.DELETED is true or if VFILE.RID is zero, then the file was either
142
+** removed from configuration management via "fossil rm" or added via
132143
** "fossil add", respectively, and in both cases we always know that
133144
** the file has changed without having the check the size, mtime,
134145
** or on-disk content.
135146
**
136147
** If the size of the file has changed, then we always know that the file
@@ -144,15 +155,16 @@
144155
**
145156
** If the mtime is used, it is used only to determine if files are the same.
146157
** If the mtime of a file has changed, we still examine the on-disk content
147158
** to see whether or not the edit was a null-edit.
148159
*/
149
-void vfile_check_signature(int vid, int notFileIsFatal, int useSha1sum){
160
+void vfile_check_signature(int vid, unsigned int cksigFlags){
150161
int nErr = 0;
151162
Stmt q;
152163
Blob fileCksum, origCksum;
153
- int useMtime = useSha1sum==0 && db_get_boolean("mtime-changes", 1);
164
+ int useMtime = (cksigFlags & CKSIG_SHA1)==0
165
+ && db_get_boolean("mtime-changes", 1);
154166
155167
db_begin_transaction();
156168
db_prepare(&q, "SELECT id, %Q || pathname,"
157169
" vfile.mrid, deleted, chnged, uuid, size, mtime"
158170
" FROM vfile LEFT JOIN blob ON vfile.mrid=blob.rid"
@@ -178,11 +190,11 @@
178190
currentMtime = file_wd_mtime(0);
179191
if( chnged==0 && (isDeleted || rid==0) ){
180192
/* "fossil rm" or "fossil add" always change the file */
181193
chnged = 1;
182194
}else if( !file_wd_isfile_or_link(0) && currentSize>=0 ){
183
- if( notFileIsFatal ){
195
+ if( cksigFlags & CKSIG_ENOTFILE ){
184196
fossil_warning("not an ordinary file: %s", zName);
185197
nErr++;
186198
}
187199
chnged = 1;
188200
}
@@ -217,10 +229,19 @@
217229
if( blob_compare(&fileCksum, &origCksum) ){
218230
chnged = 1;
219231
}
220232
blob_reset(&origCksum);
221233
blob_reset(&fileCksum);
234
+ }
235
+ if( (cksigFlags & CKSIG_SETMTIME) && (chnged==0 || chnged==2) ){
236
+ i64 desiredMtime;
237
+ if( mtime_of_manifest_file(vid,rid,&desiredMtime)==0 ){
238
+ if( currentMtime!=desiredMtime ){
239
+ file_set_mtime(zName, desiredMtime);
240
+ currentMtime = file_wd_mtime(zName);
241
+ }
242
+ }
222243
}
223244
if( currentMtime!=oldMtime || chnged!=oldChnged ){
224245
db_multi_exec("UPDATE vfile SET mtime=%lld, chnged=%d WHERE id=%d",
225246
currentMtime, chnged, id);
226247
}
@@ -360,10 +381,48 @@
360381
fossil_free(zFile);
361382
}
362383
return fileFound;
363384
}
364385
386
+/*
387
+** Return TRUE if zFile is a temporary file. Return FALSE if not.
388
+*/
389
+static int is_temporary_file(const char *zName){
390
+ static const char *azTemp[] = {
391
+ "baseline",
392
+ "merge",
393
+ "original",
394
+ "output",
395
+ };
396
+ int i, j, n;
397
+
398
+ if( strglob("ci-comment-????????????.txt", zName) ) return 1;
399
+ for(; zName[0]!=0; zName++){
400
+ if( zName[0]=='/' && strglob("/ci-comment-????????????.txt", zName) ){
401
+ return 1;
402
+ }
403
+ if( zName[0]!='-' ) continue;
404
+ for(i=0; i<sizeof(azTemp)/sizeof(azTemp[0]); i++){
405
+ n = (int)strlen(azTemp[i]);
406
+ if( memcmp(azTemp[i], zName+1, n) ) continue;
407
+ if( zName[n+1]==0 ) return 1;
408
+ if( zName[n+1]=='-' ){
409
+ for(j=n+2; zName[j] && fossil_isdigit(zName[j]); j++){}
410
+ if( zName[j]==0 ) return 1;
411
+ }
412
+ }
413
+ }
414
+ return 0;
415
+}
416
+
417
+#if INTERFACE
418
+/*
419
+** Values for the scanFlags parameter to vfile_scan().
420
+*/
421
+#define SCAN_ALL 0x001 /* Includes files that begin with "." */
422
+#define SCAN_TEMP 0x002 /* Only Fossil-generated files like *-baseline */
423
+#endif /* INTERFACE */
365424
366425
/*
367426
** Load into table SFILE the name of every ordinary file in
368427
** the directory pPath. Omit the first nPrefix characters of
369428
** of pPath when inserting into the SFILE table.
@@ -375,11 +434,11 @@
375434
**
376435
** Any files or directories that match the glob pattern pIgnore are
377436
** excluded from the scan. Name matching occurs after the first
378437
** nPrefix characters are elided from the filename.
379438
*/
380
-void vfile_scan(Blob *pPath, int nPrefix, int allFlag, Glob *pIgnore){
439
+void vfile_scan(Blob *pPath, int nPrefix, unsigned scanFlags, Glob *pIgnore){
381440
DIR *d;
382441
int origSize;
383442
const char *zDir;
384443
struct dirent *pEntry;
385444
int skipAll = 0;
@@ -409,11 +468,11 @@
409468
if( d ){
410469
while( (pEntry=readdir(d))!=0 ){
411470
char *zPath;
412471
char *zUtf8;
413472
if( pEntry->d_name[0]=='.' ){
414
- if( !allFlag ) continue;
473
+ if( (scanFlags & SCAN_ALL)==0 ) continue;
415474
if( pEntry->d_name[1]==0 ) continue;
416475
if( pEntry->d_name[1]=='.' && pEntry->d_name[2]==0 ) continue;
417476
}
418477
zUtf8 = fossil_unicode_to_utf8(pEntry->d_name);
419478
blob_appendf(pPath, "/%s", zUtf8);
@@ -421,16 +480,18 @@
421480
zPath = blob_str(pPath);
422481
if( glob_match(pIgnore, &zPath[nPrefix+1]) ){
423482
/* do nothing */
424483
}else if( file_wd_isdir(zPath)==1 ){
425484
if( !vfile_top_of_checkout(zPath) ){
426
- vfile_scan(pPath, nPrefix, allFlag, pIgnore);
485
+ vfile_scan(pPath, nPrefix, scanFlags, pIgnore);
427486
}
428487
}else if( file_wd_isfile_or_link(zPath) ){
429
- db_bind_text(&ins, ":file", &zPath[nPrefix+1]);
430
- db_step(&ins);
431
- db_reset(&ins);
488
+ if( (scanFlags & SCAN_TEMP)==0 || is_temporary_file(pEntry->d_name) ){
489
+ db_bind_text(&ins, ":file", &zPath[nPrefix+1]);
490
+ db_step(&ins);
491
+ db_reset(&ins);
492
+ }
432493
}
433494
blob_resize(pPath, origSize);
434495
}
435496
closedir(d);
436497
}
437498
--- src/vfile.c
+++ src/vfile.c
@@ -118,19 +118,30 @@
118 db_finalize(&ins);
119 manifest_destroy(p);
120 db_end_transaction(0);
121 }
122
 
 
 
 
 
 
 
 
 
 
 
123 /*
124 ** Look at every VFILE entry with the given vid and set update
125 ** VFILE.CHNGED field on every file according to whether or not
126 ** the file has changes. 0 means no change. 1 means edited. 2 means
127 ** the file has changed due to a merge. 3 means the file was added
128 ** by a merge.
129 **
130 ** If VFILE.DELETED is true or if VFILE.RID is zero, then the file was
131 ** either removed from managemented via "fossil rm" or added via
132 ** "fossil add", respectively, and in both cases we always know that
133 ** the file has changed without having the check the size, mtime,
134 ** or on-disk content.
135 **
136 ** If the size of the file has changed, then we always know that the file
@@ -144,15 +155,16 @@
144 **
145 ** If the mtime is used, it is used only to determine if files are the same.
146 ** If the mtime of a file has changed, we still examine the on-disk content
147 ** to see whether or not the edit was a null-edit.
148 */
149 void vfile_check_signature(int vid, int notFileIsFatal, int useSha1sum){
150 int nErr = 0;
151 Stmt q;
152 Blob fileCksum, origCksum;
153 int useMtime = useSha1sum==0 && db_get_boolean("mtime-changes", 1);
 
154
155 db_begin_transaction();
156 db_prepare(&q, "SELECT id, %Q || pathname,"
157 " vfile.mrid, deleted, chnged, uuid, size, mtime"
158 " FROM vfile LEFT JOIN blob ON vfile.mrid=blob.rid"
@@ -178,11 +190,11 @@
178 currentMtime = file_wd_mtime(0);
179 if( chnged==0 && (isDeleted || rid==0) ){
180 /* "fossil rm" or "fossil add" always change the file */
181 chnged = 1;
182 }else if( !file_wd_isfile_or_link(0) && currentSize>=0 ){
183 if( notFileIsFatal ){
184 fossil_warning("not an ordinary file: %s", zName);
185 nErr++;
186 }
187 chnged = 1;
188 }
@@ -217,10 +229,19 @@
217 if( blob_compare(&fileCksum, &origCksum) ){
218 chnged = 1;
219 }
220 blob_reset(&origCksum);
221 blob_reset(&fileCksum);
 
 
 
 
 
 
 
 
 
222 }
223 if( currentMtime!=oldMtime || chnged!=oldChnged ){
224 db_multi_exec("UPDATE vfile SET mtime=%lld, chnged=%d WHERE id=%d",
225 currentMtime, chnged, id);
226 }
@@ -360,10 +381,48 @@
360 fossil_free(zFile);
361 }
362 return fileFound;
363 }
364
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
365
366 /*
367 ** Load into table SFILE the name of every ordinary file in
368 ** the directory pPath. Omit the first nPrefix characters of
369 ** of pPath when inserting into the SFILE table.
@@ -375,11 +434,11 @@
375 **
376 ** Any files or directories that match the glob pattern pIgnore are
377 ** excluded from the scan. Name matching occurs after the first
378 ** nPrefix characters are elided from the filename.
379 */
380 void vfile_scan(Blob *pPath, int nPrefix, int allFlag, Glob *pIgnore){
381 DIR *d;
382 int origSize;
383 const char *zDir;
384 struct dirent *pEntry;
385 int skipAll = 0;
@@ -409,11 +468,11 @@
409 if( d ){
410 while( (pEntry=readdir(d))!=0 ){
411 char *zPath;
412 char *zUtf8;
413 if( pEntry->d_name[0]=='.' ){
414 if( !allFlag ) continue;
415 if( pEntry->d_name[1]==0 ) continue;
416 if( pEntry->d_name[1]=='.' && pEntry->d_name[2]==0 ) continue;
417 }
418 zUtf8 = fossil_unicode_to_utf8(pEntry->d_name);
419 blob_appendf(pPath, "/%s", zUtf8);
@@ -421,16 +480,18 @@
421 zPath = blob_str(pPath);
422 if( glob_match(pIgnore, &zPath[nPrefix+1]) ){
423 /* do nothing */
424 }else if( file_wd_isdir(zPath)==1 ){
425 if( !vfile_top_of_checkout(zPath) ){
426 vfile_scan(pPath, nPrefix, allFlag, pIgnore);
427 }
428 }else if( file_wd_isfile_or_link(zPath) ){
429 db_bind_text(&ins, ":file", &zPath[nPrefix+1]);
430 db_step(&ins);
431 db_reset(&ins);
 
 
432 }
433 blob_resize(pPath, origSize);
434 }
435 closedir(d);
436 }
437
--- src/vfile.c
+++ src/vfile.c
@@ -118,19 +118,30 @@
118 db_finalize(&ins);
119 manifest_destroy(p);
120 db_end_transaction(0);
121 }
122
123 #if INTERFACE
124 /*
125 ** The cksigFlags parameter to vfile_check_signature() is an OR-ed
126 ** combination of the following bits:
127 */
128 #define CKSIG_ENOTFILE 0x001 /* non-file FS objects throw an error */
129 #define CKSIG_SHA1 0x002 /* Verify file content using sha1sum */
130 #define CKSIG_SETMTIME 0x004 /* Set mtime to last check-out time */
131
132 #endif /* INTERFACE */
133
134 /*
135 ** Look at every VFILE entry with the given vid and update
136 ** VFILE.CHNGED field according to whether or not
137 ** the file has changed. 0 means no change. 1 means edited. 2 means
138 ** the file has changed due to a merge. 3 means the file was added
139 ** by a merge.
140 **
141 ** If VFILE.DELETED is true or if VFILE.RID is zero, then the file was either
142 ** removed from configuration management via "fossil rm" or added via
143 ** "fossil add", respectively, and in both cases we always know that
144 ** the file has changed without having the check the size, mtime,
145 ** or on-disk content.
146 **
147 ** If the size of the file has changed, then we always know that the file
@@ -144,15 +155,16 @@
155 **
156 ** If the mtime is used, it is used only to determine if files are the same.
157 ** If the mtime of a file has changed, we still examine the on-disk content
158 ** to see whether or not the edit was a null-edit.
159 */
160 void vfile_check_signature(int vid, unsigned int cksigFlags){
161 int nErr = 0;
162 Stmt q;
163 Blob fileCksum, origCksum;
164 int useMtime = (cksigFlags & CKSIG_SHA1)==0
165 && db_get_boolean("mtime-changes", 1);
166
167 db_begin_transaction();
168 db_prepare(&q, "SELECT id, %Q || pathname,"
169 " vfile.mrid, deleted, chnged, uuid, size, mtime"
170 " FROM vfile LEFT JOIN blob ON vfile.mrid=blob.rid"
@@ -178,11 +190,11 @@
190 currentMtime = file_wd_mtime(0);
191 if( chnged==0 && (isDeleted || rid==0) ){
192 /* "fossil rm" or "fossil add" always change the file */
193 chnged = 1;
194 }else if( !file_wd_isfile_or_link(0) && currentSize>=0 ){
195 if( cksigFlags & CKSIG_ENOTFILE ){
196 fossil_warning("not an ordinary file: %s", zName);
197 nErr++;
198 }
199 chnged = 1;
200 }
@@ -217,10 +229,19 @@
229 if( blob_compare(&fileCksum, &origCksum) ){
230 chnged = 1;
231 }
232 blob_reset(&origCksum);
233 blob_reset(&fileCksum);
234 }
235 if( (cksigFlags & CKSIG_SETMTIME) && (chnged==0 || chnged==2) ){
236 i64 desiredMtime;
237 if( mtime_of_manifest_file(vid,rid,&desiredMtime)==0 ){
238 if( currentMtime!=desiredMtime ){
239 file_set_mtime(zName, desiredMtime);
240 currentMtime = file_wd_mtime(zName);
241 }
242 }
243 }
244 if( currentMtime!=oldMtime || chnged!=oldChnged ){
245 db_multi_exec("UPDATE vfile SET mtime=%lld, chnged=%d WHERE id=%d",
246 currentMtime, chnged, id);
247 }
@@ -360,10 +381,48 @@
381 fossil_free(zFile);
382 }
383 return fileFound;
384 }
385
386 /*
387 ** Return TRUE if zFile is a temporary file. Return FALSE if not.
388 */
389 static int is_temporary_file(const char *zName){
390 static const char *azTemp[] = {
391 "baseline",
392 "merge",
393 "original",
394 "output",
395 };
396 int i, j, n;
397
398 if( strglob("ci-comment-????????????.txt", zName) ) return 1;
399 for(; zName[0]!=0; zName++){
400 if( zName[0]=='/' && strglob("/ci-comment-????????????.txt", zName) ){
401 return 1;
402 }
403 if( zName[0]!='-' ) continue;
404 for(i=0; i<sizeof(azTemp)/sizeof(azTemp[0]); i++){
405 n = (int)strlen(azTemp[i]);
406 if( memcmp(azTemp[i], zName+1, n) ) continue;
407 if( zName[n+1]==0 ) return 1;
408 if( zName[n+1]=='-' ){
409 for(j=n+2; zName[j] && fossil_isdigit(zName[j]); j++){}
410 if( zName[j]==0 ) return 1;
411 }
412 }
413 }
414 return 0;
415 }
416
417 #if INTERFACE
418 /*
419 ** Values for the scanFlags parameter to vfile_scan().
420 */
421 #define SCAN_ALL 0x001 /* Includes files that begin with "." */
422 #define SCAN_TEMP 0x002 /* Only Fossil-generated files like *-baseline */
423 #endif /* INTERFACE */
424
425 /*
426 ** Load into table SFILE the name of every ordinary file in
427 ** the directory pPath. Omit the first nPrefix characters of
428 ** of pPath when inserting into the SFILE table.
@@ -375,11 +434,11 @@
434 **
435 ** Any files or directories that match the glob pattern pIgnore are
436 ** excluded from the scan. Name matching occurs after the first
437 ** nPrefix characters are elided from the filename.
438 */
439 void vfile_scan(Blob *pPath, int nPrefix, unsigned scanFlags, Glob *pIgnore){
440 DIR *d;
441 int origSize;
442 const char *zDir;
443 struct dirent *pEntry;
444 int skipAll = 0;
@@ -409,11 +468,11 @@
468 if( d ){
469 while( (pEntry=readdir(d))!=0 ){
470 char *zPath;
471 char *zUtf8;
472 if( pEntry->d_name[0]=='.' ){
473 if( (scanFlags & SCAN_ALL)==0 ) continue;
474 if( pEntry->d_name[1]==0 ) continue;
475 if( pEntry->d_name[1]=='.' && pEntry->d_name[2]==0 ) continue;
476 }
477 zUtf8 = fossil_unicode_to_utf8(pEntry->d_name);
478 blob_appendf(pPath, "/%s", zUtf8);
@@ -421,16 +480,18 @@
480 zPath = blob_str(pPath);
481 if( glob_match(pIgnore, &zPath[nPrefix+1]) ){
482 /* do nothing */
483 }else if( file_wd_isdir(zPath)==1 ){
484 if( !vfile_top_of_checkout(zPath) ){
485 vfile_scan(pPath, nPrefix, scanFlags, pIgnore);
486 }
487 }else if( file_wd_isfile_or_link(zPath) ){
488 if( (scanFlags & SCAN_TEMP)==0 || is_temporary_file(pEntry->d_name) ){
489 db_bind_text(&ins, ":file", &zPath[nPrefix+1]);
490 db_step(&ins);
491 db_reset(&ins);
492 }
493 }
494 blob_resize(pPath, origSize);
495 }
496 closedir(d);
497 }
498

Keyboard Shortcuts

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