Fossil

Check-in [ce3b312a15]
Login

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

Overview
Comment:Merge updates from trunk.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | tclRdOnly
Files: files | file ages | folders
SHA1: ce3b312a1500692ae15bad8b4a5c27db3b990758
User & Date: mistachkin 2012-10-16 23:14:32.395
Context
2012-12-08
06:46
Merge updates from trunk. check-in: fc7e8d01d4 user: mistachkin tags: tclRdOnly
2012-10-16
23:14
Merge updates from trunk. check-in: ce3b312a15 user: mistachkin tags: tclRdOnly
01:11
unused variable includeDotFiles <p>struct utimbuf -> struct _utimbuf (compiler warning with mingw-w64) <p>a few "const" additions (lower memory footprint, allows C-compiler to optimize better) check-in: 6032dd51f2 user: jan.nijtmans tags: trunk
2012-10-07
14:49
Add the new 'tcl-rdonly' setting to the list of those that should be transferred. check-in: 2335ae4f22 user: mistachkin tags: tclRdOnly
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/add.c.
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
** from the local repository.
*/
#include "config.h"
#include "add.h"
#include <assert.h>
#include <dirent.h>

/*
** Set to true if files whose names begin with "." should be
** included when processing a recursive "add" command.
*/
static int includeDotFiles = 0;

/*
** This routine returns the names of files in a working checkout that
** are created by Fossil itself, and hence should not be added, deleted,
** or merge, and should be omitted from "clean" and "extra" lists.
**
** Return the N-th name.  The first name has N==0.  When all names have
** been used, return 0.
*/
const char *fossil_reserved_name(int N){
  /* Possible names of the local per-checkout database file and
  ** its associated journals
  */
  static const char *azName[] = {
     "_FOSSIL_",
     "_FOSSIL_-journal",
     "_FOSSIL_-wal",
     "_FOSSIL_-shm",
     ".fslckout",
     ".fslckout-journal",
     ".fslckout-wal",







<
<
<
<
<
<












|







19
20
21
22
23
24
25






26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
** from the local repository.
*/
#include "config.h"
#include "add.h"
#include <assert.h>
#include <dirent.h>







/*
** This routine returns the names of files in a working checkout that
** are created by Fossil itself, and hence should not be added, deleted,
** or merge, and should be omitted from "clean" and "extra" lists.
**
** Return the N-th name.  The first name has N==0.  When all names have
** been used, return 0.
*/
const char *fossil_reserved_name(int N){
  /* Possible names of the local per-checkout database file and
  ** its associated journals
  */
  static const char *const azName[] = {
     "_FOSSIL_",
     "_FOSSIL_-journal",
     "_FOSSIL_-wal",
     "_FOSSIL_-shm",
     ".fslckout",
     ".fslckout-journal",
     ".fslckout-wal",
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
     ".fos-wal",
     ".fos-shm",
  };

  /* Names of auxiliary files generated by SQLite when the "manifest"
  ** properity is enabled
  */
  static const char *azManifest[] = {
     "manifest",
     "manifest.uuid",
  };

  /* Cached setting "manifest" */
  static int cachedManifest = -1;








|







53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
     ".fos-wal",
     ".fos-shm",
  };

  /* Names of auxiliary files generated by SQLite when the "manifest"
  ** properity is enabled
  */
  static const char *const azManifest[] = {
     "manifest",
     "manifest.uuid",
  };

  /* Cached setting "manifest" */
  static int cachedManifest = -1;

214
215
216
217
218
219
220

221
222
223
224
225
226
227
228
229
230
void add_cmd(void){
  int i;                     /* Loop counter */
  int vid;                   /* Currently checked out version */
  int nRoot;                 /* Full path characters in g.zLocalRoot */
  const char *zIgnoreFlag;   /* The --ignore option or ignore-glob setting */
  Glob *pIgnore;             /* Ignore everything matching this glob pattern */
  int caseSensitive;         /* True if filenames are case sensitive */


  zIgnoreFlag = find_option("ignore",0,1);
  includeDotFiles = find_option("dotfiles",0,0)!=0;
  capture_case_sensitive_option();
  db_must_be_within_tree();
  caseSensitive = filenames_are_case_sensitive();
  if( zIgnoreFlag==0 ){
    zIgnoreFlag = db_get("ignore-glob", 0);
  }
  vid = db_lget_int("checkout",0);







>


|







208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
void add_cmd(void){
  int i;                     /* Loop counter */
  int vid;                   /* Currently checked out version */
  int nRoot;                 /* Full path characters in g.zLocalRoot */
  const char *zIgnoreFlag;   /* The --ignore option or ignore-glob setting */
  Glob *pIgnore;             /* Ignore everything matching this glob pattern */
  int caseSensitive;         /* True if filenames are case sensitive */
  unsigned scanFlags = 0;    /* Flags passed to vfile_scan() */

  zIgnoreFlag = find_option("ignore",0,1);
  if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL;
  capture_case_sensitive_option();
  db_must_be_within_tree();
  caseSensitive = filenames_are_case_sensitive();
  if( zIgnoreFlag==0 ){
    zIgnoreFlag = db_get("ignore-glob", 0);
  }
  vid = db_lget_int("checkout",0);
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
    int isDir;
    Blob fullName;

    file_canonical_name(g.argv[i], &fullName, 0);
    zName = blob_str(&fullName);
    isDir = file_wd_isdir(zName);
    if( isDir==1 ){
      vfile_scan(&fullName, nRoot-1, includeDotFiles, pIgnore);
    }else if( isDir==0 ){
      fossil_warning("not found: %s", zName);
    }else if( file_access(zName, R_OK) ){
      fossil_fatal("cannot open %s", zName);
    }else{
      char *zTreeName = &zName[nRoot];
      db_multi_exec(







|







243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
    int isDir;
    Blob fullName;

    file_canonical_name(g.argv[i], &fullName, 0);
    zName = blob_str(&fullName);
    isDir = file_wd_isdir(zName);
    if( isDir==1 ){
      vfile_scan(&fullName, nRoot-1, scanFlags, pIgnore);
    }else if( isDir==0 ){
      fossil_warning("not found: %s", zName);
    }else if( file_access(zName, R_OK) ){
      fossil_fatal("cannot open %s", zName);
    }else{
      char *zTreeName = &zName[nRoot];
      db_multi_exec(
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
**   --test                  If given, display instead of run actions
**
** See also: add, rm
*/
void addremove_cmd(void){
  Blob path;
  const char *zIgnoreFlag = find_option("ignore",0,1);
  int allFlag = find_option("dotfiles",0,0)!=0;
  int isTest = find_option("test",0,0)!=0;
  int caseSensitive;
  int n;
  Stmt q;
  int vid;
  int nAdd = 0;
  int nDelete = 0;







|







426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
**   --test                  If given, display instead of run actions
**
** See also: add, rm
*/
void addremove_cmd(void){
  Blob path;
  const char *zIgnoreFlag = find_option("ignore",0,1);
  unsigned scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0;
  int isTest = find_option("test",0,0)!=0;
  int caseSensitive;
  int n;
  Stmt q;
  int vid;
  int nAdd = 0;
  int nDelete = 0;
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
  ** the files in the sfile temp table to the set of managed files.
  */
  db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)");
  n = strlen(g.zLocalRoot);
  blob_init(&path, g.zLocalRoot, n-1);
  /* now we read the complete file structure into a temp table */
  pIgnore = glob_create(zIgnoreFlag);
  vfile_scan(&path, blob_size(&path), allFlag, pIgnore);
  glob_free(pIgnore);
  nAdd = add_files_in_sfile(vid, caseSensitive);

  /* step 2: search for missing files */
  db_prepare(&q,
      "SELECT pathname, %Q || pathname, deleted FROM vfile"
      " WHERE NOT deleted"







|







459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
  ** the files in the sfile temp table to the set of managed files.
  */
  db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)");
  n = strlen(g.zLocalRoot);
  blob_init(&path, g.zLocalRoot, n-1);
  /* now we read the complete file structure into a temp table */
  pIgnore = glob_create(zIgnoreFlag);
  vfile_scan(&path, blob_size(&path), scanFlags, pIgnore);
  glob_free(pIgnore);
  nAdd = add_files_in_sfile(vid, caseSensitive);

  /* step 2: search for missing files */
  db_prepare(&q,
      "SELECT pathname, %Q || pathname, deleted FROM vfile"
      " WHERE NOT deleted"
Changes to src/browse.c.
163
164
165
166
167
168
169


170
171
172
173
174
175
176
    @ %s(blob_str(&dirname))</h2>
    zSubdirLink = mprintf("%R/dir?ci=%S&name=%T", zUuid, zPrefix);
    if( zD ){
      style_submenu_element("Top", "Top", "%R/dir?ci=%S", zUuid);
      style_submenu_element("All", "All", "%R/dir?name=%t", zD);
    }else{
      style_submenu_element("All", "All", "%R/dir");


    }
  }else{
    int hasTrunk;
    @ <h2>The union of all files from all check-ins
    @ %s(blob_str(&dirname))</h2>
    hasTrunk = db_exists(
                  "SELECT 1 FROM tagxref WHERE tagid=%d AND value='trunk'",







>
>







163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
    @ %s(blob_str(&dirname))</h2>
    zSubdirLink = mprintf("%R/dir?ci=%S&name=%T", zUuid, zPrefix);
    if( zD ){
      style_submenu_element("Top", "Top", "%R/dir?ci=%S", zUuid);
      style_submenu_element("All", "All", "%R/dir?name=%t", zD);
    }else{
      style_submenu_element("All", "All", "%R/dir");
      style_submenu_element("File Ages", "File Ages", "%R/fileage?name=%S",
                            zUuid);
    }
  }else{
    int hasTrunk;
    @ <h2>The union of all files from all check-ins
    @ %s(blob_str(&dirname))</h2>
    hasTrunk = db_exists(
                  "SELECT 1 FROM tagxref WHERE tagid=%d AND value='trunk'",
291
292
293
294
295
296
297






















































































































































    }
  }
  db_finalize(&q);
  manifest_destroy(pM);
  @ </ul></td></tr></table>
  style_footer();
}





























































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
    }
  }
  db_finalize(&q);
  manifest_destroy(pM);
  @ </ul></td></tr></table>
  style_footer();
}

/*
** Look at all file containing in the version "vid".  Construct a
** temporary table named "fileage" that contains the file-id for each
** files, the pathname, the check-in where the file was added, and the
** mtime on that checkin.
*/
int compute_fileage(int vid){
  Manifest *pManifest;
  ManifestFile *pFile;
  int nFile = 0;
  double vmtime;
  Stmt ins;
  Stmt q1, q2, q3;
  Stmt upd;
  db_multi_exec(
    /*"DROP TABLE IF EXISTS temp.fileage;"*/
    "CREATE TEMP TABLE fileage("
    "  fid INTEGER,"
    "  mid INTEGER,"
    "  mtime DATETIME,"
    "  pathname TEXT"
    ");"
    "CREATE INDEX fileage_fid ON fileage(fid);"
  );
  pManifest = manifest_get(vid, CFTYPE_MANIFEST);
  if( pManifest==0 ) return 1;
  manifest_file_rewind(pManifest);
  db_prepare(&ins, 
     "INSERT INTO temp.fileage(fid, pathname)"
     "  SELECT rid, :path FROM blob WHERE uuid=:uuid"
  );
  while( (pFile = manifest_file_next(pManifest, 0))!=0 ){
    db_bind_text(&ins, ":uuid", pFile->zUuid);
    db_bind_text(&ins, ":path", pFile->zName);
    db_step(&ins);
    db_reset(&ins);
    nFile++;
  }
  db_finalize(&ins);
  manifest_destroy(pManifest);
  db_prepare(&q1,"SELECT fid FROM mlink WHERE mid=:mid");
  db_prepare(&upd, "UPDATE fileage SET mid=:mid, mtime=:vmtime"
                      " WHERE fid=:fid AND mid IS NULL");
  db_prepare(&q2,"SELECT pid FROM plink WHERE cid=:vid AND isprim");
  db_prepare(&q3,"SELECT mtime FROM event WHERE objid=:vid");
  while( nFile>0 && vid>0 ){
    db_bind_int(&q3, ":vid", vid);
    if( db_step(&q3)==SQLITE_ROW ){
      vmtime = db_column_double(&q3, 0);
    }else{
      break;
    }
    db_reset(&q3);
    db_bind_int(&q1, ":mid", vid);
    db_bind_int(&upd, ":mid", vid);
    db_bind_double(&upd, ":vmtime", vmtime);
    while( db_step(&q1)==SQLITE_ROW ){
      db_bind_int(&upd, ":fid", db_column_int(&q1, 0));
      db_step(&upd);
      nFile -= db_changes();
      db_reset(&upd);
    }
    db_reset(&q1);
    db_bind_int(&q2, ":vid", vid);
    if( db_step(&q2)!=SQLITE_ROW ) break;
    vid = db_column_int(&q2, 0);
    db_reset(&q2);
  }
  db_finalize(&q1);
  db_finalize(&upd);
  db_finalize(&q2);
  db_finalize(&q3);
  return 0;
}

/*
** WEBPAGE:  fileage
**
** Parameters:
**   name=VERSION
*/
void fileage_page(void){
  int rid;
  const char *zName;
  char *zBaseTime;
  Stmt q;
  double baseTime;
  int lastMid = -1;

  login_check_credentials();
  if( !g.perm.Read ){ login_needed(); return; }
  zName = P("name");
  if( zName==0 ) zName = "tip";
  rid = symbolic_name_to_rid(zName, "ci");
  if( rid==0 ){
    fossil_fatal("not a valid check-in: %s", zName);
  }
  style_header("File Ages", zName);
  compute_fileage(rid);
  baseTime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid);
  zBaseTime = db_text("","SELECT datetime(%.20g,'localtime')", baseTime);
  @ <h2>File Ages For Check-in
  @ %z(href("%R/info?name=%T",zName))%h(zName)</a></h2>
  @
  @ <p>The times given are relative 
  @ %z(href("%R/timeline?c=%T",zBaseTime))%s(zBaseTime)</a>, which is the
  @ check-in time for 
  @ %z(href("%R/info?name=%T",zName))%h(zName)</a></p>
  @
  @ <table border=0 cellspacing=0 cellpadding=0>
  db_prepare(&q,
    "SELECT mtime, (SELECT uuid FROM blob WHERE rid=fid), mid, pathname"
    "  FROM fileage"
    " ORDER BY mtime DESC, mid, pathname"
  );
  while( db_step(&q)==SQLITE_ROW ){
    double age = baseTime - db_column_double(&q, 0);
    int mid = db_column_int(&q, 2);
    const char *zFUuid = db_column_text(&q, 1);
    char zAge[200];
    if( lastMid!=mid ){
      @ <tr><td colspan=3><hr></tr>
      lastMid = mid;
      if( age*86400.0<120 ){
        sqlite3_snprintf(sizeof(zAge), zAge, "%d seconds", (int)(age*86400.0));
      }else if( age*1440.0<90 ){
        sqlite3_snprintf(sizeof(zAge), zAge, "%.1f minutes", age*1440.0);
      }else if( age*24.0<36 ){
        sqlite3_snprintf(sizeof(zAge), zAge, "%.1f hours", age*24.0);
      }else if( age<365.0 ){
        sqlite3_snprintf(sizeof(zAge), zAge, "%.1f days", age);
      }else{
        sqlite3_snprintf(sizeof(zAge), zAge, "%.2f years", age/365.0);
      }
    }else{
      zAge[0] = 0;
    }
    @ <tr>
    @ <td>%s(zAge)
    @ <td width="25">
    @ <td>%z(href("%R/artifact/%S?ln", zFUuid))%h(db_column_text(&q, 3))</a>
    @ </tr>
    @
  }
  @ <tr><td colspan=3><hr></tr>
  @ </table>
  db_finalize(&q);
  style_footer();  
}
Changes to src/captcha.c.
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
  z[k] = 0;
  return z;     
}
#endif /* CAPTCHA==1 */


#if CAPTCHA==2
static const char *azFont2[] = {
 /* 0 */
 "  __  ",
 " /  \\ ",
 "| () |",
 " \\__/ ",

 /* 1 */







|







96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
  z[k] = 0;
  return z;     
}
#endif /* CAPTCHA==1 */


#if CAPTCHA==2
static const char *const azFont2[] = {
 /* 0 */
 "  __  ",
 " /  \\ ",
 "| () |",
 " \\__/ ",

 /* 1 */
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
  }
  z[k] = 0;
  return z;     
}
#endif /* CAPTCHA==2 */

#if CAPTCHA==3
static const char *azFont3[] = {
  /* 0 */
  "  ___  ",
  " / _ \\ ",
  "| | | |",
  "| | | |",
  "| |_| |",
  " \\___/ ",







|







221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
  }
  z[k] = 0;
  return z;     
}
#endif /* CAPTCHA==2 */

#if CAPTCHA==3
static const char *const azFont3[] = {
  /* 0 */
  "  ___  ",
  " / _ \\ ",
  "| | | |",
  "| | | |",
  "| |_| |",
  " \\___/ ",
Changes to src/cgi.c.
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
  return 0;
}


/*
** Name of days and months.
*/
static const char *azDays[] =
    {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", 0};
static const char *azMonths[] =
    {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 0};


/*
** Returns an RFC822-formatted time string suitable for HTTP headers.
** The timezone is always GMT.  The value returned is always a







|

|







1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
  return 0;
}


/*
** Name of days and months.
*/
static const char *const azDays[] =
    {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", 0};
static const char *const azMonths[] =
    {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 0};


/*
** Returns an RFC822-formatted time string suitable for HTTP headers.
** The timezone is always GMT.  The value returned is always a
Changes to src/checkin.c.
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
  int showHdr = find_option("header",0,0)!=0;
  int verbose = find_option("verbose","v",0)!=0;
  int cwdRelative = 0;
  db_must_be_within_tree();
  cwdRelative = determine_cwd_relative_option();
  blob_zero(&report);
  vid = db_lget_int("checkout", 0);
  vfile_check_signature(vid, 0, useSha1sum);
  status_report(&report, "", 0, cwdRelative);
  if( verbose && blob_size(&report)==0 ){
    blob_append(&report, "  (none)\n", -1);
  }
  if( showHdr && blob_size(&report)>0 ){
    fossil_print("Changes for %s at %s:\n", db_get("project-name","???"),
                 g.zLocalRoot);







|







158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
  int showHdr = find_option("header",0,0)!=0;
  int verbose = find_option("verbose","v",0)!=0;
  int cwdRelative = 0;
  db_must_be_within_tree();
  cwdRelative = determine_cwd_relative_option();
  blob_zero(&report);
  vid = db_lget_int("checkout", 0);
  vfile_check_signature(vid, useSha1sum ? CKSIG_SHA1 : 0);
  status_report(&report, "", 0, cwdRelative);
  if( verbose && blob_size(&report)==0 ){
    blob_append(&report, "  (none)\n", -1);
  }
  if( showHdr && blob_size(&report)>0 ){
    fossil_print("Changes for %s at %s:\n", db_get("project-name","???"),
                 g.zLocalRoot);
203
204
205
206
207
208
209





210
211
212
213
214
215
216
217
218
219
220

221
222
223
224
225
226
227


228
229

230
231








232

233







234
235
236
237

238
239
240
241
242
243
244


245
246
247
248
249
250
251
252
  vid = db_lget_int("checkout", 0);
  if( vid ){
    show_common_info(vid, "checkout:", 1, 1);
  }
  db_record_repository_filename(0);
  changes_cmd();
}






/*
** COMMAND: ls
**
** Usage: %fossil ls ?OPTIONS?
**
** Show the names of all files in the current checkout.  The -l provides
** extra information about each file.
**
** Options:
**   -l      Provide extra information about each file.

**
** See also: changes, extra, status
*/
void ls_cmd(void){
  int vid;
  Stmt q;
  int isBrief;



  isBrief = find_option("l","l", 0)==0;

  db_must_be_within_tree();
  vid = db_lget_int("checkout", 0);








  vfile_check_signature(vid, 0, 0);

  db_prepare(&q,







     "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)"
     "  FROM vfile"
     " ORDER BY 1"
  );

  while( db_step(&q)==SQLITE_ROW ){
    const char *zPathname = db_column_text(&q,0);
    int isDeleted = db_column_int(&q, 1);
    int isNew = db_column_int(&q,2)==0;
    int chnged = db_column_int(&q,3);
    int renamed = db_column_int(&q,4);
    char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);


    if( isBrief ){
      fossil_print("%s\n", zPathname);
    }else if( isNew ){
      fossil_print("ADDED      %s\n", zPathname);
    }else if( isDeleted ){
      fossil_print("DELETED    %s\n", zPathname);
    }else if( !file_wd_isfile_or_link(zFullName) ){
      if( file_access(zFullName, 0)==0 ){







>
>
>
>
>




|





|
>







>
>


>


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







>
>
|







203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
  vid = db_lget_int("checkout", 0);
  if( vid ){
    show_common_info(vid, "checkout:", 1, 1);
  }
  db_record_repository_filename(0);
  changes_cmd();
}

/*
** Implementation of the checkin_mtime SQL function
*/


/*
** COMMAND: ls
**
** Usage: %fossil ls ?OPTIONS? ?VERSION?
**
** Show the names of all files in the current checkout.  The -l provides
** extra information about each file.
**
** Options:
**   -l              Provide extra information about each file.
**   --age           Show when each file was committed
**
** See also: changes, extra, status
*/
void ls_cmd(void){
  int vid;
  Stmt q;
  int isBrief;
  int showAge;
  char *zOrderBy = "pathname";

  isBrief = find_option("l","l", 0)==0;
  showAge = find_option("age",0,0)!=0;
  db_must_be_within_tree();
  vid = db_lget_int("checkout", 0);
  if( find_option("t","t",0)!=0 ){
    if( showAge ){
      zOrderBy = mprintf("checkin_mtime(%d,rid) DESC", vid);
    }else{
      zOrderBy = "mtime DESC";
    }
  }
  verify_all_options();
  vfile_check_signature(vid, 0);
  if( showAge ){
    db_prepare(&q,
       "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0),"
       "       datetime(checkin_mtime(%d,rid),'unixepoch','localtime')"
       "  FROM vfile"
       " ORDER BY %s", vid, zOrderBy
    );
  }else{
    db_prepare(&q,
       "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)"
       "  FROM vfile"
       " ORDER BY %s", zOrderBy
    );
  }
  while( db_step(&q)==SQLITE_ROW ){
    const char *zPathname = db_column_text(&q,0);
    int isDeleted = db_column_int(&q, 1);
    int isNew = db_column_int(&q,2)==0;
    int chnged = db_column_int(&q,3);
    int renamed = db_column_int(&q,4);
    char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
    if( showAge ){
      fossil_print("%s  %s\n", db_column_text(&q, 5), zPathname);
    }else if( isBrief ){
      fossil_print("%s\n", zPathname);
    }else if( isNew ){
      fossil_print("ADDED      %s\n", zPathname);
    }else if( isDeleted ){
      fossil_print("DELETED    %s\n", zPathname);
    }else if( !file_wd_isfile_or_link(zFullName) ){
      if( file_access(zFullName, 0)==0 ){
294
295
296
297
298
299
300
301
302
303
304
305
306

307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
*/
void extra_cmd(void){
  Blob path;
  Blob repo;
  Stmt q;
  int n;
  const char *zIgnoreFlag = find_option("ignore",0,1);
  int allFlag = find_option("dotfiles",0,0)!=0;
  int cwdRelative = 0;
  Glob *pIgnore;
  Blob rewrittenPathname;
  const char *zPathname, *zDisplayName;


  db_must_be_within_tree();
  cwdRelative = determine_cwd_relative_option();
  db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
                filename_collation());
  n = strlen(g.zLocalRoot);
  blob_init(&path, g.zLocalRoot, n-1);
  if( zIgnoreFlag==0 ){
    zIgnoreFlag = db_get("ignore-glob", 0);
  }
  pIgnore = glob_create(zIgnoreFlag);
  vfile_scan(&path, blob_size(&path), allFlag, pIgnore);
  glob_free(pIgnore);
  db_prepare(&q, 
      "SELECT x FROM sfile"
      " WHERE x NOT IN (%s)"
      " ORDER BY 1",
      fossil_all_reserved_names()
  );







|





>










|







322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
*/
void extra_cmd(void){
  Blob path;
  Blob repo;
  Stmt q;
  int n;
  const char *zIgnoreFlag = find_option("ignore",0,1);
  unsigned scanFlags = find_option("dotfiles",0,0)!=0 ? SCAN_ALL : 0;
  int cwdRelative = 0;
  Glob *pIgnore;
  Blob rewrittenPathname;
  const char *zPathname, *zDisplayName;

  if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP;
  db_must_be_within_tree();
  cwdRelative = determine_cwd_relative_option();
  db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY %s)",
                filename_collation());
  n = strlen(g.zLocalRoot);
  blob_init(&path, g.zLocalRoot, n-1);
  if( zIgnoreFlag==0 ){
    zIgnoreFlag = db_get("ignore-glob", 0);
  }
  pIgnore = glob_create(zIgnoreFlag);
  vfile_scan(&path, blob_size(&path), scanFlags, pIgnore);
  glob_free(pIgnore);
  db_prepare(&q, 
      "SELECT x FROM sfile"
      " WHERE x NOT IN (%s)"
      " ORDER BY 1",
      fossil_all_reserved_names()
  );
365
366
367
368
369
370
371

372
373
374
375
376
377
378
379
380
381
382
383
384
385

386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
** is used if the --ignore option is omitted.
**
** Options:
**    --dotfiles       include files beginning with a dot (".")   
**    --force          Remove files without prompting
**    --ignore <CSG>   ignore files matching patterns from the 
**                     comma separated list of glob patterns.

**
** See also: addremove, extra, status
*/
void clean_cmd(void){
  int allFlag;
  int dotfilesFlag;
  const char *zIgnoreFlag;
  Blob path, repo;
  Stmt q;
  int n;
  Glob *pIgnore;

  allFlag = find_option("force","f",0)!=0;
  dotfilesFlag = find_option("dotfiles",0,0)!=0;

  zIgnoreFlag = find_option("ignore",0,1);
  db_must_be_within_tree();
  if( zIgnoreFlag==0 ){
    zIgnoreFlag = db_get("ignore-glob", 0);
  }
  db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)");
  n = strlen(g.zLocalRoot);
  blob_init(&path, g.zLocalRoot, n-1);
  pIgnore = glob_create(zIgnoreFlag);
  vfile_scan(&path, blob_size(&path), dotfilesFlag, pIgnore);
  glob_free(pIgnore);
  db_prepare(&q, 
      "SELECT %Q || x FROM sfile"
      " WHERE x NOT IN (%s)"
      " ORDER BY 1",
      g.zLocalRoot, fossil_all_reserved_names()
  );







>





|







|
>









|







394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
** is used if the --ignore option is omitted.
**
** Options:
**    --dotfiles       include files beginning with a dot (".")   
**    --force          Remove files without prompting
**    --ignore <CSG>   ignore files matching patterns from the 
**                     comma separated list of glob patterns.
**    --temp           Remove only Fossil-generated temporary files
**
** See also: addremove, extra, status
*/
void clean_cmd(void){
  int allFlag;
  unsigned scanFlags = 0;
  const char *zIgnoreFlag;
  Blob path, repo;
  Stmt q;
  int n;
  Glob *pIgnore;

  allFlag = find_option("force","f",0)!=0;
  if( find_option("dotfiles",0,0)!=0 ) scanFlags |= SCAN_ALL;
  if( find_option("temp",0,0)!=0 ) scanFlags |= SCAN_TEMP;
  zIgnoreFlag = find_option("ignore",0,1);
  db_must_be_within_tree();
  if( zIgnoreFlag==0 ){
    zIgnoreFlag = db_get("ignore-glob", 0);
  }
  db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)");
  n = strlen(g.zLocalRoot);
  blob_init(&path, g.zLocalRoot, n-1);
  pIgnore = glob_create(zIgnoreFlag);
  vfile_scan(&path, blob_size(&path), scanFlags, pIgnore);
  glob_free(pIgnore);
  db_prepare(&q, 
      "SELECT %Q || x FROM sfile"
      " WHERE x NOT IN (%s)"
      " ORDER BY 1",
      g.zLocalRoot, fossil_all_reserved_names()
  );
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
    blob_appendf(pOut, "T *branch * %F\n", zBranch);
    blob_appendf(pOut, "T *sym-%F *\n", zBranch);
  }
  if( zColor && zColor[0] ){
    /* One-time background color */
    blob_appendf(pOut, "T +bgcolor * %F\n", zColor);
  }
  if( g.markPrivate ){
    /* If this manifest is private, mark it as such */
    blob_appendf(pOut, "T +private *\n");
  }
  if( azTag ){
    for(i=0; azTag[i]; i++){
      /* Add a symbolic tag to this check-in.  The tag names have already
      ** been sorted and converted using the %F format */
      blob_appendf(pOut, "T +sym-%s *\n", azTag[i]);
    }
  }







<
<
<
<







832
833
834
835
836
837
838




839
840
841
842
843
844
845
    blob_appendf(pOut, "T *branch * %F\n", zBranch);
    blob_appendf(pOut, "T *sym-%F *\n", zBranch);
  }
  if( zColor && zColor[0] ){
    /* One-time background color */
    blob_appendf(pOut, "T +bgcolor * %F\n", zColor);
  }




  if( azTag ){
    for(i=0; azTag[i]; i++){
      /* Add a symbolic tag to this check-in.  The tag names have already
      ** been sorted and converted using the %F format */
      blob_appendf(pOut, "T +sym-%s *\n", azTag[i]);
    }
  }
Changes to src/checkout.c.
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
**     2:   There is no existing checkout
*/
int unsaved_changes(void){
  int vid;
  db_must_be_within_tree();
  vid = db_lget_int("checkout",0);
  if( vid==0 ) return 2;
  vfile_check_signature(vid, 1, 0);
  return db_exists("SELECT 1 FROM vfile WHERE chnged"
                   " OR coalesce(origname!=pathname,0)");
}

/*
** Undo the current check-out.  Unlink all files from the disk.
** Clear the VFILE table.







|







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
**     2:   There is no existing checkout
*/
int unsaved_changes(void){
  int vid;
  db_must_be_within_tree();
  vid = db_lget_int("checkout",0);
  if( vid==0 ) return 2;
  vfile_check_signature(vid, CKSIG_ENOTFILE);
  return db_exists("SELECT 1 FROM vfile WHERE chnged"
                   " OR coalesce(origname!=pathname,0)");
}

/*
** Undo the current check-out.  Unlink all files from the disk.
** Clear the VFILE table.
Changes to src/content.c.
892
893
894
895
896
897
898
































    blob_reset(&content);
    n2++;
  }
  db_finalize(&q);
  fossil_print("%d non-phantom blobs (out of %d total) checked:  %d errors\n",
               n2, n1, nErr);
}







































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
    blob_reset(&content);
    n2++;
  }
  db_finalize(&q);
  fossil_print("%d non-phantom blobs (out of %d total) checked:  %d errors\n",
               n2, n1, nErr);
}

/*
** COMMAND: test-orphans
**
** Search the repository for orphaned artifacts
*/
void test_orphans(void){
  Stmt q;
  int cnt = 0;

  db_find_and_open_repository(0, 0);
  db_multi_exec(
    "CREATE TEMP TABLE used(id INTEGER PRIMARY KEY ON CONFLICT IGNORE);"
    "INSERT INTO used SELECT mid FROM mlink;"  /* Manifests */
    "INSERT INTO used SELECT fid FROM mlink;"  /* Files */
    "INSERT INTO used SELECT srcid FROM tagxref WHERE srcid>0;" /* Tags */
    "INSERT INTO used SELECT rid FROM tagxref;" /* Wiki & tickets */
    "INSERT INTO used SELECT rid FROM attachment JOIN blob ON src=uuid;"
    "INSERT INTO used SELECT attachid FROM attachment;"
    "INSERT INTO used SELECT objid FROM event;"
  );
  db_prepare(&q, "SELECT rid, uuid, size FROM blob WHERE rid NOT IN used");
  while( db_step(&q)==SQLITE_ROW ){
    fossil_print("%7d %s size: %d\n",
      db_column_int(&q, 0),
      db_column_text(&q, 1),
      db_column_int(&q,2));
    cnt++;
  }
  db_finalize(&q);
  fossil_print("%d orphans\n", cnt);
}
Changes to src/db.c.
674
675
676
677
678
679
680
















681
682
683
684
685
686
687
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  sqlite3_result_int64(context, time(0));
}


















/*
** Open a database file.  Return a pointer to the new database
** connection.  An error results in process abort.
*/
static sqlite3 *openDatabase(const char *zDbName){
  int rc;







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







674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  sqlite3_result_int64(context, time(0));
}

/*
** Function to return the check-in time for a file.
*/
void db_checkin_mtime_function(
  sqlite3_context *context,
  int argc,
  sqlite3_value **argv
){
  i64 mtime;
  int rc = mtime_of_manifest_file(sqlite3_value_int(argv[0]),
                                  sqlite3_value_int(argv[1]), &mtime);
  if( rc==0 ){
    sqlite3_result_int64(context, mtime);
  }
}


/*
** Open a database file.  Return a pointer to the new database
** connection.  An error results in process abort.
*/
static sqlite3 *openDatabase(const char *zDbName){
  int rc;
696
697
698
699
700
701
702


703
704
705
706
707
708
709
  );
  if( rc!=SQLITE_OK ){
    db_err(sqlite3_errmsg(db));
  }
  sqlite3_busy_timeout(db, 5000);
  sqlite3_wal_autocheckpoint(db, 1);  /* Set to checkpoint frequently */
  sqlite3_create_function(db, "now", 0, SQLITE_ANY, 0, db_now_function, 0, 0);


  return db;
}


/*
** Detaches the zLabel database.
*/







>
>







712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
  );
  if( rc!=SQLITE_OK ){
    db_err(sqlite3_errmsg(db));
  }
  sqlite3_busy_timeout(db, 5000);
  sqlite3_wal_autocheckpoint(db, 1);  /* Set to checkpoint frequently */
  sqlite3_create_function(db, "now", 0, SQLITE_ANY, 0, db_now_function, 0, 0);
  sqlite3_create_function(db, "checkin_mtime", 2, SQLITE_ANY, 0,
                          db_checkin_mtime_function, 0, 0);
  return db;
}


/*
** Detaches the zLabel database.
*/
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
}

/*
** zDbName is the name of a database file.  If no other database
** file is open, then open this one.  If another database file is
** already open, then attach zDbName using the name zLabel.
*/
static void db_open_or_attach(const char *zDbName, const char *zLabel){
  if( !g.db ){
    g.db = openDatabase(zDbName);
    g.zMainDbType = zLabel;
    db_connection_init();
  }else{
    db_attach(zDbName, zLabel);
  }







|







738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
}

/*
** zDbName is the name of a database file.  If no other database
** file is open, then open this one.  If another database file is
** already open, then attach zDbName using the name zLabel.
*/
void db_open_or_attach(const char *zDbName, const char *zLabel){
  if( !g.db ){
    g.db = openDatabase(zDbName);
    g.zMainDbType = zLabel;
    db_connection_init();
  }else{
    db_attach(zDbName, zLabel);
  }
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
  }
}

/*
** Return true if the string zVal represents "true" (or "false").
*/
int is_truth(const char *zVal){
  static const char *azOn[] = { "on", "yes", "true", "1" };
  int i;
  for(i=0; i<sizeof(azOn)/sizeof(azOn[0]); i++){
    if( fossil_stricmp(zVal,azOn[i])==0 ) return 1;
  }
  return 0;
}
int is_false(const char *zVal){
  static const char *azOff[] = { "off", "no", "false", "0" };
  int i;
  for(i=0; i<sizeof(azOff)/sizeof(azOff[0]); i++){
    if( fossil_stricmp(zVal,azOff[i])==0 ) return 1;
  }
  return 0;
}








|







|







1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
  }
}

/*
** Return true if the string zVal represents "true" (or "false").
*/
int is_truth(const char *zVal){
  static const char *const azOn[] = { "on", "yes", "true", "1" };
  int i;
  for(i=0; i<sizeof(azOn)/sizeof(azOn[0]); i++){
    if( fossil_stricmp(zVal,azOn[i])==0 ) return 1;
  }
  return 0;
}
int is_false(const char *zVal){
  static const char *const azOff[] = { "off", "no", "false", "0" };
  int i;
  for(i=0; i<sizeof(azOff)/sizeof(azOff[0]); i++){
    if( fossil_stricmp(zVal,azOff[i])==0 ) return 1;
  }
  return 0;
}

Changes to src/descendants.c.
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173

174
175
176
177
178
179
180
  }
}

/*
** Load the record ID rid and up to N-1 closest ancestors into
** the "ok" table.
*/
void compute_ancestors(int rid, int N){
  Bag seen;
  PQueue queue;
  Stmt ins;
  Stmt q;
  bag_init(&seen);
  pqueuex_init(&queue);
  bag_insert(&seen, rid);
  pqueuex_insert(&queue, rid, 0.0, 0);
  db_prepare(&ins, "INSERT OR IGNORE INTO ok VALUES(:rid)");
  db_prepare(&q,
    "SELECT a.pid, b.mtime FROM plink a LEFT JOIN plink b ON b.cid=a.pid"
    " WHERE a.cid=:rid"

  );
  while( (N--)>0 && (rid = pqueuex_extract(&queue, 0))!=0 ){
    db_bind_int(&ins, ":rid", rid);
    db_step(&ins);
    db_reset(&ins);
    db_bind_int(&q, ":rid", rid);
    while( db_step(&q)==SQLITE_ROW ){







|











|
>







154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
  }
}

/*
** Load the record ID rid and up to N-1 closest ancestors into
** the "ok" table.
*/
void compute_ancestors(int rid, int N, int directOnly){
  Bag seen;
  PQueue queue;
  Stmt ins;
  Stmt q;
  bag_init(&seen);
  pqueuex_init(&queue);
  bag_insert(&seen, rid);
  pqueuex_insert(&queue, rid, 0.0, 0);
  db_prepare(&ins, "INSERT OR IGNORE INTO ok VALUES(:rid)");
  db_prepare(&q,
    "SELECT a.pid, b.mtime FROM plink a LEFT JOIN plink b ON b.cid=a.pid"
    " WHERE a.cid=:rid %s",
    directOnly ? " AND a.isprim" : ""
  );
  while( (N--)>0 && (rid = pqueuex_extract(&queue, 0))!=0 ){
    db_bind_int(&ins, ":rid", rid);
    db_step(&ins);
    db_reset(&ins);
    db_bind_int(&q, ":rid", rid);
    while( db_step(&q)==SQLITE_ROW ){
200
201
202
203
204
205
206
207

208
209
210
211
212
213
214
** direct ancestor as the largest generation number.
*/
void compute_direct_ancestors(int rid, int N){
  Stmt ins;
  Stmt q;
  int gen = 0;
  db_multi_exec(
    "CREATE TEMP TABLE IF NOT EXISTS ancestor(rid INTEGER, generation INTEGER PRIMARY KEY);"

    "DELETE FROM ancestor;"
    "INSERT INTO ancestor VALUES(%d, 0);", rid
  );
  db_prepare(&ins, "INSERT INTO ancestor VALUES(:rid, :gen)");
  db_prepare(&q, 
    "SELECT pid FROM plink"
    " WHERE cid=:rid AND isprim"







|
>







201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
** direct ancestor as the largest generation number.
*/
void compute_direct_ancestors(int rid, int N){
  Stmt ins;
  Stmt q;
  int gen = 0;
  db_multi_exec(
    "CREATE TEMP TABLE IF NOT EXISTS ancestor(rid INTEGER,"
                                            " generation INTEGER PRIMARY KEY);"
    "DELETE FROM ancestor;"
    "INSERT INTO ancestor VALUES(%d, 0);", rid
  );
  db_prepare(&ins, "INSERT INTO ancestor VALUES(:rid, :gen)");
  db_prepare(&q, 
    "SELECT pid FROM plink"
    " WHERE cid=:rid AND isprim"
223
224
225
226
227
228
229


































230
231
232
233
234
235
236
    db_bind_int(&ins, ":gen", gen);
    db_step(&ins);
    db_reset(&ins);
  }
  db_finalize(&ins);
  db_finalize(&q);
}



































/*
** Load the record ID rid and up to N-1 closest descendants into
** the "ok" table.
*/
void compute_descendants(int rid, int N){
  Bag seen;







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







225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
    db_bind_int(&ins, ":gen", gen);
    db_step(&ins);
    db_reset(&ins);
  }
  db_finalize(&ins);
  db_finalize(&q);
}

/*
** Compute the "mtime" of the file given whose blob.rid is "fid" that
** is part of check-in "vid".  The mtime will be the mtime on vid or
** some ancestor of vid where fid first appears.
*/
int mtime_of_manifest_file(
  int vid,       /* The check-in that contains fid */
  int fid,       /* The id of the file whose check-in time is sought */
  i64 *pMTime    /* Write result here */
){
  static int prevVid = -1;
  static Stmt q;

  if( prevVid!=vid ){
    prevVid = vid;
    db_multi_exec("DROP TABLE IF EXISTS temp.ok;"
                  "CREATE TEMP TABLE ok(x INTEGER PRIMARY KEY);");
    compute_ancestors(vid, 100000000, 1);
  }
  db_static_prepare(&q,
    "SELECT (max(event.mtime)-2440587.5)*86400 FROM mlink, event"
    " WHERE mlink.mid=event.objid"
    "   AND +mlink.mid IN ok"
    "   AND mlink.fid=:fid");
  db_bind_int(&q, ":fid", fid);
  if( db_step(&q)!=SQLITE_ROW ){
    db_reset(&q);
    return 1;
  }
  *pMTime = db_column_int64(&q, 0);
  db_reset(&q);
  return 0;
}

/*
** Load the record ID rid and up to N-1 closest descendants into
** the "ok" table.
*/
void compute_descendants(int rid, int N){
  Bag seen;
Changes to src/diffcmd.c.
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
  int vid;
  Blob sql;
  Stmt q;
  int asNewFile;            /* Treat non-existant files as empty files */

  asNewFile = (diffFlags & DIFF_NEWFILE)!=0;
  vid = db_lget_int("checkout", 0);
  vfile_check_signature(vid, 1, 0);
  blob_zero(&sql);
  db_begin_transaction();
  if( zFrom ){
    int rid = name_to_typed_rid(zFrom, "ci");
    if( !is_a_version(rid) ){
      fossil_fatal("no such check-in: %s", zFrom);
    }







|







320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
  int vid;
  Blob sql;
  Stmt q;
  int asNewFile;            /* Treat non-existant files as empty files */

  asNewFile = (diffFlags & DIFF_NEWFILE)!=0;
  vid = db_lget_int("checkout", 0);
  vfile_check_signature(vid, CKSIG_ENOTFILE);
  blob_zero(&sql);
  db_begin_transaction();
  if( zFrom ){
    int rid = name_to_typed_rid(zFrom, "ci");
    if( !is_a_version(rid) ){
      fossil_fatal("no such check-in: %s", zFrom);
    }
Changes to src/file.c.
32
33
34
35
36
37
38

39
40
41
42
43
44
45

/*
** On Windows, include the Platform SDK header file.
*/
#ifdef _WIN32
# include <direct.h>
# include <windows.h>

#endif

/*
** The file status information from the most recent stat() call.
**
** Use _stati64 rather than stat on windows, in order to handle files
** larger than 2GB.







>







32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

/*
** On Windows, include the Platform SDK header file.
*/
#ifdef _WIN32
# include <direct.h>
# include <windows.h>
# include <sys/utime.h>
#endif

/*
** The file status information from the most recent stat() call.
**
** Use _stati64 rather than stat on windows, in order to handle files
** larger than 2GB.
387
388
389
390
391
392
393











































394
395
396
397
398
399
400
      chmod(zFilename, buf.st_mode & ~0111);
      rc = 1;
    }
  }
#endif /* _WIN32 */
  return rc;
}












































/*
** Delete a file.
*/
void file_delete(const char *zFilename){
#ifdef _WIN32
  wchar_t *z = fossil_utf8_to_unicode(zFilename);







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







388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
      chmod(zFilename, buf.st_mode & ~0111);
      rc = 1;
    }
  }
#endif /* _WIN32 */
  return rc;
}

/*
** Set the mtime for a file.
*/
void file_set_mtime(const char *zFilename, i64 newMTime){
#if !defined(_WIN32)
  struct timeval tv[2];
  memset(tv, 0, sizeof(tv[0])*2);
  tv[0].tv_sec = newMTime;
  tv[1].tv_sec = newMTime;
  utimes(zFilename, tv);
#else
  struct _utimbuf tb;
  wchar_t *zMbcs = fossil_utf8_to_unicode(zFilename);
  tb.actime = newMTime;
  tb.modtime = newMTime;
  _wutime(zMbcs, &tb);
  fossil_mbcs_free(zMbcs);
#endif
}

/*
** COMMAND: test-set-mtime
**
** Usage: %fossil test-set-mtime FILENAME DATE/TIME
**
** Sets the mtime of the named file to the date/time shown.
*/
void test_set_mtime(void){
  const char *zFile;
  char *zDate;
  i64 iMTime;
  if( g.argc!=4 ){
    usage("test-set-mtime FILENAME DATE/TIME");
  }
  db_open_or_attach(":memory:", "mem");
  iMTime = db_int64(0, "SELECT strftime('%%s',%Q)", g.argv[3]);
  zFile = g.argv[2];
  file_set_mtime(zFile, iMTime);
  iMTime = file_wd_mtime(zFile);
  zDate = db_text(0, "SELECT datetime(%lld, 'unixepoch')", iMTime);
  fossil_print("Set mtime of \"%s\" to %s (%lld)\n", zFile, zDate, iMTime);
}

/*
** Delete a file.
*/
void file_delete(const char *zFilename){
#ifdef _WIN32
  wchar_t *z = fossil_utf8_to_unicode(zFilename);
Changes to src/finfo.c.
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
    int vid;

    if( g.argc!=3 ) usage("-s|--status FILENAME");
    vid = db_lget_int("checkout", 0);
    if( vid==0 ){
      fossil_panic("no checkout to finfo files in");
    }
    vfile_check_signature(vid, 1, 0);
    file_tree_name(g.argv[2], &fname, 1);
    db_prepare(&q,
        "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)"
        "  FROM vfile WHERE vfile.pathname=%B %s",
        &fname, filename_collation());
    blob_zero(&line);
    if ( db_step(&q)==SQLITE_ROW ) {







|







64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
    int vid;

    if( g.argc!=3 ) usage("-s|--status FILENAME");
    vid = db_lget_int("checkout", 0);
    if( vid==0 ){
      fossil_panic("no checkout to finfo files in");
    }
    vfile_check_signature(vid, CKSIG_ENOTFILE);
    file_tree_name(g.argv[2], &fname, 1);
    db_prepare(&q,
        "SELECT pathname, deleted, rid, chnged, coalesce(origname!=pathname,0)"
        "  FROM vfile WHERE vfile.pathname=%B %s",
        &fname, filename_collation());
    blob_zero(&line);
    if ( db_step(&q)==SQLITE_ROW ) {
Changes to src/info.c.
628
629
630
631
632
633
634

635
636
637
638
639
640
641
        @         ZIP archive</a>
        fossil_free(zUrl);
      }
      @ </td></tr>
      @ <tr><th>Other&nbsp;Links:</th>
      @   <td>
      @     %z(href("%R/dir?ci=%S",zUuid))files</a>

      @   | %z(href("%R/artifact/%S",zUuid))manifest</a>
      if( g.perm.Write ){
        @   | %z(href("%R/ci_edit?r=%S",zUuid))edit</a>
      }
      @   </td>
      @ </tr>
    }







>







628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
        @         ZIP archive</a>
        fossil_free(zUrl);
      }
      @ </td></tr>
      @ <tr><th>Other&nbsp;Links:</th>
      @   <td>
      @     %z(href("%R/dir?ci=%S",zUuid))files</a>
      @   | %z(href("%R/fileage?name=%S",zUuid))file ages</a>
      @   | %z(href("%R/artifact/%S",zUuid))manifest</a>
      if( g.perm.Write ){
        @   | %z(href("%R/ci_edit?r=%S",zUuid))edit</a>
      }
      @   </td>
      @ </tr>
    }
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
    }else if( pFileTo==0 ){
      cmp = -1;
    }else{
      cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName);
    }
    if( cmp<0 ){
      append_file_change_line(pFileFrom->zName, 
                              pFileFrom->zUuid, 0, 0, 0, 0);
      pFileFrom = manifest_file_next(pFrom, 0);
    }else if( cmp>0 ){
      append_file_change_line(pFileTo->zName, 
                              0, pFileTo->zUuid, 0, 0,
                              manifest_file_mperm(pFileTo));
      pFileTo = manifest_file_next(pTo, 0);
    }else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){
      /* No changes */
      pFileFrom = manifest_file_next(pFrom, 0);
      pFileTo = manifest_file_next(pTo, 0);
    }else{







|



|







965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
    }else if( pFileTo==0 ){
      cmp = -1;
    }else{
      cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName);
    }
    if( cmp<0 ){
      append_file_change_line(pFileFrom->zName, 
                              pFileFrom->zUuid, 0, 0, diffFlags, 0);
      pFileFrom = manifest_file_next(pFrom, 0);
    }else if( cmp>0 ){
      append_file_change_line(pFileTo->zName, 
                              0, pFileTo->zUuid, 0, diffFlags,
                              manifest_file_mperm(pFileTo));
      pFileTo = manifest_file_next(pTo, 0);
    }else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){
      /* No changes */
      pFileFrom = manifest_file_next(pFrom, 0);
      pFileTo = manifest_file_next(pTo, 0);
    }else{
1302
1303
1304
1305
1306
1307
1308






1309
1310
1311
1312
1313
1314
1315
  if( !g.perm.Read ){ login_needed(); return; }
  if( rid==0 ) fossil_redirect_home();
  zMime = P("m");
  if( zMime==0 ){
    char *zFName = db_text(0, "SELECT filename.name FROM mlink, filename"
                              " WHERE mlink.fid=%d"
                              "   AND filename.fnid=mlink.fnid", rid);






    if( zFName ) zMime = mimetype_from_name(zFName);
    if( zMime==0 ) zMime = "application/x-fossil-artifact";
  }
  content_get(rid, &content);
  cgi_set_content_type(zMime);
  cgi_set_content(&content);
}







>
>
>
>
>
>







1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
  if( !g.perm.Read ){ login_needed(); return; }
  if( rid==0 ) fossil_redirect_home();
  zMime = P("m");
  if( zMime==0 ){
    char *zFName = db_text(0, "SELECT filename.name FROM mlink, filename"
                              " WHERE mlink.fid=%d"
                              "   AND filename.fnid=mlink.fnid", rid);
    if( !zFName ){
      /* Look also at the attachment table */
      zFName = db_text(0, "SELECT attachment.filename FROM attachment, blob"
                          " WHERE blob.rid=%d"
                          "   AND attachment.src=blob.uuid", rid);
    }
    if( zFName ) zMime = mimetype_from_name(zFName);
    if( zMime==0 ) zMime = "application/x-fossil-artifact";
  }
  content_get(rid, &content);
  cgi_set_content_type(zMime);
  cgi_set_content(&content);
}
Changes to src/main.c.
553
554
555
556
557
558
559

560
561
562
563
564
565
566
567
568
569
570
571
572

573
574
575
576
577
578
579
  i += 2;
  while( i<g.argc ) newArgv[j++] = g.argv[i++];
  newArgv[j] = 0;
  g.argc = j;
  g.argv = newArgv;
}


/*
** Make a deep copy of the provided argument array and return it.
*/
static char **copy_args(int argc, char **argv){
  char **zNewArgv;
  int i;
  zNewArgv = fossil_malloc( sizeof(char*)*(argc+1) );
  memset(zNewArgv, 0, sizeof(char*)*(argc+1));
  for(i=0; i<argc; i++){
    zNewArgv[i] = fossil_strdup(argv[i]);
  }
  return zNewArgv;
}


/*
** This procedure runs first.
*/
int main(int argc, char **argv)
{
  const char *zCmdName = "unknown";







>













>







553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
  i += 2;
  while( i<g.argc ) newArgv[j++] = g.argv[i++];
  newArgv[j] = 0;
  g.argc = j;
  g.argv = newArgv;
}

#ifdef FOSSIL_ENABLE_TCL
/*
** Make a deep copy of the provided argument array and return it.
*/
static char **copy_args(int argc, char **argv){
  char **zNewArgv;
  int i;
  zNewArgv = fossil_malloc( sizeof(char*)*(argc+1) );
  memset(zNewArgv, 0, sizeof(char*)*(argc+1));
  for(i=0; i<argc; i++){
    zNewArgv[i] = fossil_strdup(argv[i]);
  }
  return zNewArgv;
}
#endif

/*
** This procedure runs first.
*/
int main(int argc, char **argv)
{
  const char *zCmdName = "unknown";
Changes to src/merge.c.
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
                 " Use --force to override.\n");
    return;
  }
  if( detailFlag ){
    print_checkin_description(mid, 12, "merge-from:");
    print_checkin_description(pid, 12, "baseline:");
  }
  vfile_check_signature(vid, 1, 0);
  db_begin_transaction();
  if( !nochangeFlag ) undo_begin();
  load_vfile_from_rid(mid);
  load_vfile_from_rid(pid);
  if( debugFlag ){
    char *z;
    z = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", pid);







|







187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
                 " Use --force to override.\n");
    return;
  }
  if( detailFlag ){
    print_checkin_description(mid, 12, "merge-from:");
    print_checkin_description(pid, 12, "baseline:");
  }
  vfile_check_signature(vid, CKSIG_ENOTFILE);
  db_begin_transaction();
  if( !nochangeFlag ) undo_begin();
  load_vfile_from_rid(mid);
  load_vfile_from_rid(pid);
  if( debugFlag ){
    char *z;
    z = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", pid);
Changes to src/name.c.
251
252
253
254
255
256
257



258
259
260
261
262

263
264
265
266
267
268
269
    zTag, zType
  );
  if( rid>0 ) return rid;

  /* Undocumented:  numeric tags get translated directly into the RID */
  for(i=0; fossil_isdigit(zTag[i]); i++){}
  if( zTag[i]==0 ){



    rid = db_int(0, 
      "SELECT event.objid"
      "  FROM event"
      " WHERE event.objid=%s"
      "   AND event.type GLOB '%q'", zTag, zType);

  }
  return rid;
}


/*
** This routine takes a user-entered UUID which might be in mixed







>
>
>
|
|
|
|
|
>







251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
    zTag, zType
  );
  if( rid>0 ) return rid;

  /* Undocumented:  numeric tags get translated directly into the RID */
  for(i=0; fossil_isdigit(zTag[i]); i++){}
  if( zTag[i]==0 ){
    if( strcmp(zType,"*")==0 ){
      rid = atoi(zTag);
    }else{
      rid = db_int(0, 
        "SELECT event.objid"
        "  FROM event"
        " WHERE event.objid=%s"
        "   AND event.type GLOB '%q'", zTag, zType);
    }
  }
  return rid;
}


/*
** This routine takes a user-entered UUID which might be in mixed
Changes to src/rebuild.c.
923
924
925
926
927
928
929

930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957













958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985

986
987
988
989
990
991
992
993
994
995
996
997
998
999

1000
1001
1002
1003
1004
1005
1006
** If -L|--prefixlength is given, the length (default 2) of the directory
** prefix can be set to 0,1,..,9 characters.
** 
** Options:
**   -R|--repository REPOSITORY  deconstruct given REPOSITORY
**   -L|--prefixlength N         set the length of the names of the DESTINATION
**                               subdirectories to N

**
** See also: rebuild, reconstruct
*/
void deconstruct_cmd(void){
  const char *zDestDir;
  const char *zPrefixOpt;
  Stmt        s;

  /* check number of arguments */
  if( (g.argc != 3) && (g.argc != 5)  && (g.argc != 7)){
    usage ("?-R|--repository REPOSITORY? ?-L|--prefixlength N? DESTINATION");
  }
  /* get and check argument destination directory */
  zDestDir = g.argv[g.argc-1];
  if( !*zDestDir  || !file_isdir(zDestDir)) {
    fossil_panic("DESTINATION(%s) is not a directory!",zDestDir);
  }
  /* get and check prefix length argument and build format string */
  zPrefixOpt=find_option("prefixlength","L",1);
  if( !zPrefixOpt ){
    prefixLength = 2;
  }else{
    if( zPrefixOpt[0]>='0' && zPrefixOpt[0]<='9' && !zPrefixOpt[1] ){
      prefixLength = (int)(*zPrefixOpt-'0');
    }else{
      fossil_fatal("N(%s) is not a a valid prefix length!",zPrefixOpt);
    }
  }













#ifndef _WIN32
  if( file_access(zDestDir, W_OK) ){
    fossil_fatal("DESTINATION(%s) is not writeable!",zDestDir);
  }
#else
  /* write access on windows is not checked, errors will be
  ** dected on blob_write_to_file
  */
#endif
  if( prefixLength ){
    zFNameFormat = mprintf("%s/%%.%ds/%%s",zDestDir,prefixLength);
  }else{
    zFNameFormat = mprintf("%s/%%s",zDestDir);
  }
  /* open repository and open query for all artifacts */
  db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
  bag_init(&bagDone);
  ttyOutput = 1;
  processCnt = 0;
  if (!g.fQuiet) {
    fossil_print("0 (0%%)...\r");
    fflush(stdout);
  }
  totalSize = db_int(0, "SELECT count(*) FROM blob");
  db_prepare(&s,
     "SELECT rid, size FROM blob /*scan*/"
     " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)"
     "   AND NOT EXISTS(SELECT 1 FROM delta WHERE rid=blob.rid)"

  );
  while( db_step(&s)==SQLITE_ROW ){
    int rid = db_column_int(&s, 0);
    int size = db_column_int(&s, 1);
    if( size>=0 ){
      Blob content;
      content_get(rid, &content);
      rebuild_step(rid, size, &content);
    }
  }
  db_finalize(&s);
  db_prepare(&s,
     "SELECT rid, size FROM blob"
     " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)"

  );
  while( db_step(&s)==SQLITE_ROW ){
    int rid = db_column_int(&s, 0);
    int size = db_column_int(&s, 1);
    if( size>=0 ){
      if( !bag_find(&bagDone, rid) ){
        Blob content;







>







|
<
<
<
|
<
<
<
<
<











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














|
<











|
>













|
>







923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938



939





940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978

979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
** If -L|--prefixlength is given, the length (default 2) of the directory
** prefix can be set to 0,1,..,9 characters.
** 
** Options:
**   -R|--repository REPOSITORY  deconstruct given REPOSITORY
**   -L|--prefixlength N         set the length of the names of the DESTINATION
**                               subdirectories to N
**   --private                   Include private artifacts.
**
** See also: rebuild, reconstruct
*/
void deconstruct_cmd(void){
  const char *zDestDir;
  const char *zPrefixOpt;
  Stmt        s;
  int privateFlag;









  /* get and check prefix length argument and build format string */
  zPrefixOpt=find_option("prefixlength","L",1);
  if( !zPrefixOpt ){
    prefixLength = 2;
  }else{
    if( zPrefixOpt[0]>='0' && zPrefixOpt[0]<='9' && !zPrefixOpt[1] ){
      prefixLength = (int)(*zPrefixOpt-'0');
    }else{
      fossil_fatal("N(%s) is not a a valid prefix length!",zPrefixOpt);
    }
  }
  /* open repository and open query for all artifacts */
  db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
  privateFlag = find_option("private",0,0)!=0;
  verify_all_options();
  /* check number of arguments */
  if( g.argc!=3 ){
    usage ("?OPTIONS? DESTINATION");
  }
  /* get and check argument destination directory */
  zDestDir = g.argv[g.argc-1];
  if( !*zDestDir  || !file_isdir(zDestDir)) {
    fossil_fatal("DESTINATION(%s) is not a directory!",zDestDir);
  }
#ifndef _WIN32
  if( file_access(zDestDir, W_OK) ){
    fossil_fatal("DESTINATION(%s) is not writeable!",zDestDir);
  }
#else
  /* write access on windows is not checked, errors will be
  ** dected on blob_write_to_file
  */
#endif
  if( prefixLength ){
    zFNameFormat = mprintf("%s/%%.%ds/%%s",zDestDir,prefixLength);
  }else{
    zFNameFormat = mprintf("%s/%%s",zDestDir);
  }


  bag_init(&bagDone);
  ttyOutput = 1;
  processCnt = 0;
  if (!g.fQuiet) {
    fossil_print("0 (0%%)...\r");
    fflush(stdout);
  }
  totalSize = db_int(0, "SELECT count(*) FROM blob");
  db_prepare(&s,
     "SELECT rid, size FROM blob /*scan*/"
     " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)"
     "   AND NOT EXISTS(SELECT 1 FROM delta WHERE rid=blob.rid) %s",
     privateFlag==0 ? "AND rid NOT IN private" : ""
  );
  while( db_step(&s)==SQLITE_ROW ){
    int rid = db_column_int(&s, 0);
    int size = db_column_int(&s, 1);
    if( size>=0 ){
      Blob content;
      content_get(rid, &content);
      rebuild_step(rid, size, &content);
    }
  }
  db_finalize(&s);
  db_prepare(&s,
     "SELECT rid, size FROM blob"
     " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid) %s",
     privateFlag==0 ? "AND rid NOT IN private" : ""
  );
  while( db_step(&s)==SQLITE_ROW ){
    int rid = db_column_int(&s, 0);
    int size = db_column_int(&s, 1);
    if( size>=0 ){
      if( !bag_find(&bagDone, rid) ){
        Blob content;
Changes to src/report.c.
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
  }
  switch( code ){
    case SQLITE_SELECT:
    case SQLITE_FUNCTION: {
      break;
    }
    case SQLITE_READ: {
      static const char *azAllowed[] = {
         "ticket",
         "blob",
         "filename",
         "mlink",
         "plink",
         "event",
         "tag",







|







168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
  }
  switch( code ){
    case SQLITE_SELECT:
    case SQLITE_FUNCTION: {
      break;
    }
    case SQLITE_READ: {
      static const char *const azAllowed[] = {
         "ticket",
         "blob",
         "filename",
         "mlink",
         "plink",
         "event",
         "tag",
Changes to src/sqlcmd.c.
141
142
143
144
145
146
147

148
149
150
151
152
153
154
*/
void sqlite3_cmd(void){
  extern int sqlite3_shell(int, char**);
  db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
  db_close(1);
  sqlite3_shutdown();
  sqlite3_shell(g.argc-1, g.argv+1);

}

/*
** This routine is called by the patched sqlite3 command-line shell in order
** to load the name and database connection for the open Fossil database.
*/
void fossil_open(const char **pzRepoName){







>







141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
*/
void sqlite3_cmd(void){
  extern int sqlite3_shell(int, char**);
  db_find_and_open_repository(OPEN_ANY_SCHEMA, 0);
  db_close(1);
  sqlite3_shutdown();
  sqlite3_shell(g.argc-1, g.argv+1);
  g.db = 0;
}

/*
** This routine is called by the patched sqlite3 command-line shell in order
** to load the name and database connection for the open Fossil database.
*/
void fossil_open(const char **pzRepoName){
Changes to src/sqlite3.c.
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
**
** See also: [sqlite3_libversion()],
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION        "3.7.15"
#define SQLITE_VERSION_NUMBER 3007015
#define SQLITE_SOURCE_ID      "2012-10-07 14:14:44 bbb0d189b7b6aecfc0e0b6c2bcd9f49aaea8c34a"

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







|







671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
**
** See also: [sqlite3_libversion()],
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION        "3.7.15"
#define SQLITE_VERSION_NUMBER 3007015
#define SQLITE_SOURCE_ID      "2012-10-16 23:08:28 f021559d8a23934e3bdccad5b55fc7a91d185f53"

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


8464
8465
8466
8467
8468
8469
8470
SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree*, int, int*);
SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree*, int, int*);
SQLITE_PRIVATE void sqlite3BtreeTripAllCursors(Btree*, int);

SQLITE_PRIVATE void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue);
SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value);



/*
** The second parameter to sqlite3BtreeGetMeta or sqlite3BtreeUpdateMeta
** should be one of the following values. The integer values are assigned 
** to constants so that the offset of the corresponding field in an
** SQLite database header may be found using the following formula:
**
**   offset = 36 + (idx * 4)







>
>







8457
8458
8459
8460
8461
8462
8463
8464
8465
8466
8467
8468
8469
8470
8471
8472
SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree*, int, int*);
SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree*, int, int*);
SQLITE_PRIVATE void sqlite3BtreeTripAllCursors(Btree*, int);

SQLITE_PRIVATE void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue);
SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value);

SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p);

/*
** The second parameter to sqlite3BtreeGetMeta or sqlite3BtreeUpdateMeta
** should be one of the following values. The integer values are assigned 
** to constants so that the offset of the corresponding field in an
** SQLite database header may be found using the following formula:
**
**   offset = 36 + (idx * 4)
9161
9162
9163
9164
9165
9166
9167

9168
9169
9170
9171
9172


9173
9174
9175
9176
9177
9178
9179
SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager);
SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager*);
SQLITE_PRIVATE int sqlite3PagerRollback(Pager*);
SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int n);
SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint);
SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager);


SQLITE_PRIVATE int sqlite3PagerCheckpoint(Pager *pPager, int, int*, int*);
SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager);
SQLITE_PRIVATE int sqlite3PagerWalCallback(Pager *pPager);
SQLITE_PRIVATE int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
SQLITE_PRIVATE int sqlite3PagerCloseWal(Pager *pPager);


#ifdef SQLITE_ENABLE_ZIPVFS
SQLITE_PRIVATE   int sqlite3PagerWalFramesize(Pager *pPager);
#endif

/* Functions used to query pager state and configuration. */
SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager*);
SQLITE_PRIVATE int sqlite3PagerRefcount(Pager*);







>
|
|
|
|
|
>
>







9163
9164
9165
9166
9167
9168
9169
9170
9171
9172
9173
9174
9175
9176
9177
9178
9179
9180
9181
9182
9183
9184
SQLITE_PRIVATE int sqlite3PagerSync(Pager *pPager);
SQLITE_PRIVATE int sqlite3PagerCommitPhaseTwo(Pager*);
SQLITE_PRIVATE int sqlite3PagerRollback(Pager*);
SQLITE_PRIVATE int sqlite3PagerOpenSavepoint(Pager *pPager, int n);
SQLITE_PRIVATE int sqlite3PagerSavepoint(Pager *pPager, int op, int iSavepoint);
SQLITE_PRIVATE int sqlite3PagerSharedLock(Pager *pPager);

#ifndef SQLITE_OMIT_WAL
SQLITE_PRIVATE   int sqlite3PagerCheckpoint(Pager *pPager, int, int*, int*);
SQLITE_PRIVATE   int sqlite3PagerWalSupported(Pager *pPager);
SQLITE_PRIVATE   int sqlite3PagerWalCallback(Pager *pPager);
SQLITE_PRIVATE   int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
SQLITE_PRIVATE   int sqlite3PagerCloseWal(Pager *pPager);
#endif

#ifdef SQLITE_ENABLE_ZIPVFS
SQLITE_PRIVATE   int sqlite3PagerWalFramesize(Pager *pPager);
#endif

/* Functions used to query pager state and configuration. */
SQLITE_PRIVATE u8 sqlite3PagerIsreadonly(Pager*);
SQLITE_PRIVATE int sqlite3PagerRefcount(Pager*);
12239
12240
12241
12242
12243
12244
12245

12246
12247

12248
12249
12250
12251
12252
12253
12254
SQLITE_PRIVATE int sqlite3VdbeParameterIndex(Vdbe*, const char*, int);
SQLITE_PRIVATE int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *);
SQLITE_PRIVATE int sqlite3Reprepare(Vdbe*);
SQLITE_PRIVATE void sqlite3ExprListCheckLength(Parse*, ExprList*, const char*);
SQLITE_PRIVATE CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *);
SQLITE_PRIVATE int sqlite3TempInMemory(const sqlite3*);
SQLITE_PRIVATE const char *sqlite3JournalModename(int);

SQLITE_PRIVATE int sqlite3Checkpoint(sqlite3*, int, int, int*, int*);
SQLITE_PRIVATE int sqlite3WalDefaultHook(void*,sqlite3*,const char*,int);


/* Declarations for functions in fkey.c. All of these are replaced by
** no-op macros if OMIT_FOREIGN_KEY is defined. In this case no foreign
** key functionality is available. If OMIT_TRIGGER is defined but
** OMIT_FOREIGN_KEY is not, only some of the functions are no-oped. In
** this case foreign keys are parsed, but no other functionality is 
** provided (enforcement of FK constraints requires the triggers sub-system).







>
|
|
>







12244
12245
12246
12247
12248
12249
12250
12251
12252
12253
12254
12255
12256
12257
12258
12259
12260
12261
SQLITE_PRIVATE int sqlite3VdbeParameterIndex(Vdbe*, const char*, int);
SQLITE_PRIVATE int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *);
SQLITE_PRIVATE int sqlite3Reprepare(Vdbe*);
SQLITE_PRIVATE void sqlite3ExprListCheckLength(Parse*, ExprList*, const char*);
SQLITE_PRIVATE CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *);
SQLITE_PRIVATE int sqlite3TempInMemory(const sqlite3*);
SQLITE_PRIVATE const char *sqlite3JournalModename(int);
#ifndef SQLITE_OMIT_WAL
SQLITE_PRIVATE   int sqlite3Checkpoint(sqlite3*, int, int, int*, int*);
SQLITE_PRIVATE   int sqlite3WalDefaultHook(void*,sqlite3*,const char*,int);
#endif

/* Declarations for functions in fkey.c. All of these are replaced by
** no-op macros if OMIT_FOREIGN_KEY is defined. In this case no foreign
** key functionality is available. If OMIT_TRIGGER is defined but
** OMIT_FOREIGN_KEY is not, only some of the functions are no-oped. In
** this case foreign keys are parsed, but no other functionality is 
** provided (enforcement of FK constraints requires the triggers sub-system).
24940
24941
24942
24943
24944
24945
24946
24947
24948
24949
24950
24951
24952
24953

24954
24955
24956
24957
24958
24959
24960
  return SQLITE_OK;
}

/*
** Close a file.  Make sure the lock has been released before closing.
*/
static int dotlockClose(sqlite3_file *id) {
  int rc;
  if( id ){
    unixFile *pFile = (unixFile*)id;
    dotlockUnlock(id, NO_LOCK);
    sqlite3_free(pFile->lockingContext);
  }
  rc = closeUnixFile(id);

  return rc;
}
/****************** End of the dot-file lock implementation *******************
******************************************************************************/

/******************************************************************************
************************** Begin flock Locking ********************************







|




<
|
>







24947
24948
24949
24950
24951
24952
24953
24954
24955
24956
24957
24958

24959
24960
24961
24962
24963
24964
24965
24966
24967
  return SQLITE_OK;
}

/*
** Close a file.  Make sure the lock has been released before closing.
*/
static int dotlockClose(sqlite3_file *id) {
  int rc = SQLITE_OK;
  if( id ){
    unixFile *pFile = (unixFile*)id;
    dotlockUnlock(id, NO_LOCK);
    sqlite3_free(pFile->lockingContext);

    rc = closeUnixFile(id);
  }
  return rc;
}
/****************** End of the dot-file lock implementation *******************
******************************************************************************/

/******************************************************************************
************************** Begin flock Locking ********************************
25150
25151
25152
25153
25154
25155
25156

25157
25158

25159
25160
25161
25162
25163
25164
25165
25166
25167
  }
}

/*
** Close a file.
*/
static int flockClose(sqlite3_file *id) {

  if( id ){
    flockUnlock(id, NO_LOCK);

  }
  return closeUnixFile(id);
}

#endif /* SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORK */

/******************* End of the flock lock implementation *********************
******************************************************************************/








>


>

|







25157
25158
25159
25160
25161
25162
25163
25164
25165
25166
25167
25168
25169
25170
25171
25172
25173
25174
25175
25176
  }
}

/*
** Close a file.
*/
static int flockClose(sqlite3_file *id) {
  int rc = SQLITE_OK;
  if( id ){
    flockUnlock(id, NO_LOCK);
    rc = closeUnixFile(id);
  }
  return rc;
}

#endif /* SQLITE_ENABLE_LOCKING_STYLE && !OS_VXWORK */

/******************* End of the flock lock implementation *********************
******************************************************************************/

26952
26953
26954
26955
26956
26957
26958
26959
26960
26961
26962
26963
26964
26965
26966
    }
    pShmNode->apRegion = apNew;
    while(pShmNode->nRegion<=iRegion){
      void *pMem;
      if( pShmNode->h>=0 ){
        pMem = mmap(0, szRegion,
            pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE, 
            MAP_SHARED, pShmNode->h, pShmNode->nRegion*szRegion
        );
        if( pMem==MAP_FAILED ){
          rc = unixLogError(SQLITE_IOERR_SHMMAP, "mmap", pShmNode->zFilename);
          goto shmpage_out;
        }
      }else{
        pMem = sqlite3_malloc(szRegion);







|







26961
26962
26963
26964
26965
26966
26967
26968
26969
26970
26971
26972
26973
26974
26975
    }
    pShmNode->apRegion = apNew;
    while(pShmNode->nRegion<=iRegion){
      void *pMem;
      if( pShmNode->h>=0 ){
        pMem = mmap(0, szRegion,
            pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE, 
            MAP_SHARED, pShmNode->h, szRegion*(i64)pShmNode->nRegion
        );
        if( pMem==MAP_FAILED ){
          rc = unixLogError(SQLITE_IOERR_SHMMAP, "mmap", pShmNode->zFilename);
          goto shmpage_out;
        }
      }else{
        pMem = sqlite3_malloc(szRegion);
29991
29992
29993
29994
29995
29996
29997



















































29998
29999
30000
30001
30002
30003
30004
** available in Windows platforms based on the NT kernel.
*/
#if !SQLITE_OS_WINNT && !defined(SQLITE_OMIT_WAL)
# error "WAL mode requires support from the Windows NT kernel, compile\
 with SQLITE_OMIT_WAL."
#endif




















































/*
** Macro to find the minimum of two numeric values.
*/
#ifndef MIN
# define MIN(x,y) ((x)<(y)?(x):(y))
#endif








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







30000
30001
30002
30003
30004
30005
30006
30007
30008
30009
30010
30011
30012
30013
30014
30015
30016
30017
30018
30019
30020
30021
30022
30023
30024
30025
30026
30027
30028
30029
30030
30031
30032
30033
30034
30035
30036
30037
30038
30039
30040
30041
30042
30043
30044
30045
30046
30047
30048
30049
30050
30051
30052
30053
30054
30055
30056
30057
30058
30059
30060
30061
30062
30063
30064
** available in Windows platforms based on the NT kernel.
*/
#if !SQLITE_OS_WINNT && !defined(SQLITE_OMIT_WAL)
# error "WAL mode requires support from the Windows NT kernel, compile\
 with SQLITE_OMIT_WAL."
#endif

/*
** Are most of the Win32 ANSI APIs available (i.e. with certain exceptions
** based on the sub-platform)?
*/
#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
#  define SQLITE_WIN32_HAS_ANSI
#endif

/*
** Are most of the Win32 Unicode APIs available (i.e. with certain exceptions
** based on the sub-platform)?
*/
#if SQLITE_OS_WINCE || SQLITE_OS_WINNT || SQLITE_OS_WINRT
#  define SQLITE_WIN32_HAS_WIDE
#endif

/*
** Do we need to manually define the Win32 file mapping APIs for use with WAL
** mode (e.g. these APIs are available in the Windows CE SDK; however, they
** are not present in the header file)?
*/
#if SQLITE_WIN32_FILEMAPPING_API && !defined(SQLITE_OMIT_WAL)
/*
** Two of the file mapping APIs are different under WinRT.  Figure out which
** set we need.
*/
#if SQLITE_OS_WINRT
WINBASEAPI HANDLE WINAPI CreateFileMappingFromApp(HANDLE, \
        LPSECURITY_ATTRIBUTES, ULONG, ULONG64, LPCWSTR);

WINBASEAPI LPVOID WINAPI MapViewOfFileFromApp(HANDLE, ULONG, ULONG64, SIZE_T);
#else
#if defined(SQLITE_WIN32_HAS_ANSI)
WINBASEAPI HANDLE WINAPI CreateFileMappingA(HANDLE, LPSECURITY_ATTRIBUTES, \
        DWORD, DWORD, DWORD, LPCSTR);
#endif /* defined(SQLITE_WIN32_HAS_ANSI) */

#if defined(SQLITE_WIN32_HAS_WIDE)
WINBASEAPI HANDLE WINAPI CreateFileMappingW(HANDLE, LPSECURITY_ATTRIBUTES, \
        DWORD, DWORD, DWORD, LPCWSTR);
#endif /* defined(SQLITE_WIN32_HAS_WIDE) */

WINBASEAPI LPVOID WINAPI MapViewOfFile(HANDLE, DWORD, DWORD, DWORD, SIZE_T);
#endif /* SQLITE_OS_WINRT */

/*
** This file mapping API is common to both Win32 and WinRT.
*/
WINBASEAPI BOOL WINAPI UnmapViewOfFile(LPCVOID);
#endif /* SQLITE_WIN32_FILEMAPPING_API && !defined(SQLITE_OMIT_WAL) */

/*
** Macro to find the minimum of two numeric values.
*/
#ifndef MIN
# define MIN(x,y) ((x)<(y)?(x):(y))
#endif

30196
30197
30198
30199
30200
30201
30202
30203
30204
30205
30206
30207
30208
30209
30210
30211
30212
30213
30214
30215
30216
30217
*/
#ifdef SQLITE_TEST
SQLITE_API int sqlite3_os_type = 0;
#else
static int sqlite3_os_type = 0;
#endif

#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
#  define SQLITE_WIN32_HAS_ANSI
#endif

#if SQLITE_OS_WINCE || SQLITE_OS_WINNT || SQLITE_OS_WINRT
#  define SQLITE_WIN32_HAS_WIDE
#endif

#ifndef SYSCALL
#  define SYSCALL sqlite3_syscall_ptr
#endif

/*
** This function is not available on Windows CE or WinRT.
 */







<
<
<
<
<
<
<
<







30256
30257
30258
30259
30260
30261
30262








30263
30264
30265
30266
30267
30268
30269
*/
#ifdef SQLITE_TEST
SQLITE_API int sqlite3_os_type = 0;
#else
static int sqlite3_os_type = 0;
#endif









#ifndef SYSCALL
#  define SYSCALL sqlite3_syscall_ptr
#endif

/*
** This function is not available on Windows CE or WinRT.
 */
42767
42768
42769
42770
42771
42772
42773
42774
42775
42776
42777
42778
42779
42780
42781
# define DIRECT_MODE 0
  assert( isDirectMode==0 );
  UNUSED_PARAMETER(isDirectMode);
#else
# define DIRECT_MODE isDirectMode
#endif

  if( !pPager->changeCountDone && pPager->dbSize>0 ){
    PgHdr *pPgHdr;                /* Reference to page 1 */

    assert( !pPager->tempFile && isOpen(pPager->fd) );

    /* Open page 1 of the file for writing. */
    rc = sqlite3PagerGet(pPager, 1, &pPgHdr);
    assert( pPgHdr==0 || rc==SQLITE_OK );







|







42819
42820
42821
42822
42823
42824
42825
42826
42827
42828
42829
42830
42831
42832
42833
# define DIRECT_MODE 0
  assert( isDirectMode==0 );
  UNUSED_PARAMETER(isDirectMode);
#else
# define DIRECT_MODE isDirectMode
#endif

  if( !pPager->changeCountDone && ALWAYS(pPager->dbSize>0) ){
    PgHdr *pPgHdr;                /* Reference to page 1 */

    assert( !pPager->tempFile && isOpen(pPager->fd) );

    /* Open page 1 of the file for writing. */
    rc = sqlite3PagerGet(pPager, 1, &pPgHdr);
    assert( pPgHdr==0 || rc==SQLITE_OK );
44018
44019
44020
44021
44022
44023
44024


44025
44026
44027
44028
44029
44030
44031
                           pPager->pageSize, (u8*)pPager->pTmpSpace);
      pPager->pWal = 0;
    }
  }
  return rc;
}



#ifdef SQLITE_ENABLE_ZIPVFS
/*
** A read-lock must be held on the pager when this function is called. If
** the pager is in WAL mode and the WAL file currently contains one or more
** frames, return the size in bytes of the page images stored within the
** WAL frames. Otherwise, if this is not a WAL database or the WAL file
** is empty, return 0.







>
>







44070
44071
44072
44073
44074
44075
44076
44077
44078
44079
44080
44081
44082
44083
44084
44085
                           pPager->pageSize, (u8*)pPager->pTmpSpace);
      pPager->pWal = 0;
    }
  }
  return rc;
}

#endif /* !SQLITE_OMIT_WAL */

#ifdef SQLITE_ENABLE_ZIPVFS
/*
** A read-lock must be held on the pager when this function is called. If
** the pager is in WAL mode and the WAL file currently contains one or more
** frames, return the size in bytes of the page images stored within the
** WAL frames. Otherwise, if this is not a WAL database or the WAL file
** is empty, return 0.
44047
44048
44049
44050
44051
44052
44053
44054
44055
44056
44057
44058
44059
44060
44061
44062
SQLITE_PRIVATE void *sqlite3PagerCodec(PgHdr *pPg){
  void *aData = 0;
  CODEC2(pPg->pPager, pPg->pData, pPg->pgno, 6, return 0, aData);
  return aData;
}
#endif /* SQLITE_HAS_CODEC */

#endif /* !SQLITE_OMIT_WAL */

#endif /* SQLITE_OMIT_DISKIO */

/************** End of pager.c ***********************************************/
/************** Begin file wal.c *********************************************/
/*
** 2010 February 1
**







<
<







44101
44102
44103
44104
44105
44106
44107


44108
44109
44110
44111
44112
44113
44114
SQLITE_PRIVATE void *sqlite3PagerCodec(PgHdr *pPg){
  void *aData = 0;
  CODEC2(pPg->pPager, pPg->pData, pPg->pgno, 6, return 0, aData);
  return aData;
}
#endif /* SQLITE_HAS_CODEC */



#endif /* SQLITE_OMIT_DISKIO */

/************** End of pager.c ***********************************************/
/************** Begin file wal.c *********************************************/
/*
** 2010 February 1
**
46572
46573
46574
46575
46576
46577
46578
46579
46580
46581
46582
46583
46584
46585
46586
      ** are no outstanding references to any page other than page 1. And
      ** page 1 is never written to the log until the transaction is
      ** committed. As a result, the call to xUndo may not fail.
      */
      assert( walFramePgno(pWal, iFrame)!=1 );
      rc = xUndo(pUndoCtx, walFramePgno(pWal, iFrame));
    }
    walCleanupHash(pWal);
  }
  assert( rc==SQLITE_OK );
  return rc;
}

/* 
** Argument aWalData must point to an array of WAL_SAVEPOINT_NDATA u32 







|







46624
46625
46626
46627
46628
46629
46630
46631
46632
46633
46634
46635
46636
46637
46638
      ** are no outstanding references to any page other than page 1. And
      ** page 1 is never written to the log until the transaction is
      ** committed. As a result, the call to xUndo may not fail.
      */
      assert( walFramePgno(pWal, iFrame)!=1 );
      rc = xUndo(pUndoCtx, walFramePgno(pWal, iFrame));
    }
    if( iMax!=pWal->hdr.mxFrame ) walCleanupHash(pWal);
  }
  assert( rc==SQLITE_OK );
  return rc;
}

/* 
** Argument aWalData must point to an array of WAL_SAVEPOINT_NDATA u32 
50625
50626
50627
50628
50629
50630
50631














50632
50633
50634
50635
50636
50637
50638
  put4byte(&data[36 + 4*4], pBt->autoVacuum);
  put4byte(&data[36 + 7*4], pBt->incrVacuum);
#endif
  pBt->nPage = 1;
  data[31] = 1;
  return SQLITE_OK;
}















/*
** Attempt to start a new transaction. A write-transaction
** is started if the second argument is nonzero, otherwise a read-
** transaction.  If the second argument is 2 or more and exclusive
** transaction is started, meaning that no other process is allowed
** to access the database.  A preexisting transaction may not be







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







50677
50678
50679
50680
50681
50682
50683
50684
50685
50686
50687
50688
50689
50690
50691
50692
50693
50694
50695
50696
50697
50698
50699
50700
50701
50702
50703
50704
  put4byte(&data[36 + 4*4], pBt->autoVacuum);
  put4byte(&data[36 + 7*4], pBt->incrVacuum);
#endif
  pBt->nPage = 1;
  data[31] = 1;
  return SQLITE_OK;
}

/*
** Initialize the first page of the database file (creating a database
** consisting of a single page and no schema objects). Return SQLITE_OK
** if successful, or an SQLite error code otherwise.
*/
SQLITE_PRIVATE int sqlite3BtreeNewDb(Btree *p){
  int rc;
  sqlite3BtreeEnter(p);
  p->pBt->nPage = 0;
  rc = newDatabase(p->pBt);
  sqlite3BtreeLeave(p);
  return rc;
}

/*
** Attempt to start a new transaction. A write-transaction
** is started if the second argument is nonzero, otherwise a read-
** transaction.  If the second argument is 2 or more and exclusive
** transaction is started, meaning that no other process is allowed
** to access the database.  A preexisting transaction may not be
56843
56844
56845
56846
56847
56848
56849





56850

56851
56852
56853
56854
56855
56856
56857
  
    /* Update the schema version field in the destination database. This
    ** is to make sure that the schema-version really does change in
    ** the case where the source and destination databases have the
    ** same schema version.
    */
    if( rc==SQLITE_DONE ){





      rc = sqlite3BtreeUpdateMeta(p->pDest,1,p->iDestSchema+1);

      if( rc==SQLITE_OK ){
        if( p->pDestDb ){
          sqlite3ResetAllSchemasOfConnection(p->pDestDb);
        }
        if( destMode==PAGER_JOURNALMODE_WAL ){
          rc = sqlite3BtreeSetVersion(p->pDest, 2);
        }







>
>
>
>
>
|
>







56909
56910
56911
56912
56913
56914
56915
56916
56917
56918
56919
56920
56921
56922
56923
56924
56925
56926
56927
56928
56929
  
    /* Update the schema version field in the destination database. This
    ** is to make sure that the schema-version really does change in
    ** the case where the source and destination databases have the
    ** same schema version.
    */
    if( rc==SQLITE_DONE ){
      if( nSrcPage==0 ){
        rc = sqlite3BtreeNewDb(p->pDest);
        nSrcPage = 1;
      }
      if( rc==SQLITE_OK || rc==SQLITE_DONE ){
        rc = sqlite3BtreeUpdateMeta(p->pDest,1,p->iDestSchema+1);
      }
      if( rc==SQLITE_OK ){
        if( p->pDestDb ){
          sqlite3ResetAllSchemasOfConnection(p->pDestDb);
        }
        if( destMode==PAGER_JOURNALMODE_WAL ){
          rc = sqlite3BtreeSetVersion(p->pDest, 2);
        }
56877
56878
56879
56880
56881
56882
56883

56884
56885
56886
56887
56888
56889
56890
56891
56892
56893
56894
56895
56896
56897
56898
56899
56900
56901

56902
56903
56904
56905
56906
56907
56908
56909
          nDestTruncate = (nSrcPage+ratio-1)/ratio;
          if( nDestTruncate==(int)PENDING_BYTE_PAGE(p->pDest->pBt) ){
            nDestTruncate--;
          }
        }else{
          nDestTruncate = nSrcPage * (pgszSrc/pgszDest);
        }

        sqlite3PagerTruncateImage(pDestPager, nDestTruncate);

        if( pgszSrc<pgszDest ){
          /* If the source page-size is smaller than the destination page-size,
          ** two extra things may need to happen:
          **
          **   * The destination may need to be truncated, and
          **
          **   * Data stored on the pages immediately following the 
          **     pending-byte page in the source database may need to be
          **     copied into the destination database.
          */
          const i64 iSize = (i64)pgszSrc * (i64)nSrcPage;
          sqlite3_file * const pFile = sqlite3PagerFile(pDestPager);
          i64 iOff;
          i64 iEnd;

          assert( pFile );

          assert( (i64)nDestTruncate*(i64)pgszDest >= iSize || (
                nDestTruncate==(int)(PENDING_BYTE_PAGE(p->pDest->pBt)-1)
             && iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest
          ));

          /* This call ensures that all data required to recreate the original
          ** database has been stored in the journal for pDestPager and the
          ** journal synced to disk. So at this point we may safely modify







>


















>
|







56949
56950
56951
56952
56953
56954
56955
56956
56957
56958
56959
56960
56961
56962
56963
56964
56965
56966
56967
56968
56969
56970
56971
56972
56973
56974
56975
56976
56977
56978
56979
56980
56981
56982
56983
          nDestTruncate = (nSrcPage+ratio-1)/ratio;
          if( nDestTruncate==(int)PENDING_BYTE_PAGE(p->pDest->pBt) ){
            nDestTruncate--;
          }
        }else{
          nDestTruncate = nSrcPage * (pgszSrc/pgszDest);
        }
        assert( nDestTruncate>0 );
        sqlite3PagerTruncateImage(pDestPager, nDestTruncate);

        if( pgszSrc<pgszDest ){
          /* If the source page-size is smaller than the destination page-size,
          ** two extra things may need to happen:
          **
          **   * The destination may need to be truncated, and
          **
          **   * Data stored on the pages immediately following the 
          **     pending-byte page in the source database may need to be
          **     copied into the destination database.
          */
          const i64 iSize = (i64)pgszSrc * (i64)nSrcPage;
          sqlite3_file * const pFile = sqlite3PagerFile(pDestPager);
          i64 iOff;
          i64 iEnd;

          assert( pFile );
          assert( nDestTruncate==0 
              || (i64)nDestTruncate*(i64)pgszDest >= iSize || (
                nDestTruncate==(int)(PENDING_BYTE_PAGE(p->pDest->pBt)-1)
             && iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest
          ));

          /* This call ensures that all data required to recreate the original
          ** database has been stored in the journal for pDestPager and the
          ** journal synced to disk. So at this point we may safely modify
72392
72393
72394
72395
72396
72397
72398
72399
72400
72401
72402
72403
72404
72405
72406
  struct SrcList_item *pMatch = 0;  /* The matching pSrcList item */
  NameContext *pTopNC = pNC;        /* First namecontext in the list */
  Schema *pSchema = 0;              /* Schema of the expression */
  int isTrigger = 0;

  assert( pNC );     /* the name context cannot be NULL. */
  assert( zCol );    /* The Z in X.Y.Z cannot be NULL */
  assert( ~ExprHasAnyProperty(pExpr, EP_TokenOnly|EP_Reduced) );

  /* Initialize the node to no-match */
  pExpr->iTable = -1;
  pExpr->pTab = 0;
  ExprSetIrreducible(pExpr);

  /* Start at the inner-most context and move outward until a match is found */







|







72466
72467
72468
72469
72470
72471
72472
72473
72474
72475
72476
72477
72478
72479
72480
  struct SrcList_item *pMatch = 0;  /* The matching pSrcList item */
  NameContext *pTopNC = pNC;        /* First namecontext in the list */
  Schema *pSchema = 0;              /* Schema of the expression */
  int isTrigger = 0;

  assert( pNC );     /* the name context cannot be NULL. */
  assert( zCol );    /* The Z in X.Y.Z cannot be NULL */
  assert( !ExprHasAnyProperty(pExpr, EP_TokenOnly|EP_Reduced) );

  /* Initialize the node to no-match */
  pExpr->iTable = -1;
  pExpr->pTab = 0;
  ExprSetIrreducible(pExpr);

  /* Start at the inner-most context and move outward until a match is found */
82394
82395
82396
82397
82398
82399
82400

82401
82402
82403
82404
82405
82406
82407
        iLargest = iIdx;
      }
    }
    if( iLargest==0 ){
      return;
    }else{
      int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);

      destroyRootPage(pParse, iLargest, iDb);
      iDestroyed = iLargest;
    }
  }
#endif
}








>







82468
82469
82470
82471
82472
82473
82474
82475
82476
82477
82478
82479
82480
82481
82482
        iLargest = iIdx;
      }
    }
    if( iLargest==0 ){
      return;
    }else{
      int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
      assert( iDb>=0 && iDb<pParse->db->nDb );
      destroyRootPage(pParse, iLargest, iDb);
      iDestroyed = iLargest;
    }
  }
#endif
}

82952
82953
82954
82955
82956
82957
82958

82959
82960
82961
82962
82963
82964
82965
82966
        sqlite3FixSrcList(&sFix, pTblName)
    ){
      /* Because the parser constructs pTblName from a single identifier,
      ** sqlite3FixSrcList can never fail. */
      assert(0);
    }
    pTab = sqlite3LocateTableItem(pParse, 0, &pTblName->a[0]);

    if( !pTab || db->mallocFailed ) goto exit_create_index;
    assert( db->aDb[iDb].pSchema==pTab->pSchema );
  }else{
    assert( pName==0 );
    assert( pStart==0 );
    pTab = pParse->pNewTable;
    if( !pTab ) goto exit_create_index;
    iDb = sqlite3SchemaToIndex(db, pTab->pSchema);







>
|







83027
83028
83029
83030
83031
83032
83033
83034
83035
83036
83037
83038
83039
83040
83041
83042
        sqlite3FixSrcList(&sFix, pTblName)
    ){
      /* Because the parser constructs pTblName from a single identifier,
      ** sqlite3FixSrcList can never fail. */
      assert(0);
    }
    pTab = sqlite3LocateTableItem(pParse, 0, &pTblName->a[0]);
    assert( db->mallocFailed==0 || pTab==0 );
    if( pTab==0 ) goto exit_create_index;
    assert( db->aDb[iDb].pSchema==pTab->pSchema );
  }else{
    assert( pName==0 );
    assert( pStart==0 );
    pTab = pParse->pNewTable;
    if( !pTab ) goto exit_create_index;
    iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
89475
89476
89477
89478
89479
89480
89481

89482
89483
89484
89485
89486
89487
89488
89489
89490
89491
89492
89493
89494
89495
89496

89497
89498
89499
89500
89501
89502
89503
  if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){
    ExprList *pCheck = pTab->pCheck;
    pParse->ckBase = regData;
    onError = overrideError!=OE_Default ? overrideError : OE_Abort;
    for(i=0; i<pCheck->nExpr; i++){
      int allOk = sqlite3VdbeMakeLabel(v);
      Expr *pDup = sqlite3ExprDup(db, pCheck->a[i].pExpr, 0);

      if( pDup==0 ) break;
      sqlite3ExprIfTrue(pParse, pDup, allOk, SQLITE_JUMPIFNULL);
      if( onError==OE_Ignore ){
        sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
      }else{
        char *zConsName = pCheck->a[i].zName;
        if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-15569-63625 */
        if( zConsName ){
          zConsName = sqlite3MPrintf(db, "constraint %s failed", zConsName);
        }else{
          zConsName = 0;
        }
        sqlite3HaltConstraint(pParse, onError, zConsName, P4_DYNAMIC);
      }
      sqlite3VdbeResolveLabel(v, allOk);

      sqlite3ExprDelete(db, pDup);
    }
  }
#endif /* !defined(SQLITE_OMIT_CHECK) */

  /* If we have an INTEGER PRIMARY KEY, make sure the primary key
  ** of the new record does not previously exist.  Except, if this







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







89551
89552
89553
89554
89555
89556
89557
89558
89559
89560
89561
89562
89563
89564
89565
89566
89567
89568
89569
89570
89571
89572
89573
89574
89575
89576
89577
89578
89579
89580
89581
  if( pTab->pCheck && (db->flags & SQLITE_IgnoreChecks)==0 ){
    ExprList *pCheck = pTab->pCheck;
    pParse->ckBase = regData;
    onError = overrideError!=OE_Default ? overrideError : OE_Abort;
    for(i=0; i<pCheck->nExpr; i++){
      int allOk = sqlite3VdbeMakeLabel(v);
      Expr *pDup = sqlite3ExprDup(db, pCheck->a[i].pExpr, 0);
      if( !db->mallocFailed ){
        assert( pDup!=0 );
        sqlite3ExprIfTrue(pParse, pDup, allOk, SQLITE_JUMPIFNULL);
        if( onError==OE_Ignore ){
          sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
        }else{
          char *zConsName = pCheck->a[i].zName;
          if( onError==OE_Replace ) onError = OE_Abort; /* IMP: R-15569-63625 */
          if( zConsName ){
            zConsName = sqlite3MPrintf(db, "constraint %s failed", zConsName);
          }else{
            zConsName = 0;
          }
          sqlite3HaltConstraint(pParse, onError, zConsName, P4_DYNAMIC);
        }
        sqlite3VdbeResolveLabel(v, allOk);
      }
      sqlite3ExprDelete(db, pDup);
    }
  }
#endif /* !defined(SQLITE_OMIT_CHECK) */

  /* If we have an INTEGER PRIMARY KEY, make sure the primary key
  ** of the new record does not previously exist.  Except, if this
92936
92937
92938
92939
92940
92941
92942
92943
92944
92945
92946
92947
92948
92949
92950
92951
92952
92953
92954
92955
92956
    int i;
    sqlite3VdbeSetNumCols(v, 2);
    pParse->nMem = 2;
    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "database", SQLITE_STATIC);
    sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "status", SQLITE_STATIC);
    for(i=0; i<db->nDb; i++){
      Btree *pBt;
      Pager *pPager;
      const char *zState = "unknown";
      int j;
      if( db->aDb[i].zName==0 ) continue;
      sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, db->aDb[i].zName, P4_STATIC);
      pBt = db->aDb[i].pBt;
      if( pBt==0 || (pPager = sqlite3BtreePager(pBt))==0 ){
        zState = "closed";
      }else if( sqlite3_file_control(db, i ? db->aDb[i].zName : 0, 
                                     SQLITE_FCNTL_LOCKSTATE, &j)==SQLITE_OK ){
         zState = azLockName[j];
      }
      sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, zState, P4_STATIC);
      sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2);







<





|







93014
93015
93016
93017
93018
93019
93020

93021
93022
93023
93024
93025
93026
93027
93028
93029
93030
93031
93032
93033
    int i;
    sqlite3VdbeSetNumCols(v, 2);
    pParse->nMem = 2;
    sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "database", SQLITE_STATIC);
    sqlite3VdbeSetColName(v, 1, COLNAME_NAME, "status", SQLITE_STATIC);
    for(i=0; i<db->nDb; i++){
      Btree *pBt;

      const char *zState = "unknown";
      int j;
      if( db->aDb[i].zName==0 ) continue;
      sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, db->aDb[i].zName, P4_STATIC);
      pBt = db->aDb[i].pBt;
      if( pBt==0 || sqlite3BtreePager(pBt)==0 ){
        zState = "closed";
      }else if( sqlite3_file_control(db, i ? db->aDb[i].zName : 0, 
                                     SQLITE_FCNTL_LOCKSTATE, &j)==SQLITE_OK ){
         zState = azLockName[j];
      }
      sqlite3VdbeAddOp4(v, OP_String8, 0, 2, 0, zState, P4_STATIC);
      sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 2);
96981
96982
96983
96984
96985
96986
96987
96988
96989
96990
96991
96992
96993
96994
96995
96996
96997
96998
    **
    ** We look at every expression in the outer query and every place we see
    ** "a" we substitute "x*3" and every place we see "b" we substitute "y+10".
    */
    pList = pParent->pEList;
    for(i=0; i<pList->nExpr; i++){
      if( pList->a[i].zName==0 ){
        const char *zSpan = pList->a[i].zSpan;
        if( ALWAYS(zSpan) ){
          pList->a[i].zName = sqlite3DbStrDup(db, zSpan);
        }
      }
    }
    substExprList(db, pParent->pEList, iParent, pSub->pEList);
    if( isAgg ){
      substExprList(db, pParent->pGroupBy, iParent, pSub->pEList);
      pParent->pHaving = substExpr(db, pParent->pHaving, iParent, pSub->pEList);
    }







|
|
|
<







97058
97059
97060
97061
97062
97063
97064
97065
97066
97067

97068
97069
97070
97071
97072
97073
97074
    **
    ** We look at every expression in the outer query and every place we see
    ** "a" we substitute "x*3" and every place we see "b" we substitute "y+10".
    */
    pList = pParent->pEList;
    for(i=0; i<pList->nExpr; i++){
      if( pList->a[i].zName==0 ){
        char *zName = sqlite3DbStrDup(db, pList->a[i].zSpan);
        sqlite3Dequote(zName);
        pList->a[i].zName = zName;

      }
    }
    substExprList(db, pParent->pEList, iParent, pSub->pEList);
    if( isAgg ){
      substExprList(db, pParent->pGroupBy, iParent, pSub->pEList);
      pParent->pHaving = substExpr(db, pParent->pHaving, iParent, pSub->pEList);
    }
100629
100630
100631
100632
100633
100634
100635

100636
100637
100638
100639
100640
100641
100642
** with 2.0.0, SQLite no longer uses GDBM so this command has
** become a no-op.
*/
SQLITE_PRIVATE void sqlite3Vacuum(Parse *pParse){
  Vdbe *v = sqlite3GetVdbe(pParse);
  if( v ){
    sqlite3VdbeAddOp2(v, OP_Vacuum, 0, 0);

  }
  return;
}

/*
** This routine implements the OP_Vacuum opcode of the VDBE.
*/







>







100705
100706
100707
100708
100709
100710
100711
100712
100713
100714
100715
100716
100717
100718
100719
** with 2.0.0, SQLite no longer uses GDBM so this command has
** become a no-op.
*/
SQLITE_PRIVATE void sqlite3Vacuum(Parse *pParse){
  Vdbe *v = sqlite3GetVdbe(pParse);
  if( v ){
    sqlite3VdbeAddOp2(v, OP_Vacuum, 0, 0);
    sqlite3VdbeUsesBtree(v, 0);
  }
  return;
}

/*
** This routine implements the OP_Vacuum opcode of the VDBE.
*/
101156
101157
101158
101159
101160
101161
101162
101163
101164
101165
101166
101167
101168
101169
101170
101171
101172
** in the list are moved to the sqlite3.pDisconnect list of the associated 
** database connection.
*/
SQLITE_PRIVATE void sqlite3VtabClear(sqlite3 *db, Table *p){
  if( !db || db->pnBytesFreed==0 ) vtabDisconnectAll(0, p);
  if( p->azModuleArg ){
    int i;
    assert( p->nModuleArg<2 || p->azModuleArg[1]==0 );
    for(i=0; i<p->nModuleArg; i++){
      sqlite3DbFree(db, p->azModuleArg[i]);
    }
    sqlite3DbFree(db, p->azModuleArg);
  }
}

/*
** Add a new module argument to pTable->azModuleArg[].







<

|







101233
101234
101235
101236
101237
101238
101239

101240
101241
101242
101243
101244
101245
101246
101247
101248
** in the list are moved to the sqlite3.pDisconnect list of the associated 
** database connection.
*/
SQLITE_PRIVATE void sqlite3VtabClear(sqlite3 *db, Table *p){
  if( !db || db->pnBytesFreed==0 ) vtabDisconnectAll(0, p);
  if( p->azModuleArg ){
    int i;

    for(i=0; i<p->nModuleArg; i++){
      if( i!=1 ) sqlite3DbFree(db, p->azModuleArg[i]);
    }
    sqlite3DbFree(db, p->azModuleArg);
  }
}

/*
** Add a new module argument to pTable->azModuleArg[].
103439
103440
103441
103442
103443
103444
103445
103446
103447
103448
103449
103450
103451
103452
103453
103454
103455
103456
103457
103458
103459
103460
103461
103462
103463
103464
103465
103466
103467
103468

  /* Prevent ON clause terms of a LEFT JOIN from being used to drive
  ** an index for tables to the left of the join.
  */
  pTerm->prereqRight |= extraRight;
}

/*
** Return TRUE if the given index is UNIQUE and all columns past the
** first nSkip columns are NOT NULL.
*/
static int indexIsUniqueNotNull(Index *pIdx, int nSkip){
  Table *pTab = pIdx->pTable;
  int i;
  if( pIdx->onError==OE_None ) return 0;
  for(i=nSkip; i<pIdx->nColumn; i++){
    int j = pIdx->aiColumn[i];
    assert( j>=0 && j<pTab->nCol );
    if( pTab->aCol[j].notNull==0 ) return 0;
  }
  return 1;
}

/*
** This function searches the expression list passed as the second argument
** for an expression of type TK_COLUMN that refers to the same column and
** uses the same collation sequence as the iCol'th column of index pIdx.
** Argument iBase is the cursor number used for the table that pIdx refers
** to.
**







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







103515
103516
103517
103518
103519
103520
103521
















103522
103523
103524
103525
103526
103527
103528

  /* Prevent ON clause terms of a LEFT JOIN from being used to drive
  ** an index for tables to the left of the join.
  */
  pTerm->prereqRight |= extraRight;
}

















/*
** This function searches the expression list passed as the second argument
** for an expression of type TK_COLUMN that refers to the same column and
** uses the same collation sequence as the iCol'th column of index pIdx.
** Argument iBase is the cursor number used for the table that pIdx refers
** to.
**
104723
104724
104725
104726
104727
104728
104729
104730
104731

104732
104733
104734
104735


104736
104737




104738
104739
104740
104741
104742
104743
104744
104745
104746
104747
104748
104749
104750
104751
104752
104753
104754
104755
104756
  }
  return rc;
}
#endif /* defined(SQLITE_ENABLE_STAT3) */

/*
** Check to see if column iCol of the table with cursor iTab will appear
** in sorted order according to the current query plan.  Return true if
** it will and false if not.  

**
** If *pbRev is initially 2 (meaning "unknown") then set *pbRev to the
** sort order of iTab.iCol.  If *pbRev is 0 or 1 but does not match
** the sort order of iTab.iCol, then consider the column to be unordered.


*/
static int isOrderedColumn(WhereBestIdx *p, int iTab, int iCol, int *pbRev){




  int i, j;
  WhereLevel *pLevel = &p->aLevel[p->i-1];
  Index *pIdx;
  u8 sortOrder;
  for(i=p->i-1; i>=0; i--, pLevel--){
    if( pLevel->iTabCur!=iTab ) continue;
    if( (pLevel->plan.wsFlags & WHERE_ALL_UNIQUE)!=0 ){
      return 1;
    }
    if( (pLevel->plan.wsFlags & WHERE_ORDERED)==0 ){
      return 0;
    }
    if( (pIdx = pLevel->plan.u.pIdx)!=0 ){
      if( iCol<0 ){
        sortOrder = 0;
        testcase( (pLevel->plan.wsFlags & WHERE_REVERSE)!=0 );
      }else{
        int n = pIdx->nColumn;
        for(j=0; j<n; j++){







|
|
>

<
|
|
>
>

|
>
>
>
>









|
<
<







104783
104784
104785
104786
104787
104788
104789
104790
104791
104792
104793

104794
104795
104796
104797
104798
104799
104800
104801
104802
104803
104804
104805
104806
104807
104808
104809
104810
104811
104812
104813


104814
104815
104816
104817
104818
104819
104820
  }
  return rc;
}
#endif /* defined(SQLITE_ENABLE_STAT3) */

/*
** Check to see if column iCol of the table with cursor iTab will appear
** in sorted order according to the current query plan.
**
** Return values:
**

**    0   iCol is not ordered
**    1   iCol has only a single value
**    2   iCol is in ASC order
**    3   iCol is in DESC order
*/
static int isOrderedColumn(
  WhereBestIdx *p,
  int iTab,
  int iCol
){
  int i, j;
  WhereLevel *pLevel = &p->aLevel[p->i-1];
  Index *pIdx;
  u8 sortOrder;
  for(i=p->i-1; i>=0; i--, pLevel--){
    if( pLevel->iTabCur!=iTab ) continue;
    if( (pLevel->plan.wsFlags & WHERE_ALL_UNIQUE)!=0 ){
      return 1;
    }
    assert( (pLevel->plan.wsFlags & WHERE_ORDERED)!=0 );


    if( (pIdx = pLevel->plan.u.pIdx)!=0 ){
      if( iCol<0 ){
        sortOrder = 0;
        testcase( (pLevel->plan.wsFlags & WHERE_REVERSE)!=0 );
      }else{
        int n = pIdx->nColumn;
        for(j=0; j<n; j++){
104766
104767
104768
104769
104770
104771
104772
104773
104774
104775
104776
104777
104778
104779
104780
104781
104782
104783
104784
104785
104786
104787
104788
104789
104790
104791
104792
104793
104794
104795
104796
104797
104798
104799
104800
104801
104802
104803
104804
104805
104806
104807
104808
104809
104810
104811
104812
104813
104814
104815
104816
104817
104818
104819
104820
104821
104822
104823
104824
104825
104826
104827
104828
104829
104830
104831
104832
104833
104834
104835
104836
104837
104838

104839
104840
104841
104842
104843
104844
104845
104846
104847
104848
104849



104850
104851
104852
104853


104854
104855
104856
104857
104858
104859
104860
104861
104862
104863
104864
104865
104866




104867

104868
104869
104870
104871
104872
104873
104874
104875
104876
104877
104878
104879
104880
104881
104882

104883
104884
104885
104886
104887
104888


104889

104890

104891

104892
104893
104894
104895
104896
104897
104898
104899
104900
104901


104902
104903
104904
104905
104906
104907
104908

104909
104910
104911
104912
104913
104914

104915


104916
104917
104918
104919
104920



104921
104922
104923

104924
104925
104926
104927
104928
104929
104930
104931


104932
104933
104934
104935




104936


















104937
104938





104939
104940
104941











104942


104943

104944
104945
104946
104947
104948





104949
104950






104951
104952
104953
104954
104955
104956
104957
104958
104959
104960
104961
104962
104963
104964
104965
104966
104967
104968
104969
      testcase( (pLevel->plan.wsFlags & WHERE_REVERSE)!=0 );
    }
    if( (pLevel->plan.wsFlags & WHERE_REVERSE)!=0 ){
      assert( sortOrder==0 || sortOrder==1 );
      testcase( sortOrder==1 );
      sortOrder = 1 - sortOrder;
    }
    if( *pbRev==2 ){
      *pbRev = sortOrder;
      return 1;
    }
    return (*pbRev==sortOrder);
  }
  return 0;
}

/*
** pTerm is an == constraint.  Check to see if the other side of
** the == is a constant or a value that is guaranteed to be ordered
** by outer loops.  Return 1 if pTerm is ordered, and 0 if not.
*/
static int isOrderedTerm(WhereBestIdx *p, WhereTerm *pTerm, int *pbRev){
  Expr *pExpr = pTerm->pExpr;
  assert( pExpr->op==TK_EQ );
  assert( pExpr->pLeft!=0 && pExpr->pLeft->op==TK_COLUMN );
  assert( pExpr->pRight!=0 );
  if( pTerm->prereqRight==0 ){
    return 1;  /* RHS of the == is a constant */
  }
  if( pExpr->pRight->op==TK_COLUMN 
   && isOrderedColumn(p, pExpr->pRight->iTable, pExpr->pRight->iColumn, pbRev)
  ){
    return 1;
  }

  /* If we cannot prove that the constraint is ordered, assume it is not */
  return 0;
}

/*
** This routine decides if pIdx can be used to satisfy the ORDER BY
** clause, either in whole or in part.  The return value is the 
** cumulative number of terms in the ORDER BY clause that are satisfied
** by the index pIdx and other indices in outer loops.
**
** The table being queried has a cursor number of "base".  pIdx is the
** index that is postulated for use to access the table.
**
** nEqCol is the number of columns of pIdx that are used as equality
** constraints and where the other side of the == is an ordered column
** or constant.  An "order column" in the previous sentence means a column
** in table from an outer loop whose values will always appear in the 
** correct order due to othre index, or because the outer loop generates
** a unique result.  Any of the first nEqCol columns of pIdx may be missing
** from the ORDER BY clause and the match can still be a success.
**
** The *pbRev value is set to 0 order 1 depending on whether or not
** pIdx should be run in the forward order or in reverse order.
*/
static int isSortingIndex(
  WhereBestIdx *p,    /* Best index search context */
  Index *pIdx,        /* The index we are testing */
  int base,           /* Cursor number for the table to be sorted */
  int nEqCol,         /* Number of index columns with ordered == constraints */
  int wsFlags,        /* Index usages flags */
  int bOuterRev,      /* True if outer loops scan in reverse order */
  int *pbRev          /* Set to 1 for reverse-order scan of pIdx */
){
  int i;                        /* Number of pIdx terms used */
  int j;                        /* Number of ORDER BY terms satisfied */
  int sortOrder = 0;            /* XOR of index and ORDER BY sort direction */
  int nTerm;                    /* Number of ORDER BY terms */
  struct ExprList_item *pTerm;  /* A term of the ORDER BY clause */

  ExprList *pOrderBy;           /* The ORDER BY clause */
  Parse *pParse = p->pParse;    /* Parser context */
  sqlite3 *db = pParse->db;     /* Database connection */
  int nPriorSat;                /* ORDER BY terms satisfied by outer loops */
  int seenRowid = 0;            /* True if an ORDER BY rowid term is seen */
  int nEqOneRow;                /* Idx columns that ref unique values */

  if( p->i==0 ){
    nPriorSat = 0;
  }else{
    nPriorSat = p->aLevel[p->i-1].plan.nOBSat;



    if( OptimizationDisabled(db, SQLITE_OrderByIdxJoin) ) return nPriorSat;
  }
  if( nEqCol==0 ){
    if( p->i && (p->aLevel[p->i-1].plan.wsFlags & WHERE_ORDERED)==0 ){


      return nPriorSat;
    }
    nEqOneRow = 0;
  }else if( p->i==0 || (p->aLevel[p->i-1].plan.wsFlags & WHERE_ALL_UNIQUE)!=0 ){
    nEqOneRow = nEqCol;
  }else{
    sortOrder = bOuterRev;
    nEqOneRow = -1;
  }
  pOrderBy = p->pOrderBy;
  assert( pOrderBy!=0 );
  if( wsFlags & WHERE_COLUMN_IN ) return nPriorSat;
  if( pIdx->bUnordered ) return nPriorSat;




  nTerm = pOrderBy->nExpr;

  assert( nTerm>0 );

  /* Argument pIdx must either point to a 'real' named index structure, 
  ** or an index structure allocated on the stack by bestBtreeIndex() to
  ** represent the rowid index that is part of every table.  */
  assert( pIdx->zName || (pIdx->nColumn==1 && pIdx->aiColumn[0]==-1) );

  /* Match terms of the ORDER BY clause against columns of
  ** the index.
  **
  ** Note that indices have pIdx->nColumn regular columns plus
  ** one additional column containing the rowid.  The rowid column
  ** of the index is also allowed to match against the ORDER BY
  ** clause.
  */

  for(i=0,j=nPriorSat,pTerm=&pOrderBy->a[j]; j<nTerm; i++){
    Expr *pExpr;       /* The expression of the ORDER BY pTerm */
    CollSeq *pColl;    /* The collating sequence of pExpr */
    int termSortOrder; /* Sort order for this term */
    int iColumn;       /* The i-th column of the index.  -1 for rowid */
    int iSortOrder;    /* 1 for DESC, 0 for ASC on the i-th index term */


    const char *zColl; /* Name of the collating sequence for i-th index term */



    assert( i<=pIdx->nColumn );

    pExpr = pTerm->pExpr;
    if( pExpr->op!=TK_COLUMN || pExpr->iTable!=base ){
      /* Can not use an index sort on anything that is not a column in the
      ** left-most table of the FROM clause */
      break;
    }
    pColl = sqlite3ExprCollSeq(pParse, pExpr);
    if( !pColl ){
      pColl = db->pDfltColl;
    }


    if( pIdx->zName && i<pIdx->nColumn ){
      iColumn = pIdx->aiColumn[i];
      if( iColumn==pIdx->pTable->iPKey ){
        iColumn = -1;
      }
      iSortOrder = pIdx->aSortOrder[i];
      zColl = pIdx->azColl[i];

    }else{
      iColumn = -1;
      iSortOrder = 0;
      zColl = pColl->zName;
    }
    if( pExpr->iColumn!=iColumn || sqlite3StrICmp(pColl->zName, zColl) ){

      /* Term j of the ORDER BY clause does not match column i of the index */


      if( i<nEqCol ){
        /* If an index column that is constrained by == fails to match an
        ** ORDER BY term, that is OK.  Just ignore that column of the index
        */
        continue;



      }else if( i==pIdx->nColumn ){
        /* Index column i is the rowid.  All other terms match. */
        break;

      }else{
        /* If an index column fails to match and is not constrained by ==
        ** then the index cannot satisfy the ORDER BY constraint.
        */
        return nPriorSat;
      }
    }
    assert( pIdx->aSortOrder!=0 || iColumn==-1 );


    assert( pTerm->sortOrder==0 || pTerm->sortOrder==1 );
    assert( iSortOrder==0 || iSortOrder==1 );
    termSortOrder = iSortOrder ^ pTerm->sortOrder;
    if( i>nEqOneRow ){




      if( termSortOrder!=sortOrder ){


















        /* Indices can only be used if all ORDER BY terms past the
        ** equality constraints have the correct DESC or ASC. */





        break;
      }
    }else{











      sortOrder = termSortOrder;


    }

    j++;
    pTerm++;
    if( iColumn<0 ){
      seenRowid = 1;
      break;





    }
  }






  *pbRev = sortOrder;

  /* If there was an "ORDER BY rowid" term that matched, or it is only
  ** possible for a single row from this table to match, then skip over
  ** any additional ORDER BY terms dealing with this table.
  */
  if( seenRowid ||
     (   (wsFlags & WHERE_COLUMN_NULL)==0
      && i>=pIdx->nColumn
      && indexIsUniqueNotNull(pIdx, nEqCol)
     )
  ){
    /* Advance j over additional ORDER BY terms associated with base */
    WhereMaskSet *pMS = p->pWC->pMaskSet;
    Bitmask m = ~getMask(pMS, base);
    while( j<nTerm && (exprTableUsage(pMS, pOrderBy->a[j].pExpr)&m)==0 ){
      j++;
    }
  }







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












<
<
<
<
<
<
<
<







<
<
<




|

|
>





|





>
>
>
|
|
|
<
>
>


<
<
<
<
<
<



<
|
>
>
>
>

>















>
|
|
|
|
|
|
>
>
|
>

>
|
>
|
|
<
<


<
<
<
|
>
>







>



|

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

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

|



>
>
>
>
>


>
>
>
>
>
>
|





|
<
<
<
<
<







104830
104831
104832
104833
104834
104835
104836


104837
104838

























104839
104840
104841
104842
104843
104844
104845
104846
104847
104848
104849
104850








104851
104852
104853
104854
104855
104856
104857



104858
104859
104860
104861
104862
104863
104864
104865
104866
104867
104868
104869
104870
104871
104872
104873
104874
104875
104876
104877
104878
104879
104880
104881
104882

104883
104884
104885
104886






104887
104888
104889

104890
104891
104892
104893
104894
104895
104896
104897
104898
104899
104900
104901
104902
104903
104904
104905
104906
104907
104908
104909
104910
104911
104912
104913
104914
104915
104916
104917
104918
104919
104920
104921
104922
104923
104924
104925
104926
104927
104928


104929
104930



104931
104932
104933
104934
104935
104936
104937
104938
104939
104940
104941
104942
104943
104944
104945
104946
104947
104948
104949
104950
104951
104952




104953
104954
104955
104956
104957

104958
104959



104960
104961
104962
104963
104964
104965
104966
104967
104968
104969
104970
104971
104972
104973
104974
104975
104976
104977
104978
104979
104980
104981
104982
104983
104984
104985
104986
104987
104988
104989
104990
104991
104992
104993
104994
104995
104996
104997
104998
104999
105000
105001
105002
105003
105004
105005
105006
105007
105008
105009
105010
105011
105012
105013
105014
105015
105016
105017
105018
105019
105020
105021
105022
105023
105024
105025
105026
105027
105028
105029
105030
105031
105032
105033
105034
105035
105036
105037
105038
105039
105040
105041
105042
105043





105044
105045
105046
105047
105048
105049
105050
      testcase( (pLevel->plan.wsFlags & WHERE_REVERSE)!=0 );
    }
    if( (pLevel->plan.wsFlags & WHERE_REVERSE)!=0 ){
      assert( sortOrder==0 || sortOrder==1 );
      testcase( sortOrder==1 );
      sortOrder = 1 - sortOrder;
    }


    return sortOrder+2;
  }

























  return 0;
}

/*
** This routine decides if pIdx can be used to satisfy the ORDER BY
** clause, either in whole or in part.  The return value is the 
** cumulative number of terms in the ORDER BY clause that are satisfied
** by the index pIdx and other indices in outer loops.
**
** The table being queried has a cursor number of "base".  pIdx is the
** index that is postulated for use to access the table.
**








** The *pbRev value is set to 0 order 1 depending on whether or not
** pIdx should be run in the forward order or in reverse order.
*/
static int isSortingIndex(
  WhereBestIdx *p,    /* Best index search context */
  Index *pIdx,        /* The index we are testing */
  int base,           /* Cursor number for the table to be sorted */



  int *pbRev          /* Set to 1 for reverse-order scan of pIdx */
){
  int i;                        /* Number of pIdx terms used */
  int j;                        /* Number of ORDER BY terms satisfied */
  int sortOrder = 2;            /* 0: forward.  1: backward.  2: unknown */
  int nTerm;                    /* Number of ORDER BY terms */
  struct ExprList_item *pOBItem;/* A term of the ORDER BY clause */
  Table *pTab = pIdx->pTable;   /* Table that owns index pIdx */
  ExprList *pOrderBy;           /* The ORDER BY clause */
  Parse *pParse = p->pParse;    /* Parser context */
  sqlite3 *db = pParse->db;     /* Database connection */
  int nPriorSat;                /* ORDER BY terms satisfied by outer loops */
  int seenRowid = 0;            /* True if an ORDER BY rowid term is seen */
  int uniqueNotNull;            /* pIdx is UNIQUE with all terms are NOT NULL */

  if( p->i==0 ){
    nPriorSat = 0;
  }else{
    nPriorSat = p->aLevel[p->i-1].plan.nOBSat;
    if( (p->aLevel[p->i-1].plan.wsFlags & WHERE_ORDERED)==0 ){
      /* This loop cannot be ordered unless the next outer loop is
      ** also ordered */
      return nPriorSat;
    }
    if( OptimizationDisabled(db, SQLITE_OrderByIdxJoin) ){

      /* Only look at the outer-most loop if the OrderByIdxJoin
      ** optimization is disabled */
      return nPriorSat;
    }






  }
  pOrderBy = p->pOrderBy;
  assert( pOrderBy!=0 );

  if( pIdx->bUnordered ){
    /* Hash indices (indicated by the "unordered" tag on sqlite_stat1) cannot
    ** be used for sorting */
    return nPriorSat;
  }
  nTerm = pOrderBy->nExpr;
  uniqueNotNull = pIdx->onError!=OE_None;
  assert( nTerm>0 );

  /* Argument pIdx must either point to a 'real' named index structure, 
  ** or an index structure allocated on the stack by bestBtreeIndex() to
  ** represent the rowid index that is part of every table.  */
  assert( pIdx->zName || (pIdx->nColumn==1 && pIdx->aiColumn[0]==-1) );

  /* Match terms of the ORDER BY clause against columns of
  ** the index.
  **
  ** Note that indices have pIdx->nColumn regular columns plus
  ** one additional column containing the rowid.  The rowid column
  ** of the index is also allowed to match against the ORDER BY
  ** clause.
  */
  j = nPriorSat;
  for(i=0,pOBItem=&pOrderBy->a[j]; j<nTerm && i<=pIdx->nColumn; i++){
    Expr *pOBExpr;          /* The expression of the ORDER BY pOBItem */
    CollSeq *pColl;         /* The collating sequence of pOBExpr */
    int termSortOrder;      /* Sort order for this term */
    int iColumn;            /* The i-th column of the index.  -1 for rowid */
    int iSortOrder;         /* 1 for DESC, 0 for ASC on the i-th index term */
    int isEq;               /* Subject to an == or IS NULL constraint */
    int isMatch;            /* ORDER BY term matches the index term */
    const char *zColl;      /* Name of collating sequence for i-th index term */
    WhereTerm *pConstraint; /* A constraint in the WHERE clause */

    /* If the next term of the ORDER BY clause refers to anything other than
    ** a column in the "base" table, then this index will not be of any
    ** further use in handling the ORDER BY. */
    pOBExpr = pOBItem->pExpr;
    if( pOBExpr->op!=TK_COLUMN || pOBExpr->iTable!=base ){


      break;
    }




    /* Find column number and collating sequence for the next entry
    ** in the index */
    if( pIdx->zName && i<pIdx->nColumn ){
      iColumn = pIdx->aiColumn[i];
      if( iColumn==pIdx->pTable->iPKey ){
        iColumn = -1;
      }
      iSortOrder = pIdx->aSortOrder[i];
      zColl = pIdx->azColl[i];
      assert( zColl!=0 );
    }else{
      iColumn = -1;
      iSortOrder = 0;
      zColl = 0;
    }

    /* Check to see if the column number and collating sequence of the
    ** index match the column number and collating sequence of the ORDER BY
    ** clause entry.  Set isMatch to 1 if they both match. */
    if( pOBExpr->iColumn==iColumn ){
      if( zColl ){




        pColl = sqlite3ExprCollSeq(pParse, pOBExpr);
        if( !pColl ) pColl = db->pDfltColl;
        isMatch = sqlite3StrICmp(pColl->zName, zColl)==0;
      }else{
        isMatch = 1;

      }
    }else{



      isMatch = 0;
    }

    /* termSortOrder is 0 or 1 for whether or not the access loop should
    ** run forward or backwards (respectively) in order to satisfy this 
    ** term of the ORDER BY clause. */
    assert( pOBItem->sortOrder==0 || pOBItem->sortOrder==1 );
    assert( iSortOrder==0 || iSortOrder==1 );
    termSortOrder = iSortOrder ^ pOBItem->sortOrder;

    /* If X is the column in the index and ORDER BY clause, check to see
    ** if there are any X= or X IS NULL constraints in the WHERE clause. */
    pConstraint = findTerm(p->pWC, base, iColumn, p->notReady,
                           WO_EQ|WO_ISNULL|WO_IN, pIdx);
    if( pConstraint==0 ){
      isEq = 0;
    }else if( pConstraint->eOperator==WO_IN ){
      /* Constraints of the form: "X IN ..." cannot be used with an ORDER BY
      ** because we do not know in what order the values on the RHS of the IN
      ** operator will occur. */
      break;
    }else if( pConstraint->eOperator==WO_ISNULL ){
      uniqueNotNull = 0;
      isEq = 1;  /* "X IS NULL" means X has only a single value */
    }else if( pConstraint->prereqRight==0 ){
      isEq = 1;  /* Constraint "X=constant" means X has only a single value */
    }else{
      Expr *pRight = pConstraint->pExpr->pRight;
      if( pRight->op==TK_COLUMN ){
        WHERETRACE(("       .. isOrderedColumn(tab=%d,col=%d)",
                    pRight->iTable, pRight->iColumn));
        isEq = isOrderedColumn(p, pRight->iTable, pRight->iColumn);
        WHERETRACE((" -> isEq=%d\n", isEq));

        /* If the constraint is of the form X=Y where Y is an ordered value
        ** in an outer loop, then make sure the sort order of Y matches the
        ** sort order required for X. */
        if( isMatch && isEq>=2 && isEq!=pOBItem->sortOrder+2 ){
          testcase( isEq==2 );
          testcase( isEq==3 );
          break;
        }
      }else{
        isEq = 0;  /* "X=expr" places no ordering constraints on X */
      }
    }
    if( !isMatch ){
      if( isEq==0 ){
        break;
      }else{
        continue;
      }
    }else if( isEq!=1 ){
      if( sortOrder==2 ){
        sortOrder = termSortOrder;
      }else if( termSortOrder!=sortOrder ){
        break;
      }
    }
    j++;
    pOBItem++;
    if( iColumn<0 ){
      seenRowid = 1;
      break;
    }else if( pTab->aCol[iColumn].notNull==0 && isEq!=1 ){
      testcase( isEq==0 );
      testcase( isEq==2 );
      testcase( isEq==3 );
      uniqueNotNull = 0;
    }
  }

  /* If we have not found at least one ORDER BY term that matches the
  ** index, then show no progress. */
  if( pOBItem==&pOrderBy->a[nPriorSat] ) return nPriorSat;

  /* Return the necessary scan order back to the caller */
  *pbRev = sortOrder & 1;

  /* If there was an "ORDER BY rowid" term that matched, or it is only
  ** possible for a single row from this table to match, then skip over
  ** any additional ORDER BY terms dealing with this table.
  */
  if( seenRowid || (uniqueNotNull && i>=pIdx->nColumn) ){





    /* Advance j over additional ORDER BY terms associated with base */
    WhereMaskSet *pMS = p->pWC->pMaskSet;
    Bitmask m = ~getMask(pMS, base);
    while( j<nTerm && (exprTableUsage(pMS, pOrderBy->a[j].pExpr)&m)==0 ){
      j++;
    }
  }
105061
105062
105063
105064
105065
105066
105067
105068
105069
105070
105071
105072
105073
105074
105075

  /* Loop over all indices looking for the best one to use
  */
  for(; pProbe; pIdx=pProbe=pProbe->pNext){
    const tRowcnt * const aiRowEst = pProbe->aiRowEst;
    WhereCost pc;               /* Cost of using pProbe */
    double log10N = (double)1;  /* base-10 logarithm of nRow (inexact) */
    int bRev = 2;               /* 0=forward scan.  1=reverse.  2=undecided */

    /* The following variables are populated based on the properties of
    ** index being evaluated. They are then used to determine the expected
    ** cost and number of rows returned.
    **
    **  pc.plan.nEq: 
    **    Number of equality terms that can be implemented using the index.







<







105142
105143
105144
105145
105146
105147
105148

105149
105150
105151
105152
105153
105154
105155

  /* Loop over all indices looking for the best one to use
  */
  for(; pProbe; pIdx=pProbe=pProbe->pNext){
    const tRowcnt * const aiRowEst = pProbe->aiRowEst;
    WhereCost pc;               /* Cost of using pProbe */
    double log10N = (double)1;  /* base-10 logarithm of nRow (inexact) */


    /* The following variables are populated based on the properties of
    ** index being evaluated. They are then used to determine the expected
    ** cost and number of rows returned.
    **
    **  pc.plan.nEq: 
    **    Number of equality terms that can be implemented using the index.
105092
105093
105094
105095
105096
105097
105098
105099
105100
105101
105102
105103
105104
105105
105106
105107
105108
105109
    **
    **    nInMul is set to 1.
    **
    **    If there exists a WHERE term of the form "x IN (SELECT ...)", then 
    **    the sub-select is assumed to return 25 rows for the purposes of 
    **    determining nInMul.
    **
    **  nOrdered:
    **    The number of equality terms that are constrainted by outer loop
    **    variables that are well-ordered.
    **
    **  bInEst:  
    **    Set to true if there was at least one "x IN (SELECT ...)" term used 
    **    in determining the value of nInMul.  Note that the RHS of the
    **    IN operator must be a SELECT, not a value list, for this variable
    **    to be true.
    **
    **  rangeDiv:







<
<
<
<







105172
105173
105174
105175
105176
105177
105178




105179
105180
105181
105182
105183
105184
105185
    **
    **    nInMul is set to 1.
    **
    **    If there exists a WHERE term of the form "x IN (SELECT ...)", then 
    **    the sub-select is assumed to return 25 rows for the purposes of 
    **    determining nInMul.
    **




    **  bInEst:  
    **    Set to true if there was at least one "x IN (SELECT ...)" term used 
    **    in determining the value of nInMul.  Note that the RHS of the
    **    IN operator must be a SELECT, not a value list, for this variable
    **    to be true.
    **
    **  rangeDiv:
105133
105134
105135
105136
105137
105138
105139
105140
105141
105142
105143
105144
105145
105146
105147
105148
105149
105150
105151
105152
105153
105154




105155
105156
105157
105158
105159
105160
105161
105162
105163
105164
105165
105166
105167
105168
105169
105170
105171
105172
105173
105174
105175
105176
105177
105178
105179
105180
105181
105182
105183
105184
105185
105186
105187
105188
105189
105190
105191
105192
105193
105194
105195
105196
105197
    **    two queries requires table b-tree lookups in order to find the value
    **    of column c, but the first does not because columns a and b are
    **    both available in the index.
    **
    **             SELECT a, b    FROM tbl WHERE a = 1;
    **             SELECT a, b, c FROM tbl WHERE a = 1;
    */
    int nOrdered;                 /* Number of ordered terms matching index */
    int bInEst = 0;               /* True if "x IN (SELECT...)" seen */
    int nInMul = 1;               /* Number of distinct equalities to lookup */
    double rangeDiv = (double)1;  /* Estimated reduction in search space */
    int nBound = 0;               /* Number of range constraints seen */
    int bSort;                    /* True if external sort required */
    int bDist;                    /* True if index cannot help with DISTINCT */
    int bLookup = 0;              /* True if not a covering index */
    int nPriorSat;                /* ORDER BY terms satisfied by outer loops */
    int nOrderBy;                 /* Number of ORDER BY terms */
    WhereTerm *pTerm;             /* A single term of the WHERE clause */
#ifdef SQLITE_ENABLE_STAT3
    WhereTerm *pFirstTerm = 0;    /* First term matching the index */
#endif





    memset(&pc, 0, sizeof(pc));
    nOrderBy = p->pOrderBy ? p->pOrderBy->nExpr : 0;
    if( p->i ){
      nPriorSat = pc.plan.nOBSat = p->aLevel[p->i-1].plan.nOBSat;
      bSort = nPriorSat<nOrderBy;
      bDist = 0;
    }else{
      nPriorSat = pc.plan.nOBSat = 0;
      bSort = nOrderBy>0;
      bDist = p->pDistinct!=0;
    }

    /* Determine the values of pc.plan.nEq and nInMul */
    for(pc.plan.nEq=nOrdered=0; pc.plan.nEq<pProbe->nColumn; pc.plan.nEq++){
      int j = pProbe->aiColumn[pc.plan.nEq];
      pTerm = findTerm(pWC, iCur, j, p->notReady, eqTermMask, pIdx);
      if( pTerm==0 ) break;
      pc.plan.wsFlags |= (WHERE_COLUMN_EQ|WHERE_ROWID_EQ);
      testcase( pTerm->pWC!=pWC );
      if( pTerm->eOperator & WO_IN ){
        Expr *pExpr = pTerm->pExpr;
        pc.plan.wsFlags |= WHERE_COLUMN_IN;
        if( ExprHasProperty(pExpr, EP_xIsSelect) ){
          /* "x IN (SELECT ...)":  Assume the SELECT returns 25 rows */
          nInMul *= 25;
          bInEst = 1;
        }else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){
          /* "x IN (value, value, ...)" */
          nInMul *= pExpr->x.pList->nExpr;
        }
      }else if( pTerm->eOperator & WO_ISNULL ){
        pc.plan.wsFlags |= WHERE_COLUMN_NULL;
        if( pc.plan.nEq==nOrdered ) nOrdered++;
      }else if( bSort && pc.plan.nEq==nOrdered
             && isOrderedTerm(p,pTerm,&bRev) ){
        nOrdered++;
      }
#ifdef SQLITE_ENABLE_STAT3
      if( pc.plan.nEq==0 && pProbe->aSample ) pFirstTerm = pTerm;
#endif
      pc.used |= pTerm->prereqRight;
    }
 







<














>
>
>
>













|


















<
<
<
<







105209
105210
105211
105212
105213
105214
105215

105216
105217
105218
105219
105220
105221
105222
105223
105224
105225
105226
105227
105228
105229
105230
105231
105232
105233
105234
105235
105236
105237
105238
105239
105240
105241
105242
105243
105244
105245
105246
105247
105248
105249
105250
105251
105252
105253
105254
105255
105256
105257
105258
105259
105260
105261
105262
105263
105264
105265




105266
105267
105268
105269
105270
105271
105272
    **    two queries requires table b-tree lookups in order to find the value
    **    of column c, but the first does not because columns a and b are
    **    both available in the index.
    **
    **             SELECT a, b    FROM tbl WHERE a = 1;
    **             SELECT a, b, c FROM tbl WHERE a = 1;
    */

    int bInEst = 0;               /* True if "x IN (SELECT...)" seen */
    int nInMul = 1;               /* Number of distinct equalities to lookup */
    double rangeDiv = (double)1;  /* Estimated reduction in search space */
    int nBound = 0;               /* Number of range constraints seen */
    int bSort;                    /* True if external sort required */
    int bDist;                    /* True if index cannot help with DISTINCT */
    int bLookup = 0;              /* True if not a covering index */
    int nPriorSat;                /* ORDER BY terms satisfied by outer loops */
    int nOrderBy;                 /* Number of ORDER BY terms */
    WhereTerm *pTerm;             /* A single term of the WHERE clause */
#ifdef SQLITE_ENABLE_STAT3
    WhereTerm *pFirstTerm = 0;    /* First term matching the index */
#endif

    WHERETRACE((
      "   %s(%s):\n",
      pSrc->pTab->zName, (pIdx ? pIdx->zName : "ipk")
    ));
    memset(&pc, 0, sizeof(pc));
    nOrderBy = p->pOrderBy ? p->pOrderBy->nExpr : 0;
    if( p->i ){
      nPriorSat = pc.plan.nOBSat = p->aLevel[p->i-1].plan.nOBSat;
      bSort = nPriorSat<nOrderBy;
      bDist = 0;
    }else{
      nPriorSat = pc.plan.nOBSat = 0;
      bSort = nOrderBy>0;
      bDist = p->pDistinct!=0;
    }

    /* Determine the values of pc.plan.nEq and nInMul */
    for(pc.plan.nEq=0; pc.plan.nEq<pProbe->nColumn; pc.plan.nEq++){
      int j = pProbe->aiColumn[pc.plan.nEq];
      pTerm = findTerm(pWC, iCur, j, p->notReady, eqTermMask, pIdx);
      if( pTerm==0 ) break;
      pc.plan.wsFlags |= (WHERE_COLUMN_EQ|WHERE_ROWID_EQ);
      testcase( pTerm->pWC!=pWC );
      if( pTerm->eOperator & WO_IN ){
        Expr *pExpr = pTerm->pExpr;
        pc.plan.wsFlags |= WHERE_COLUMN_IN;
        if( ExprHasProperty(pExpr, EP_xIsSelect) ){
          /* "x IN (SELECT ...)":  Assume the SELECT returns 25 rows */
          nInMul *= 25;
          bInEst = 1;
        }else if( ALWAYS(pExpr->x.pList && pExpr->x.pList->nExpr) ){
          /* "x IN (value, value, ...)" */
          nInMul *= pExpr->x.pList->nExpr;
        }
      }else if( pTerm->eOperator & WO_ISNULL ){
        pc.plan.wsFlags |= WHERE_COLUMN_NULL;




      }
#ifdef SQLITE_ENABLE_STAT3
      if( pc.plan.nEq==0 && pProbe->aSample ) pFirstTerm = pTerm;
#endif
      pc.used |= pTerm->prereqRight;
    }
 
105238
105239
105240
105241
105242
105243
105244
105245
105246
105247
105248
105249

105250

105251
105252
105253
105254
105255
105256
105257
105258
    }

    /* If there is an ORDER BY clause and the index being considered will
    ** naturally scan rows in the required order, set the appropriate flags
    ** in pc.plan.wsFlags. Otherwise, if there is an ORDER BY clause but
    ** the index will scan rows in a different order, set the bSort
    ** variable.  */
    assert( bRev>=0 && bRev<=2 );
    if( bSort ){
      testcase( bRev==0 );
      testcase( bRev==1 );
      testcase( bRev==2 );

      pc.plan.nOBSat = isSortingIndex(p, pProbe, iCur, nOrdered,

                                 pc.plan.wsFlags, bRev&1, &bRev);
      if( nPriorSat<pc.plan.nOBSat || (pc.plan.wsFlags & WHERE_UNIQUE)!=0 ){
        pc.plan.wsFlags |= WHERE_ORDERED;
      }
      if( nOrderBy==pc.plan.nOBSat ){
        bSort = 0;
        pc.plan.wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE;
      }







<
|
|
<
<
>
|
>
|







105313
105314
105315
105316
105317
105318
105319

105320
105321


105322
105323
105324
105325
105326
105327
105328
105329
105330
105331
105332
    }

    /* If there is an ORDER BY clause and the index being considered will
    ** naturally scan rows in the required order, set the appropriate flags
    ** in pc.plan.wsFlags. Otherwise, if there is an ORDER BY clause but
    ** the index will scan rows in a different order, set the bSort
    ** variable.  */

    if( bSort && (pSrc->jointype & JT_LEFT)==0 ){
      int bRev = 2;


      WHERETRACE(("      --> before isSortingIndex: nPriorSat=%d\n",nPriorSat));
      pc.plan.nOBSat = isSortingIndex(p, pProbe, iCur, &bRev);
      WHERETRACE(("      --> after  isSortingIndex: bRev=%d nOBSat=%d\n",
                  bRev, pc.plan.nOBSat));
      if( nPriorSat<pc.plan.nOBSat || (pc.plan.wsFlags & WHERE_UNIQUE)!=0 ){
        pc.plan.wsFlags |= WHERE_ORDERED;
      }
      if( nOrderBy==pc.plan.nOBSat ){
        bSort = 0;
        pc.plan.wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE;
      }
105362
105363
105364
105365
105366
105367
105368

105369


105370
105371
105372
105373
105374
105375
105376
      ** the cost function to err on the side of choosing an index over
      ** choosing a full scan.  This 4x full-scan penalty is an arguable
      ** decision and one which we expect to revisit in the future.  But
      ** it seems to be working well enough at the moment.
      */
      pc.rCost = aiRowEst[0]*4;
      pc.plan.wsFlags &= ~WHERE_IDX_ONLY;

      if( pIdx ) pc.plan.wsFlags &= ~WHERE_ORDERED;


    }else{
      log10N = estLog(aiRowEst[0]);
      pc.rCost = pc.plan.nRow;
      if( pIdx ){
        if( bLookup ){
          /* For an index lookup followed by a table lookup:
          **    nInMul index searches to find the start of each index range







>
|
>
>







105436
105437
105438
105439
105440
105441
105442
105443
105444
105445
105446
105447
105448
105449
105450
105451
105452
105453
      ** the cost function to err on the side of choosing an index over
      ** choosing a full scan.  This 4x full-scan penalty is an arguable
      ** decision and one which we expect to revisit in the future.  But
      ** it seems to be working well enough at the moment.
      */
      pc.rCost = aiRowEst[0]*4;
      pc.plan.wsFlags &= ~WHERE_IDX_ONLY;
      if( pIdx ){
        pc.plan.wsFlags &= ~WHERE_ORDERED;
        pc.plan.nOBSat = nPriorSat;
      }
    }else{
      log10N = estLog(aiRowEst[0]);
      pc.rCost = pc.plan.nRow;
      if( pIdx ){
        if( bLookup ){
          /* For an index lookup followed by a table lookup:
          **    nInMul index searches to find the start of each index range
105467
105468
105469
105470
105471
105472
105473
105474
105475
105476
105477
105478
105479
105480
105481
105482
105483
105484
105485
105486
105487
        }
      }
      if( pc.plan.nRow<2 ) pc.plan.nRow = 2;
    }


    WHERETRACE((
      "%s(%s):\n"
      "    nEq=%d nInMul=%d rangeDiv=%d bSort=%d bLookup=%d wsFlags=0x%08x\n"
      "    notReady=0x%llx log10N=%.1f nRow=%.1f cost=%.1f\n"
      "    used=0x%llx nOrdered=%d nOBSat=%d\n",
      pSrc->pTab->zName, (pIdx ? pIdx->zName : "ipk"), 
      pc.plan.nEq, nInMul, (int)rangeDiv, bSort, bLookup, pc.plan.wsFlags,
      p->notReady, log10N, pc.plan.nRow, pc.rCost, pc.used, nOrdered,
      pc.plan.nOBSat
    ));

    /* If this index is the best we have seen so far, then record this
    ** index and its cost in the p->cost structure.
    */
    if( (!pIdx || pc.plan.wsFlags) && compareCost(&pc, &p->cost) ){







<
|
|
|
<

|







105544
105545
105546
105547
105548
105549
105550

105551
105552
105553

105554
105555
105556
105557
105558
105559
105560
105561
105562
        }
      }
      if( pc.plan.nRow<2 ) pc.plan.nRow = 2;
    }


    WHERETRACE((

      "      nEq=%d nInMul=%d rangeDiv=%d bSort=%d bLookup=%d wsFlags=0x%08x\n"
      "      notReady=0x%llx log10N=%.1f nRow=%.1f cost=%.1f\n"
      "      used=0x%llx nOBSat=%d\n",

      pc.plan.nEq, nInMul, (int)rangeDiv, bSort, bLookup, pc.plan.wsFlags,
      p->notReady, log10N, pc.plan.nRow, pc.rCost, pc.used,
      pc.plan.nOBSat
    ));

    /* If this index is the best we have seen so far, then record this
    ** index and its cost in the p->cost structure.
    */
    if( (!pIdx || pc.plan.wsFlags) && compareCost(&pc, &p->cost) ){
105511
105512
105513
105514
105515
105516
105517
105518
105519
105520
105521
105522
105523
105524
105525
  assert( p->pOrderBy || (p->cost.plan.wsFlags&WHERE_ORDERED)==0 );
  assert( p->cost.plan.u.pIdx==0 || (p->cost.plan.wsFlags&WHERE_ROWID_EQ)==0 );
  assert( pSrc->pIndex==0 
       || p->cost.plan.u.pIdx==0 
       || p->cost.plan.u.pIdx==pSrc->pIndex 
  );

  WHERETRACE(("best index is: %s\n",
         p->cost.plan.u.pIdx ? p->cost.plan.u.pIdx->zName : "ipk"));
  
  bestOrClauseIndex(p);
  bestAutomaticIndex(p);
  p->cost.plan.wsFlags |= eqTermMask;
}








|







105586
105587
105588
105589
105590
105591
105592
105593
105594
105595
105596
105597
105598
105599
105600
  assert( p->pOrderBy || (p->cost.plan.wsFlags&WHERE_ORDERED)==0 );
  assert( p->cost.plan.u.pIdx==0 || (p->cost.plan.wsFlags&WHERE_ROWID_EQ)==0 );
  assert( pSrc->pIndex==0 
       || p->cost.plan.u.pIdx==0 
       || p->cost.plan.u.pIdx==pSrc->pIndex 
  );

  WHERETRACE(("   best index is: %s\n",
         p->cost.plan.u.pIdx ? p->cost.plan.u.pIdx->zName : "ipk"));
  
  bestOrClauseIndex(p);
  bestAutomaticIndex(p);
  p->cost.plan.wsFlags |= eqTermMask;
}

106603
106604
106605
106606
106607
106608
106609
106610
106611
106612
106613
106614
106615
106616
106617

          /* Finish the loop through table entries that match term pOrTerm. */
          sqlite3WhereEnd(pSubWInfo);
        }
      }
    }
    pLevel->u.pCovidx = pCov;
    pLevel->iIdxCur = iCovCur;
    if( pAndExpr ){
      pAndExpr->pLeft = 0;
      sqlite3ExprDelete(pParse->db, pAndExpr);
    }
    sqlite3VdbeChangeP1(v, iRetInit, sqlite3VdbeCurrentAddr(v));
    sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel->addrBrk);
    sqlite3VdbeResolveLabel(v, iLoopBody);







|







106678
106679
106680
106681
106682
106683
106684
106685
106686
106687
106688
106689
106690
106691
106692

          /* Finish the loop through table entries that match term pOrTerm. */
          sqlite3WhereEnd(pSubWInfo);
        }
      }
    }
    pLevel->u.pCovidx = pCov;
    if( pCov ) pLevel->iIdxCur = iCovCur;
    if( pAndExpr ){
      pAndExpr->pLeft = 0;
      sqlite3ExprDelete(pParse->db, pAndExpr);
    }
    sqlite3VdbeChangeP1(v, iRetInit, sqlite3VdbeCurrentAddr(v));
    sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel->addrBrk);
    sqlite3VdbeResolveLabel(v, iLoopBody);
107061
107062
107063
107064
107065
107066
107067
107068
107069
107070
107071
107072
107073
107074
107075
        if( (m & sWBI.notValid)==0 ){
          if( j==iFrom ) iFrom++;
          continue;
        }
        sWBI.notReady = (isOptimal ? m : sWBI.notValid);
        if( sWBI.pSrc->pIndex==0 ) nUnconstrained++;
  
        WHERETRACE(("=== trying table %d (%s) with isOptimal=%d ===\n",
                    j, sWBI.pSrc->pTab->zName, isOptimal));
        assert( sWBI.pSrc->pTab );
#ifndef SQLITE_OMIT_VIRTUALTABLE
        if( IsVirtual(sWBI.pSrc->pTab) ){
          sWBI.ppIdxInfo = &pWInfo->a[j].pIdxInfo;
          bestVirtualIndex(&sWBI);
        }else 







|







107136
107137
107138
107139
107140
107141
107142
107143
107144
107145
107146
107147
107148
107149
107150
        if( (m & sWBI.notValid)==0 ){
          if( j==iFrom ) iFrom++;
          continue;
        }
        sWBI.notReady = (isOptimal ? m : sWBI.notValid);
        if( sWBI.pSrc->pIndex==0 ) nUnconstrained++;
  
        WHERETRACE(("   === trying table %d (%s) with isOptimal=%d ===\n",
                    j, sWBI.pSrc->pTab->zName, isOptimal));
        assert( sWBI.pSrc->pTab );
#ifndef SQLITE_OMIT_VIRTUALTABLE
        if( IsVirtual(sWBI.pSrc->pTab) ){
          sWBI.ppIdxInfo = &pWInfo->a[j].pIdxInfo;
          bestVirtualIndex(&sWBI);
        }else 
107114
107115
107116
107117
107118
107119
107120
107121
107122
107123
107124
107125
107126
107127
107128
107129
            && (bestJ<0 || (notIndexed&m)!=0                     /* (2) */
                || (bestPlan.plan.wsFlags & WHERE_NOT_FULLSCAN)==0
                || (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0)
            && (nUnconstrained==0 || sWBI.pSrc->pIndex==0        /* (3) */
                || NEVER((sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0))
            && (bestJ<0 || compareCost(&sWBI.cost, &bestPlan))   /* (4) */
        ){
          WHERETRACE(("=== table %d (%s) is best so far\n"
                      "    cost=%.1f, nRow=%.1f, nOBSat=%d, wsFlags=%08x\n",
                      j, sWBI.pSrc->pTab->zName,
                      sWBI.cost.rCost, sWBI.cost.plan.nRow,
                      sWBI.cost.plan.nOBSat, sWBI.cost.plan.wsFlags));
          bestPlan = sWBI.cost;
          bestJ = j;
        }
        if( doNotReorder ) break;







|
|







107189
107190
107191
107192
107193
107194
107195
107196
107197
107198
107199
107200
107201
107202
107203
107204
            && (bestJ<0 || (notIndexed&m)!=0                     /* (2) */
                || (bestPlan.plan.wsFlags & WHERE_NOT_FULLSCAN)==0
                || (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0)
            && (nUnconstrained==0 || sWBI.pSrc->pIndex==0        /* (3) */
                || NEVER((sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0))
            && (bestJ<0 || compareCost(&sWBI.cost, &bestPlan))   /* (4) */
        ){
          WHERETRACE(("   === table %d (%s) is best so far\n"
                      "       cost=%.1f, nRow=%.1f, nOBSat=%d, wsFlags=%08x\n",
                      j, sWBI.pSrc->pTab->zName,
                      sWBI.cost.rCost, sWBI.cost.plan.nRow,
                      sWBI.cost.plan.nOBSat, sWBI.cost.plan.wsFlags));
          bestPlan = sWBI.cost;
          bestJ = j;
        }
        if( doNotReorder ) break;
110699
110700
110701
110702
110703
110704
110705

110706
110707
110708
110709
110710
110711
110712
      /* (318) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==318);
      /* (320) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==320);
      /* (324) anylist ::= */ yytestcase(yyruleno==324);
      /* (325) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==325);
      /* (326) anylist ::= anylist ANY */ yytestcase(yyruleno==326);
        break;
  };

  yygoto = yyRuleInfo[yyruleno].lhs;
  yysize = yyRuleInfo[yyruleno].nrhs;
  yypParser->yyidx -= yysize;
  yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto);
  if( yyact < YYNSTATE ){
#ifdef NDEBUG
    /* If we are not debugging and the reduce action popped at least







>







110774
110775
110776
110777
110778
110779
110780
110781
110782
110783
110784
110785
110786
110787
110788
      /* (318) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==318);
      /* (320) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==320);
      /* (324) anylist ::= */ yytestcase(yyruleno==324);
      /* (325) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==325);
      /* (326) anylist ::= anylist ANY */ yytestcase(yyruleno==326);
        break;
  };
  assert( yyruleno>=0 && yyruleno<sizeof(yyRuleInfo)/sizeof(yyRuleInfo[0]) );
  yygoto = yyRuleInfo[yyruleno].lhs;
  yysize = yyRuleInfo[yyruleno].nrhs;
  yypParser->yyidx -= yysize;
  yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto);
  if( yyact < YYNSTATE ){
#ifdef NDEBUG
    /* If we are not debugging and the reduce action popped at least
Changes to src/sqlite3.h.
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
**
** See also: [sqlite3_libversion()],
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION        "3.7.15"
#define SQLITE_VERSION_NUMBER 3007015
#define SQLITE_SOURCE_ID      "2012-10-07 14:14:44 bbb0d189b7b6aecfc0e0b6c2bcd9f49aaea8c34a"

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







|







105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
**
** See also: [sqlite3_libversion()],
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION        "3.7.15"
#define SQLITE_VERSION_NUMBER 3007015
#define SQLITE_SOURCE_ID      "2012-10-16 23:08:28 f021559d8a23934e3bdccad5b55fc7a91d185f53"

/*
** CAPI3REF: Run-Time Library Version Numbers
** KEYWORDS: sqlite3_version, sqlite3_sourceid
**
** These interfaces provide the same information as the [SQLITE_VERSION],
** [SQLITE_VERSION_NUMBER], and [SQLITE_SOURCE_ID] C preprocessor macros
Changes to src/stash.c.
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
    prompt_for_user_comment(&comment, &prompt);
    blob_reset(&prompt);
    zComment = blob_str(&comment);
  }
  stashid = db_lget_int("stash-next", 1);
  db_lset_int("stash-next", stashid+1);
  vid = db_lget_int("checkout", 0);
  vfile_check_signature(vid, 0, 0);
  db_multi_exec(
    "INSERT INTO stash(stashid,vid,comment,ctime)"
    "VALUES(%d,%d,%Q,julianday('now'))",
    stashid, vid, zComment
  );
  if( g.argc>3 ){
    int i;







|







170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
    prompt_for_user_comment(&comment, &prompt);
    blob_reset(&prompt);
    zComment = blob_str(&comment);
  }
  stashid = db_lget_int("stash-next", 1);
  db_lset_int("stash-next", stashid+1);
  vid = db_lget_int("checkout", 0);
  vfile_check_signature(vid, 0);
  db_multi_exec(
    "INSERT INTO stash(stashid,vid,comment,ctime)"
    "VALUES(%d,%d,%Q,julianday('now'))",
    stashid, vid, zComment
  );
  if( g.argc>3 ){
    int i;
Changes to src/timeline.c.
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
      nd = db_int(0, "SELECT count(*)-1 FROM ok");
      if( nd>=0 ) db_multi_exec("%s", blob_str(&sql));
      if( nd>0 ) blob_appendf(&desc, "%d descendant%s", nd,(1==nd)?"":"s");
      if( useDividers ) timeline_add_dividers(0, d_rid);
      db_multi_exec("DELETE FROM ok");
    }
    if( p_rid ){
      compute_ancestors(p_rid, nEntry+1);
      np = db_int(0, "SELECT count(*)-1 FROM ok");
      if( np>0 ){
        if( nd>0 ) blob_appendf(&desc, " and ");
        blob_appendf(&desc, "%d ancestors", np);
        db_multi_exec("%s", blob_str(&sql));
      }
      if( d_rid==0 && useDividers ) timeline_add_dividers(0, p_rid);







|







1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
      nd = db_int(0, "SELECT count(*)-1 FROM ok");
      if( nd>=0 ) db_multi_exec("%s", blob_str(&sql));
      if( nd>0 ) blob_appendf(&desc, "%d descendant%s", nd,(1==nd)?"":"s");
      if( useDividers ) timeline_add_dividers(0, d_rid);
      db_multi_exec("DELETE FROM ok");
    }
    if( p_rid ){
      compute_ancestors(p_rid, nEntry+1, 0);
      np = db_int(0, "SELECT count(*)-1 FROM ok");
      if( np>0 ){
        if( nd>0 ) blob_appendf(&desc, " and ");
        blob_appendf(&desc, "%d ancestors", np);
        db_multi_exec("%s", blob_str(&sql));
      }
      if( d_rid==0 && useDividers ) timeline_add_dividers(0, p_rid);
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
  );

  if( mode==3 || mode==4 ){
    db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)");
    if( mode==3 ){
      compute_descendants(objid, n);
    }else{
      compute_ancestors(objid, n);
    }
    blob_appendf(&sql, " AND blob.rid IN ok");
  }
  if( zType && (zType[0]!='a') ){
    blob_appendf(&sql, " AND event.type=%Q ", zType);
  }
  blob_appendf(&sql, " ORDER BY event.mtime DESC");







|







1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
  );

  if( mode==3 || mode==4 ){
    db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)");
    if( mode==3 ){
      compute_descendants(objid, n);
    }else{
      compute_ancestors(objid, n, 0);
    }
    blob_appendf(&sql, " AND blob.rid IN ok");
  }
  if( zType && (zType[0]!='a') ){
    blob_appendf(&sql, " AND event.type=%Q ", zType);
  }
  blob_appendf(&sql, " ORDER BY event.mtime DESC");
Changes to src/tkt.c.
431
432
433
434
435
436
437

438
439
440
441
442
443
444
  const char **argv, 
  int *argl
){
  char *zDate;
  const char *zUuid;
  int i;
  int rid;

  Blob tktchng, cksum;

  login_verify_csrf_secret();
  zUuid = (const char *)pUuid;
  blob_zero(&tktchng);
  zDate = date_in_standard_format("now");
  blob_appendf(&tktchng, "D %s\n", zDate);







>







431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
  const char **argv, 
  int *argl
){
  char *zDate;
  const char *zUuid;
  int i;
  int rid;
  int nJ = 0;
  Blob tktchng, cksum;

  login_verify_csrf_secret();
  zUuid = (const char *)pUuid;
  blob_zero(&tktchng);
  zDate = date_in_standard_format("now");
  blob_appendf(&tktchng, "D %s\n", zDate);
459
460
461
462
463
464
465

466
467
468
469
470
471
472
473
474
475
476
477
478
479
480




481
482
483
484
485
486
487
      if( strncmp(zValue, azValue[i], nValue) || strlen(azValue[i])!=nValue ){
        if( strncmp(azField[i], "private_", 8)==0 ){
          zValue = db_conceal(zValue, nValue);
          blob_appendf(&tktchng, "J %s %s\n", azField[i], zValue);
        }else{
          blob_appendf(&tktchng, "J %s %#F\n", azField[i], nValue, zValue);
        }

      }
    }
  }
  if( *(char**)pUuid ){
    zUuid = db_text(0, 
       "SELECT tkt_uuid FROM ticket WHERE tkt_uuid GLOB '%q*'", P("name")
    );
  }else{
    zUuid = db_text(0, "SELECT lower(hex(randomblob(20)))");
  }
  *(const char**)pUuid = zUuid;
  blob_appendf(&tktchng, "K %s\n", zUuid);
  blob_appendf(&tktchng, "U %F\n", g.zLogin ? g.zLogin : "");
  md5sum_blob(&tktchng, &cksum);
  blob_appendf(&tktchng, "Z %b\n", &cksum);




  if( g.zPath[0]=='d' ){
    /* If called from /debug_tktnew or /debug_tktedit... */
    @ <font color="blue">
    @ <p>Ticket artifact that would have been submitted:</p>
    @ <blockquote><pre>%h(blob_str(&tktchng))</pre></blockquote>
    @ <hr /></font>
    return TH_OK;







>















>
>
>
>







460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
      if( strncmp(zValue, azValue[i], nValue) || strlen(azValue[i])!=nValue ){
        if( strncmp(azField[i], "private_", 8)==0 ){
          zValue = db_conceal(zValue, nValue);
          blob_appendf(&tktchng, "J %s %s\n", azField[i], zValue);
        }else{
          blob_appendf(&tktchng, "J %s %#F\n", azField[i], nValue, zValue);
        }
        nJ++;
      }
    }
  }
  if( *(char**)pUuid ){
    zUuid = db_text(0, 
       "SELECT tkt_uuid FROM ticket WHERE tkt_uuid GLOB '%q*'", P("name")
    );
  }else{
    zUuid = db_text(0, "SELECT lower(hex(randomblob(20)))");
  }
  *(const char**)pUuid = zUuid;
  blob_appendf(&tktchng, "K %s\n", zUuid);
  blob_appendf(&tktchng, "U %F\n", g.zLogin ? g.zLogin : "");
  md5sum_blob(&tktchng, &cksum);
  blob_appendf(&tktchng, "Z %b\n", &cksum);
  if( nJ==0 ){
    blob_reset(&tktchng);
    return TH_OK;
  }
  if( g.zPath[0]=='d' ){
    /* If called from /debug_tktnew or /debug_tktedit... */
    @ <font color="blue">
    @ <p>Ticket artifact that would have been submitted:</p>
    @ <blockquote><pre>%h(blob_str(&tktchng))</pre></blockquote>
    @ <hr /></font>
    return TH_OK;
Changes to src/update.c.
98
99
100
101
102
103
104

105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120

121
122
123
124
125
126
127
  int vid;              /* Current version */
  int tid=0;            /* Target version - version we are changing to */
  Stmt q;
  int latestFlag;       /* --latest.  Pick the latest version if true */
  int nochangeFlag;     /* -n or --nochange.  Do a dry run */
  int verboseFlag;      /* -v or --verbose.  Output extra information */
  int debugFlag;        /* --debug option */

  int nChng;            /* Number of file renames */
  int *aChng;           /* Array of file renames */
  int i;                /* Loop counter */
  int nConflict = 0;    /* Number of merge conflicts */
  int nOverwrite = 0;   /* Number of unmanaged files overwritten */
  int nUpdate = 0;      /* Number of chagnes of any kind */
  Stmt mtimeXfer;       /* Statment to transfer mtimes */

  if( !internalUpdate ){
    undo_capture_command_line();
    url_proxy_options();
  }
  latestFlag = find_option("latest",0, 0)!=0;
  nochangeFlag = find_option("nochange","n",0)!=0;
  verboseFlag = find_option("verbose","v",0)!=0;
  debugFlag = find_option("debug",0,0)!=0;

  db_must_be_within_tree();
  vid = db_lget_int("checkout", 0);
  if( vid==0 ){
    fossil_fatal("cannot find current version");
  }
  if( !nochangeFlag && !internalUpdate ) autosync(AUTOSYNC_PULL);
  







>
















>







98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
  int vid;              /* Current version */
  int tid=0;            /* Target version - version we are changing to */
  Stmt q;
  int latestFlag;       /* --latest.  Pick the latest version if true */
  int nochangeFlag;     /* -n or --nochange.  Do a dry run */
  int verboseFlag;      /* -v or --verbose.  Output extra information */
  int debugFlag;        /* --debug option */
  int setmtimeFlag;     /* --setmtime.  Set mtimes on files */
  int nChng;            /* Number of file renames */
  int *aChng;           /* Array of file renames */
  int i;                /* Loop counter */
  int nConflict = 0;    /* Number of merge conflicts */
  int nOverwrite = 0;   /* Number of unmanaged files overwritten */
  int nUpdate = 0;      /* Number of chagnes of any kind */
  Stmt mtimeXfer;       /* Statment to transfer mtimes */

  if( !internalUpdate ){
    undo_capture_command_line();
    url_proxy_options();
  }
  latestFlag = find_option("latest",0, 0)!=0;
  nochangeFlag = find_option("nochange","n",0)!=0;
  verboseFlag = find_option("verbose","v",0)!=0;
  debugFlag = find_option("debug",0,0)!=0;
  setmtimeFlag = find_option("setmtime",0,0)!=0;
  db_must_be_within_tree();
  vid = db_lget_int("checkout", 0);
  if( vid==0 ){
    fossil_fatal("cannot find current version");
  }
  if( !nochangeFlag && !internalUpdate ) autosync(AUTOSYNC_PULL);
  
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
  }

  if( tid==0 ){
    fossil_panic("Internal Error: unable to find a version to update to.");
  }

  db_begin_transaction();
  vfile_check_signature(vid, 1, 0);
  if( !nochangeFlag && !internalUpdate ) undo_begin();
  load_vfile_from_rid(tid);

  /*
  ** The record.fn field is used to match files against each other.  The
  ** FV table contains one row for each each unique filename in
  ** in the current checkout, the pivot, and the version being merged.







|







194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
  }

  if( tid==0 ){
    fossil_panic("Internal Error: unable to find a version to update to.");
  }

  db_begin_transaction();
  vfile_check_signature(vid, CKSIG_ENOTFILE);
  if( !nochangeFlag && !internalUpdate ) undo_begin();
  load_vfile_from_rid(tid);

  /*
  ** The record.fn field is used to match files against each other.  The
  ** FV table contains one row for each each unique filename in
  ** in the current checkout, the pivot, and the version being merged.
527
528
529
530
531
532
533

534
535
536
537
538
539
540
      db_lset_int("checkout", tid);
    }else{
      /* A subset of files have been checked out.  Keep the current
      ** checkout unchanged. */
      db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid);
    }
    if( !internalUpdate ) undo_finish();

    db_end_transaction(0);
  }
}

/*
** Make sure empty directories are created
*/







>







529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
      db_lset_int("checkout", tid);
    }else{
      /* A subset of files have been checked out.  Keep the current
      ** checkout unchanged. */
      db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid);
    }
    if( !internalUpdate ) undo_finish();
    if( setmtimeFlag ) vfile_check_signature(vid, CKSIG_SETMTIME);
    db_end_transaction(0);
  }
}

/*
** Make sure empty directories are created
*/
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
      file_tree_name(zFile, &fname, 1);
      db_multi_exec("REPLACE INTO torevert VALUES(%B)", &fname);
      blob_reset(&fname);
    }
  }else{
    int vid;
    vid = db_lget_int("checkout", 0);
    vfile_check_signature(vid, 0, 0);
    db_multi_exec(
      "DELETE FROM vmerge;"
      "INSERT INTO torevert "
      "SELECT pathname"
      "  FROM vfile "
      " WHERE chnged OR deleted OR rid=0 OR pathname!=origname;"
    );







|







697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
      file_tree_name(zFile, &fname, 1);
      db_multi_exec("REPLACE INTO torevert VALUES(%B)", &fname);
      blob_reset(&fname);
    }
  }else{
    int vid;
    vid = db_lget_int("checkout", 0);
    vfile_check_signature(vid, 0);
    db_multi_exec(
      "DELETE FROM vmerge;"
      "INSERT INTO torevert "
      "SELECT pathname"
      "  FROM vfile "
      " WHERE chnged OR deleted OR rid=0 OR pathname!=origname;"
    );
Changes to src/vfile.c.
116
117
118
119
120
121
122

123










124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152

153
154
155
156
157
158
159
160
  }
  db_finalize(&ridq);
  db_finalize(&ins);
  manifest_destroy(p);
  db_end_transaction(0);
}


/*










** Look at every VFILE entry with the given vid and  set update
** VFILE.CHNGED field on every file according to whether or not
** the file has changes.  0 means no change.  1 means edited.  2 means
** the file has changed due to a merge.  3 means the file was added
** by a merge.
**
** If VFILE.DELETED is true or if VFILE.RID is zero, then the file was
** either removed from managemented via "fossil rm" or added via
** "fossil add", respectively, and in both cases we always know that 
** the file has changed without having the check the size, mtime,
** or on-disk content.
**
** If the size of the file has changed, then we always know that the file
** changed without having to look at the mtime or on-disk content.
**
** The mtime of the file is only a factor if the mtime-changes setting
** is false and the useSha1sum flag is false.  If the mtime-changes
** setting is true (or undefined - it defaults to true) or if useSha1sum
** is true, then we do not trust the mtime and will examine the on-disk
** content to determine if a file really is the same.
**
** If the mtime is used, it is used only to determine if files are the same.
** If the mtime of a file has changed, we still examine the on-disk content
** to see whether or not the edit was a null-edit.
*/
void vfile_check_signature(int vid, int notFileIsFatal, int useSha1sum){
  int nErr = 0;
  Stmt q;
  Blob fileCksum, origCksum;

  int useMtime = useSha1sum==0 && db_get_boolean("mtime-changes", 1);

  db_begin_transaction();
  db_prepare(&q, "SELECT id, %Q || pathname,"
                 "       vfile.mrid, deleted, chnged, uuid, size, mtime"
                 "  FROM vfile LEFT JOIN blob ON vfile.mrid=blob.rid"
                 " WHERE vid=%d ", g.zLocalRoot, vid);
  while( db_step(&q)==SQLITE_ROW ){







>

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



|
|

















|



>
|







116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
  }
  db_finalize(&ridq);
  db_finalize(&ins);
  manifest_destroy(p);
  db_end_transaction(0);
}

#if INTERFACE
/*
** The cksigFlags parameter to vfile_check_signature() is an OR-ed
** combination of the following bits:
*/
#define CKSIG_ENOTFILE  0x001   /* non-file FS objects throw an error */
#define CKSIG_SHA1      0x002   /* Verify file content using sha1sum */
#define CKSIG_SETMTIME  0x004   /* Set mtime to last check-out time */

#endif /* INTERFACE */

/*
** Look at every VFILE entry with the given vid and update
** VFILE.CHNGED field according to whether or not
** the file has changed.  0 means no change.  1 means edited.  2 means
** the file has changed due to a merge.  3 means the file was added
** by a merge.
**
** If VFILE.DELETED is true or if VFILE.RID is zero, then the file was either
** removed from configuration management via "fossil rm" or added via
** "fossil add", respectively, and in both cases we always know that 
** the file has changed without having the check the size, mtime,
** or on-disk content.
**
** If the size of the file has changed, then we always know that the file
** changed without having to look at the mtime or on-disk content.
**
** The mtime of the file is only a factor if the mtime-changes setting
** is false and the useSha1sum flag is false.  If the mtime-changes
** setting is true (or undefined - it defaults to true) or if useSha1sum
** is true, then we do not trust the mtime and will examine the on-disk
** content to determine if a file really is the same.
**
** If the mtime is used, it is used only to determine if files are the same.
** If the mtime of a file has changed, we still examine the on-disk content
** to see whether or not the edit was a null-edit.
*/
void vfile_check_signature(int vid, unsigned int cksigFlags){
  int nErr = 0;
  Stmt q;
  Blob fileCksum, origCksum;
  int useMtime = (cksigFlags & CKSIG_SHA1)==0
                    && db_get_boolean("mtime-changes", 1);

  db_begin_transaction();
  db_prepare(&q, "SELECT id, %Q || pathname,"
                 "       vfile.mrid, deleted, chnged, uuid, size, mtime"
                 "  FROM vfile LEFT JOIN blob ON vfile.mrid=blob.rid"
                 " WHERE vid=%d ", g.zLocalRoot, vid);
  while( db_step(&q)==SQLITE_ROW ){
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
    currentSize = file_wd_size(zName);
    origSize = db_column_int64(&q, 6);
    currentMtime = file_wd_mtime(0);
    if( chnged==0 && (isDeleted || rid==0) ){
      /* "fossil rm" or "fossil add" always change the file */
      chnged = 1;
    }else if( !file_wd_isfile_or_link(0) && currentSize>=0 ){
      if( notFileIsFatal ){
        fossil_warning("not an ordinary file: %s", zName);
        nErr++;
      }
      chnged = 1;
    }
    if( origSize!=currentSize ){
      if( chnged!=1 ){







|







188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
    currentSize = file_wd_size(zName);
    origSize = db_column_int64(&q, 6);
    currentMtime = file_wd_mtime(0);
    if( chnged==0 && (isDeleted || rid==0) ){
      /* "fossil rm" or "fossil add" always change the file */
      chnged = 1;
    }else if( !file_wd_isfile_or_link(0) && currentSize>=0 ){
      if( cksigFlags & CKSIG_ENOTFILE ){
        fossil_warning("not an ordinary file: %s", zName);
        nErr++;
      }
      chnged = 1;
    }
    if( origSize!=currentSize ){
      if( chnged!=1 ){
215
216
217
218
219
220
221









222
223
224
225
226
227
228
        blob_zero(&fileCksum);
      }
      if( blob_compare(&fileCksum, &origCksum) ){
        chnged = 1;
      }
      blob_reset(&origCksum);
      blob_reset(&fileCksum);









    }
    if( currentMtime!=oldMtime || chnged!=oldChnged ){
      db_multi_exec("UPDATE vfile SET mtime=%lld, chnged=%d WHERE id=%d",
                    currentMtime, chnged, id);
    }
  }
  db_finalize(&q);







>
>
>
>
>
>
>
>
>







227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
        blob_zero(&fileCksum);
      }
      if( blob_compare(&fileCksum, &origCksum) ){
        chnged = 1;
      }
      blob_reset(&origCksum);
      blob_reset(&fileCksum);
    }
    if( (cksigFlags & CKSIG_SETMTIME) && (chnged==0 || chnged==2) ){
      i64 desiredMtime;
      if( mtime_of_manifest_file(vid,rid,&desiredMtime)==0 ){
        if( currentMtime!=desiredMtime ){
          file_set_mtime(zName, desiredMtime);
          currentMtime = file_wd_mtime(zName);
        }
      }
    }
    if( currentMtime!=oldMtime || chnged!=oldChnged ){
      db_multi_exec("UPDATE vfile SET mtime=%lld, chnged=%d WHERE id=%d",
                    currentMtime, chnged, id);
    }
  }
  db_finalize(&q);
358
359
360
361
362
363
364






































365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
    zFile = mprintf("%s/.fos", zPath);
    fileFound = file_size(zFile)>=1024;
    fossil_free(zFile);
  }
  return fileFound;
}








































/*
** Load into table SFILE the name of every ordinary file in
** the directory pPath.   Omit the first nPrefix characters of
** of pPath when inserting into the SFILE table.
**
** Subdirectories are scanned recursively.
** Omit files named in VFILE.
**
** Files whose names begin with "." are omitted unless allFlag is true.
**
** Any files or directories that match the glob pattern pIgnore are 
** excluded from the scan.  Name matching occurs after the first
** nPrefix characters are elided from the filename.
*/
void vfile_scan(Blob *pPath, int nPrefix, int allFlag, Glob *pIgnore){
  DIR *d;
  int origSize;
  const char *zDir;
  struct dirent *pEntry;
  int skipAll = 0;
  static Stmt ins;
  static int depth = 0;







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















|







379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
    zFile = mprintf("%s/.fos", zPath);
    fileFound = file_size(zFile)>=1024;
    fossil_free(zFile);
  }
  return fileFound;
}

/*
** Return TRUE if zFile is a temporary file.  Return FALSE if not.
*/
static int is_temporary_file(const char *zName){
  static const char *const azTemp[] = {
     "baseline",
     "merge",
     "original",
     "output",
  };
  int i, j, n;
  
  if( strglob("ci-comment-????????????.txt", zName) ) return 1;
  for(; zName[0]!=0; zName++){
    if( zName[0]=='/' && strglob("/ci-comment-????????????.txt", zName) ){
      return 1;
    }
    if( zName[0]!='-' ) continue;
    for(i=0; i<sizeof(azTemp)/sizeof(azTemp[0]); i++){
      n = (int)strlen(azTemp[i]);
      if( memcmp(azTemp[i], zName+1, n) ) continue;
      if( zName[n+1]==0 ) return 1;
      if( zName[n+1]=='-' ){
        for(j=n+2; zName[j] && fossil_isdigit(zName[j]); j++){}
        if( zName[j]==0 ) return 1;
      }
    }      
  }
  return 0;
}

#if INTERFACE
/*
** Values for the scanFlags parameter to vfile_scan().
*/
#define SCAN_ALL    0x001    /* Includes files that begin with "." */
#define SCAN_TEMP   0x002    /* Only Fossil-generated files like *-baseline */
#endif /* INTERFACE */

/*
** Load into table SFILE the name of every ordinary file in
** the directory pPath.   Omit the first nPrefix characters of
** of pPath when inserting into the SFILE table.
**
** Subdirectories are scanned recursively.
** Omit files named in VFILE.
**
** Files whose names begin with "." are omitted unless allFlag is true.
**
** Any files or directories that match the glob pattern pIgnore are 
** excluded from the scan.  Name matching occurs after the first
** nPrefix characters are elided from the filename.
*/
void vfile_scan(Blob *pPath, int nPrefix, unsigned scanFlags, Glob *pIgnore){
  DIR *d;
  int origSize;
  const char *zDir;
  struct dirent *pEntry;
  int skipAll = 0;
  static Stmt ins;
  static int depth = 0;
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428

429
430
431
432


433
434
435
436
437
438
439
  zMbcs = fossil_utf8_to_unicode(zDir);
  d = opendir(zMbcs);
  if( d ){
    while( (pEntry=readdir(d))!=0 ){
      char *zPath;
      char *zUtf8;
      if( pEntry->d_name[0]=='.' ){
        if( !allFlag ) continue;
        if( pEntry->d_name[1]==0 ) continue;
        if( pEntry->d_name[1]=='.' && pEntry->d_name[2]==0 ) continue;
      }
      zUtf8 = fossil_unicode_to_utf8(pEntry->d_name);
      blob_appendf(pPath, "/%s", zUtf8);
      fossil_mbcs_free(zUtf8);
      zPath = blob_str(pPath);
      if( glob_match(pIgnore, &zPath[nPrefix+1]) ){
        /* do nothing */
      }else if( file_wd_isdir(zPath)==1 ){
        if( !vfile_top_of_checkout(zPath) ){
          vfile_scan(pPath, nPrefix, allFlag, pIgnore);
        }
      }else if( file_wd_isfile_or_link(zPath) ){

        db_bind_text(&ins, ":file", &zPath[nPrefix+1]);
        db_step(&ins);
        db_reset(&ins);
      }


      blob_resize(pPath, origSize);
    }
    closedir(d);
  }
  fossil_mbcs_free(zMbcs);

  depth--;







|





<





|


>
|
|
|
|
>
>







466
467
468
469
470
471
472
473
474
475
476
477
478

479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
  zMbcs = fossil_utf8_to_unicode(zDir);
  d = opendir(zMbcs);
  if( d ){
    while( (pEntry=readdir(d))!=0 ){
      char *zPath;
      char *zUtf8;
      if( pEntry->d_name[0]=='.' ){
        if( (scanFlags & SCAN_ALL)==0 ) continue;
        if( pEntry->d_name[1]==0 ) continue;
        if( pEntry->d_name[1]=='.' && pEntry->d_name[2]==0 ) continue;
      }
      zUtf8 = fossil_unicode_to_utf8(pEntry->d_name);
      blob_appendf(pPath, "/%s", zUtf8);

      zPath = blob_str(pPath);
      if( glob_match(pIgnore, &zPath[nPrefix+1]) ){
        /* do nothing */
      }else if( file_wd_isdir(zPath)==1 ){
        if( !vfile_top_of_checkout(zPath) ){
          vfile_scan(pPath, nPrefix, scanFlags, pIgnore);
        }
      }else if( file_wd_isfile_or_link(zPath) ){
        if( (scanFlags & SCAN_TEMP)==0 || is_temporary_file(zUtf8) ){
          db_bind_text(&ins, ":file", &zPath[nPrefix+1]);
          db_step(&ins);
          db_reset(&ins);
        }
      }
      fossil_mbcs_free(zUtf8);
      blob_resize(pPath, origSize);
    }
    closedir(d);
  }
  fossil_mbcs_free(zMbcs);

  depth--;
Changes to src/xfer.c.
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
static int send_delta_parent(
  Xfer *pXfer,            /* The transfer context */
  int rid,                /* record id of the file to send */
  int isPrivate,          /* True if rid is a private artifact */
  Blob *pContent,         /* The content of the file to send */
  Blob *pUuid             /* The UUID of the file to send */
){
  static const char *azQuery[] = {
    "SELECT pid FROM plink x"
    " WHERE cid=%d"
    "   AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=pid)"
    "   AND NOT EXISTS(SELECT 1 FROM plink y"
                      " WHERE y.pid=x.cid AND y.cid=x.pid)",

    "SELECT pid FROM mlink x"







|







268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
static int send_delta_parent(
  Xfer *pXfer,            /* The transfer context */
  int rid,                /* record id of the file to send */
  int isPrivate,          /* True if rid is a private artifact */
  Blob *pContent,         /* The content of the file to send */
  Blob *pUuid             /* The UUID of the file to send */
){
  static const char *const azQuery[] = {
    "SELECT pid FROM plink x"
    " WHERE cid=%d"
    "   AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=pid)"
    "   AND NOT EXISTS(SELECT 1 FROM plink y"
                      " WHERE y.pid=x.cid AND y.cid=x.pid)",

    "SELECT pid FROM mlink x"